Saya bingung tentang metode view()
dalam cuplikan kode berikut.
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()
Kebingungan saya mengenai baris berikut.
x = x.view(-1, 16*5*5)
Apa tensor.view()
fungsinya? Saya telah melihat penggunaannya di banyak tempat, tapi saya tidak mengerti bagaimana ia mengartikan parameternya.
Apa yang terjadi jika saya memberikan nilai negatif sebagai parameter ke view()
fungsi? Misalnya, apa yang terjadi jika saya menelepon tensor_variable.view(1, 1, -1)
,?
Adakah yang bisa menjelaskan prinsip utama view()
fungsi dengan beberapa contoh?
reshape
di PyTorch ?!Mari kita lakukan beberapa contoh, dari yang sederhana hingga yang lebih sulit.
The
view
Metode mengembalikan tensor dengan data yang sama denganself
tensor (yang berarti bahwa tensor kembali memiliki jumlah elemen yang sama), tapi dengan bentuk yang berbeda. Sebagai contoh:Dengan asumsi itu
-1
bukan salah satu parameter, ketika Anda mengalikannya bersama-sama, hasilnya harus sama dengan jumlah elemen dalam tensor. Jika Anda melakukannya:,a.view(3, 3)
ia akan menaikkanRuntimeError
bentuk karena (3 x 3) tidak valid untuk input dengan 16 elemen. Dengan kata lain: 3 x 3 tidak sama dengan 16 tetapi 9.Anda dapat menggunakan
-1
sebagai salah satu parameter yang Anda berikan ke fungsi, tetapi hanya sekali. Yang terjadi hanyalah bahwa metode ini akan menghitung untuk Anda tentang cara mengisi dimensi itu. Misalnyaa.view(2, -1, 4)
setara dengana.view(2, 2, 4)
. [16 / (2 x 4) = 2]Perhatikan bahwa tensor yang dikembalikan membagikan data yang sama . Jika Anda membuat perubahan dalam "tampilan" Anda mengubah data tensor asli:
Sekarang, untuk use case yang lebih kompleks. Dokumentasi mengatakan bahwa setiap dimensi tampilan baru harus berupa subruang dari dimensi asli, atau hanya rentang d, d + 1, ..., d + k yang memenuhi kondisi seperti-kedekatan berikut ini untuk semua i = 0,. .., k - 1, langkah [i] = langkah [i + 1] x ukuran [i + 1] . Kalau tidak,
contiguous()
perlu dipanggil sebelum tensor dapat dilihat. Sebagai contoh:Perhatikan bahwa untuk
a_t
, langkah [0]! = Langkah [1] x ukuran [1] sejak 24! = 2 x 3sumber
torch.Tensor.view()
Sederhananya,
torch.Tensor.view()
yang terinspirasi olehnumpy.ndarray.reshape()
ataunumpy.reshape()
, menciptakan tampilan tensor baru, selama bentuk baru tersebut kompatibel dengan bentuk tensor asli.Mari kita pahami ini secara detail dengan menggunakan contoh nyata.
Dengan tensor ini
t
bentuk(18,)
, baru dilihat dapat hanya dibuat untuk bentuk berikut:(1, 18)
atau ekuivalen(1, -1)
atau atau setara atau atau ekuivalen atau atau ekuivalen atau atau ekuivalen atau atau ekuivalen atau(-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)
Seperti yang sudah dapat kita amati dari bentuk tuple di atas, penggandaan elemen-elemen dari tuple bentuk (misalnya
2*9
,3*6
dll.) Harus selalu sama dengan jumlah total elemen dalam tensor asli (18
dalam contoh kita).Hal lain yang perlu diperhatikan adalah bahwa kami menggunakan a
-1
di salah satu tempat di masing-masing bentuk tuple. Dengan menggunakan-1
, kita menjadi malas dalam melakukan perhitungan diri kita sendiri dan agak mendelegasikan tugas untuk PyTorch untuk melakukan perhitungan yang nilai untuk bentuk ketika ia menciptakan baru tampilan . Satu hal penting yang perlu diperhatikan adalah kita hanya bisa menggunakan satu-1
tuple dalam bentuk. Nilai yang tersisa harus diberikan secara eksplisit oleh kami. Lain PyTorch akan mengeluh dengan melemparkanRuntimeError
:Jadi, dengan semua bentuk yang disebutkan di atas, PyTorch akan selalu mengembalikan tampilan baru dari tensor asli
t
. Ini pada dasarnya berarti bahwa itu hanya mengubah informasi langkah tensor untuk setiap tampilan baru yang diminta.Di bawah ini adalah beberapa contoh yang menggambarkan bagaimana langkah tensor diubah dengan setiap tampilan baru .
Sekarang, kita akan melihat langkah untuk tampilan baru :
Jadi itulah keajaiban
view()
fungsinya. Itu hanya mengubah langkah dari tensor (asli) untuk masing-masing tampilan baru , selama bentuk tampilan baru kompatibel dengan bentuk aslinya.Hal lain yang satu yang menarik bisa mengamati dari tupel langkah adalah bahwa nilai dari elemen dalam 0 th posisi sama dengan nilai dari elemen dalam 1 st posisi tuple bentuk.
Hal ini karena:
langkahnya
(6, 1)
mengatakan bahwa untuk beralih dari satu elemen ke elemen berikutnya sepanjang dimensi ke- 0 , kita harus melompat atau mengambil 6 langkah. (yaitu untuk pergi dari0
ke6
, kita harus mengambil 6 langkah.) Tapi untuk pergi dari satu elemen ke elemen berikutnya dalam 1 st dimensi, kita hanya perlu satu langkah (untuk misalnya untuk pergi dari2
ke3
).Dengan demikian, informasi langkah adalah inti dari bagaimana elemen diakses dari memori untuk melakukan perhitungan.
torch.reshape ()
Fungsi ini akan mengembalikan tampilan dan persis sama dengan menggunakan
torch.Tensor.view()
selama bentuk baru tersebut kompatibel dengan bentuk tensor asli. Jika tidak, itu akan mengembalikan salinan.Namun, catatan
torch.reshape()
memperingatkan bahwa:sumber
Saya menemukan itu
x.view(-1, 16 * 5 * 5)
setara denganx.flatten(1)
, di mana parameter 1 menunjukkan proses perataan dimulai dari dimensi 1 (tidak meratakan dimensi 'sampel') Seperti yang Anda lihat, penggunaan yang terakhir secara semantik lebih jelas dan lebih mudah digunakan, jadi saya lebih sukaflatten()
.sumber
Anda dapat membaca
-1
sebagai jumlah parameter dinamis atau "apa pun". Karena itu hanya ada satu parameter-1
dalamview()
.Jika Anda bertanya
x.view(-1,1)
ini akan menampilkan bentuk tensor[anything, 1]
tergantung pada jumlah elemen dalamx
. Sebagai contoh:Akan menghasilkan:
sumber
weights.reshape(a, b)
akan mengembalikan tensor baru dengan data yang sama dengan bobot dengan ukuran (a, b) karena di dalamnya menyalin data ke bagian lain dari memori.weights.resize_(a, b)
mengembalikan tensor yang sama dengan bentuk yang berbeda. Namun, jika bentuk baru menghasilkan elemen lebih sedikit dari tensor asli, beberapa elemen akan dihapus dari tensor (tetapi tidak dari memori). Jika bentuk baru menghasilkan lebih banyak elemen daripada tensor asli, elemen baru akan diinisialisasi dalam memori.weights.view(a, b)
akan mengembalikan tensor baru dengan data yang sama dengan bobot dengan ukuran (a, b)sumber
Saya sangat menyukai contoh @Jadiel de Armas.
Saya ingin menambahkan wawasan kecil tentang bagaimana elemen dipesan untuk .view (...)
sumber
Mari kita coba memahami tampilan dengan contoh-contoh berikut:
-1 sebagai nilai argumen adalah cara mudah untuk menghitung nilai katakan x asalkan kita tahu nilai y, z atau sebaliknya dalam kasus 3d dan untuk 2d lagi cara mudah untuk menghitung nilai katakan x asalkan kita mengetahui nilai-nilai y atau sebaliknya ..
sumber