def create_per(sigma2, lengthscale, period_length): per = PeriodicKernel() per.lengthscale = lengthscale per.period_length = period_length kernel = ScaleKernel(per) kernel.outputscale = sigma2 return kernel
def test_computes_periodic_function(self): a = torch.tensor([4, 2, 8], dtype=torch.float).view(3, 1) b = torch.tensor([0, 2], dtype=torch.float).view(2, 1) lengthscale = 2 period = 3 kernel = PeriodicKernel().initialize(log_lengthscale=math.log(lengthscale), log_period_length=math.log(period)) kernel.eval() actual = torch.zeros(3, 2) for i in range(3): for j in range(2): val = 2 * torch.pow(torch.sin(math.pi * (a[i] - b[j]) / 3), 2) / lengthscale actual[i, j] = torch.exp(-val).item() res = kernel(a, b).evaluate() self.assertLess(torch.norm(res - actual), 1e-5)
def test_batch(self): a = torch.tensor([[4, 2, 8], [1, 2, 3]], dtype=torch.float).view(2, 3, 1) b = torch.tensor([[0, 2], [-1, 2]], dtype=torch.float).view(2, 2, 1) period = torch.tensor(1, dtype=torch.float).view(1, 1, 1) lengthscale = torch.tensor(2, dtype=torch.float).view(1, 1, 1) kernel = PeriodicKernel().initialize(lengthscale=lengthscale, period_length=period) kernel.eval() actual = torch.zeros(2, 3, 2) for k in range(2): actual[k] = kernel(a[k], b[k]).evaluate() res = kernel(a, b).evaluate() self.assertLess(torch.norm(res - actual), 1e-5)
def test_computes_periodic_function(self): a = torch.Tensor([4, 2, 8]).view(3, 1) b = torch.Tensor([0, 2]).view(2, 1) lengthscale = 2 period = 1 kernel = PeriodicKernel().initialize(log_lengthscale=math.log(lengthscale), log_period_length=math.log(period)) kernel.eval() actual = torch.zeros(3, 2) for i in range(3): for j in range(2): val = 2 * torch.pow(torch.sin(math.pi * (a[i] - b[j])), 2) / lengthscale actual[i, j] = torch.exp(-val)[0] res = kernel(Variable(a), Variable(b)).evaluate().data self.assertLess(torch.norm(res - actual), 1e-5)
def test_is_pd(self): # ensures 1d input is positive definite with additional jitter x = torch.randn(100).reshape(-1, 1) kernel = PeriodicKernel() with torch.no_grad(): K = kernel(x, x).evaluate() + 1e-4 * torch.eye(len(x)) eig = torch.symeig(K)[0] self.assertTrue((eig > 0.0).all().item())
def test_batch_separate(self): a = torch.tensor([[4, 2, 8], [1, 2, 3]], dtype=torch.float).view(2, 3, 1) b = torch.tensor([[0, 2], [-1, 2]], dtype=torch.float).view(2, 2, 1) period = torch.tensor([1, 2], dtype=torch.float).view(2, 1, 1) lengthscale = torch.tensor([2, 1], dtype=torch.float).view(2, 1, 1) kernel = PeriodicKernel(batch_shape=torch.Size([2])).initialize(lengthscale=lengthscale, period_length=period) kernel.eval() actual = torch.zeros(2, 3, 2) for k in range(2): for i in range(3): for j in range(2): val = 2 * torch.pow(torch.sin(math.pi * (a[k, i] - b[k, j]) / period[k]), 2) / lengthscale[k] actual[k, i, j] = torch.exp(-val).item() res = kernel(a, b).evaluate() self.assertLess(torch.norm(res - actual), 1e-5)
def test_multidimensional_inputs(self): # test taken from issue #835 # ensures multidimensional input results in a positive definite kernel matrix, with additional jitter x = torch.randn(1000, 2) kernel = PeriodicKernel() with torch.no_grad(): K = kernel(x, x).evaluate() + 1e-4 * torch.eye(len(x)) eig = torch.symeig(K)[0] self.assertTrue((eig > 0.0).all().item())
def test_batch_separate(self): a = torch.tensor([[4, 2, 8], [1, 2, 3]], dtype=torch.float).view(2, 3, 1) b = torch.tensor([[0, 2], [-1, 2]], dtype=torch.float).view(2, 2, 1) period = torch.tensor([1, 2], dtype=torch.float).view(2, 1, 1) lengthscale = torch.tensor([2, 1], dtype=torch.float).view(2, 1, 1) kernel = PeriodicKernel(batch_shape=torch.Size([2])).initialize( lengthscale=lengthscale, period_length=period) kernel.eval() actual = torch.zeros(2, 3, 2) for k in range(2): diff = a[k].unsqueeze(1) - b[k].unsqueeze(0) diff = diff * math.pi / period[k].unsqueeze(-1) actual[k] = diff.sin().pow(2).sum(dim=-1).div( lengthscale[k]).mul(-2.0).exp_() res = kernel(a, b).evaluate() self.assertLess(torch.norm(res - actual), 1e-5)
def __init__(self, mean_name='constant', kernel_name='RBF', grid_bounds=[(-1, 1), (-1, 1)], grid_size=100, num_samples=1000): self.mean = mean_name self.kernel = kernel_name self.num_samples = num_samples self.grid_bounds = grid_bounds self.grid_size = grid_size self.x_dim = 2 # x and y dim are fixed for this dataset. self.y_dim = 1 self.data = [] # create grid grid = torch.zeros(grid_size, len(grid_bounds)) for i in range(len(grid_bounds)): grid_diff = float(grid_bounds[i][1] - grid_bounds[i][0]) / (grid_size - 2) grid[:, i] = torch.linspace(grid_bounds[i][0] - grid_diff, grid_bounds[i][1] + grid_diff, grid_size) x = gpytorch.utils.grid.create_data_from_grid(grid) # initialize likelihood and model likelihood = gpytorch.likelihoods.GaussianLikelihood() mean_dict = {'constant': ConstantMean()} kernel_dict = { 'RBF': RBFKernel(), 'cosine': CosineKernel(), 'linear': LinearKernel(), 'periodic': PeriodicKernel(), 'LCM': LCMKernel(base_kernels=[CosineKernel()], num_tasks=1), 'polynomial': PolynomialKernel(power=3), 'matern': MaternKernel() } # evaluate GP on prior distribution with gpytorch.settings.prior_mode(True): model = ExactGPModel(x, None, likelihood, mean_module=mean_dict[self.mean], kernel_module=gpytorch.kernels.GridKernel( kernel_dict[self.kernel], grid=grid)) gp = model(x) for i in range(num_samples): y = gp.sample() self.data.append( (x, y.unsqueeze(1))) #+torch.randn(y.size())*0.2))
def __init__(self, mean_list, kernel_list, num_points=100, num_samples=1000, amplitude_range=(-5., 5.)): self.mean_list = mean_list self.kernel_list = kernel_list self.num_config = len(mean_list) * len(kernel_list) self.num_samples = num_samples self.num_points = num_points self.x_dim = 1 # x and y dim are fixed for this dataset. self.y_dim = 1 self.amplitude_range = amplitude_range self.data = [] # initialize likelihood and model x = torch.linspace(self.amplitude_range[0], self.amplitude_range[1], num_points).unsqueeze(1) likelihood = gpytorch.likelihoods.GaussianLikelihood() mean_dict = {'constant': ConstantMean(), 'linear': LinearMean(1)} kernel_dict = { 'RBF': RBFKernel(), 'cosine': CosineKernel(), 'linear': LinearKernel(), 'periodic': PeriodicKernel(period_length=0.5), 'LCM': LCMKernel(base_kernels=[CosineKernel()], num_tasks=1), 'polynomial': PolynomialKernel(power=2), 'matern': MaternKernel() } # create a different GP from each possible configuration for mean in self.mean_list: for kernel in self.kernel_list: # evaluate GP on prior distribution with gpytorch.settings.prior_mode(True): model = ExactGPModel(x, None, likelihood, mean_module=mean_dict[mean], kernel_module=kernel_dict[kernel]) gp = model(x) # sample from current configuration for i in range(num_samples // self.num_config + 1): y = gp.sample() self.data.append( (x, y.unsqueeze(1))) #+torch.randn(y.shape)*0))
def test_random_fourier_features(self): # test kernel that is not Scale, RBF, or Matern with self.assertRaises(NotImplementedError): RandomFourierFeatures( kernel=PeriodicKernel(), input_dim=2, num_rff_features=3, ) # test batched kernel with self.assertRaises(NotImplementedError): RandomFourierFeatures( kernel=RBFKernel(batch_shape=torch.Size([2])), input_dim=2, num_rff_features=3, ) tkwargs = {"device": self.device} for dtype in (torch.float, torch.double): tkwargs["dtype"] = dtype # test init # test ScaleKernel base_kernel = RBFKernel(ard_num_dims=2) kernel = ScaleKernel(base_kernel).to(**tkwargs) rff = RandomFourierFeatures( kernel=kernel, input_dim=2, num_rff_features=3, ) self.assertTrue(torch.equal(rff.outputscale, kernel.outputscale)) # check that rff makes a copy self.assertFalse(rff.outputscale is kernel.outputscale) self.assertTrue( torch.equal(rff.lengthscale, base_kernel.lengthscale)) # check that rff makes a copy self.assertFalse(rff.lengthscale is kernel.lengthscale) for sample_shape in [torch.Size(), torch.Size([5])]: # test not ScaleKernel rff = RandomFourierFeatures( kernel=base_kernel, input_dim=2, num_rff_features=3, sample_shape=sample_shape, ) self.assertTrue( torch.equal(rff.outputscale, torch.tensor(1, **tkwargs))) self.assertTrue( torch.equal(rff.lengthscale, base_kernel.lengthscale)) # check that rff makes a copy self.assertFalse(rff.lengthscale is kernel.lengthscale) self.assertEqual(rff.weights.shape, torch.Size([*sample_shape, 2, 3])) self.assertEqual(rff.bias.shape, torch.Size([*sample_shape, 3])) self.assertTrue( ((rff.bias <= 2 * pi) & (rff.bias >= 0.0)).all()) # test forward for sample_shape in [torch.Size(), torch.Size([7])]: rff = RandomFourierFeatures( kernel=kernel, input_dim=2, num_rff_features=3, sample_shape=sample_shape, ) for input_batch_shape in [torch.Size([]), torch.Size([5])]: X = torch.rand(*input_batch_shape, *sample_shape, 1, 2, **tkwargs) Y = rff(X) self.assertTrue( Y.shape, torch.Size([*input_batch_shape, *sample_shape, 1, 1])) _constant = torch.sqrt(2 * rff.outputscale / rff.weights.shape[-1]) _arg_to_cos = X / base_kernel.lengthscale @ rff.weights _bias_expanded = rff.bias.unsqueeze(-2) expected_Y = _constant * (torch.cos(_arg_to_cos + _bias_expanded)) self.assertTrue(torch.allclose(Y, expected_Y)) # test get_weights for sample_shape in [torch.Size(), torch.Size([5])]: with mock.patch("torch.randn", wraps=torch.randn) as mock_randn: rff._get_weights( base_kernel=base_kernel, input_dim=2, num_rff_features=3, sample_shape=sample_shape, ) mock_randn.assert_called_once_with( *sample_shape, 2, 3, dtype=base_kernel.lengthscale.dtype, device=base_kernel.lengthscale.device, ) # test get_weights with Matern kernel with mock.patch( "torch.randn", wraps=torch.randn) as mock_randn, mock.patch( "torch.distributions.Gamma", wraps=torch.distributions.Gamma) as mock_gamma: base_kernel = MaternKernel(ard_num_dims=2).to(**tkwargs) rff._get_weights( base_kernel=base_kernel, input_dim=2, num_rff_features=3, sample_shape=sample_shape, ) mock_randn.assert_called_once_with( *sample_shape, 2, 3, dtype=base_kernel.lengthscale.dtype, device=base_kernel.lengthscale.device, ) mock_gamma.assert_called_once_with( base_kernel.nu, base_kernel.nu, )
def create_kernel_with_prior(self, period_length_prior): return PeriodicKernel(period_length_prior=period_length_prior)
def create_kernel_ard(self, num_dims, **kwargs): return PeriodicKernel(ard_num_dims=num_dims, **kwargs)
def create_kernel_no_ard(self, **kwargs): return PeriodicKernel(**kwargs)