예제 #1
0
    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
예제 #2
0
    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)
예제 #3
0
    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]))
예제 #4
0
    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)
예제 #6
0
    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)
        )
예제 #7
0
    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)
예제 #8
0
    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)
예제 #9
0
    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)
예제 #10
0
    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)))
예제 #11
0
    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)
예제 #12
0
    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)
예제 #13
0
    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
        )
예제 #14
0
    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)
예제 #15
0
    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,
        )
예제 #16
0
    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)
예제 #17
0
    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
        )
예제 #18
0
    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)
예제 #19
0
    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))
예제 #20
0
    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()
예제 #21
0
    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))
예제 #22
0
    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))
예제 #23
0
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,
        )
예제 #24
0
    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")
예제 #25
0
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
예제 #26
0
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