GPyTorchで多クラス分類
GPyTorchとは
PyTorch上で実装されたガウス過程(GP)のライブラリである. ハイパーパラメータをPyTorchのシステムを使用してGPUなどで最適化できるのが特徴である. GPは逆行列を計算する際に の計算量がかかり,スケーラビリティに難があるが,PyTorchのシステムを使ってそれを補おうとしている.
GPでは尤度を変更することで回帰や二値分類,多クラス分類が可能となる. 今回はアヤメ(iris)データセットを用いて3クラスの多クラス分類をGPyTorchで分類してみる.
コード
# -*- coding: utf-8 -*- import torch import gpytorch import numpy as np from gpytorch.models import AbstractVariationalGP from gpytorch.variational import CholeskyVariationalDistribution from gpytorch.mlls.variational_elbo import VariationalELBO from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split class GPMultiClassificationModel(AbstractVariationalGP): def __init__(self, num_dim=2, grid_bounds=(-10., 10.), grid_size=64): variational_distribution = gpytorch.variational.CholeskyVariationalDistribution( num_inducing_points=grid_size, batch_size=num_dim ) variational_strategy = gpytorch.variational.AdditiveGridInterpolationVariationalStrategy( self, grid_size=grid_size, grid_bounds=[grid_bounds], num_dim=num_dim, variational_distribution=variational_distribution, mixing_params=False, sum_output=False ) super().__init__(variational_strategy) self.mean_module = gpytorch.means.ConstantMean() self.covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.RBFKernel()) def forward(self, x): mean_x = self.mean_module(x) covar_x = self.covar_module(x) latent_pred = gpytorch.distributions.MultivariateNormal(mean_x, covar_x) return latent_pred device = 'cuda' if torch.cuda.is_available() else 'cpu' iris = load_iris() # 特徴量は2次元 # testデータは3割 (train_x, test_x, train_y, test_y) = train_test_split(iris.data[:, [0, 2]].astype(np.float32), iris.target, test_size=0.3, random_state=0,) # 3クラス分類 n_labels = len(np.unique(train_y)) train_x = torch.from_numpy(train_x).to(device) train_y = torch.from_numpy(train_y).to(device) test_x = torch.from_numpy(test_x).to(device) test_y = torch.from_numpy(test_y).to(device) model = GPMultiClassificationModel(num_dim=2).to(device) # 多クラス分類なのでSoftmaxを使用する likelihood = gpytorch.likelihoods.SoftmaxLikelihood(num_classes=n_labels, num_features=2).to(device) # 周辺尤度 mll = VariationalELBO(likelihood, model, train_y.numel()) optimizer = torch.optim.Adam(model.parameters(), lr=0.1) # train model.train() likelihood.train() training_iter = 10000 for i in range(training_iter): optimizer.zero_grad() output = model(train_x) loss = -mll(output, train_y) loss.backward() print('\rIter %d/%d - Loss: %.3f' % (i + 1, training_iter, loss.item()), end='') optimizer.step() print('') # test model.eval() likelihood.eval() correct = 0.0 # sample数を64とする with torch.no_grad(), gpytorch.settings.num_likelihood_samples(64): data = test_x target = test_y output = likelihood(model(data)) pred = output.probs.mean(0).argmax(-1) correct += pred.eq(target.view_as(pred)).cpu().sum() acc = correct.numpy() / float(len(test_x)) * 100.0 print('Accuracy:', acc)
出力結果
Iter 10000/10000 - Loss: 0.397 Accuracy: 86.66666666666667