我目前找到了 gpytorch ( https://github.com/cornellius-gp/gpytorch )。它似乎是将 GPR 集成到 pytorch 的一个很好的包。第一次测试也呈阳性。与其他软件包(如 scikit-learn)相比,使用 gpytorch 可以使用 GPU-Power 以及智能算法来提高性能。
但是,我发现估计所需的超参数要困难得多。在 scikit-learn 中,这发生在后台并且非常健壮。我想从社区获取一些关于原因的提要,并讨论是否有比 gpytorch 文档中的示例提供的更好的方法来估计这些参数。
为了进行比较,我采用了 gpytorch ( https://github.com/cornellius-gp/gpytorch/blob/master/examples/03_Multitask_GP_Regression/Multitask_GP_Regression.ipynb ) 官方页面上提供的示例代码,并将其分为两部分进行了修改:

  • 我使用不同的内核 (gpytorch.kernels.MaternKernel(nu=2.5) 而不是 gpytorch.kernels.RBFKernel())
  • 我使用了不同的输出函数

  • 下面,我首先提供使用 gpytorch 的代码。随后,我提供了 scikit-learn 的代码。最后,我比较一下结果
    导入(用于 gpytorch 和 scikit-learn):
    import math
    import torch
    import numpy as np
    import gpytorch
    
    生成数据(用于 gpytorch 和 scikit-learn):
    n = 20
    train_x = torch.zeros(pow(n, 2), 2)
    for i in range(n):
        for j in range(n):
            # Each coordinate varies from 0 to 1 in n=100 steps
            train_x[i * n + j][0] = float(i) / (n-1)
            train_x[i * n + j][1] = float(j) / (n-1)
    
    train_y_1 = (torch.sin(train_x[:, 0]) + torch.cos(train_x[:, 1]) * (2 * math.pi) + torch.randn_like(train_x[:, 0]).mul(0.01))/4
    train_y_2 = torch.sin(train_x[:, 0]) + torch.cos(train_x[:, 1]) * (2 * math.pi) + torch.randn_like(train_x[:, 0]).mul(0.01)
    
    train_y = torch.stack([train_y_1, train_y_2], -1)
    
    test_x = torch.rand((n, len(train_x.shape)))
    test_y_1 = (torch.sin(test_x[:, 0]) + torch.cos(test_x[:, 1]) * (2 * math.pi) + torch.randn_like(test_x[:, 0]).mul(0.01))/4
    test_y_2 = torch.sin(test_x[:, 0]) + torch.cos(test_x[:, 1]) * (2 * math.pi) + torch.randn_like(test_x[:, 0]).mul(0.01)
    test_y = torch.stack([test_y_1, test_y_2], -1)
    
    现在是引用文档中提供的示例中描述的估计:
    torch.manual_seed(2) # For a more robust comparison
    class MultitaskGPModel(gpytorch.models.ExactGP):
        def __init__(self, train_x, train_y, likelihood):
            super(MultitaskGPModel, self).__init__(train_x, train_y, likelihood)
            self.mean_module = gpytorch.means.MultitaskMean(
                gpytorch.means.ConstantMean(), num_tasks=2
            )
            self.covar_module = gpytorch.kernels.MultitaskKernel(
                gpytorch.kernels.MaternKernel(nu=2.5), num_tasks=2, rank=1
            )
    
        def forward(self, x):
            mean_x = self.mean_module(x)
            covar_x = self.covar_module(x)
            return gpytorch.distributions.MultitaskMultivariateNormal(mean_x, covar_x)
    
    
    likelihood = gpytorch.likelihoods.MultitaskGaussianLikelihood(num_tasks=2)
    model = MultitaskGPModel(train_x, train_y, likelihood)
    
    # Find optimal model hyperparameters
    model.train()
    likelihood.train()
    
    # Use the adam optimizer
    optimizer = torch.optim.Adam([
        {'params': model.parameters()},  # Includes GaussianLikelihood parameters
    ], lr=0.1)
    
    # "Loss" for GPs - the marginal log likelihood
    mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model)
    
    n_iter = 50
    for i in range(n_iter):
        optimizer.zero_grad()
        output = model(train_x)
        loss = -mll(output, train_y)
        loss.backward()
        # print('Iter %d/%d - Loss: %.3f' % (i + 1, n_iter, loss.item()))
        optimizer.step()
    
    # Set into eval mode
    model.eval()
    likelihood.eval()
    
    # Make predictions
    with torch.no_grad(), gpytorch.settings.fast_pred_var():
        predictions = likelihood(model(test_x))
        mean = predictions.mean
        lower, upper = predictions.confidence_region()
    
    test_results_gpytorch = np.median((test_y - mean) / test_y, axis=0)
    
    下面,我提供了 scikit-learn 的代码。哪个比较方便^^:
    from sklearn.gaussian_process import GaussianProcessRegressor
    from sklearn.gaussian_process.kernels import WhiteKernel, Matern
    kernel = 1.0 * Matern(length_scale=0.1, length_scale_bounds=(1e-5, 1e5), nu=2.5) \
             + WhiteKernel()
    gp = GaussianProcessRegressor(kernel=kernel, alpha=0.0).fit(train_x.numpy(),
                                                                train_y.numpy())
    # x_interpolation = test_x.detach().numpy()[np.newaxis, :].transpose()
    y_mean_interpol, y_std_norm = gp.predict(test_x.numpy(), return_std=True)
    
    test_results_scitlearn = np.median((test_y.numpy() - y_mean_interpol) / test_y.numpy(), axis=0)
    
    最后我比较一下结果:
    comparisson = (test_results_scitlearn - test_results_gpytorch)/test_results_scitlearn
    print('Variable 1: scitkit learn is more accurate my factor: ' + str(abs(comparisson[0]))
    print('Variable 2: scitkit learn is more accurate my factor: ' + str(comparisson[1]))
    
    不幸的是,我没有找到一种简单的方法来修复 scikit-learn 的种子。我上次运行代码时,它返回:

    在 gpytorch 的情况下,我假设优化器在某些局部最优中运行。但是我想不出任何仍然使用 pytorch 的更强大的优化算法。
    我期待着建议!
    拉兹卢

    最佳答案

    (我还在您为它创建的 GitHub 问题 here 上回答了您的问题)

    这主要是因为您在 sklearn 和 gpytorch 中使用了不同的模型。特别是,sklearn 默认在多输出设置中学习独立的 GP(参见例如讨论 here )。在 GPyTorch 中,您使用了 Bonilla et al, 2008 中引入的多任务 GP 方法。纠正这种差异产生:

    关于python - 为什么 gpytorch 似乎不如 scikit-learn 准确?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54389944/

    10-12 18:10