Mówiąc prosto, torch.Tensor.view()
który jest inspirowany przez numpy.ndarray.reshape()
lub numpy.reshape()
, tworzy nowy widok tensora, o ile nowy kształt jest zgodny z kształtem oryginalnego tensora.
Rozumiemy to szczegółowo na konkretnym przykładzie.
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])
Za pomocą tego tensora t
kształtu można tworzyć (18,)
nowe widoki tylko dla następujących kształtów:
(1, 18)
lub równoważnie (1, -1)
lub lub równoważnie lub lub równoważnie lub lub równoważnie lub lub równoważnie lub lub równoważnie lub(-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)
Jak możemy już obserwować z powyższych krotki kształtu, mnożenie elementów krotki kształt (np 2*9
, 3*6
etc.) zawsze musi być równa całkowitej liczbie elementów w oryginalnym tensora ( 18
w naszym przykładzie).
Kolejną rzeczą do zaobserwowania jest to, że użyliśmy a -1
w jednym z miejsc w każdym krotce kształtu. Korzystając z a -1
, jesteśmy leniwi w samodzielnym wykonywaniu obliczeń i raczej przekazujemy zadanie PyTorchowi, aby wykonał obliczenia tej wartości kształtu podczas tworzenia nowego widoku . Jedną ważną rzeczą do zapamiętania jest to, że możemy użyć tylko jednego -1
krotki w kształcie. Pozostałe wartości powinny być przez nas wyraźnie podane. W przeciwnym razie PyTorch będzie narzekał, rzucając RuntimeError
:
RuntimeError: można wywnioskować tylko jeden wymiar
Tak więc, przy wszystkich wyżej wymienionych kształtach, PyTorch zawsze zwraca nowy widok oryginalnego tensora t
. Zasadniczo oznacza to, że po prostu zmienia informacje o kroku napinacza dla każdego żądanego nowego widoku.
Poniżej znajduje się kilka przykładów ilustrujących, w jaki sposób postępy tensorów są zmieniane przy każdym nowym widoku .
# stride of our original tensor `t`
In [53]: t.stride()
Out[53]: (1,)
Teraz zobaczymy postępy dla nowych widoków :
# 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)
To jest magia tej view()
funkcji. Po prostu zmienia kroki (pierwotnego) tensora dla każdego z nowych widoków , o ile kształt nowego widoku jest zgodny z oryginalnym kształtem.
Inną ciekawą rzeczą może obserwować jeden z krokami krotek jest to, że wartość elementu w 0 th pozycji jest równa wartości elementu w 1 st położenia kształtu krotki.
In [74]: t3.shape
Out[74]: torch.Size([3, 6])
|
In [75]: t3.stride() |
Out[75]: (6, 1) |
|_____________|
To dlatego, że:
In [76]: t3
Out[76]:
tensor([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17]])
krok (6, 1)
mówi, że aby przejść od jednego elementu do następnego elementu wzdłuż zerowego wymiaru, musimy przeskoczyć lub zrobić 6 kroków. (tzn. aby przejść od 0
do 6
, trzeba zrobić 6 kroków.) Ale aby przejść od jednego elementu do następnego elementu w pierwszym wymiarze, wystarczy tylko jeden krok (na przykład, aby przejść od 2
do 3
).
Tak więc informacja o krokach ma kluczowe znaczenie dla dostępu do elementów z pamięci w celu wykonania obliczeń.
Ta funkcja zwróci widok i jest dokładnie taka sama, jak użycie, torch.Tensor.view()
o ile nowy kształt jest zgodny z kształtem oryginalnego tensora. W przeciwnym razie zwróci kopię.
Jednak notatki torch.reshape()
ostrzegają, że:
ciągłe dane wejściowe i dane wejściowe ze zgodnymi krokami można przekształcać bez kopiowania, ale nie należy polegać na kopiowaniu a oglądaniu.
reshape
w PyTorch ?!