Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Batch evaluation of fantasy models #1712

Closed
JackBuck opened this issue Mar 1, 2023 · 3 comments
Closed

[Question] Batch evaluation of fantasy models #1712

JackBuck opened this issue Mar 1, 2023 · 3 comments
Labels
bug Something isn't working

Comments

@JackBuck
Copy link

JackBuck commented Mar 1, 2023

🐛 Bug / Question

I am unsure whether this is me misunderstanding how batch dimensions work, or if there is a bug somewhere. I would like to evaluate the mean of a batch of points on a model generated by fantasize. I am using the PosteriorMean class but it is raising errors on a dimension check.

As I understand things, calling .fantasize on a SingleTaskGP creates a batched model, say with batch_dimension = (num_fantasies, 1). If I want to evaluate each fantasy GP on the same batch of inputs, I need to call .posterior with an input of shape b1 x ... x bk x 1 x 1 x m x d where:

  • b1 x ... x bk is the batch dimension of the points I wish to evaluate,
  • the 1s give space for the batch dimensions of the fantasy model,
  • m is the number of points to evaluate jointly,
  • d is the dimension of the input space.

I got this understanding from the documentation here: https://botorch.org/docs/batching#batched-evaluation-of-models-and-acquisition-functions

Doing the above experiment, the dimensions do appear to work like this. However, the PosteriorMean class complains about the dimensions through its t_batch_mode_transform decorator and I do not understand why. See the following example.

To reproduce

import torch
from botorch.acquisition import PosteriorMean
from botorch.models import SingleTaskGP
from botorch.sampling import SobolQMCNormalSampler


if __name__ == "__main__":
    train_x = torch.cartesian_prod(  # 20 x 2
        torch.linspace(0, 1, 4),
        torch.linspace(0, 1, 5)
    )
    train_y = torch.randn(20, 1)  # 20 x 1
    model = SingleTaskGP(train_x, train_y)  # batch_shape = []

    fantasy_x = torch.tensor([[[0.5, 0.6]]])  # 1x1x2 (t-batch = 1, q-batch=1)
    sampler = SobolQMCNormalSampler(sample_shape=torch.Size([7]))  # 7 fantasy samples
    fantasy_model = model.fantasize(fantasy_x, sampler) 
    # fantasy_model has batch_shape = 7 x 1 (with the 1 coming from the t-batch shape of the training data)

    # Evaluation batch shape 3x3 => 3x3xmxd where m=1, d=2
    test_x = torch.rand(3, 3, 1, 2)
    # Add in the fantasy batch shape so that they are broadcastable
    fantasy_batch_dim = len(fantasy_model.batch_shape)
    test_x = test_x.reshape(
        test_x.shape[:-2] + fantasy_batch_dim * (1,) + test_x.shape[-2:]
    )
    # test_x now has shape 3x3x1x1xmxd with m=1, d=2
    value_function = PosteriorMean(fantasy_model)
    posterior_mean = value_function(test_x)
    # ^^ This line blows up
AssertionError: Expected the output shape to match either the t-batch shape of X, or the
    `model.batch_shape` in the case of acquisition functions using batch models; but got
    output with shape torch.Size([3, 3, 7, 1]) for X with shape
    torch.Size([3, 3, 1, 1, 1, 2]).

Expected Behavior

The output of shape (3, 3, 7, 1) makes sense to me, since it is what you get when you concatenate (3, 3) (the batch dimension of the inputs) with (7, 1) the batch dimension of the fantasy model. I would expect no error. However, I am unsure whether I have correctly understood all the conventions around batch dimensions here.

System information

Please complete the following information:

  • BoTorch Version: 0.8.1
  • GPyTorch Version: 1.9.1
  • PyTorch Version: 1.13.1+cpu
  • Python version: 3.10.9
  • Computer OS: Ubuntu 20.04.5 LTS
@JackBuck JackBuck added the bug Something isn't working label Mar 1, 2023
@saitcakmak
Copy link
Contributor

Hi @JackBuck. Thanks for flagging this and the nice repro. Looks like we check equality of the shapes rather than broadcastability. For now, you can get around the issue by expanding the model batch dimensions.

test_x = test_x.reshape(
    test_x.shape[:-2] + fantasy_batch_dim * (1,) + test_x.shape[-2:]
).expand(test_x.shape[:-2] + fantasy_model.batch_shape + test_x.shape[-2:])
# This will be 3 x 3 x 7 x 1 x 1 x 2

@JackBuck
Copy link
Author

JackBuck commented Mar 1, 2023

Ahh that's what's going on. Thanks - works a treat!

saitcakmak added a commit to saitcakmak/botorch that referenced this issue Mar 1, 2023
Summary: Previously, this would error out if X was getting broadcasted to the model batch shape. Fixes pytorch#1712

Differential Revision: D43708320

fbshipit-source-id: cdbba22dff686707af26bf24d8711548bf890152
@saitcakmak
Copy link
Contributor

#1715 should fix this for good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants