def _get_model(n, fixed_noise=False, use_octf=False, **tkwargs): train_x1, train_y1 = _get_random_data(batch_shape=torch.Size(), m=1, n=10, **tkwargs) train_x2, train_y2 = _get_random_data(batch_shape=torch.Size(), m=1, n=11, **tkwargs) octfs = [Standardize(m=1), Standardize(m=1)] if use_octf else [None, None] if fixed_noise: train_y1_var = 0.1 + 0.1 * torch.rand_like(train_y1, **tkwargs) train_y2_var = 0.1 + 0.1 * torch.rand_like(train_y2, **tkwargs) model1 = FixedNoiseGP( train_X=train_x1, train_Y=train_y1, train_Yvar=train_y1_var, outcome_transform=octfs[0], ) model2 = FixedNoiseGP( train_X=train_x2, train_Y=train_y2, train_Yvar=train_y2_var, outcome_transform=octfs[1], ) else: model1 = SingleTaskGP(train_X=train_x1, train_Y=train_y1, outcome_transform=octfs[0]) model2 = SingleTaskGP(train_X=train_x2, train_Y=train_y2, outcome_transform=octfs[1]) model = ModelListGP(model1, model2) return model.to(**tkwargs)
def fit_model(self): """ If no state_dict exists, fits the model and saves the state_dict. Otherwise, constructs the model but uses the fit given by the state_dict. """ # read the data data_list = list() for i in range(1, 31): data_file = os.path.join(script_dir, "port_evals", "port_n=100_seed=%d" % i) data_list.append(torch.load(data_file)) # join the data together X = torch.cat([data_list[i]["X"] for i in range(len(data_list))], dim=0).squeeze(-2) Y = torch.cat([data_list[i]["Y"] for i in range(len(data_list))], dim=0).squeeze(-2) # fit GP noise_prior = GammaPrior(1.1, 0.5) noise_prior_mode = (noise_prior.concentration - 1) / noise_prior.rate likelihood = GaussianLikelihood( noise_prior=noise_prior, batch_shape=[], noise_constraint=GreaterThan( 0.000005, # minimum observation noise assumed in the GP model transform=None, initial_value=noise_prior_mode, ), ) # We save the state dict to avoid fitting the GP every time which takes ~3 mins try: state_dict = torch.load( os.path.join(script_dir, "portfolio_surrogate_state_dict.pt")) model = SingleTaskGP(X, Y, likelihood, outcome_transform=Standardize(m=1)) model.load_state_dict(state_dict) except FileNotFoundError: model = SingleTaskGP(X, Y, likelihood, outcome_transform=Standardize(m=1)) mll = ExactMarginalLogLikelihood(model.likelihood, model) from time import time start = time() fit_gpytorch_model(mll) print("fitting took %s seconds" % (time() - start)) torch.save( model.state_dict(), os.path.join(script_dir, "portfolio_surrogate_state_dict.pt"), ) self.model = model
def fit_gp_model(self, arm: int, alternative: int = None, update: bool = False) -> None: """ Fits a GP model to the given arm :param arm: Arm index :param alternative: Last sampled arm alternative. Used when adding samples without refitting :param update: Forces GP to be fitted. Otherwise, it is fitted every self.gp_update_freq samples. :return: None """ arm_sample_count = sum([len(e) for e in self.observations[arm]]) if update or arm_sample_count % self.gp_update_freq == 0: train_X_list = list() train_Y_list = list() for j in range(len(self.alternative_points[arm])): for k in range(len(self.observations[arm][j])): train_X_list.append( self.alternative_points[arm][j].unsqueeze(-2)) train_Y_list.append( self.observations[arm][j][k].unsqueeze(-2)) train_X = torch.cat(train_X_list, dim=0) train_Y = torch.cat(train_Y_list, dim=0) if self.noise_std is None: model = SingleTaskGP(train_X, train_Y, outcome_transform=Standardize(m=1)) else: model = FixedNoiseGP( train_X, train_Y, train_Yvar=torch.tensor([self.noise_std**2 ]).expand_as(train_Y), outcome_transform=Standardize(m=1), ) mll = ExactMarginalLogLikelihood(model.likelihood, model) fit_gpytorch_model(mll) self.models[arm] = model else: last_point = self.alternative_points[arm][alternative].reshape( 1, -1) last_observation = self.observations[arm][alternative][-1].reshape( 1, -1) self.models[arm].condition_on_observations(last_point, last_observation, noise=self.noise_std**2)
def test_fantasize(self): for batch_shape, m, dtype, use_octf in itertools.product( (torch.Size(), torch.Size([2])), (1, 2), (torch.float, torch.double), (False, True), ): tkwargs = {"device": self.device, "dtype": dtype} octf = Standardize(m=m, batch_shape=batch_shape) if use_octf else None model, _ = self._get_model_and_data( batch_shape=batch_shape, m=m, outcome_transform=octf, **tkwargs ) # fantasize X_f = torch.rand(torch.Size(batch_shape + torch.Size([4, 1])), **tkwargs) sampler = SobolQMCNormalSampler(num_samples=3) fm = model.fantasize(X=X_f, sampler=sampler) self.assertIsInstance(fm, model.__class__) fm = model.fantasize(X=X_f, sampler=sampler, observation_noise=False) self.assertIsInstance(fm, model.__class__) # check that input transforms are applied to X. tkwargs = {"device": self.device, "dtype": torch.float} intf = Normalize(d=1, bounds=torch.tensor([[0], [10]], **tkwargs)) model, _ = self._get_model_and_data( batch_shape=torch.Size(), m=1, input_transform=intf, **tkwargs, ) X_f = torch.rand(4, 1, **tkwargs) fm = model.fantasize(X_f, sampler=SobolQMCNormalSampler(num_samples=3)) self.assertTrue( torch.allclose(fm.train_inputs[0][:, -4:], intf(X_f).expand(3, -1, -1)) )
def initialize_model(train_x, train_y, train_y_sem): """ Defines a GP given X, Y, and noise observations (standard error of mean) train_x (theta): (n_observations, n_parameters) train_y (G_obs): (n_observations, n_black_box_outputs) train_y (G_obs_sem): (n_observations, n_black_box_outputs) """ train_ynoise = train_y_sem.pow(2.0) # noise is in variance units # standardize outputs to zero mean, unit variance (over n_observations dimension) n_output_dims = (n_days * n_age if per_age_group_objective else n_days) \ if args.model_multi_output_simulator else 1 outcome_transform = Standardize(m=n_output_dims) # train_y = standardize(train_y) (the above also normalizes noise) # choose model if args.model_noise_via_sem: assert (args.model_multi_output_simulator) model = FixedNoiseGP(train_x, train_y, train_ynoise, outcome_transform=outcome_transform) else: model = SingleTaskGP(train_x, train_y, outcome_transform=outcome_transform) # "Loss" for GPs - the marginal log likelihood mll = ExactMarginalLogLikelihood(model.likelihood, model) return mll, model
def test_subset_model(self): for batch_shape, dtype, use_octf in itertools.product( (torch.Size(), torch.Size([2])), (torch.float, torch.double), (True, False)): tkwargs = {"device": self.device, "dtype": dtype} octf = Standardize(m=2, batch_shape=batch_shape) if use_octf else None model, model_kwargs = self._get_model_and_data( batch_shape=batch_shape, m=2, outcome_transform=octf, **tkwargs) subset_model = model.subset_output([0]) X = torch.rand(torch.Size(batch_shape + torch.Size([3, 1])), **tkwargs) p = model.posterior(X) p_sub = subset_model.posterior(X) self.assertTrue( torch.allclose(p_sub.mean, p.mean[..., [0]], atol=1e-4, rtol=1e-4)) self.assertTrue( torch.allclose(p_sub.variance, p.variance[..., [0]], atol=1e-4, rtol=1e-4))
def _initialize_model(self, num_init_samples: int) -> None: """ initialize the GP model with num_init_samples of initial samples """ self.train_X = torch.rand((num_init_samples, self.dim)) self.train_Y = self._function_call(self.train_X) self.model = SingleTaskGP( self.train_X, self.train_Y, outcome_transform=Standardize(m=1) ) mll = ExactMarginalLogLikelihood(self.model.likelihood, self.model) fit_gpytorch_model(mll)
def initialize_model(train_x, train_y, train_y_sem): """ Defines a GP given X, Y, and noise observations (standard error of mean) """ train_ynoise = train_y_sem.pow(2.0) # noise is in variance units # standardize outputs to zero mean, unit variance to have good hyperparameter tuning model = FixedNoiseGP(train_x, train_y, train_ynoise, outcome_transform=Standardize(m=n_days * n_age)) # "Loss" for GPs - the marginal log likelihood mll = ExactMarginalLogLikelihood(model.likelihood, model) return mll, model
def test_input_transforms(self): for infer_noise in [True, False]: tkwargs = {"device": self.device, "dtype": torch.double} train_X, train_Y, train_Yvar, test_X = self._get_unnormalized_data( infer_noise=infer_noise, **tkwargs ) n, d = train_X.shape lb, ub = train_X.min(dim=0).values, train_X.max(dim=0).values mu, sigma = train_Y.mean(), train_Y.std() # Fit without transforms with torch.random.fork_rng(): torch.manual_seed(0) gp1 = SaasFullyBayesianSingleTaskGP( train_X=(train_X - lb) / (ub - lb), train_Y=(train_Y - mu) / sigma, train_Yvar=train_Yvar / sigma ** 2 if train_Yvar is not None else train_Yvar, ) fit_fully_bayesian_model_nuts( gp1, warmup_steps=8, num_samples=5, thinning=2, disable_progbar=True ) posterior1 = gp1.posterior( (test_X - lb) / (ub - lb), marginalize_over_mcmc_samples=True ) pred_mean1 = mu + sigma * posterior1.mean pred_var1 = (sigma ** 2) * posterior1.variance # Fit with transforms with torch.random.fork_rng(): torch.manual_seed(0) gp2 = SaasFullyBayesianSingleTaskGP( train_X=train_X, train_Y=train_Y, train_Yvar=train_Yvar, input_transform=Normalize(d=train_X.shape[-1]), outcome_transform=Standardize(m=1), ) fit_fully_bayesian_model_nuts( gp2, warmup_steps=8, num_samples=5, thinning=2, disable_progbar=True ) posterior2 = gp2.posterior(test_X, marginalize_over_mcmc_samples=True) pred_mean2, pred_var2 = posterior2.mean, posterior2.variance self.assertTrue(torch.allclose(pred_mean1, pred_mean2)) self.assertTrue(torch.allclose(pred_var1, pred_var2))
def test_decoupled_sampler(self): # tests the sample shape to ensure everything is working for train_n, dim, test_n, sample_shape, num_basis, transform in [ [5, 1, 3, [1], 1, None], [20, 5, 15, [3, 5, 6], 5, Standardize(m=1)], ]: model = SingleTaskGP( torch.rand(train_n, dim), torch.rand(train_n, 1), # outcome_transform=transform, ) sampler = decoupled_sampler(model=model, sample_shape=sample_shape, num_basis=num_basis) test_X = torch.rand(test_n, dim) out = sampler(test_X) self.assertTupleEqual((*sample_shape, test_n, 1), tuple(out.shape))
def test_fantasize(self): for batch_shape, m, dtype, use_octf in itertools.product( (torch.Size(), torch.Size([2])), (1, 2), (torch.float, torch.double), (False, True), ): tkwargs = {"device": self.device, "dtype": dtype} octf = Standardize(m=m, batch_shape=batch_shape) if use_octf else None model, _ = self._get_model_and_data( batch_shape=batch_shape, m=m, outcome_transform=octf, **tkwargs ) # fantasize X_f = torch.rand(torch.Size(batch_shape + torch.Size([4, 1])), **tkwargs) sampler = SobolQMCNormalSampler(num_samples=3) fm = model.fantasize(X=X_f, sampler=sampler) self.assertIsInstance(fm, model.__class__) fm = model.fantasize(X=X_f, sampler=sampler, observation_noise=False) self.assertIsInstance(fm, model.__class__)
def generate_random_gp(dim: int, num_train: int, standardized: bool = True): r""" Returns a fitted gp trained on random input. Useful for testing purposes. Args: dim: Input dimension num_train: Number of training points standardized: If True, the train outcomes are standardized Returns: A fitted SingleTaskGP model """ if standardized: transform = Standardize(m=1) else: transform = None train_X = torch.rand(num_train, dim) train_Y = torch.rand(num_train, 1) model = SingleTaskGP(train_X, train_Y, outcome_transform=transform) mll = ExactMarginalLogLikelihood(model.likelihood, model) fit_gpytorch_model(mll) return model
def fit_gp(self) -> None: """ Re-fits the GP using the most up to date data. """ noise_prior = GammaPrior(1.1, 0.5) noise_prior_mode = (noise_prior.concentration - 1) / noise_prior.rate likelihood = GaussianLikelihood( noise_prior=noise_prior, batch_shape=[], noise_constraint=GreaterThan( # 0.000005, # minimum observation noise assumed in the GP model 0.0001, transform=None, initial_value=noise_prior_mode, ), ) self.model = SingleTaskGP( self.X, self.Y, likelihood, outcome_transform=Standardize(m=1) ) mll = ExactMarginalLogLikelihood(self.model.likelihood, self.model) fit_gpytorch_model(mll) # dummy computation to be safe with gp fit try: dummy = torch.rand( (1, self.q, self.dim), dtype=self.dtype, device=self.device ) _ = self.model.posterior(dummy).mean except RuntimeError as err: if self.fit_count < 5: self.fit_count += 1 self.Y = self.Y + torch.randn_like(self.Y) * 0.001 self.fit_gp() else: raise err self.fit_count = 0 self.passed = False
def test_gp(self): for batch_shape, m, dtype, use_octf in itertools.product( (torch.Size(), torch.Size([2])), (1, 2), (torch.float, torch.double), (False, True), ): tkwargs = {"device": self.device, "dtype": dtype} octf = Standardize(m=m, batch_shape=batch_shape) if use_octf else None model, _ = self._get_model_and_data(batch_shape=batch_shape, m=m, outcome_transform=octf, **tkwargs) mll = ExactMarginalLogLikelihood(model.likelihood, model).to(**tkwargs) with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=OptimizationWarning) fit_gpytorch_model(mll, options={"maxiter": 1}, max_retries=1) # test init self.assertIsInstance(model.mean_module, ConstantMean) self.assertIsInstance(model.covar_module, ScaleKernel) matern_kernel = model.covar_module.base_kernel self.assertIsInstance(matern_kernel, MaternKernel) self.assertIsInstance(matern_kernel.lengthscale_prior, GammaPrior) if use_octf: self.assertIsInstance(model.outcome_transform, Standardize) # test param sizes params = dict(model.named_parameters()) for p in params: self.assertEqual(params[p].numel(), m * torch.tensor(batch_shape).prod().item()) # test posterior # test non batch evaluation X = torch.rand(batch_shape + torch.Size([3, 1]), **tkwargs) expected_shape = batch_shape + torch.Size([3, m]) posterior = model.posterior(X) self.assertIsInstance(posterior, GPyTorchPosterior) self.assertEqual(posterior.mean.shape, expected_shape) self.assertEqual(posterior.variance.shape, expected_shape) # test adding observation noise posterior_pred = model.posterior(X, observation_noise=True) self.assertIsInstance(posterior_pred, GPyTorchPosterior) self.assertEqual(posterior_pred.mean.shape, expected_shape) self.assertEqual(posterior_pred.variance.shape, expected_shape) if use_octf: # ensure un-transformation is applied tmp_tf = model.outcome_transform del model.outcome_transform pp_tf = model.posterior(X, observation_noise=True) model.outcome_transform = tmp_tf expected_var = tmp_tf.untransform_posterior(pp_tf).variance self.assertTrue( torch.allclose(posterior_pred.variance, expected_var)) else: pvar = posterior_pred.variance pvar_exp = _get_pvar_expected(posterior, model, X, m) self.assertTrue( torch.allclose(pvar, pvar_exp, rtol=1e-4, atol=1e-5)) # test batch evaluation X = torch.rand(2, *batch_shape, 3, 1, **tkwargs) expected_shape = torch.Size([2]) + batch_shape + torch.Size([3, m]) posterior = model.posterior(X) self.assertIsInstance(posterior, GPyTorchPosterior) self.assertEqual(posterior.mean.shape, expected_shape) # test adding observation noise in batch mode posterior_pred = model.posterior(X, observation_noise=True) self.assertIsInstance(posterior_pred, GPyTorchPosterior) self.assertEqual(posterior_pred.mean.shape, expected_shape) if use_octf: # ensure un-transformation is applied tmp_tf = model.outcome_transform del model.outcome_transform pp_tf = model.posterior(X, observation_noise=True) model.outcome_transform = tmp_tf expected_var = tmp_tf.untransform_posterior(pp_tf).variance self.assertTrue( torch.allclose(posterior_pred.variance, expected_var)) else: pvar = posterior_pred.variance pvar_exp = _get_pvar_expected(posterior, model, X, m) self.assertTrue( torch.allclose(pvar, pvar_exp, rtol=1e-4, atol=1e-5))
def test_condition_on_observations(self): for batch_shape, m, dtype, use_octf in itertools.product( (torch.Size(), torch.Size([2])), (1, 2), (torch.float, torch.double), (False, True), ): tkwargs = {"device": self.device, "dtype": dtype} octf = Standardize(m=m, batch_shape=batch_shape) if use_octf else None model, model_kwargs = self._get_model_and_data( batch_shape=batch_shape, m=m, outcome_transform=octf, **tkwargs) # evaluate model model.posterior(torch.rand(torch.Size([4, 1]), **tkwargs)) # test condition_on_observations fant_shape = torch.Size([2]) # fantasize at different input points X_fant, Y_fant = _get_random_data(fant_shape + batch_shape, m, n=3, **tkwargs) c_kwargs = ({ "noise": torch.full_like(Y_fant, 0.01) } if isinstance(model, FixedNoiseGP) else {}) cm = model.condition_on_observations(X_fant, Y_fant, **c_kwargs) # fantasize at same input points (check proper broadcasting) c_kwargs_same_inputs = ({ "noise": torch.full_like(Y_fant[0], 0.01) } if isinstance(model, FixedNoiseGP) else {}) cm_same_inputs = model.condition_on_observations( X_fant[0], Y_fant, **c_kwargs_same_inputs) test_Xs = [ # test broadcasting single input across fantasy and model batches torch.rand(4, 1, **tkwargs), # separate input for each model batch and broadcast across # fantasy batches torch.rand(batch_shape + torch.Size([4, 1]), **tkwargs), # separate input for each model and fantasy batch torch.rand(fant_shape + batch_shape + torch.Size([4, 1]), **tkwargs), ] for test_X in test_Xs: posterior = cm.posterior(test_X) self.assertEqual(posterior.mean.shape, fant_shape + batch_shape + torch.Size([4, m])) posterior_same_inputs = cm_same_inputs.posterior(test_X) self.assertEqual( posterior_same_inputs.mean.shape, fant_shape + batch_shape + torch.Size([4, m]), ) # check that fantasies of batched model are correct if len(batch_shape) > 0 and test_X.dim() == 2: state_dict_non_batch = { key: (val[0] if val.numel() > 1 else val) for key, val in model.state_dict().items() } model_kwargs_non_batch = { "train_X": model_kwargs["train_X"][0], "train_Y": model_kwargs["train_Y"][0], } if "train_Yvar" in model_kwargs: model_kwargs_non_batch["train_Yvar"] = model_kwargs[ "train_Yvar"][0] if "outcome_transform" in model_kwargs: model_kwargs_non_batch[ "outcome_transform"] = Standardize(m=m) model_non_batch = type(model)(**model_kwargs_non_batch) model_non_batch.load_state_dict(state_dict_non_batch) model_non_batch.eval() model_non_batch.likelihood.eval() model_non_batch.posterior( torch.rand(torch.Size([4, 1]), **tkwargs)) c_kwargs = ({ "noise": torch.full_like(Y_fant[0, 0, :], 0.01) } if isinstance(model, FixedNoiseGP) else {}) cm_non_batch = model_non_batch.condition_on_observations( X_fant[0][0], Y_fant[:, 0, :], **c_kwargs) non_batch_posterior = cm_non_batch.posterior(test_X) self.assertTrue( torch.allclose( posterior_same_inputs.mean[:, 0, ...], non_batch_posterior.mean, atol=1e-3, )) self.assertTrue( torch.allclose( posterior_same_inputs.mvn. covariance_matrix[:, 0, :, :], non_batch_posterior.mvn.covariance_matrix, atol=1e-3, ))
def test_gp(self): for (iteration_fidelity, data_fidelity) in self.FIDELITY_TEST_PAIRS: num_dim = 1 + (iteration_fidelity is not None) + (data_fidelity is not None) for batch_shape, m, dtype, lin_trunc, use_octf in itertools.product( (torch.Size(), torch.Size([2])), (1, 2), (torch.float, torch.double), (False, True), (False, True), ): tkwargs = {"device": self.device, "dtype": dtype} octf = Standardize( m=m, batch_shape=batch_shape) if use_octf else None model, _ = _get_model_and_data( iteration_fidelity=iteration_fidelity, data_fidelity=data_fidelity, batch_shape=batch_shape, m=m, lin_truncated=lin_trunc, outcome_transform=octf, **tkwargs, ) mll = ExactMarginalLogLikelihood(model.likelihood, model) mll.to(**tkwargs) with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=OptimizationWarning) fit_gpytorch_model(mll, sequential=False, options={"maxiter": 1}) # test init self.assertIsInstance(model.mean_module, ConstantMean) self.assertIsInstance(model.covar_module, ScaleKernel) if use_octf: self.assertIsInstance(model.outcome_transform, Standardize) # test param sizes params = dict(model.named_parameters()) for p in params: self.assertEqual( params[p].numel(), m * torch.tensor(batch_shape).prod().item()) # test posterior # test non batch evaluation X = torch.rand(*batch_shape, 3, num_dim, **tkwargs) expected_shape = batch_shape + torch.Size([3, m]) posterior = model.posterior(X) self.assertIsInstance(posterior, GPyTorchPosterior) self.assertEqual(posterior.mean.shape, expected_shape) self.assertEqual(posterior.variance.shape, expected_shape) if use_octf: # ensure un-transformation is applied tmp_tf = model.outcome_transform del model.outcome_transform pp_tf = model.posterior(X) model.outcome_transform = tmp_tf expected_var = tmp_tf.untransform_posterior(pp_tf).variance self.assertTrue( torch.allclose(posterior.variance, expected_var)) # test batch evaluation X = torch.rand(2, *batch_shape, 3, num_dim, **tkwargs) expected_shape = torch.Size([2]) + batch_shape + torch.Size( [3, m]) posterior = model.posterior(X) self.assertIsInstance(posterior, GPyTorchPosterior) self.assertEqual(posterior.mean.shape, expected_shape) self.assertEqual(posterior.variance.shape, expected_shape) if use_octf: # ensure un-transformation is applied tmp_tf = model.outcome_transform del model.outcome_transform pp_tf = model.posterior(X) model.outcome_transform = tmp_tf expected_var = tmp_tf.untransform_posterior(pp_tf).variance self.assertTrue( torch.allclose(posterior.variance, expected_var))
def test_gpytorch_model(self): for dtype, use_octf in itertools.product((torch.float, torch.double), (False, True)): tkwargs = {"device": self.device, "dtype": dtype} octf = Standardize(m=1) if use_octf else None train_X = torch.rand(5, 1, **tkwargs) train_Y = torch.sin(train_X) # basic test model = SimpleGPyTorchModel(train_X, train_Y, octf) self.assertEqual(model.num_outputs, 1) self.assertEqual(model.batch_shape, torch.Size()) test_X = torch.rand(2, 1, **tkwargs) posterior = model.posterior(test_X) self.assertIsInstance(posterior, GPyTorchPosterior) self.assertEqual(posterior.mean.shape, torch.Size([2, 1])) if use_octf: # ensure un-transformation is applied tmp_tf = model.outcome_transform del model.outcome_transform p_tf = model.posterior(test_X) model.outcome_transform = tmp_tf expected_var = tmp_tf.untransform_posterior(p_tf).variance self.assertTrue( torch.allclose(posterior.variance, expected_var)) # test observation noise posterior = model.posterior(test_X, observation_noise=True) self.assertIsInstance(posterior, GPyTorchPosterior) self.assertEqual(posterior.mean.shape, torch.Size([2, 1])) posterior = model.posterior(test_X, observation_noise=torch.rand( 2, 1, **tkwargs)) self.assertIsInstance(posterior, GPyTorchPosterior) self.assertEqual(posterior.mean.shape, torch.Size([2, 1])) # test noise shape validation with self.assertRaises(BotorchTensorDimensionError): model.posterior(test_X, observation_noise=torch.rand(2, **tkwargs)) # test conditioning on observations cm = model.condition_on_observations(torch.rand(2, 1, **tkwargs), torch.rand(2, 1, **tkwargs)) self.assertIsInstance(cm, SimpleGPyTorchModel) self.assertEqual(cm.train_targets.shape, torch.Size([7])) # test subset_output with self.assertRaises(NotImplementedError): model.subset_output([0]) # test fantasize sampler = SobolQMCNormalSampler(num_samples=2) cm = model.fantasize(torch.rand(2, 1, **tkwargs), sampler=sampler) self.assertIsInstance(cm, SimpleGPyTorchModel) self.assertEqual(cm.train_targets.shape, torch.Size([2, 7])) cm = model.fantasize(torch.rand(2, 1, **tkwargs), sampler=sampler, observation_noise=True) self.assertIsInstance(cm, SimpleGPyTorchModel) self.assertEqual(cm.train_targets.shape, torch.Size([2, 7])) cm = model.fantasize( torch.rand(2, 1, **tkwargs), sampler=sampler, observation_noise=torch.rand(2, 1, **tkwargs), ) self.assertIsInstance(cm, SimpleGPyTorchModel) self.assertEqual(cm.train_targets.shape, torch.Size([2, 7]))
import torch from botorch.test_functions import Branin from botorch.models import SingleTaskGP from botorch.fit import fit_gpytorch_model from botorch.models.transforms import Standardize from gpytorch.mlls import ExactMarginalLogLikelihood from parametric_bandit.discrete_KG import DiscreteKGAlg torch.manual_seed(0) # generate input n = 10 noise_std = 0.1 function = Branin(noise_std=0.1) dim = function.dim train_X = torch.rand((n, dim)) train_Y = function(train_X).unsqueeze(-1) # fit model gp = SingleTaskGP(train_X, train_Y, outcome_transform=Standardize(m=1)) mll = ExactMarginalLogLikelihood(gp.likelihood, gp) fit_gpytorch_model(mll) # get mu and Sigma mu = gp.posterior(train_X).mean Sigma = gp.posterior(train_X).mvn.covariance_matrix # initiate the algorithm for testing dkg = DiscreteKGAlg(M=n, error=noise_std**2, mu_0=mu, Sigma_0=Sigma) print(dkg.find_maximizer())
def EI_run(seed, alpha, rho, x0=5, n0=100, iter_count=1000, mu_1=2, mu_2=5, sigma_1=1, sigma_2=1, SAA_seed=None): """ Does a single run of the Expected Improvement algorithm for the simple normal problem, without derivatives :param seed: random seed :param alpha: risk level :param rho: risk measure :param x0: Ignored! Just to keep the same arglist as others :param n0: outer sample starting size :param iter_count: number of iterations :param kwargs: passed to estimator :param SAA_seed: if given, an SAA version is run with this seed. :return: """ np.random.seed(seed) begin = datetime.datetime.now() args = (n0, alpha, rho, mu_1, mu_2, sigma_1, sigma_2, SAA_seed) points = torch.empty(iter_count, 1) values = torch.empty(points.shape) points[:4] = draw_sobol_samples(torch.tensor([[-5.], [5.]]), n=4, q=1).reshape(-1, 1) for i in range(4): values[i] = estimate_no_grad(points[i], *args) for i in range(4, iter_count): # fit gp # this transforms the GP to unit domain - botorch priors work best there transformed_points = points / 10. + 0.5 model = SingleTaskGP(transformed_points[:i], values[:i], outcome_transform=Standardize(m=1)) mll = ExactMarginalLogLikelihood(model.likelihood, model) fit_gpytorch_model(mll) # optimize EI to get the candidate acqf = ExpectedImprovement(model, best_f=torch.min(values), maximize=False) best_p, _ = optimize_acqf(acqf, bounds=torch.tensor([[0.], [1.]]), q=1, num_restarts=10, raw_samples=50) # transform it back to original domain best_p = best_p.detach() * 10. - 5. points[i] = best_p values[i] = estimate_no_grad(points[i], *args) best_list = torch.empty(points.shape) for i in range(1, iter_count + 1): # pick the arg min of the history to return best_ind = torch.argmin(values[:i], dim=0) best_list[i - 1] = points[best_ind] x_list = best_list now = datetime.datetime.now() print('done time: %s' % (now - begin)) print('call count: %d' % call_count) # np.save("sa_out/normal/EI_" + rho + "_" + str(alpha) + "_iter_" + str(iter_count) + "_x.npy", x_list) return x_list
def test_gp(self): d = 3 bounds = torch.tensor([[-1.0] * d, [1.0] * d]) for batch_shape, m, ncat, dtype in itertools.product( (torch.Size(), torch.Size([2])), (1, 2), (0, 1, 3), (torch.float, torch.double), ): tkwargs = {"device": self.device, "dtype": dtype} train_X, train_Y = _get_random_data( batch_shape=batch_shape, m=m, d=d, **tkwargs ) cat_dims = list(range(ncat)) # test unsupported options with self.assertRaises(UnsupportedError): MixedSingleTaskGP( train_X, train_Y, cat_dims=cat_dims, outcome_transform=Standardize(m=m, batch_shape=batch_shape), ) with self.assertRaises(UnsupportedError): MixedSingleTaskGP( train_X, train_Y, cat_dims=cat_dims, input_transform=Normalize( d=d, bounds=bounds.to(**tkwargs), transform_on_preprocess=True ), ) if len(cat_dims) == 0: with self.assertRaises(ValueError): MixedSingleTaskGP(train_X, train_Y, cat_dims=cat_dims) continue model = MixedSingleTaskGP(train_X, train_Y, cat_dims=cat_dims) mll = ExactMarginalLogLikelihood(model.likelihood, model).to(**tkwargs) with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=OptimizationWarning) fit_gpytorch_model(mll, options={"maxiter": 1}, max_retries=1) # test init self.assertIsInstance(model.mean_module, ConstantMean) if ncat < 3: self.assertIsInstance(model.covar_module, AdditiveKernel) sum_kernel, prod_kernel = model.covar_module.kernels self.assertIsInstance(sum_kernel, ScaleKernel) self.assertIsInstance(sum_kernel.base_kernel, AdditiveKernel) self.assertIsInstance(prod_kernel, ScaleKernel) self.assertIsInstance(prod_kernel.base_kernel, ProductKernel) sum_cont_kernel, sum_cat_kernel = sum_kernel.base_kernel.kernels prod_cont_kernel, prod_cat_kernel = prod_kernel.base_kernel.kernels self.assertIsInstance(sum_cont_kernel, MaternKernel) self.assertIsInstance(sum_cat_kernel, ScaleKernel) self.assertIsInstance(sum_cat_kernel.base_kernel, CategoricalKernel) self.assertIsInstance(prod_cont_kernel, MaternKernel) self.assertIsInstance(prod_cat_kernel, CategoricalKernel) else: self.assertIsInstance(model.covar_module, ScaleKernel) self.assertIsInstance(model.covar_module.base_kernel, CategoricalKernel) # test posterior # test non batch evaluation X = torch.rand(batch_shape + torch.Size([4, d]), **tkwargs) expected_shape = batch_shape + torch.Size([4, m]) posterior = model.posterior(X) self.assertIsInstance(posterior, GPyTorchPosterior) self.assertEqual(posterior.mean.shape, expected_shape) self.assertEqual(posterior.variance.shape, expected_shape) # test adding observation noise posterior_pred = model.posterior(X, observation_noise=True) self.assertIsInstance(posterior_pred, GPyTorchPosterior) self.assertEqual(posterior_pred.mean.shape, expected_shape) self.assertEqual(posterior_pred.variance.shape, expected_shape) pvar = posterior_pred.variance pvar_exp = _get_pvar_expected(posterior, model, X, m) self.assertTrue(torch.allclose(pvar, pvar_exp, rtol=1e-4, atol=1e-5)) # test batch evaluation X = torch.rand(2, *batch_shape, 3, d, **tkwargs) expected_shape = torch.Size([2]) + batch_shape + torch.Size([3, m]) posterior = model.posterior(X) self.assertIsInstance(posterior, GPyTorchPosterior) self.assertEqual(posterior.mean.shape, expected_shape) # test adding observation noise in batch mode posterior_pred = model.posterior(X, observation_noise=True) self.assertIsInstance(posterior_pred, GPyTorchPosterior) self.assertEqual(posterior_pred.mean.shape, expected_shape) pvar = posterior_pred.variance pvar_exp = _get_pvar_expected(posterior, model, X, m) self.assertTrue(torch.allclose(pvar, pvar_exp, rtol=1e-4, atol=1e-5))
rbounds[0] -= rdelta rbounds[1] += rdelta r_train_target = normalize(r_train, rbounds) train_kw_error = dict( train_x=x_train, train_y=r_train_target, n_inducing_points=500, tkwargs=tkwargs, init=True, scale=True, covar_name=ker_name, gp_file='', save_file=os.path.join(data_folder, f"{gp_recon_model_name_str}/gp.npz"), input_wp=inp_w, outcome_transform=Standardize(m=1) if transfo == 'standardize' else None, options={'lr': 1e-2, 'maxiter': 500} ) gp_recon_model = gp_torch_train(**train_kw_error) gp_recon_model.eval() # ======================================================================== # Test Models # ======================================================================== with torch.no_grad(): pred_r_train_mean = gp_recon_model.posterior(x_train).mean pred_r_train_std = gp_recon_model.posterior(x_train).variance.sqrt() pred_r_test_mean = gp_recon_model.posterior(x_val).mean pred_r_test_std = gp_recon_model.posterior(x_val).variance.sqrt()