Deep Kernel Learning ist eine Kombination aus Deep Learning und Gaußschen Prozessen und gehört zum Bayes'schen Deep Learning. Als Methode wird ein tiefer Kernel erstellt, indem die vom tiefen neuronalen Netz (DNN) ausgegebenen Merkmale als Eingabe des Kernels im Gaußschen Prozess verwendet werden. Die Formel lautet wie folgt.
k_{deep}(x,x') = k(f(x),f(x'))
Da der Gaußsche Prozess einem neuronalen Netz mit unendlichen Einheiten entspricht, scheint er am Ende von DNN hinzugefügt worden zu sein. Wie ich im vorherigen Artikel (https://qiita.com/takeajioka/items/f24d58d2b13017ab2b18) versucht habe, ist es wichtig, die Kernel-Hyperparameter während des Gaußschen Prozesses zu optimieren. Deep Kernel Learning scheint DNN-Parameter und Kernel-Hyper-Parameter gleichzeitig zu optimieren und zu lernen.
Weitere Informationen finden Sie im folgenden Dokument. [1] Deep Kernel Learning, 2015, Andrew G. Wilson et al.,https://arxiv.org/abs/1511.02222 [2] Stochastic Variational Deep Kernel Learning, 2016, Andrew G. Wilson et al., https://arxiv.org/abs/1611.00336
In Pyro können Sie mithilfe der Klasse gp.kernels.Warping auf einfache Weise einen tiefen Kernel erstellen. In Pyros offiziellem Tutorial gibt es einen Code für Deep Kernel Learning. Lassen Sie uns also anhand dieses Codes lernen.
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
from torchvision import transforms
import pyro
import pyro.contrib.gp as gp
import pyro.infer as infer
Da MNIST über eine große Datenmenge verfügt, werden wir diese in einem Mini-Batch lernen. Stellen Sie den Datensatz ein.
batch_size = 100
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, ), (0.5, ))])
trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True)
testset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size, shuffle=False)
Bereiten Sie zunächst ein normales DNN-Modell vor.
class CNN(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
self.fc1 = nn.Linear(320, 50)
self.fc2 = nn.Linear(50, 10)
def forward(self, x):
x = F.relu(F.max_pool2d(self.conv1(x), 2))
x = F.relu(F.max_pool2d(self.conv2(x), 2))
x = x.view(-1, 320)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
Wickeln Sie den Kernel darin ein, um einen tiefen Kernel zu erstellen.
rbf = gp.kernels.RBF(input_dim=10, lengthscale=torch.ones(10))
deep_kernel = gp.kernels.Warping(rbf, iwarping_fn=CNN())
Eine spärliche Näherung wird verwendet, um die Berechnungskosten des Gaußschen Prozesses zu reduzieren. In der spärlichen Näherung wird der Induktionspunkt verwendet, aber dieses Mal werden wir die Trainingsdaten für eine Chargengröße verwenden.
Xu, _ = next(iter(trainloader))
likelihood = gp.likelihoods.MultiClass(num_classes=10)
gpmodule = gp.models.VariationalSparseGP(X=None, y=None, kernel=deep_kernel, Xu=Xu, likelihood=likelihood, latent_shape=torch.Size([10]), num_data=60000)
optimizer = torch.optim.Adam(gpmodule.parameters(), lr=0.01)
elbo = infer.TraceMeanField_ELBO()
loss_fn = elbo.differentiable_loss
Definiert eine Funktion für das Mini-Batch-Lernen.
def train(train_loader, gpmodule, optimizer, loss_fn, epoch):
total_loss = 0
for data, target in train_loader:
gpmodule.set_data(data, target)
optimizer.zero_grad()
loss = loss_fn(gpmodule.model, gpmodule.guide)
loss.backward()
optimizer.step()
total_loss += loss
return total_loss / len(train_loader)
def test(test_loader, gpmodule):
correct = 0
for data, target in test_loader:
f_loc, f_var = gpmodule(data)
pred = gpmodule.likelihood(f_loc, f_var)
correct += pred.eq(target).long().sum().item()
return 100. * correct / len(test_loader.dataset)
Lerne.
import time
losses = []
accuracy = []
epochs = 10
for epoch in range(epochs):
start_time = time.time()
loss = train(trainloader, gpmodule, optimizer, loss_fn, epoch)
losses.append(loss)
with torch.no_grad():
acc = test(testloader, gpmodule)
accuracy.append(acc)
print("Amount of time spent for epoch {}: {}s\n".format(epoch+1, int(time.time() - start_time)))
print("loss:{:.2f}, accuracy:{}".format(losses[-1],accuracy[-1]))
Ich konnte eine Epoche in ungefähr 30 Sekunden lernen. Die endgültige Genauigkeit betrug 96,23%. (Es scheint, dass es im offiziellen Tutorial bis zu 99,41% sein kann.) Zeigen Sie die Lernkurve an.
import matplotlib.pyplot as plt
plt.subplot(2,1,1)
plt.plot(losses)
plt.xlabel("epoch")
plt.ylabel("loss")
plt.subplot(2,1,2)
plt.plot(accuracy)
plt.xlabel("epoch")
plt.ylabel("accuracy")
Schauen wir uns das Testbild und die vorhergesagte Ausgabe nebeneinander an.
data, target = next(iter(testloader))
f_loc, f_var = gpmodule(data)
pred = gpmodule.likelihood(f_loc, f_var)
for i in range(len(data)):
plt.subplot(1,2,1)
plt.imshow(data[i].reshape(28, 28))
plt.subplot(1,2,2)
plt.bar(range(10), f_loc[:,i].detach(), yerr= f_var[:,i].detach())
ax = plt.gca()
ax.set_xticks(range(10))
plt.xlabel("class")
plt.savefig('image/figure'+ str(i) +'.png')
plt.clf()
Der blaue Balken ist der Durchschnittswert und der Fehlerbalken ist die Verteilung. Es wurde festgestellt, dass jede der 10 Klassen eine Ausgabe hatte und die richtige Klassenausgabe einen hohen Wert.
Schauen wir uns auch Bilder an, die schwer zu unterscheiden sind. Die Ausgabe ist in mehreren Klassen hoch. In Anbetracht der Fehlerleiste scheint es keinen signifikanten Unterschied zu geben.
Ich konnte wie normales Deep Learning lernen. Ich denke, dass es ein Vorteil ist, dass normales Deep Learnig nicht hat, dass es den Durchschnittswert und die Varianz als Ausgabe ausgeben kann. Es gibt auch einen tiefen Gaußschen Prozess (DGP), der ein Stapel von Gaußschen Prozessen ist, daher möchte ich das auch untersuchen.
Recommended Posts