Dieser Artikel ist ein Memorandum darüber, wie man ein Modell von Pytorch definiert, das eines der Deep-Learning-Frameworks ist, wie man lernt und wie man eine selbst erstellte Funktion erstellt.
Pytorch kann einfach mit Conda oder Pip installiert werden. Wenn Sie die Version von os, python oder cuda unter hier auswählen, wird ein geeignetes Skript angezeigt, damit Sie es durch Kopieren installieren können. (Cuda und Cudnn müssen separat eingerichtet werden) Derzeit wird anscheinend nur Linux oder OSX unterstützt und Windows wird nicht unterstützt. (Seit 0.4 wird Windows auch offiziell unterstützt.)
Wenn Sie Pytorch von nun an verwenden möchten, ist Official Tutorials viel einfacher zu verstehen als dieser Artikel. Sie sollten daher darauf verweisen. Auch Beispiel ist sehr hilfreich. Andere Wenn Sie sich Dokumente und Foren ansehen, werden die meisten Dinge, die Sie nicht verstehen, gelöst.
Pytorch verwendet grundsätzlich torch.Tensor für Matrixoperationen. Die Verwendung ist im Grunde die gleiche wie bei torch.Tensor of Torch7. Im Gegensatz zu Torch7 basiert die Eingabe in das Modell jedoch auf der Eingabe im Mini-Batch. Im Fall der 2D-Faltung gab es kein Problem mit der 3D- oder 4D-Eingabe in Torch7, aber 4D wird in Pytorch angenommen. Ändern Sie bei der Berechnung mit dem Modell den Fackel.Tensor in Variable und verwenden Sie ihn. Wenn in Pytorch 0.4 oder früher Folgendes importiert wird, können Sie grundlegende Modelldefinitionen und Schulungen durchführen.
import torch
import torch.nn as nn
import torch.optim as optim
from torch.autograd import Variable
Da Variable in torch.Tensor in Pytorch 0.4 und höher integriert ist, muss Variable nicht importiert werden.
In Pytorch ist es möglich, ein Modell wie folgt in Torch7 zu definieren.
model1.
model = nn.Sequential()
model.add_module('fc1', nn.Linear(10,100))
model.add_module('relu', nn.ReLU())
model.add_module('fc2', nn.Linear(100,10))
Der Unterschied besteht darin, dass Sie jeder Ebene einen Namen geben. Es ist auch möglich, eine Ebene in die Liste aufzunehmen und in nn.Sequential () einzutauchen.
model2.py
layer = []
layer.append(nn.Linear(10,100))
layer.append(nn.ReLU())
layer.append(nn.Linear(100,10))
model = nn.Sequential(*layer)
Es kann auch wie unten gezeigt als Klasse definiert werden.
model3.py
import torch.nn.functional as F
class Model(nn.Module):
def __init__(self):
super(Model,self).__init__()
self.fc1 = nn.Linear(10,100)
self.fc2 = nn.Linear(100,10)
def forward(self,x):
x = self.fc1(x)
x = F.relu(x)
x = self.fc2(x)
return x
Wenn Sie schon einmal Chainer verwendet haben, ist dies meiner Meinung nach eine bekannte Definitionsmethode. In Pytorch ist es möglich, den Umfang der Modelldefinition und den Umfang der Vorwärtsbeschreibung zu reduzieren, indem nn.Sequential vollständig genutzt wird. Implementierungsbeispiel des Fackelvisionspakets von Pytorch kann als Referenz für die Erstellung eines Modells verwendet werden. Wir werden ein Modell erstellen, indem wir die obigen drei je nach Zweck verwenden oder kombinieren.
Einer der häufigsten Fehler, den Sie machen, wenn Sie Pytorch verwenden, besteht darin, Ebenen in einer Liste zu halten. Wenn Sie dieselbe Hyperparameterschicht häufig verwenden, ist es einfacher, sie mit der for-Anweisung zu definieren. Wenn Sie jedoch die lernbaren Parameter in einer Liste behalten, können Sie sie in der Liste behalten, wenn Sie die Modellparameter aufrufen. Die Parameter der Ebene werden nicht als Parameter erkannt und nicht aufgerufen. Was passiert ist, dass die Parameter während des Lernens nicht aktualisiert werden. Das Folgende ist ein schlechtes Beispiel.
list.py
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.layer = [nn.Linear(10,10) for _ in range(10)]
def forward(self, x):
for i in range(len(self.layer)):
x = self.layer[i](x)
return x
model = Model()
# model.parameters()Sie können den Iterator des Lernparameters mit abrufen
#Wenn Sie es in der Liste halten, können Sie die Parameter der Module in der Liste nicht abrufen
#optim wird später beschrieben
optimize = optim.SGD(model.parameters(), lr=0.1)
Definieren Sie es daher in einem solchen Fall mit nn.ModuleList.
modulelist.py
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
layer = [nn.Linear(10,10) for _ in range(10)]
self.layer = nn.ModuleList(layer)
def forward(self, x):
for i in range(len(self.layer)):
x = self.layer[i](x)
return x
model = Model()
# model.parameters()Sie können den Iterator des Lernparameters mit abrufen
#Wenn Sie es in der Liste halten, können Sie die Parameter der Module in der Liste nicht abrufen
#optim wird später beschrieben
optimize = optim.SGD(model.parameters(), lr=0.1)
Sei vorsichtig, weil du süchtig danach bist.
Sie kann auf der GPU berechnet werden, indem das Modell und die Variablen wie unten gezeigt als Cudatensor definiert werden.
gpu.py
import torch
x = torch.randn(10)
y = torch.randn(10)
"""
Pytorch 0.4 oder früher
x = x.cuda()
y = y.cuda(0) #Wenn Sie im Argument eine Nummer eingeben, können Sie die GPU mit der der Nummer entsprechenden ID verwenden
z = x * y #Die Berechnung erfolgt auf der GPU.
z = z.cpu() #zu CPU
"""
"""
Pytorch 0.4 oder später
x = x.to('cuda')
y = y.to('cuda:0') #Nach Cuda:Verwenden Sie eine GPU, die Zahlen unterstützt
z = x * y
z = z.to('cpu') #zu CPU
"""
print(x.is_cuda) #True, wenn sich die Variable auf der GPU befindet
Mit torchvision.models macht es Pytorch einfach, AlexNet, VGGNet, ResNet, DenseNet, SqueezeNet, GoogleNet zu definieren und diese trainierten Modelle einfach zu verwenden.
get_model.py
import torchvision.models as models
alexnet = models.alexnet()
pretrain_alexnet = models.alexnet(pretrained=True) #Geschulte Modelle können heruntergeladen werden, indem Sie die Option Pretrained auf True setzen
Darüber hinaus kann eine Feinabstimmung durchgeführt werden, indem die Anzahl der Abmessungen des Ausgangs wie unten gezeigt geändert wird.
finetune1.py
resnet = models.resnet50(pretrained=True)
resnet.fc = nn.Liear(2048, 100)
Wenn Sie nur einige Ebenen verwenden möchten, können Sie wie folgt schreiben.
finetune2.py
resnet = models.resnet50(pretrained=True)
resnet = nn.Sequential(*list(resnet.children())[:-3])
Es ist möglich, jede Schicht mit Scheiben herauszunehmen. Hier ist ein Beispiel für die Änderung des globalen Durchschnittspools von resnet in Max Pooling, um die Ausgabe 10-dimensional zu machen.
resnet_finetune.py
class Resnet(nn.Module):
def __init__(self):
super(Resnet,self).__init__()
resnet = models.resnet50(pretrained=True)
self.resnet = nn.Sequential(*list(resnet.children())[:-2])
self.maxpool = nn.MaxPool2d(kernel_size=7)
self.fc = nn.Linear(2048, 10)
def forward(self,x):
x = self.resnet(x)
x = self.maxpool(x)
x = self.fc(x)
return x
Verwenden Sie das Optim-Paket, um die Parameter mithilfe einer beliebigen Optimierungstechnik zu aktualisieren. Nachdem Sie die Parameter der Optimierungsmethode festgelegt haben, können Sie jedes Mal, wenn Sie eine Rückwärtsberechnung durchführen, durch Aufrufen von step () aktualisieren.
update.py
"""
Pytorch 0.4 oder später
if torch.cuda.is_available(): #Überprüfen Sie, ob eine GPU verfügbar ist
device = 'cuda'
else:
device = 'cpu'
"""
#Definition des Modells
model = models.resnet18()
"""
Pytorch 0.4 oder später
model = model.to(device)
"""
#Parametereinstellung der Optimierungsmethode
optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
#Definition der Verlustfunktion
criterion = nn.MSELoss()
#Generieren Sie Eingaben und korrigieren Sie die Antwort mit Zufallszahlen
input = torch.randn(1,3,224,224) #Charge x Kanal x Höhe x Breite
target = torch.randn(1,1000)
"""
# Pytorch 0.4 oder früher
#Wechseln Sie zu Variable und berechnen Sie
input = Variable(input)
"""
# requires_Wenn Sie grad auf False setzen, kann der Gradient für diese Variable nicht berechnet werden.
#Es ist standardmäßig auf False gesetzt, sodass es nicht explizit wie dieses Mal geschrieben werden muss.
"""
Pytorch 0.4 oder früher
target = Variable(target, requires_grad=False)
"""
"""
Pytorch 0.4 oder später
target.requires_grad = False
"""
#Das Verhalten von Modulen, die sich während des Lernens und der Inferenz unterschiedlich verhalten, wie z. B. die Batch-Normalisierung, kann in das Verhalten während des Lernens geändert werden.
# model.eval()Kann zum Zeitpunkt der Inferenz mit auf das Verhalten geändert werden
model.train()
#Lernschleife
for i in range(100):
#Vorwärtsausbreitung
out = model(input)
#Verlustberechnung
loss = criterion(out, target)
#Gradienteninitialisierung
optimizer.zero_grad()
#Gradientenberechnung
loss.backward()
#Parameteraktualisierung
optimizer.step()
Wenn Sie optim nicht verwenden, können Sie die Parameter aktualisieren, indem Sie den Teil von optimizer.step () wie folgt umschreiben.
update_without_optim.py
for param in model.parameters():
param.data -= learning_rate * param.grad.data
Im Fall von RNN ist es möglich, eine Rückausbreitung durchzuführen, indem ein Verlust wie unten gezeigt hinzugefügt und step () zum Aktualisierungszeitpunkt aufgerufen wird.
rnn_update.py
class RNN(nn.Module):
def __init__(self, data_size, hidden_size, output_size):
super(RNN, self).__init__()
self.hidden_size = hidden_size
input_size = data_size + hidden_size
self.i2h = nn.Linear(input_size, hidden_size)
self.h2o = nn.Linear(hidden_size, output_size)
def forward(self, data, last_hidden):
input = torch.cat((data, last_hidden), 1)
hidden = self.i2h(input)
output = self.h2o(hidden)
return hidden, output
RNN = RNN()
#Ausgelassen wie Optimierer
for i in range(10):
hidden, output = RNN(input, hidden)
loss += criterion(output, target)
loss.backward()
optimizer.step()
Im obigen Code wird der Verlust berechnet und die Parameter werden nach 10 Schritten aktualisiert.
Grundsätzlich kann es mit torch.save () wie Torch7 gespeichert werden, aber nur die Lernparameter werden mit state_dict () gespeichert.
model_save.py
model = models.resnet50(pretrained=True)
#Modell speichern
torch.save(model.state_dict(), 'weight.pth')
model2 = models.resnet50()
#Parameter laden
param = torch.load('weight.pth')
model2.load_state_dict(param)
Mit torch.save () und state_dict () kann nicht nur das Modell, sondern auch der Optimierer gespeichert werden.
optimizer_save.py
optimizer = optim.SGD(model.parameters(), lr=0.1)
torch.save(optimizer.state_dict(), 'optimizer.pth')
optimizer2 = optim.SGD(model.parameters(), lr=0.1)
optimizer2.load_state_dict(torch.load('optimizer.pth')
Pytorch kann mit Numpy auf einfache Weise originelle Ebenen und Funktionen erstellen. (Sie können auch in C schreiben) Erben Sie einfach die Funktionsklasse und schreiben Sie Vorwärts- und Rückwärtsberechnungen. Wenn Sie beispielsweise eine eigene ReLU-Funktion erstellen, sieht diese wie folgt aus. (Die Relu-Funktion ist ursprünglich implementiert, sodass Sie sie nicht selbst schreiben müssen.)
relu.py
from torch.autograd import Function
class relu(Function):
def forward(self,x):
# torch.Von Tensor bis Numpy
numpy_x = x.numpy()
result = np.maximum(numpy_x,0)
#von numpy bis fackel.Zu Tensor
result = torch.FloatTensor(result)
#Halten Sie den Tensor für die Rückwärtsberechnung gedrückt
self.save_for_backward(result)
return result
def backward(self, grad_output):
result = self.saved_tensors[0]
grad_input = grad_output.numpy() * (result.numpy() > 0)
#Gibt den Gradienten in Bezug auf die Eingabe zurück
return torch.FloatTensor(grad_input)
Wenn ein Parameter gelernt werden muss, muss Parameter in den Lernparameter gebissen und eine Klasse definiert werden, die nn.Module erbt. Implementieren Sie eine Operation, die nur die Eingabe als Beispiel gewichtet. (Wenn x = [1,2,3], w = [0,1,0,2,0,3] ist, ist die Ausgabe [0,1,0,4,0,9]. W ist ein lernbarer Parameter)
elemwise.py
from torch.autograd import Function
from torch.nn.parameter import Parameter
class elemwiseFunction(Function):
def forward(self, x, w):
self.save_for_backward(x, w)
numpy_x = x.numpy()
numpy_w = w.numpy()
result = numpy_x*numpy_w
return torch.FloatTensor(result)
def backward(self, grad_output):
input, w = self.saved_tensors
w_grad = input.numpy() * grad_output
x_grad = w.numpy() * grad_output
#Gibt den Gradienten für die Eingabe und den Gradienten für die Lernparameter zurück
return torch.FloatTensor(x_grad), torch.FloatTensor(w_grad)
class elemwise(nn.Module):
def __init__(self):
super(elemwise,self).__init__()
self.w = Parameter(torch.randn(10)
def forward(self):
return elemwiseFunction()(x, self.w)
Der obige Code muss nicht numpy verwenden, da die Eingabe und Ausgabe von vorwärts und rückwärts torch.Tensor sein sollte. Sie können beispielsweise mit cupy oder mit extremer Theorie oder anderen Bibliotheken schreiben. Da Pytorch über eine automatische Differenzierung verfügt, ist es auch nicht erforderlich, rückwärts zu schreiben, indem die Berechnung des Fackels abgeschlossen wird. Tensor ohne Verwendung von numpy in der obigen Berechnung.
elemwise_without_backward.py
class elemwise(nn.Module):
def __init__(self):
super(elemwise,self).__init__()
self.w = Parameter(torch.randn(10)
def forward(self, x):
return x * self.w
Im Folgenden finden Sie eine Referenzsite zum Definieren eigener Layer in C oder C ++ und zum Definieren von Funktionen mithilfe des CUDA-Kernels. Offizielles Tutorial zum Erweitern mit C, Offizielle Implementierung mit C, Offizielles Implementierungsbeispiel in C ++, Offizielles Tutorial zur Erweiterung mit C ++ und Cuda-Kernel ), Pytorch-Quellcode Im Quellcode haben TH ,, THS, THC und THCS Implementierungen, die sich auf torch.Tensor beziehen, und THNN und THCUNN haben Implementierungen, die sich auf neuronale Netze beziehen.
Im Folgenden finden Sie einige Tipps zum Erlernen von NN. Ich möchte es jedes Mal hinzufügen, wenn ich mich an etwas erinnere.
pytorch führt Berechnungen durch, während ein Berechnungsdiagramm für Rückwärts während der Vorwärtsausbreitung erstellt wird. Dies ist während der Inferenz nicht erforderlich und es wird empfohlen, es wie folgt zu stoppen, um Speicherplatz zu sparen.
no_grad.py
import torch
x = torch.randn(10)
"""
Pytorch 0.4 oder früher
"""
from torch.autograd import Variable
x = Variable(x, volatile=True) #Setzen Sie die flüchtige Option auf True
y = x**2
"""
Pytorch 0.4 oder später
"""
with torch.no_grad():
#Führen Sie Operationen aus, mit denen Sie kein Berechnungsdiagramm erstellen möchten
y = x**2
Möglicherweise möchten Sie den durchschnittlichen Verlust berechnen, um den Lernprozess anzuzeigen. Wenn Sie zu diesem Zeitpunkt einfach die Verluste jeder Iteration addieren, besteht das Problem, dass das Berechnungsdiagramm weiterhin erstellt wird und der Speicher belegt wird. Beschreiben Sie daher Folgendes.
mean_loss.py
sum_loss = 0
#Lernschleife
for i in range(100):
"""
Beschreibung wie Vorwärtsausbreitung
"""
loss = loss_function(outputs, targets) #Berechnen Sie den Verlust mit einer geeigneten Verlustfunktion
"""
Pytorch 0.4 oder früher
"""
#Variable zum Fackeln nach Daten.Zu Tensor. Wechseln Sie außerdem von gpu zu cpu und geben Sie den 0. Index an.
sum_loss += loss.data.cpu()[0]
"""
Pytorch 0.4 oder später
"""
sum_loss += loss.item()
print("mean loss: ", sum_loss/i)
Die Operation war vor Pytorch 0.4 mühsam, wurde jedoch durch Aufrufen von item () nach 0.4 einfacher.
Recommended Posts