def __init__( self, lb, ub, restarts=10, samps=1000, dim=1, acqf=None, extra_acqf_args=None, model=None, ): if extra_acqf_args is None: extra_acqf_args = {} super().__init__(lb=lb, ub=ub, dim=dim, acqf=acqf, extra_acqf_args=extra_acqf_args) self.restarts = restarts self.samps = samps self.likelihood = gpytorch.likelihoods.BernoulliLikelihood() if model is None: self.model = GPClassificationModel(inducing_min=self.lb, inducing_max=self.ub) else: self.model = model
def test_1d_classification(self): """ Just see if we memorize the training set """ X, y = self.X, self.y model = GPClassificationModel( torch.Tensor([-3]), torch.Tensor([3]), inducing_size=10 ) model.fit(X[:50], y[:50]) # pspace pm, _ = model.predict(X[:50], probability_space=True) pred = (pm > 0.5).numpy() npt.assert_allclose(pred, y[:50]) # fspace pm, _ = model.predict(X[:50], probability_space=False) pred = (pm > 0).numpy() npt.assert_allclose(pred, y[:50]) # smoke test update model.update(X, y) # pspace pm, _ = model.predict(X, probability_space=True) pred = (pm > 0.5).numpy() npt.assert_allclose(pred, y) # fspace pm, _ = model.predict(X, probability_space=False) pred = (pm > 0).numpy() npt.assert_allclose(pred, y)
def test_dim_grid_model_size(self): lb = -4.0 ub = 4.0 dim = 1 gridsize = 10 mb = GPClassificationModel(lb=lb, ub=ub, dim=dim) grid = GPClassificationModel.dim_grid(mb, gridsize=gridsize) self.assertEqual(grid.shape, torch.Size([10, 1]))
def test_reset_variational_strategy(self): model = GPClassificationModel(lb=[-3], ub=[3], inducing_size=20) variational_params_before = [ v.clone().detach().numpy() for v in model.variational_parameters() ] induc_before = model.variational_strategy.inducing_points model.fit(torch.Tensor(self.X), torch.Tensor(self.y)) variational_params_after = [ v.clone().detach().numpy() for v in model.variational_parameters() ] induc_after = model.variational_strategy.inducing_points model._reset_variational_strategy() variational_params_reset = [ v.clone().detach().numpy() for v in model.variational_parameters() ] induc_reset = model.variational_strategy.inducing_points # before should be different from after and after should be different # from reset self.assertFalse(np.allclose(induc_before, induc_after)) self.assertFalse(np.allclose(induc_after, induc_reset)) for before, after in zip(variational_params_before, variational_params_after): self.assertFalse(np.allclose(before, after)) for after, reset in zip(variational_params_after, variational_params_reset): self.assertFalse(np.allclose(after, reset))
def test_time_limits(self): seed = 1 torch.manual_seed(seed) np.random.seed(seed) X, y = make_classification( n_samples=100, n_features=8, n_redundant=3, n_informative=5, random_state=1, n_clusters_per_class=4, ) X, y = torch.Tensor(X), torch.Tensor(y) model = GPClassificationModel( lb=-3 * torch.ones(8), ub=3 * torch.ones(8), max_fit_time=0.5, inducing_size=10, ) model.fit(X, y) generator = OptimizeAcqfGenerator(acqf=MCLevelSetEstimation, acqf_kwargs={ "beta": 1.96, "target": 0.5 }) start = time.time() generator.gen(1, model) end = time.time() long = end - start generator = OptimizeAcqfGenerator( acqf=MCLevelSetEstimation, acqf_kwargs={ "beta": 1.96, "target": 0.5 }, max_gen_time=0.1, ) start = time.time() generator.gen(1, model) end = time.time() short = end - start # very loose test because fit time is only approximately computed self.assertTrue(long > short)
def test_mi_acqf(self): mean = ConstantMean().initialize(constant=1.2) covar = LinearKernel().initialize(variance=1.0) model = GPClassificationModel( inducing_min=torch.Tensor([0]), inducing_max=torch.Tensor([1]), inducing_size=10, mean_module=mean, covar_module=covar, ) x = torch.rand(size=(10, 1)) acqf = BernoulliMCMutualInformation(model=model, objective=ProbitObjective()) acq_pytorch = acqf(x) samps_numpy = norm.cdf( multivariate_normal.rvs(mean=np.ones(10) * 1.2, cov=x @ x.T, size=10000) ) samp_entropies = bernoulli(samps_numpy).entropy() mean_entropy = bernoulli(samps_numpy.mean(axis=0)).entropy() acq_numpy = mean_entropy - samp_entropies.mean(axis=0) # this assertion fails, not sure why, these should be equal to numerical # precision # self.assertTrue(np.allclose(acq_numpy, acq_pytorch.detach().numpy().flatten())) # this one succeeds self.assertTrue( pearsonr(acq_numpy, acq_pytorch.detach().numpy().flatten())[0] > (1 - 1e-5) )
def test_1d_query(self): seed = 1 torch.manual_seed(seed) np.random.seed(seed) n_init = 150 n_opt = 1 lb = -4.0 ub = 4.0 target = 0.5 def obj(x): return -((Normal(0, 1).cdf(x[..., 0]) - target) ** 2) # Test sine function with period 4 def test_fun(x): return np.sin(np.pi * x / 4) strat_list = [ Strategy( lb=lb, ub=ub, n_trials=n_init, generator=SobolGenerator(lb=lb, ub=ub, seed=seed), ), Strategy( lb=lb, ub=ub, model=GPClassificationModel(lb=lb, ub=ub, inducing_size=10), generator=OptimizeAcqfGenerator( qUpperConfidenceBound, acqf_kwargs={"beta": 1.96, "objective": GenericMCObjective(obj)}, ), n_trials=n_opt, ), ] strat = SequentialStrategy(strat_list) for _i in range(n_init + n_opt): next_x = strat.gen() strat.add_data(next_x, [bernoulli.rvs(norm.cdf(test_fun(next_x)))]) # We expect the global max to be at (2, 1), the min at (-2, -1) fmax, argmax = strat.get_max() self.assertTrue(np.abs(fmax - 1) < 0.5) self.assertTrue(np.abs(argmax[0] - 2) < 0.5) fmin, argmin = strat.get_min() self.assertTrue(np.abs(fmin + 1) < 0.5) self.assertTrue(np.abs(argmin[0] + 2) < 0.5) # Query at x=2 should be f=1 self.assertTrue(np.abs(strat.predict(torch.tensor([2]))[0] - 1) < 0.5) # Inverse query at val 1 should return (1,[2]) val, loc = strat.inv_query(1.0, constraints={}) self.assertTrue(np.abs(val - 1) < 0.5) self.assertTrue(np.abs(loc[0] - 2) < 0.5)
def test_1d_classification_different_scales(self): """ Just see if we memorize the training set """ np.random.seed(1) torch.manual_seed(1) X, y = make_classification( n_features=2, n_redundant=0, n_informative=1, random_state=1, n_clusters_per_class=1, ) X, y = torch.Tensor(X), torch.Tensor(y) X[:, 0] = X[:, 0] * 1000 X[:, 1] = X[:, 1] / 1000 lb = [-3000, -0.003] ub = [3000, 0.003] model = GPClassificationModel(lb=lb, ub=ub, inducing_size=20) model.fit(X[:50], y[:50]) # pspace pm, _ = model.predict(X[:50], probability_space=True) pred = (pm > 0.5).numpy() npt.assert_allclose(pred, y[:50]) # fspace pm, _ = model.predict(X[:50], probability_space=False) pred = (pm > 0).numpy() npt.assert_allclose(pred, y[:50]) # smoke test update model.update(X, y) # pspace pm, _ = model.predict(X, probability_space=True) pred = (pm > 0.5).numpy() npt.assert_allclose(pred, y) # fspace pm, _ = model.predict(X, probability_space=False) pred = (pm > 0).numpy() npt.assert_allclose(pred, y)
def test_1d_jnd(self): seed = 1 torch.manual_seed(seed) np.random.seed(seed) n_init = 150 n_opt = 1 lb = -4.0 ub = 4.0 target = 0.5 def obj(x): return -((Normal(0, 1).cdf(x[..., 0]) - target) ** 2) strat_list = [ Strategy( lb=lb, ub=ub, n_trials=n_init, generator=SobolGenerator(lb=lb, ub=ub, seed=seed), ), Strategy( lb=lb, ub=ub, model=GPClassificationModel(lb=lb, ub=ub, inducing_size=10), generator=OptimizeAcqfGenerator( qUpperConfidenceBound, acqf_kwargs={"beta": 1.96} ), n_trials=n_opt, ), ] strat = SequentialStrategy(strat_list) for _i in range(n_init + n_opt): next_x = strat.gen() strat.add_data(next_x, [bernoulli.rvs(norm.cdf(next_x / 1.5))]) x = torch.linspace(-4, 4, 100) zhat, _ = strat.predict(x) # we expect jnd close to the target to be close to the correct # jnd (1.5), and since this is linear model this should be true # for both definitions of JND jnd_step = strat.get_jnd(grid=x[:, None], method="step") est_jnd_step = jnd_step[50] # looser test because step-jnd is hurt more by reverting to the mean self.assertTrue(np.abs(est_jnd_step - 1.5) < 0.5) jnd_taylor = strat.get_jnd(grid=x[:, None], method="taylor") est_jnd_taylor = jnd_taylor[50] self.assertTrue(np.abs(est_jnd_taylor - 1.5) < 0.25)
def test_hyperparam_consistency(self): # verify that creating the model `from_config` or with `__init__` has the same hyperparams m1 = GPClassificationModel(lb=[1, 2], ub=[3, 4]) m2 = GPClassificationModel.from_config( config=Config(config_dict={"common": {"lb": "[1,2]", "ub": "[3,4]"}}) ) self.assertTrue(isinstance(m1.covar_module, type(m2.covar_module))) self.assertTrue( isinstance(m1.covar_module.base_kernel, type(m2.covar_module.base_kernel)) ) self.assertTrue(isinstance(m1.mean_module, type(m2.mean_module))) m1priors = list(m1.covar_module.named_priors()) m2priors = list(m2.covar_module.named_priors()) for p1, p2 in zip(m1priors, m2priors): name1, parent1, prior1, paramtransforms1, priortransforms1 = p1 name2, parent2, prior2, paramtransforms2, priortransforms2 = p2 self.assertTrue(name1 == name2) self.assertTrue(isinstance(parent1, type(parent2))) self.assertTrue(isinstance(prior1, type(prior2)))
def test_1d_classification(self): """ Just see if we memorize the training set """ np.random.seed(1) torch.manual_seed(1) X, y = make_classification( n_features=1, n_redundant=0, n_informative=1, random_state=1, n_clusters_per_class=1, ) X, y = torch.Tensor(X), torch.Tensor(y) model = GPClassificationModel(torch.Tensor([-3]), torch.Tensor([3])) model.set_train_data(X, y) likelihood = gpytorch.likelihoods.BernoulliLikelihood() mll = gpytorch.mlls.VariationalELBO(likelihood, model, 100) fit_gpytorch_model(mll) pred = (torch.sigmoid(model.posterior(X).mean) > 0.5).numpy() npt.assert_allclose(pred[:, 0], y)
def test_1d_single_targeting(self): seed = 1 torch.manual_seed(seed) np.random.seed(seed) n_init = 50 n_opt = 1 lb = -4.0 ub = 4.0 target = 0.75 def obj(x): return -((Normal(0, 1).cdf(x[..., 0]) - target) ** 2) strat_list = [ Strategy( lb=lb, ub=ub, n_trials=n_init, generator=SobolGenerator(lb=lb, ub=ub, seed=seed), ), Strategy( lb=lb, ub=ub, model=GPClassificationModel(lb=lb, ub=ub, inducing_size=10), generator=OptimizeAcqfGenerator( qUpperConfidenceBound, acqf_kwargs={"beta": 1.96} ), n_trials=n_opt, ), ] strat = SequentialStrategy(strat_list) for _i in range(n_init + n_opt): next_x = strat.gen() strat.add_data(next_x, [bernoulli.rvs(norm.cdf(next_x))]) x = torch.linspace(-4, 4, 100) zhat, _ = strat.predict(x) # since target is 0.75, find the point at which f_est is 0.75 est_max = x[np.argmin((norm.cdf(zhat.detach().numpy()) - 0.75) ** 2)] # since true z is just x, the true max is where phi(x)=0.75, self.assertTrue(np.abs(est_max - norm.ppf(0.75)) < 0.5)
def test_1d_single_probit_pure_exploration(self): seed = 1 torch.manual_seed(seed) np.random.seed(seed) n_init = 50 n_opt = 1 lb = -4.0 ub = 4.0 strat_list = [ Strategy( lb=lb, ub=ub, n_trials=n_init, generator=SobolGenerator(lb=lb, ub=ub, seed=seed), ), Strategy( lb=lb, ub=ub, model=GPClassificationModel(lb=lb, ub=ub, inducing_size=10), generator=OptimizeAcqfGenerator( qUpperConfidenceBound, acqf_kwargs={"beta": 1.96} ), n_trials=n_opt, ), ] strat = SequentialStrategy(strat_list) for _i in range(n_init + n_opt): next_x = strat.gen() strat.add_data(next_x, [bernoulli.rvs(norm.cdf(next_x))]) x = torch.linspace(-4, 4, 100) zhat, _ = strat.predict(x) # f(x) = x so we're just looking at corr between cdf(zhat) and cdf(x) self.assertTrue( pearsonr(norm.cdf(zhat.detach().numpy()).flatten(), norm.cdf(x).flatten())[ 0 ] > 0.95 )
def test_1d_single_lse(self): seed = 1 torch.manual_seed(seed) np.random.seed(seed) n_init = 50 n_opt = 1 lb = -4.0 ub = 4.0 # target is in z space not phi(z) space, maybe that's # weird extra_acqf_args = {"target": 0.75, "beta": 1.96} strat_list = [ Strategy( lb=lb, ub=ub, n_trials=n_init, generator=SobolGenerator(lb=lb, ub=ub, seed=seed), ), Strategy( lb=lb, ub=ub, model=GPClassificationModel(lb=lb, ub=ub, inducing_size=10), n_trials=n_opt, generator=OptimizeAcqfGenerator( MCLevelSetEstimation, acqf_kwargs=extra_acqf_args ), ), ] strat = SequentialStrategy(strat_list) for _i in range(n_init + n_opt): next_x = strat.gen() strat.add_data(next_x, [bernoulli.rvs(norm.cdf(next_x))]) x = torch.linspace(-4, 4, 100) zhat, _ = strat.predict(x) # since target is 0.75, find the point at which f_est is 0.75 est_max = x[np.argmin((norm.cdf(zhat.detach().numpy()) - 0.75) ** 2)] # since true z is just x, the true max is where phi(x)=0.75, self.assertTrue(np.abs(est_max - norm.ppf(0.75)) < 0.5)
def from_config(cls, config): classname = cls.__name__ model = GPClassificationModel.from_config(config) lb = config.gettensor(classname, "lb") ub = config.gettensor(classname, "ub") restarts = config.getint(classname, "restarts", fallback=10) samps = config.getint(classname, "samps", fallback=1000) assert lb.shape[0] == ub.shape[0], "bounds are of different shapes!" dim = lb.shape[0] acqf = config.getobj("experiment", "acqf", fallback=MCLevelSetEstimation) acqf_name = acqf.__name__ default_extra_acqf_args = { "beta": 3.98, "target": 0.75, "objective": ProbitObjective, } extra_acqf_args = { k: config.getobj(acqf_name, k, fallback_type=float, fallback=v, warn=False) for k, v in default_extra_acqf_args.items() } extra_acqf_args = _prune_extra_acqf_args(acqf, extra_acqf_args) if ("objective" in extra_acqf_args.keys() and extra_acqf_args["objective"] is not None): extra_acqf_args["objective"] = extra_acqf_args["objective"]() return cls( lb=lb, ub=ub, restarts=restarts, samps=samps, dim=dim, acqf=acqf, model=model, extra_acqf_args=extra_acqf_args, )
def test_1d_single_probit(self): seed = 1 torch.manual_seed(seed) np.random.seed(seed) n_init = 15 n_opt = 20 lb = -4.0 ub = 4.0 acqf = BernoulliMCMutualInformation extra_acqf_args = {"objective": ProbitObjective()} model_list = [ Strategy( lb=lb, ub=ub, n_trials=n_init, generator=SobolGenerator(lb=lb, ub=ub, seed=seed), ), Strategy( lb=lb, ub=ub, model=GPClassificationModel(lb=lb, ub=ub, dim=1, inducing_size=10), generator=OptimizeAcqfGenerator(acqf, extra_acqf_args), n_trials=n_opt, ), ] strat = SequentialStrategy(model_list) for _i in range(n_init + n_opt): next_x = strat.gen() strat.add_data(next_x, [bernoulli.rvs(f_1d(next_x))]) x = torch.linspace(-4, 4, 100) zhat, _ = strat.predict(x) true = f_1d(x.detach().numpy()) est = zhat.detach().numpy() # close enough! self.assertTrue((((norm.cdf(est) - true) ** 2).mean()) < 0.25)
def test_2d_single_probit_pure_exploration(self): seed = 1 torch.manual_seed(seed) np.random.seed(seed) n_init = 50 n_opt = 1 lb = [-1, -1] ub = [1, 1] strat_list = [ Strategy( lb=lb, ub=ub, n_trials=n_init, generator=SobolGenerator(lb=lb, ub=ub, seed=seed), ), Strategy( lb=lb, ub=ub, model=GPClassificationModel(lb=lb, ub=ub, inducing_size=10), generator=OptimizeAcqfGenerator( qUpperConfidenceBound, acqf_kwargs={"beta": 1.96} ), n_trials=n_opt, ), ] strat = SequentialStrategy(strat_list) for _i in range(n_init + n_opt): next_x = strat.gen() strat.add_data(next_x, [bernoulli.rvs(cdf_new_novel_det(next_x))]) xy = np.mgrid[-1:1:30j, -1:1:30j].reshape(2, -1).T post_mean, _ = strat.predict(torch.Tensor(xy)) phi_post_mean = norm.cdf(post_mean.reshape(30, 30).detach().numpy()) phi_post_true = cdf_new_novel_det(xy) self.assertTrue( pearsonr(phi_post_mean.flatten(), phi_post_true.flatten())[0] > 0.9 )
def test_1d_single_probit_new_interface(self): seed = 1 torch.manual_seed(seed) np.random.seed(seed) n_init = 50 n_opt = 1 lb = -4.0 ub = 4.0 model_list = [ Strategy( lb=lb, ub=ub, n_trials=n_init, generator=SobolGenerator(lb=lb, ub=ub, seed=seed), ), Strategy( lb=lb, ub=ub, model=GPClassificationModel(lb=lb, ub=ub, inducing_size=10), generator=OptimizeAcqfGenerator( qUpperConfidenceBound, acqf_kwargs={"beta": 1.96} ), n_trials=n_opt, ), ] strat = SequentialStrategy(model_list) while not strat.finished: next_x = strat.gen() strat.add_data(next_x, [bernoulli.rvs(f_1d(next_x))]) self.assertTrue(strat.y.shape[0] == n_init + n_opt) x = torch.linspace(-4, 4, 100) zhat, _ = strat.predict(x) # true max is 0, very loose test self.assertTrue(np.abs(x[np.argmax(zhat.detach().numpy())]) < 0.5)
def test_2d_single_probit(self): seed = 1 torch.manual_seed(seed) np.random.seed(seed) n_init = 150 n_opt = 1 lb = [-1, -1] ub = [1, 1] strat_list = [ Strategy( lb=lb, ub=ub, n_trials=n_init, generator=SobolGenerator(lb=lb, ub=ub, seed=seed), ), Strategy( lb=lb, ub=ub, model=GPClassificationModel(lb=lb, ub=ub, inducing_size=20), generator=OptimizeAcqfGenerator( qUpperConfidenceBound, acqf_kwargs={"beta": 1.96} ), n_trials=n_opt, ), ] strat = SequentialStrategy(strat_list) for _i in range(n_init + n_opt): next_x = strat.gen() strat.add_data(next_x, [bernoulli.rvs(f_2d(next_x[None, :]))]) xy = np.mgrid[-1:1:30j, -1:1:30j].reshape(2, -1).T zhat, _ = strat.predict(torch.Tensor(xy)) self.assertTrue(np.all(np.abs(xy[np.argmax(zhat.detach().numpy())]) < 0.5))
def test_extra_ask_warns(self): # test that when we ask more times than we have models, we warn but keep going seed = 1 torch.manual_seed(seed) np.random.seed(seed) n_init = 3 n_opt = 1 lb = -4.0 ub = 4.0 model_list = [ Strategy( lb=lb, ub=ub, n_trials=n_init, generator=SobolGenerator(lb=lb, ub=ub, seed=seed), ), Strategy( lb=lb, ub=ub, model=GPClassificationModel(lb=lb, ub=ub, inducing_size=10), generator=OptimizeAcqfGenerator( qUpperConfidenceBound, acqf_kwargs={"beta": 1.96} ), n_trials=n_opt, ), ] strat = SequentialStrategy(model_list) for _i in range(n_init + n_opt): next_x = strat.gen() strat.add_data(next_x, [bernoulli.rvs(norm.cdf(f_1d(next_x)))]) with self.assertWarns(RuntimeWarning): strat.gen()
def test_predict_p(self): """ Verify analytic p-space mean and var is correct. """ X, y = self.X, self.y model = GPClassificationModel( torch.Tensor([-3]), torch.Tensor([3]), inducing_size=10 ) model.fit(X, y) pmean_analytic, pvar_analytic = model.predict(X, probability_space=True) fsamps = model.sample(X, 150000) psamps = norm.cdf(fsamps) pmean_samp = psamps.mean(0) pvar_samp = psamps.var(0) # TODO these tolerances are a bit loose, verify this is right. self.assertTrue(np.allclose(pmean_analytic, pmean_samp, atol=0.001)) self.assertTrue(np.allclose(pvar_analytic, pvar_samp, atol=0.001))
def test_reset_hyperparams(self): model = GPClassificationModel(lb=[-3], ub=[3], inducing_size=20) os_before = model.covar_module.outputscale.clone().detach().numpy() ls_before = model.covar_module.base_kernel.lengthscale.clone().detach().numpy() model.fit(torch.Tensor(self.X), torch.Tensor(self.y)) os_after = model.covar_module.outputscale.clone().detach().numpy() ls_after = model.covar_module.base_kernel.lengthscale.clone().detach().numpy() model._reset_hyperparameters() os_reset = model.covar_module.outputscale.clone().detach().numpy() ls_reset = model.covar_module.base_kernel.lengthscale.clone().detach().numpy() # before should be different from after and after should be different # from reset but before and reset should be same self.assertFalse(np.allclose(os_before, os_after)) self.assertFalse(np.allclose(os_after, os_reset)) self.assertTrue(np.allclose(os_before, os_reset)) self.assertFalse(np.allclose(ls_before, ls_after)) self.assertFalse(np.allclose(ls_after, ls_reset)) self.assertTrue(np.allclose(ls_before, ls_reset))
class SingleProbitModelbridge(ModelBridge): outcome_type = "single_probit" def __init__( self, lb, ub, restarts=10, samps=1000, dim=1, acqf=None, extra_acqf_args=None, model=None, ): if extra_acqf_args is None: extra_acqf_args = {} super().__init__(lb=lb, ub=ub, dim=dim, acqf=acqf, extra_acqf_args=extra_acqf_args) self.restarts = restarts self.samps = samps self.likelihood = gpytorch.likelihoods.BernoulliLikelihood() if model is None: self.model = GPClassificationModel(inducing_min=self.lb, inducing_max=self.ub) else: self.model = model def fit(self, train_x, train_y): n = train_y.shape[0] self.mll = gpytorch.mlls.VariationalELBO(self.likelihood, self.model, n) self.model.train() self.model.set_train_data(train_x, train_y) fit_gpytorch_model(self.mll) def gen(self, num_points=1, **kwargs): self.model.eval() train_x = self.model.train_inputs[0] acq = self._get_acquisition_fn() new_candidate, batch_acq_values = optimize_acqf( acq_function=acq, bounds=torch.tensor(np.c_[self.lb, self.ub]).T.to(train_x), q=num_points, num_restarts=self.restarts, raw_samples=self.samps, ) return new_candidate.numpy() def predict(self, x): post = self.model.posterior(x) return post.mean.squeeze(), post.variance.squeeze() def sample(self, x, num_samples): return self.model(x).rsample(torch.Size([num_samples])) @classmethod def from_config(cls, config): classname = cls.__name__ model = GPClassificationModel.from_config(config) lb = config.gettensor(classname, "lb") ub = config.gettensor(classname, "ub") restarts = config.getint(classname, "restarts", fallback=10) samps = config.getint(classname, "samps", fallback=1000) assert lb.shape[0] == ub.shape[0], "bounds are of different shapes!" dim = lb.shape[0] acqf = config.getobj("experiment", "acqf", fallback=MCLevelSetEstimation) acqf_name = acqf.__name__ default_extra_acqf_args = { "beta": 3.98, "target": 0.75, "objective": ProbitObjective, } extra_acqf_args = { k: config.getobj(acqf_name, k, fallback_type=float, fallback=v, warn=False) for k, v in default_extra_acqf_args.items() } extra_acqf_args = _prune_extra_acqf_args(acqf, extra_acqf_args) if ("objective" in extra_acqf_args.keys() and extra_acqf_args["objective"] is not None): extra_acqf_args["objective"] = extra_acqf_args["objective"]() return cls( lb=lb, ub=ub, restarts=restarts, samps=samps, dim=dim, acqf=acqf, model=model, extra_acqf_args=extra_acqf_args, )
def test_select_inducing_points(self): """Verify that when we have n_induc > data size, we use data as inducing, and otherwise we correctly select inducing points.""" X, y = make_classification( n_samples=100, n_features=1, n_redundant=0, n_informative=1, random_state=1, n_clusters_per_class=1, ) X, y = torch.Tensor(X), torch.Tensor(y) model = GPClassificationModel( torch.Tensor([-3]), torch.Tensor([3]), inducing_size=20 ) model.set_train_data(X[:10, ...], y[:10]) # (inducing point selection sorts the inputs so we sort X to verify) self.assertTrue( np.allclose( model._select_inducing_points(method="auto"), X[:10].sort(0).values, ) ) model.set_train_data(X, y) self.assertTrue(len(model._select_inducing_points(method="auto")) <= 20) self.assertTrue(len(model._select_inducing_points(method="pivoted_chol")) <= 20) self.assertEqual(len(model._select_inducing_points(method="kmeans++")), 20) with self.assertRaises(AssertionError): model._select_inducing_points(method="12345")
def plot_prior_samps_2d(): config = Config( config_dict={ "common": { "outcome_type": "single_probit", "target": 0.75, "lb": "[-3, -3]", "ub": "[3, 3]", }, "default_mean_covar_factory": {}, "song_mean_covar_factory": {}, "monotonic_mean_covar_factory": {"monotonic_idxs": "[1]"}, } ) lb = torch.Tensor([-3, -3]) ub = torch.Tensor([3, 3]) nsamps = 5 gridsize = 30 grid = _dim_grid(lower=lb, upper=ub, dim=2, gridsize=gridsize) np.random.seed(global_seed) torch.random.manual_seed(global_seed) with gpytorch.settings.prior_mode(True): rbf_mean, rbf_covar = default_mean_covar_factory(config) rbf_model = GPClassificationModel( inducing_min=lb, inducing_max=ub, inducing_size=100, mean_module=rbf_mean, covar_module=rbf_covar, ) # add just two samples at high and low rbf_model.set_train_data(torch.Tensor([-3, -3])[:, None], torch.LongTensor([0])) rbf_samps = rbf_model(grid).sample(torch.Size([nsamps])) song_mean, song_covar = song_mean_covar_factory(config) song_model = GPClassificationModel( inducing_min=lb, inducing_max=ub, inducing_size=100, mean_module=song_mean, covar_module=song_covar, ) song_model.set_train_data( torch.Tensor([-3, -3])[:, None], torch.LongTensor([0]) ) song_samps = song_model(grid).sample(torch.Size([nsamps])) mono_mean, mono_covar = monotonic_mean_covar_factory(config) mono_model = MonotonicRejectionGP( likelihood="probit-bernoulli", monotonic_idxs=[1], mean_module=mono_mean, covar_module=mono_covar, num_induc=1000, ) bounds_ = torch.tensor([-3.0, -3.0, 3.0, 3.0]).reshape(2, -1) # Select inducing points mono_model.inducing_points = draw_sobol_samples( bounds=bounds_, n=mono_model.num_induc, q=1 ).squeeze(1) inducing_points_aug = mono_model._augment_with_deriv_index( mono_model.inducing_points, 0 ) scales = ub - lb dummy_train_x = mono_model._augment_with_deriv_index( torch.Tensor([-3, 3])[None, :], 0 ) mono_model.model = MixedDerivativeVariationalGP( train_x=dummy_train_x, train_y=torch.LongTensor([0]), inducing_points=inducing_points_aug, scales=scales, fixed_prior_mean=torch.Tensor([0.75]), covar_module=mono_covar, mean_module=mono_mean, ) mono_samps = mono_model.sample(grid, nsamps) intensity_grid = np.linspace(-3, 3, gridsize) fig, ax = plt.subplots(1, 3, figsize=(7.5, 3)) fig.tight_layout(rect=[0, 0.03, 1, 0.9]) fig.suptitle("Prior samples") square_samps = np.array([s.reshape((gridsize,) * 2).numpy() for s in song_samps]) plotsamps = norm.cdf(square_samps[:, ::5, :]).T.reshape(gridsize, -1) ax[0].plot(intensity_grid, plotsamps, "b") ax[0].set_title("Linear kernel model") square_samps = np.array([s.reshape((gridsize,) * 2).numpy() for s in rbf_samps]) plotsamps = norm.cdf(square_samps[:, ::5, :]).T.reshape(gridsize, -1) ax[1].plot(intensity_grid, plotsamps, "b") ax[1].set_title("Nonmonotonic RBF kernel model") square_samps = np.array([s.reshape((gridsize,) * 2).numpy() for s in mono_samps]) plotsamps = norm.cdf(square_samps[:, ::5, :]).T.reshape(gridsize, -1) ax[2].plot(intensity_grid, plotsamps, "b") ax[2].set_title("Monotonic RBF kernel model") return fig
def plot_prior_samps_1d(): config = Config( config_dict={ "common": { "outcome_type": "single_probit", "target": 0.75, "lb": "[-3]", "ub": "[3]", }, "default_mean_covar_factory": {}, "song_mean_covar_factory": {}, "monotonic_mean_covar_factory": {"monotonic_idxs": "[0]"}, } ) lb = torch.Tensor([-3]) ub = torch.Tensor([3]) nsamps = 10 gridsize = 50 grid = _dim_grid(lower=lb, upper=ub, dim=1, gridsize=gridsize) np.random.seed(global_seed) torch.random.manual_seed(global_seed) with gpytorch.settings.prior_mode(True): rbf_mean, rbf_covar = default_mean_covar_factory(config) rbf_model = GPClassificationModel( inducing_min=lb, inducing_max=ub, inducing_size=100, mean_module=rbf_mean, covar_module=rbf_covar, ) # add just two samples at high and low rbf_model.set_train_data( torch.Tensor([-3, 3])[:, None], torch.LongTensor([0, 1]) ) rbf_samps = rbf_model(grid).sample(torch.Size([nsamps])) song_mean, song_covar = song_mean_covar_factory(config) song_model = GPClassificationModel( inducing_min=lb, inducing_max=ub, inducing_size=100, mean_module=song_mean, covar_module=song_covar, ) song_model.set_train_data( torch.Tensor([-3, 3])[:, None], torch.LongTensor([0, 1]) ) song_samps = song_model(grid).sample(torch.Size([nsamps])) mono_mean, mono_covar = monotonic_mean_covar_factory(config) mono_model = MonotonicRejectionGP( likelihood="probit-bernoulli", monotonic_idxs=[0], mean_module=mono_mean, covar_module=mono_covar, ) bounds_ = torch.tensor([-3.0, 3.0])[:, None] # Select inducing points mono_model.inducing_points = draw_sobol_samples( bounds=bounds_, n=mono_model.num_induc, q=1 ).squeeze(1) inducing_points_aug = mono_model._augment_with_deriv_index( mono_model.inducing_points, 0 ) scales = ub - lb dummy_train_x = mono_model._augment_with_deriv_index( torch.Tensor([-3, 3])[:, None], 0 ) mono_model.model = MixedDerivativeVariationalGP( train_x=dummy_train_x, train_y=torch.LongTensor([0, 1]), inducing_points=inducing_points_aug, scales=scales, fixed_prior_mean=torch.Tensor([0.75]), covar_module=mono_covar, mean_module=mono_mean, ) mono_samps = mono_model.sample(grid, nsamps) fig, ax = plt.subplots(1, 3, figsize=(7.5, 3)) fig.tight_layout(rect=[0.01, 0.03, 1, 0.9]) fig.suptitle("GP prior samples (probit-transformed)") ax[0].plot(grid.squeeze(), norm.cdf(song_samps.T), "b") ax[0].set_ylabel("Response Probability") ax[0].set_title("Linear kernel") ax[1].plot(grid.squeeze(), norm.cdf(rbf_samps.T), "b") ax[1].set_xlabel("Intensity") ax[1].set_title("RBF kernel (nonmonotonic)") ax[2].plot(grid.squeeze(), norm.cdf(mono_samps.T), "b") ax[2].set_title("RBF kernel (monotonic)") return fig