Einfach ausgedrückt, torch.Tensor.view()
die von numpy.ndarray.reshape()
oder inspiriert ist numpy.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.
In [43]: t = torch.arange(18)
In [44]: t
Out[44]:
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17])
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 (gleich 18
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 einem RuntimeError
:
RuntimeError: Es kann nur eine Dimension abgeleitet werden
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 .
# stride of our original tensor `t`
In [53]: t.stride()
Out[53]: (1,)
Jetzt werden wir die Schritte für die neuen Ansichten sehen :
# shape (1, 18)
In [54]: t1 = t.view(1, -1)
# stride tensor `t1` with shape (1, 18)
In [55]: t1.stride()
Out[55]: (18, 1)
# shape (2, 9)
In [56]: t2 = t.view(2, -1)
# stride of tensor `t2` with shape (2, 9)
In [57]: t2.stride()
Out[57]: (9, 1)
# shape (3, 6)
In [59]: t3 = t.view(3, -1)
# stride of tensor `t3` with shape (3, 6)
In [60]: t3.stride()
Out[60]: (6, 1)
# shape (6, 3)
In [62]: t4 = t.view(6,-1)
# stride of tensor `t4` with shape (6, 3)
In [63]: t4.stride()
Out[63]: (3, 1)
# shape (9, 2)
In [65]: t5 = t.view(9, -1)
# stride of tensor `t5` with shape (9, 2)
In [66]: t5.stride()
Out[66]: (2, 1)
# shape (18, 1)
In [68]: t6 = t.view(18, -1)
# stride of tensor `t6` with shape (18, 1)
In [69]: t6.stride()
Out[69]: (1, 1)
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.
In [74]: t3.shape
Out[74]: torch.Size([3, 6])
|
In [75]: t3.stride() |
Out[75]: (6, 1) |
|_____________|
Das ist weil:
In [76]: t3
Out[76]:
tensor([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17]])
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 von 0
zu 6
, 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 von 2
zu 3
).
Somit ist die Schrittinformation das Herzstück dessen, wie auf die Elemente aus dem Speicher zugegriffen wird, um die Berechnung durchzuführen.
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:
zusammenhängende Eingaben und Eingaben mit kompatiblen Schritten können ohne Kopieren umgeformt werden, aber man sollte nicht vom Kopier- oder Anzeigeverhalten abhängen.
reshape
in PyTorch genannt?!