pytorch Eine Einführung in pytorch durch Anfänger.
Wenn Sie ein solches neues Framework verwenden, ist es meiner Meinung nach die beste Abkürzung, sich das Beispiel anzusehen und die dort verwendeten Funktionen zu googeln, das Dokument zu lesen oder damit zu spielen. Dies ist also ein Memo.
Wenn Sie versuchen, auf ähnliche Weise mit Pytorch zu beginnen, sparen Sie in diesem Artikel Zeit. (Ich bin froh, wenn du wirst.)
Im Code von cifar10-tutorial wird CNN mit CIFAR10 ausgeführt Dekodierung oder Google-Arbeit ist erledigt.
Die Installation von pytorch ist sehr einfach. Wenn Sie auf der offiziellen Website auf Ihre Umgebung klicken, wird der Installationscode angezeigt. In meiner Umgebung war es wie folgt.
http://pytorch.org/
pip install http://download.pytorch.org/whl/cu80/torch-0.2.0.post3-cp36-cp36m-manylinux1_x86_64.whl
pip install torchvision
Schauen wir uns zunächst diesen Code an, der die Daten lädt und vorbereitet.
import torch
import torchvision
import torchvision.transforms as transforms
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,shuffle=False, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
torchvision ist ein Paket für die Computer Vision von pytorch und scheint Funktionen zum Laden von Daten und zur Vorverarbeitung zu enthalten. ..
Verwenden Sie transforms.Compose
, um die Vorverarbeitungsfunktion zu konfigurieren, die nach dem Laden der Daten ausgeführt werden soll.
Wie der Name schon sagt, ändert "ToTensor ()" den Datentyp in einen Tensor namens "torch.Tensor", der von pytorch definiert wird.
Da das Argument von "transforms.Normalize" "torch.Tensor" ist, werden die Funktionen in der Reihenfolge vom Anfang der Liste ausgeführt.
[`` transforms.Normalize ((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)
`](http://pytorch.org/docs/master/torchvision/transforms.html#torchvision.transforms. In Normalize) repräsentiert das erste Taple des Arguments den Durchschnitt jedes RGB-Kanals und das zweite Taple die Standardabweichung. Normalisieren Sie gemäß diesen Durchschnittswerten und Standardabweichungen.
Mit anderen Worten
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
Jetzt haben Sie eine Funktion, die die Daten in einen Tensortyp für Pytorch umwandelt und eine Normalisierung durchführt.
`` `Torchvision.datasets.CIFAR10``` ist eine Klasse zum Laden von CIFAR10-Daten, wie der Name schon sagt.
Wenn download = True
, speichern Sie die Daten im Stammverzeichnis.
Für MNIST und CIFAR10 sind die Datensätze bereits in Training und Test unterteilt. (Ich denke, Sie können es mischen und selbst teilen)
In CIFAR10 gibt es 60000 Bilder, von denen 50000 zum Training und 10000 zum Testen dienen. Wenn "Zug = Wahr" eingestellt ist, werden 50000 geladen, die für das Training im Voraus verwendet werden sollen, und wenn "Zug = Falsch", werden 10000 Testdaten geladen.
Wenn Sie eine Reihe von Vorverarbeitungsabläufen übergeben, die mit transforms.Compose
mit dem Argument transform
erstellt wurden, wird die nach dem Laden übergebene Vorverarbeitung ausgeführt.
DataLoader fügt sampler in den geladenen Datensatz ein. /_modules/torch/utils/data/sampler.html) Dies ist eine Klasse, die ein Objekt zum Abtasten von Daten ist. Wenn Sie es überprüfen, ist der Sampler sicherlich angeschlossen.
trainloader.sampler
# <torch.utils.data.sampler.RandomSampler at 0x7f9099e13ef0>
Sampler hatte offenbar Zufallsstichproben, sequentielle Stichproben, gewichtete Stichproben usw. ..
Das Argument von [DataLoader] enthält einen Sampler (http://pytorch.org/docs/master/data.html#torch.utils.data.DataLoader). Wenn Sie also den hier definierten Sampler übergeben Ich habe ein gutes Gefühl, also lass es uns versuchen.
Um das Ergebnis verständlich zu machen, werden wir hier nur ein Datenelement gewichten und abtasten. Da die Anzahl der Daten gering und einfach ist, werde ich es mit Testdaten versuchen.
import numpy as np
#Erstellen Sie einen Gewichtsvektor von 1 für nur ein Bild.
weights = np.zeros(10000) #Die Anzahl der Testdaten beträgt 10000
weights[300] = 1. #300 ist geeignet
num_samples = 4 #Anzahl der Probenahmen
#Versuchen Sie WeightedRandomSampler.
my_sampler = torch.utils.data.sampler.WeightedRandomSampler(weights, num_samples, replacement=True)
my_testloader = torch.utils.data.DataLoader(testset, batch_size=4,shuffle=False, num_workers=2, sampler=my_sampler)
my_testiter = iter(my_testloader)
images, labels = my_testiter.next()
#Die imshow-Funktion wird als nächstes erklärt, aber ich werde sie etwas früher verwenden.
def imshow(img):
img = img / 2 + 0.5 # unnormalize
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
imshow(torchvision.utils.make_grid(images))
Oh, es ist nur ein Frosch.
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
# functions to show an image
def imshow(img):
img = img / 2 + 0.5 # unnormalize
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()
# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
img = img / 2 + 0.Der Kommentar im 5. Teil enthält eine Unnormalisierung, aber ich halte die Unnormalisierung für etwas irreführend. Es wird gesagt, dass es normalisiert ist.
Da die Eingabe von [plt.imshow](https://matplotlib.org/devdocs/api/_as_gen/matplotlib.pyplot.imshow.html) [0,1] ist, wird sie entsprechend verschoben.
## 3.7. Was ist img.numpy ()?
```python
type(img) # torch.FloatTensor
torch.Tensor ist der von Pytorch behandelte Tensortyp und wird als "Elementdatentyp + Tensor" bezeichnet. .. In diesem Fall handelt es sich, da es sich um einen Float-Tensor handelt, um einen Float, dh einen 32-Bit-Gleitkomma.
Entweder der in `` `Document``` zurückgegebene ndarray und der ursprüngliche Tensor teilen sich den gleichen Bereich. Wenn Sie es ändern, wird auch das andere geändert.
Lass es uns überprüfen.
a = torch.FloatTensor([1])
b = a.numpy()
#Ändern Sie ndarray
b[0] = 2
#Der ursprüngliche Tensor ist ebenfalls 2.
print("original tensor: ", a) # original tensor: 2
print("ndarray : ", b) # ndarray : [ 2.]
#Es bezieht sich auf einen anderen Speicherbereich.
print(id(a)) # 140024484781832
print(id(b)) # 140024044621056
Oh, die Änderungen in ndarray spiegeln sich auch im ursprünglichen Tensor wider. Da die reservierten Speicherbereiche unterschiedlich sind, scheinen sie so zu funktionieren, als würden sie praktisch denselben Bereich gemeinsam nutzen, indem die Werte gleich bleiben.
npimg = img.numpy()
npimg2 = np.transpose(npimg, (1, 2, 0))
print(npimg.shape) # (3, 36, 138)
print(npimg2.shape) # (36, 138, 3)
In der Dokumentation sind die Argumente für plt.imshow
wie (n, m, RGB) angeordnet. Muss sein.
Da npimg ursprünglich mit (RGB, vertikal, horizontal) ausgerichtet ist, wird es in der Reihenfolge des zweiten Arguments von `` `np.transpose``` sortiert.
dataiter = iter(trainloader)
print(type(trainloader))
# <class 'torch.utils.data.dataloader.DataLoader'>
print(type(dataiter))
# <class 'torch.utils.data.dataloader.DataLoaderIter'>
Der in DataLoader definierte __iter__
wird von iter () aufgerufen und gibt DataLoaderIter
zurück.
Im Gegensatz zu einem normalen Iterator müssen Sie Daten in Schritten von batch_size übergeben, sodass sie anscheinend einen dedizierten Iterator definiert haben. (Code)
Infolgedessen werden jedes Mal, wenn Sie "dataiter.next ()" aufrufen, der n-te Stapel, der n + 1-Stapel und wiederholte Daten erfasst.
img = torchvision.utils.make_grid(images)
print(type(images)) # <class 'torch.FloatTensor'>
print(images.size) # torch.Size([4, 3, 32, 32])
print(type(img)) # <class 'torch.FloatTensor'>
print(img.size) # torch.Size([3, 36, 138])
Die Dokumentation lautet torchvision.utils.make_grid.
Die Funktion make_grid
ordnet mehrere Bilder nebeneinander an.
Das Argument von make_grid
ist ein 4-dimensionaler Tensor, während der Rückgabewert ein 3-dimensionaler Tensor ist. Das Argument Tensor war ein 4-dimensionaler Tensor von [Anzahl der Bilder, RGB, vertikal, horizontal], aber die Dimension der Anzahl der Bilder ist verschwunden.
Und wie in der Dokumentation angegeben, werden standardmäßig `` `padding = 2``` verwendet, sodass 2 über und unter 36 hinzugefügt werden und 2 zwischen jedem Bild und an beiden Enden 32 * n + 2 * hinzugefügt werden. (n + 1) = 138 (n = 4) Mit anderen Worten ist 32 138 für die Horizontale.
Werfen wir einen Blick auf diesen Code.
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
Variable
umschließt torch.Tensor so, dass es Gradientendaten usw. aufnehmen kann. ..
Variable umschließt einen Tensor, sodass ein Schritt erforderlich ist, wenn Sie die in Variable enthaltenen Daten anzeigen möchten.
a = torch.FloatTensor([1.])
a2 = Variable(a)
print(type(a)) # <class 'torch.FloatTensor'>
print(type(a2)) # <class 'torch.autograd.variable.Variable'>
print(type(a2.data)) # <class 'torch.FloatTensor'>
print(a.numpy()) # [ 1.]
print(a2.data.numpy()) # [ 1.]
Wie oben gezeigt, wird der Tensor in ".data" gespeichert. (Referenz)
Die Gradienteninformation ist übrigens
print(a2.grad) # None
Es wird hier gespeichert. Momentan gibt es nichts, daher ist keines enthalten. Es scheint, dass nur "Keine" oder "Variable" akzeptiert wird.
a2.grad = Variable(torch.FloatTensor([100]))
print(a2.grad) # Variable containing: 100
Es scheint, dass Sie es auf der Rückseite so ersetzen können. Und die Tatsache, dass nur Variable akzeptiert wird, bedeutet, dass dort auch Gradienteninformationen gespeichert werden.
a2.grad.grad = Variable(torch.FloatTensor([200]))
print(a2.grad.grad) # Variable containing: 200
Wird die höhere Ableitung auf diese Weise manipuliert? Es ist interessant.
class Net(nn.Module):
nn.Module Die Klasse ist eine Basisklasse, und Forward usw. werden in dieser und beim Erstellen eines Modells definiert. Es erbt dies. (Tatsächlich ist etwas Konkretes nicht vorwärts definiert, und es scheint anzunehmen, dass es nach der Vererbung zugewiesen wird.)
Das Argument von nn.Conv2d lautet Von links die Anzahl der Eingangskanäle, die Anzahl der Ausgangskanäle und die Kernelgröße.
Zum Zeitpunkt dieser Modelldefinition wird ein Zufallswert nahe 0 in den Filter eingegeben, der ein Parameter der Faltungsschicht ist, und er wird vorbereitet. Dies kann wie folgt bestätigt werden.
conv1 = nn.Conv2d(3, 6, 5)
print(conv1.weight)
Parameter containing:
(0 ,0 ,.,.) =
-0.0011 -0.1120 0.0351 -0.0488 0.0323
-0.0529 -0.0126 0.1139 -0.0234 -0.0729
0.0384 -0.0263 -0.0903 0.1065 0.0702
0.0087 -0.0492 0.0519 0.0254 -0.0941
0.0351 -0.0556 -0.0279 -0.0641 -0.0790
(0 ,1 ,.,.) =
-0.0738 0.0853 0.0817 -0.1121 0.0463
-0.0266 0.0360 0.0215 -0.0997 -0.0559
0.0441 -0.0151 0.0309 -0.0026 0.0167
-0.0534 0.0699 -0.0295 -0.1043 -0.0614
-0.0820 -0.0549 -0.0654 -0.1144 0.0049
...
[torch.FloatTensor of size 6x3x5x5]
Da die Kernelgröße auf 5 eingestellt ist, wird der Tensor (Anzahl der Ausgangskanäle, RGB, Kernelgröße, Kernelgröße) vorbereitet. Apropos,
conv1 = nn.Conv2d(3, 6, (5,1))
print(conv1.weight)
Parameter containing:
(0 ,0 ,.,.) =
0.2339
-0.0756
0.0604
-0.0185
-0.0975
...
Es scheint, dass Sie etwas anderes als Quadrat tun können.
Auch dieser Parameter ist
type(conv1.weight)
# torch.nn.parameter.Parameter
Es wird durch das Parameter-Objekt wie folgt definiert und ist eine Unterklasse von Variable
. Es sieht aus wie ein kurzer Blick. , Die Anzeigefunktion ist definiert. Wenn es sich um eine Variable handelt, wird sie als Variable mit angezeigt. In Parameter wird sie jedoch als Parameter mit: angezeigt.
nn.MaxPool2d ist die MAX-Pooling-Schicht. Die Hauptargumente sind kernel_size, stride und padding.
Lassen Sie uns also das adaptive Bild falten und MAX bündeln und sehen, wie es konvertiert wird.
images, labels = dataiter.next()
print(images.size())
print(type(images))
image_plot = images[0][1].numpy()
plt.imshow(image_plot, cmap='Greys', interpolation='nearest')
plt.show()
#Modelldefinition
img_input = Variable(images)
conv = nn.Conv2d(3, 1, 3, padding=1)
pool = nn.MaxPool2d(3, padding=1, stride=1)
#nach vorne
conv_output = conv(img_input)
pool_output = pool(conv_output)
print(pool_output.size())
#Handlung
conv_plot = conv_output[0][0].data.numpy()
conv_plot
plt.imshow(conv_plot, cmap='Greys', interpolation='nearest')
plt.show()
pool_plot = pool_output[0][0].data.numpy()
plt.imshow(pool_plot, cmap='Greys', interpolation='nearest')
plt.show()
--Original Bild Es ist ein Pferd.
Bild nach dem Falten Da die Faltung die Filterparameter noch nicht gelernt hat, handelt es sich um einen Zufallsparameter in der Nähe von 0, und alle haben den gleichen Wert, so dass es anscheinend keinen großen Unterschied gibt.
Bild nach dem Falten & MAX Pooling Sie können sehen, dass das MAX-Pooling ein 3 * 3-MAX hat und unscharf ist.
Schauen wir uns als nächstes [diesen Code] an (http://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#define-a-loss-function-and-optimizer).
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
nn.CrossEntropyLoss () definiert ein Objekt als Zielfunktion.
`` `torch.optim``` definiert verschiedene Optimierungsalgorithmen. SGD, Adam usw.
Unter den in torch.optim
definierten Optimierungsalgorithmen verwenden wir hier optim.SGD. Ich werde.
Wir übergeben "net.parameters ()" als Argument an "optim.SGD".
net.parameters ()
scheint die im Modell (torch.nn.parameter.Parameter
) definierten Parameter als Generator zurückzugeben.
type(net.parameters())
# generator
type(net.parameters().__next__())
# torch.nn.parameter.Parameter
print(net.parameters().__next__())
Parameter containing:
(0 ,0 ,.,.) =
-0.0998 0.0035 -0.0438 -0.1150 -0.0435
0.0310 -0.0750 -0.0405 -0.0745 -0.1095
-0.0355 0.0065 -0.0225 0.0729 -0.1114
0.0708 -0.0170 -0.0253 0.1060 0.0557
0.1057 0.0873 0.0793 -0.0309 -0.0861
...
Wenn Sie das vom Optimierer gehaltene Objekt überprüfen,
optimizer.__dict__
{'param_groups': [{'dampening': 0,
'lr': 0.001,
'momentum': 0.9,
'nesterov': False,
'params': [Parameter containing:
(0 ,0 ,.,.) =
0.0380 -0.1152 0.0761 0.0964 -0.0555
-0.0325 -0.0455 -0.0755 0.0413 -0.0589
0.0116 0.1136 -0.0992 -0.1149 -0.0414
-0.0611 0.0827 -0.0906 0.0631 0.0170
0.0903 -0.0816 -0.0690 0.0470 -0.0578
...
net.parameters ()
behält alle im Modell enthaltenen Parameter bei, einschließlich meiner Parameter.
Werfen wir einen Blick auf den [Code] für das Training (http://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#train-the-network).
for epoch in range(2): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
#Das zweite Argument ist die Startposition, die 0 ist(trainloader)Gleich wie
# https://docs.python.org/3/library/functions.html#enumerate
# get the inputs
inputs, labels = data
# wrap them in Variable
inputs, labels = Variable(inputs), Variable(labels)
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# print statistics
running_loss += loss.data[0]
if i % 2000 == 1999: # print every 2000 mini-batches
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training')
Wie wir zuvor bestätigt haben, enthält `` `Optimizer``` alle Parameter.
optimizer.zero_grad ()
initialisiert den Grad dieser gehaltenen Variablen. Es scheint.
Ich denke es ist alles keine.
outputs = net(inputs)
print(type(outputs))
# <class 'torch.autograd.variable.Variable'>
print(outputs.size())
# torch.Size([4, 10])
outputs
Variable containing:
-2.4825 -4.4286 2.2041 3.4353 2.0734 2.8198 1.9374 0.7751 -2.6798 -3.1932
-1.7512 -4.6657 2.7911 3.9570 0.7931 5.9005 -0.8023 2.9664 -4.3328 -3.2921
2.4015 2.8962 0.9330 -1.2107 -0.0525 -2.2119 -1.2474 -2.6026 -0.1120 0.4869
-1.3042 -2.7538 1.0985 -0.2462 3.7435 1.1724 -1.4233 6.6892 -3.8201 -2.3132
[torch.FloatTensor of size 4x10]
Wenn Sie es an "net" übergeben, können Sie sehen, dass die endgültige Ausgabe über die Zielfunktion zurückgegeben wird.
Der Kommentar sagt vorwärts + rückwärts + optimieren, aber ich kann die Vorwärtsmethode nicht sehen.
Dies liegt tatsächlich daran, dass CrossEntropyLoss mit call weiterleitet, was bedeutet
loss = criterion(outputs, labels)
loss = criterion.forward(outputs, labels)
Die beiden machen das Gleiche. "Verlust = Kriterium (Ausgaben, Beschriftungen)" ist also vorwärts.
loss
ist ein variables Objekt.
type(loss)
# torch.autograd.variable.Variable
Variable.backward () befindet sich in diesem [torch.autograd.backward ()](http: / /pytorch.org/docs/master/autograd.html#torch.autograd.backward) wird aufgerufen.
Dann ermittelt dieses ".backward ()" den Differentialkoeffizienten des in der Zielfunktion enthaltenen Parameters. Versuchen wir es mit einem einfachen Beispiel.
x = torch.autograd.Variable(torch.Tensor([3,4]), requires_grad=True)
# requires_grad=True sagt Ihnen, dass diese Variable differenziert
print("x.grad : ", x.grad)
# None
#Zu diesem Zeitpunkt ist noch nichts drin.
#Erstellen Sie eine Zielfunktion entsprechend.
y = x[0]**2 + 5*x[1] + x[0]*x[1]
# x[0]Derivat von: 2*x[0] + x[1]
# x[0]Differenzkoeffizient von: 2*3 + 4 = 10
# x[1]Derivat von: 5 + x[0]
# x[1]Differenzkoeffizient von: 5 + 3 = 8
y.backward()
# torch.autograd.backward(y)Aber es ist okay.
print("x.grad : ", x.grad)
# 10
# 8
# .zero_grad()anstatt
x.grad = None
Es ist der Differentialkoeffizient der Zielfunktion "y" am Eingangsdatenpunkt. Hierbei ist zu beachten, dass es bei Rückwärts um die Verlustfunktion geht, also muss Rückwärts y ein Skalar sein.
Zum Beispiel
y = x
y.backward()
# RuntimeError: grad can be implicitly created only for scalar outputs
Dann werde ich wütend, es zu einem Skalar zu machen.
.step () aktualisiert die Parameter basierend auf dem von .backward ()
berechneten Gradienten Werde es tun.
Lass es uns überprüfen.
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
print(net.parameters().__next__())
Parameter containing:
(0 ,0 ,.,.) =
-0.0839 0.1434 -0.0371 -0.1394 -0.0277
Nach mehrmaliger Ausführung (obwohl es mit denselben Daten optimiert wurde)
print(net.parameters().__next__())
Parameter containing:
(0 ,0 ,.,.) =
-0.0834 0.1436 -0.0371 -0.1389 -0.0276
Und so werden die Parameter nach und nach aktualisiert.
Sagen Sie das Modell für die Testdaten voraus. Dieser Code.
correct = 0
total = 0
for data in testloader:
images, labels = data
outputs = net(Variable(images))
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
for data in testloader:
images, labels = data
#print("images type : ", type(images))
#print("images.shape : ", images.shape)
outputs = net(Variable(images))
_, predicted = torch.max(outputs.data, 1)
c = (predicted == labels).squeeze()
for i in range(4):
label = labels[i]
class_correct[label] += c[i]
class_total[label] += 1
for i in range(10):
print('Accuracy of %5s : %2d %%' % (
classes[i], 100 * class_correct[i] / class_total[i]))
# Accuracy of plane : 51 %
# Accuracy of car : 54 %
# Accuracy of bird : 53 %
# Accuracy of cat : 33 %
# Accuracy of deer : 41 %
# Accuracy of dog : 50 %
# Accuracy of frog : 54 %
# Accuracy of horse : 65 %
# Accuracy of ship : 70 %
# Accuracy of truck : 67 %
Ist dies der einzige, mit dem ich nicht vertraut bin? torch.squeeze Löschen Sie in der Dimension des Tensors die von 1. Es scheint, dass Quetschen Quetschen bedeutet.
Sie können herausfinden, um welche Art von Modell es sich handelt, indem Sie auf ~~ net.parameters
schauen. ~~ (Korrigiert am 27. Oktober 2017)
Da das __repr__
von nn.Module so definiert ist, dass das Modell leicht lesbar angezeigt wird, können Sie grob verstehen, um welche Art von Modell es sich handelt.
In [22]: net
Out[22]:
Net (
(conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
(pool): MaxPool2d (size=(2, 2), stride=(2, 2), dilation=(1, 1))
(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear (400 -> 120)
(fc2): Linear (120 -> 84)
(fc3): Linear (84 -> 10)
)
Recommended Posts