Ich bin verwirrt über die Methode view()
im folgenden Code-Snippet.
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()
Meine Verwirrung betrifft die folgende Zeile.
x = x.view(-1, 16*5*5)
Was macht die tensor.view()
Funktion? Ich habe seine Verwendung an vielen Stellen gesehen, aber ich kann nicht verstehen, wie es seine Parameter interpretiert.
Was passiert, wenn ich der view()
Funktion negative Werte als Parameter gebe ? Was passiert zum Beispiel, wenn ich anrufe tensor_variable.view(1, 1, -1)
?
Kann jemand das Hauptfunktionsprinzip anhand view()
einiger Beispiele erklären ?
reshape
in PyTorch genannt?!Lassen Sie uns einige Beispiele machen, von einfacher bis schwieriger.
Die
view
Methode gibt einen Tensor mit denselben Daten wie derself
Tensor zurück (was bedeutet, dass der zurückgegebene Tensor die gleiche Anzahl von Elementen hat), jedoch mit einer anderen Form. Beispielsweise:Angenommen, dies
-1
ist keiner der Parameter. Wenn Sie sie miteinander multiplizieren, muss das Ergebnis der Anzahl der Elemente im Tensor entsprechen. Wenn Sie: tuna.view(3, 3)
, wird eineRuntimeError
weil-Form (3 x 3) ausgelöst, die für die Eingabe mit 16 Elementen ungültig ist. Mit anderen Worten: 3 x 3 entspricht nicht 16, sondern 9.Sie können
-1
als einen der Parameter verwenden, die Sie an die Funktion übergeben, jedoch nur einmal. Alles, was passiert, ist, dass die Methode die Mathematik für Sie erledigt, wie diese Dimension gefüllt werden soll. Zum Beispiela.view(2, -1, 4)
ist äquivalent zua.view(2, 2, 4)
. [16 / (2 x 4) = 2]Beachten Sie, dass der zurückgegebene Tensor dieselben Daten verwendet . Wenn Sie in der "Ansicht" eine Änderung vornehmen, ändern Sie die Daten des ursprünglichen Tensors:
Nun zu einem komplexeren Anwendungsfall. Die Dokumentation besagt, dass jede neue Ansichtsdimension entweder ein Unterraum einer ursprünglichen Dimension sein muss oder nur d, d + 1, ..., d + k überspannen muss , die die folgende zusammenhängungsähnliche Bedingung erfüllen, dass für alle i = 0 ,. .., k - 1, Schritt [i] = Schritt [i + 1] x Größe [i + 1] . Andernfalls
contiguous()
muss aufgerufen werden, bevor der Tensor angezeigt werden kann. Beispielsweise:Beachten Sie, dass für
a_t
, schreiten [0]! = Schritt [1] x Größe [1] seit 24! = 2 x 3quelle
torch.Tensor.view()
Einfach ausgedrückt,
torch.Tensor.view()
die vonnumpy.ndarray.reshape()
oder inspiriert istnumpy.reshape()
, erzeugt eine neue Ansicht des Tensors, solange die neue Form mit der Form des ursprünglichen Tensors kompatibel ist.Lassen Sie uns dies anhand eines konkreten Beispiels im Detail verstehen.
Mit dieser Tensor
t
der Form(18,)
, neue Ansichten können nur für die folgenden Formen erstellt werden:(1, 18)
oder gleichwertig(1, -1)
oder oder gleichwertig oder oder gleichwertig oder oder gleichwertig oder oder gleichwertig oder oder gleichwertig oder(-1, 18)
(2, 9)
(2, -1)
(-1, 9)
(3, 6)
(3, -1)
(-1, 6)
(6, 3)
(6, -1)
(-1, 3)
(9, 2)
(9, -1)
(-1, 2)
(18, 1)
(18, -1)
(-1, 1)
Wie wir bereits aus der obigen Form Tupeln beobachten können, die Multiplikation der Elemente der Form Tupel (zB
2*9
,3*6
usw.) muß immer auf die Gesamtzahl der Elemente in der ursprünglichen Tensor (gleich18
in unserem Beispiel).Eine andere Sache zu beobachten ist, dass wir ein
-1
an einer der Stellen in jedem der Formtupel verwendet haben. Durch die Verwendung von a-1
sind wir bei der Berechnung selbst faul und delegieren die Aufgabe eher an PyTorch, um diesen Wert für die Form zu berechnen, wenn die neue Ansicht erstellt wird . Eine wichtige Sache zu beachten ist, dass wir nur ein einzelnes-1
in der Form Tupel verwenden können. Die restlichen Werte sollten ausdrücklich von uns angegeben werden. Andernfalls beschwert sich PyTorch mit einemRuntimeError
:Bei allen oben genannten Formen gibt PyTorch immer eine neue Ansicht des ursprünglichen Tensors zurück
t
. Dies bedeutet im Grunde, dass nur die Schrittinformationen des Tensors für jede der neuen angeforderten Ansichten geändert werden.Im Folgenden finden Sie einige Beispiele, die veranschaulichen, wie sich die Schritte der Tensoren bei jeder neuen Ansicht ändern .
Jetzt werden wir die Schritte für die neuen Ansichten sehen :
Das ist also die Magie der
view()
Funktion. Es werden nur die Schritte des (ursprünglichen) Tensors für jede der neuen Ansichten geändert , solange die Form der neuen Ansicht mit der ursprünglichen Form kompatibel ist.Ein weitere interessante Sache könnte man aus den Schritten Tupeln beobachten ist , dass der Wert des Elements in der 0 - ten Position auf den Wert des Elements in der gleich 1 st Position des Form Tupels.
Das ist weil:
der Schritt
(6, 1)
sagt , dass entlang der 0 auf das nächste Element von einem Elemente gehen th Dimension, müssen wir springen 6 Stufen oder nehmen. (dh , um von0
zu6
, hat man 6 Schritte unternehmen.) Aber von einem Element zum nächsten Element in der 1 zu gehen st Dimension, wir müssen nur nur einen Schritt (zum Beispiel , um von2
zu3
).Somit ist die Schrittinformation das Herzstück dessen, wie auf die Elemente aus dem Speicher zugegriffen wird, um die Berechnung durchzuführen.
torch.reshape ()
Diese Funktion würde eine Ansicht zurückgeben und entspricht genau der Verwendung
torch.Tensor.view()
, solange die neue Form mit der Form des ursprünglichen Tensors kompatibel ist. Andernfalls wird eine Kopie zurückgegeben.Die Notizen von
torch.reshape()
warnen jedoch, dass:quelle
Ich habe herausgefunden, dass dies
x.view(-1, 16 * 5 * 5)
äquivalent zu istx.flatten(1)
, wenn der Parameter 1 angibt, dass der Abflachungsprozess ab der 1. Dimension beginnt (ohne die 'Beispiel'-Dimension abzuflachen). Wie Sie sehen können, ist die letztere Verwendung semantisch klarer und einfacher zu verwenden, also ich bevorzugenflatten()
.quelle
Sie können
-1
als dynamische Anzahl von Parametern oder "irgendetwas" lesen . Aus diesem Grunde kann es nur ein Parameter sein-1
inview()
.Wenn Sie danach fragen,
x.view(-1,1)
wird[anything, 1]
abhängig von der Anzahl der Elemente in die Tensorform ausgegebenx
. Beispielsweise:Wird ausgegeben:
quelle
weights.reshape(a, b)
gibt einen neuen Tensor mit denselben Daten wie Gewichte mit der Größe (a, b) zurück, in dem die Daten in einen anderen Teil des Speichers kopiert werden.weights.resize_(a, b)
Gibt den gleichen Tensor mit einer anderen Form zurück. Wenn die neue Form jedoch zu weniger Elementen als der ursprüngliche Tensor führt, werden einige Elemente aus dem Tensor entfernt (jedoch nicht aus dem Speicher). Wenn die neue Form zu mehr Elementen als der ursprüngliche Tensor führt, werden neue Elemente im Speicher nicht initialisiert.weights.view(a, b)
gibt einen neuen Tensor mit denselben Daten zurück wie Gewichte mit Größe (a, b)quelle
Ich mochte @ Jadiel de Armas Beispiele sehr.
Ich möchte einen kleinen Einblick in die Reihenfolge der Elemente für .view (...) geben.
quelle
Versuchen wir, die Ansicht anhand der folgenden Beispiele zu verstehen:
-1 als Argumentwert ist eine einfache Methode, um den Wert von say x zu berechnen, vorausgesetzt, wir kennen die Werte von y, z oder umgekehrt, im Fall von 3d, und für 2d wiederum eine einfache Methode, um den Wert von say x zu berechnen, vorausgesetzt, wir Werte von y kennen oder umgekehrt ..
quelle