pytorch / botorch

Bayesian optimization in PyTorch
https://botorch.org/
MIT License
3.11k stars 406 forks source link

Adding use examples and better documentation of expected inputs for synthetic functions #2039

Open DavidSiretMarques opened 1 year ago

DavidSiretMarques commented 1 year ago

🚀 Feature Request: Add use examples in synthetic functions

Example uses for functions in botorch.test_functions.synthetic

Motivation

Is your feature request related to a problem? Please describe.

I'm trying to do some benchmark testing for a project I'm working on, and I decided to understand first how the synthetic function module works and what and how it returns things. But I'm not able to do an Ackley 2-dimensional function plot. I've tried everything I can think about, giving it single values, trying with different sized tensors,... But I don't get how to use this function (or any other function in the module).

Pitch

Describe the solution you'd like

I think it would be useful for the docs to have a couple of examples for the functions in this module, with how they work and with that it would be easier to understand how to use them.

Describe alternatives you've considered

Alternatively, there could be a jupyter notebook where some of these functions are used, to show how they work

Are you willing to open a pull request? (See CONTRIBUTING) Sure, If I can understand how the function works...

Additional context

Balandat commented 1 year ago

Hey, sorry you're having trouble with this.

Not sure where you got stuck, but here is an example for how to use 2d Ackley:

import torch

from botorch.test_functions import Ackley

ack = Ackley(dim=2)

n = 5  # number of random locations to evaluate on

# Ackley is usually evaluated on [-32.768, 32.768]^d so we scale X to that
X = ack.bounds[0] + torch.rand(5, 2) * (ack.bounds[1] - ack.bounds[0])

f = ack(X)

f
tensor([21.0521, 19.9780, 20.2577, 21.0732, 21.8011], dtype=torch.float64)

You can also add a noise_std if you want the function to produce observations of the form f(X) + noise_std * eps, where eps is a standard normal RV.

We can add this to the docstring of the test functions module if that would be helpful.

DavidSiretMarques commented 1 year ago

That does help, thanks!

I've also found this code on how to plot the Ackley function with matplotlib:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from botorch.test_functions import Ackley
import torch  # Import PyTorch

# Initialize the Ackley function from BoTorch
ackley = Ackley(dim=2, negate=True)

# Generate X and Y coordinates
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)

# Create meshgrid
X, Y = np.meshgrid(x, y)

# Evaluate the Ackley function for each (x, y) pair
Z = np.zeros_like(X)
for i in range(X.shape[0]):
    for j in range(X.shape[1]):
        Z[i, j] = ackley.evaluate_true(torch.tensor([[X[i, j], Y[i, j]]], dtype=torch.float))

# Create plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# Plot surface
ax.plot_surface(X, Y, Z, cmap='viridis')

# Set labels and title
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('Ackley Function')

# Show plot
plt.show()

And it's helping me a lot understanding how the function works.

I thought of either creating a notebook with this code (and maybe other use cases for other functions) and linking that in the docs, or just adding the code snippet you passed.

The point being to give a simple example on how to call the function and which dimensions (of the X tensor) will be interpreted by the function as number of points and which ones as dimensions for the evaluation of the d-dimensional function

DavidSiretMarques commented 1 year ago

I spent a good part of yesterday trying to understand why if I gave Ackley 2 vectors with 5 points each (like [1,2,3,4,5]) it only returned 2 numbers, instead of 5.

Just to be clear, I was doing

Ackley([[1,2,3,4,5],
        [1,2,3,4,5]])

And this returned only 2 points, instead of the 5 i was expecting... @_@

DavidSiretMarques commented 1 year ago

In any case, even if not everything is done, I think you should specify the shape of the tensor to feed the evaluate_true(X) method. Saying in the docs that X should have shape dim x n-points would be really helpful to any person trying to use the function (I might have it wrong and the tensor should be the other way around, but I think the point is clear anyway...)