Nie jestem pewien co do tej metody view()
w poniższym fragmencie kodu.
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()
Moje zamieszanie dotyczy następującej linii.
x = x.view(-1, 16*5*5)
Do czego tensor.view()
służy funkcja? Widziałem jego użycie w wielu miejscach, ale nie rozumiem, w jaki sposób interpretuje jego parametry.
Co się stanie, jeśli podam funkcji wartości ujemne jako parametry view()
? Na przykład, co się stanie, jeśli zadzwonię tensor_variable.view(1, 1, -1)
?
Czy ktoś może wyjaśnić główną zasadę view()
działania na kilku przykładach?
reshape
w PyTorch ?!Zróbmy kilka przykładów, od prostszych do trudniejszych.
view
Sposób powraca tensora o tych samych danych, coself
tensora (co oznacza, że zwrócona napinacz ma taką samą liczbę elementów), ale o innym kształcie. Na przykład:Zakładając, że
-1
nie jest to jeden z parametrów, po pomnożeniu ich razem wynik musi być równy liczbie elementów w tensorze. Jeśli to zrobisz:a.view(3, 3)
podniesieRuntimeError
kształt ponieważ (3 x 3) jest nieprawidłowy dla danych wejściowych z 16 elementami. Innymi słowy: 3 x 3 nie jest równe 16, ale 9.Możesz użyć
-1
jako jednego z parametrów przekazywanych do funkcji, ale tylko raz. Wszystko, co się dzieje, polega na tym, że metoda zrobi dla ciebie matematykę, jak wypełnić ten wymiar. Na przykłada.view(2, -1, 4)
jest równoważne za.view(2, 2, 4)
. [16 / (2 x 4) = 2]Zauważ, że zwrócony tensor ma te same dane . Jeśli wprowadzisz zmianę w „widoku”, zmienisz dane pierwotnego tensora:
Teraz dla bardziej złożonego przypadku użycia. Dokumentacja mówi, że każdy nowy wymiar widoku musi być podprzestrzenią oryginalnego wymiaru lub tylko rozpiętością d, d + 1, ..., d + k, które spełniają następujący warunek podobny do ciągłości, który dla wszystkich i = 0 ,. .., k - 1, krok [i] = krok [i + 1] x rozmiar [i + 1] . W przeciwnym razie
contiguous()
należy wywołać, zanim będzie można zobaczyć tensor. Na przykład:Zauważ, że dla
a_t
, stride [0]! = Stride [1] x size [1] od 24! = 2 x 3źródło
torch.Tensor.view()
Mówiąc prosto,
torch.Tensor.view()
który jest inspirowany przeznumpy.ndarray.reshape()
lubnumpy.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.
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ącRuntimeError
: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 .
Teraz zobaczymy postępy dla nowych widoków :
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.
To dlatego, że:
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ść od0
do6
, 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ść od2
do3
).Tak więc informacja o krokach ma kluczowe znaczenie dla dostępu do elementów z pamięci w celu wykonania obliczeń.
torch.reshape ()
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:źródło
Doszedłem do wniosku, że
x.view(-1, 16 * 5 * 5)
jest to równoważne z tymx.flatten(1)
, że parametr 1 wskazuje, że proces spłaszczania rozpoczyna się od pierwszego wymiaru (nie spłaszczając wymiaru „próbki”) Jak widać, to drugie użycie jest semantycznie bardziej przejrzyste i łatwiejsze w użyciu, więc I wolęflatten()
.źródło
Możesz odczytać
-1
jako dynamiczną liczbę parametrów lub „cokolwiek”. Z tego powodu nie może być tylko jeden parametr-1
wview()
.Jeśli poprosisz
x.view(-1,1)
, wyświetli kształt tensora w[anything, 1]
zależności od liczby elementów wx
. Na przykład:Wyjdzie:
źródło
weights.reshape(a, b)
zwróci nowy tensor z tymi samymi danymi co wagi o rozmiarze (a, b), ponieważ w nim kopiuje dane do innej części pamięci.weights.resize_(a, b)
zwraca ten sam tensor o innym kształcie. Jeśli jednak nowy kształt spowoduje mniej elementów niż pierwotny tensor, niektóre elementy zostaną usunięte z tensora (ale nie z pamięci). Jeśli nowy kształt spowoduje powstanie większej liczby elementów niż oryginalny tensor, nowe elementy nie zostaną zainicjowane w pamięci.weights.view(a, b)
zwróci nowy tensor z tymi samymi danymi co wagi o rozmiarze (a, b)źródło
Bardzo podobały mi się przykłady @Jadiel de Armas.
Chciałbym dodać mały wgląd w sposób zamawiania elementów dla .view (...)
źródło
Spróbujmy zrozumieć widok za pomocą następujących przykładów:
-1 jako wartość argumentu jest łatwym sposobem obliczenia wartości powiedz x, pod warunkiem, że znamy wartości y, z lub odwrotnie w przypadku 3d, a dla 2d ponownie łatwym sposobem obliczenia wartości powiedz x znać wartości y lub vice versa ..
źródło