Saya membaca dokumentasi dari PyTorch dan menemukan sebuah contoh di mana mereka menulis
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)
di mana x adalah sebuah awal variabel, dari mana y dibangun (3-vektor). Pertanyaannya adalah, apa 0.1, 1.0 dan 0.0001 argumen dari gradien tensor ? Dokumentasi sangat tidak jelas itu.
Untuk jaringan saraf, biasanya kita menggunakan kehilangan
untuk menilai seberapa baik jaringan telah belajar untuk mengklasifikasikan citra masukan (atau tugas-tugas lainnya). Dengan hilangnya
istilah ini biasanya sebuah nilai skalar. Dalam rangka untuk memperbarui parameter jaringan, kita perlu untuk menghitung gradien dari loss
w.r.t untuk parameter, yang sebenarnya adalah leaf node
dalam perhitungan grafik (by the way, parameter ini adalah kebanyakan berat dan bias dari berbagai lapisan seperti Konvolusi, Linear dan sebagainya).
Menurut aturan rantai, dalam rangka untuk menghitung gradien dari loss
w.r.t untuk simpul daun, kita dapat menghitung turunan dari loss
w.r.t beberapa intermediate variabel, dan gradien antara variabel w.r.t untuk daun variabel, melakukan dot produk dan jumlah semua ini.
The gradient
argumen dari Variabel
's mundur()
metode ini digunakan untuk hitung tertimbang jumlah dari masing-masing elemen Variabel w.r.t daun Variable. Berat badan ini adalah salah satu derivat dari akhir kehilangan
w.r.t masing-masing elemen menengah variabel.
Let's mengambil beton dan contoh sederhana untuk memahami hal ini.
from torch.autograd import Variable
import torch
x = Variable(torch.FloatTensor([[1, 2, 3, 4]]), requires_grad=True)
z = 2*x
loss = z.sum(dim=1)
# do backward for first element of z
z.backward(torch.FloatTensor([[1, 0, 0, 0]]), retain_graph=True)
print(x.grad.data)
x.grad.data.zero_() #remove gradient in x.grad, or it will be accumulated
# do backward for second element of z
z.backward(torch.FloatTensor([[0, 1, 0, 0]]), retain_graph=True)
print(x.grad.data)
x.grad.data.zero_()
# do backward for all elements of z, with weight equal to the derivative of
# loss w.r.t z_1, z_2, z_3 and z_4
z.backward(torch.FloatTensor([[1, 1, 1, 1]]), retain_graph=True)
print(x.grad.data)
x.grad.data.zero_()
# or we can directly backprop using loss
loss.backward() # equivalent to loss.backward(torch.FloatTensor([1.0]))
print(x.grad.data)
Dalam contoh di atas, hasil pertama cetak
adalah
2 0 0 0 [obor.FloatTensor ukuran 1x4]
yang sebenarnya turunan dari z_1 w.r.t x.
Hasil dari kedua print
adalah :
0 2 0 0 [obor.FloatTensor ukuran 1x4]
yang merupakan turunan dari z_2 w.r.t x.
Sekarang jika menggunakan berat dari [1, 1, 1, 1] untuk menghitung turunan dari z w.r.t dengan x, hasilnya adalah 1*dz_1/dx + 1*dz_2/dx + 1*dz_3/dx + 1*dz_4/dx
. Jadi tidak mengherankan, output dari 3 cetak
adalah:
2 2 2 2 [obor.FloatTensor ukuran 1x4]
Perlu dicatat bahwa berat vektor [1, 1, 1, 1] adalah persis turunan dari loss
w.r.t untuk z_1, z_2, z_3 dan z_4. Turunan dari loss
w.r.t untuk x
dihitung sebagai:
d(loss)/dx = d(loss)/dz_1 * dz_1/dx + d(loss)/dz_2 * dz_2/dx + d(loss)/dz_3 * dz_3/dx + d(loss)/dz_4 * dz_4/dx
Sehingga output dari 4 cetak
adalah sama seperti ke-3 print
:
2 2 2 2 [obor.FloatTensor ukuran 1x4]
Biasanya, anda komputasi grafik memiliki satu skalar output mengatakan loss
. Kemudian anda dapat menghitung gradien dari loss
w.r.t. bobot (w
) dengan kerugian.mundur()
. Di mana default argumen dari mundur()
adalah 1.0
.
Jika output anda memiliki beberapa nilai (misalnya loss=[loss1, loss2, loss3]
), anda dapat menghitung gradien kehilangan w.r.t. bobot dengan kerugian.mundur(obor.FloatTensor([1.0, 1.0, 1.0]))
.
Selain itu, jika anda ingin menambahkan beban atau importances ke berbagai kerugian, anda dapat menggunakan loss.mundur(obor.FloatTensor([-0.1, 1.0, 0.0001]))
.
Ini berarti untuk menghitung -0.1*d(loss1)/dw, d(loss2)/dw, 0.0001*d(loss3)/dw
secara bersamaan.
Di sini, output dari depan(), yaitu y adalah 3-vektor.
Tiga nilai gradien pada output dari jaringan. Mereka biasanya ditetapkan untuk 1.0 jika y adalah keluaran terakhir, tetapi dapat memiliki nilai-nilai lain juga, terutama jika y adalah bagian dari jaringan yang lebih besar.
Untuk misalnya. jika x adalah masukan, y = [y1, y2, y3] adalah intermediate output yang digunakan untuk menghitung hasil akhir z,
Kemudian,
dz/dx = dz/dy1 * dy1/dx + dz/dy2 * dy2/dx + dz/dy3 * dy3/dx
Jadi di sini, tiga nilai untuk mundur
[dz/dy1, dz/dy2, dz/dy3]
dan kemudian mundur() menghitung dz/dx
asli kode saya belum't ditemukan di PyTorch website lagi.
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)
Masalah dengan kode di atas tidak ada fungsi yang didasarkan pada apa yang harus menghitung gradien. Ini berarti kita don't tahu berapa banyak parameter (argumen fungsi waktu) dan dimensi parameter.
Untuk memahami hal ini saya membuat beberapa contoh yang dekat dengan aslinya:
Contoh 1:
a = torch.tensor([1.0, 2.0, 3.0], requires_grad = True)
b = torch.tensor([3.0, 4.0, 5.0], requires_grad = True)
c = torch.tensor([6.0, 7.0, 8.0], requires_grad = True)
y=3*a + 2*b*b + torch.log(c)
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients,retain_graph=True)
print(a.grad) # tensor([3.0000e-01, 3.0000e+00, 3.0000e-04])
print(b.grad) # tensor([1.2000e+00, 1.6000e+01, 2.0000e-03])
print(c.grad) # tensor([1.6667e-02, 1.4286e-01, 1.2500e-05])
Seperti yang anda lihat saya diasumsikan dalam contoh pertama fungsi kita adalah y=3*a + 2*b*b + torch.log(c)
dan parameter yang tensors dengan tiga unsur di dalamnya.
Tapi ada pilihan lain:
Contoh 2:
import torch
a = torch.tensor(1.0, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(1.0, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(a.grad) # tensor(3.3003)
print(b.grad) # tensor(4.4004)
print(c.grad) # tensor(1.1001)
The gradien = obor.FloatTensor([0.1, 1.0, 0.0001])
adalah akumulator.
Contoh selanjutnya akan memberikan hasil identik.
Contoh 3:
a = torch.tensor(1.0, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(1.0, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)
gradients = torch.FloatTensor([0.1])
y.backward(gradients,retain_graph=True)
gradients = torch.FloatTensor([1.0])
y.backward(gradients,retain_graph=True)
gradients = torch.FloatTensor([0.0001])
y.backward(gradients)
print(a.grad) # tensor(3.3003)
print(b.grad) # tensor(4.4004)
print(c.grad) # tensor(1.1001)
Seperti yang anda mungkin mendengar PyTorch autograd sistem perhitungan setara dengan Jacobian produk.
Dalam kasus anda memiliki sebuah fungsi, seperti yang kami lakukan:
y=3*a + 2*b*b + torch.log(c)
Jacobian akan [3, 4*b, 1/c]
. Namun, ini Jacobian adalah bukan bagaimana PyTorch adalah melakukan hal-hal untuk menghitung gradien pada titik tertentu.
Sebelumnya fungsi PyTorch akan dilakukan misalnya δy/δb
, untuk b=1
dan b=1+ε
di mana ε adalah kecil. Jadi tidak ada yang seperti simbol matematika yang terlibat.
Jika anda don't menggunakan gradien pada y.mundur()
:
Contoh 4
a = torch.tensor(0.1, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(0.1, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)
y.backward()
print(a.grad) # tensor(3.)
print(b.grad) # tensor(4.)
print(c.grad) # tensor(10.)
Anda akan mudah mendapatkan hasil pada suatu titik, didasarkan pada bagaimana anda mengatur a
, b
, c
tensors awalnya.
Berhati-hatilah bagaimana anda menginisialisasi a
, b
, c
:
Contoh 5:
a = torch.empty(1, requires_grad = True, pin_memory=True)
b = torch.empty(1, requires_grad = True, pin_memory=True)
c = torch.empty(1, requires_grad = True, pin_memory=True)
y=3*a + 2*b*b + torch.log(c)
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(a.grad) # tensor([3.3003])
print(b.grad) # tensor([0.])
print(c.grad) # tensor([inf])
Jika anda menggunakan obor.kosong()
dan don't menggunakan pin_memory=True
anda mungkin memiliki hasil yang berbeda setiap kali.
Juga, perhatikan gradien seperti akumulator jadi nol mereka bila diperlukan.
Contoh 6:
a = torch.tensor(1.0, requires_grad = True)
b = torch.tensor(1.0, requires_grad = True)
c = torch.tensor(1.0, requires_grad = True)
y=3*a + 2*b*b + torch.log(c)
y.backward(retain_graph=True)
y.backward()
print(a.grad) # tensor(6.)
print(b.grad) # tensor(8.)
print(c.grad) # tensor(2.)
Terakhir saya hanya ingin menyatakan beberapa hal PyTorch menggunakan:
PyTorch menciptakan dinamis komputasi grafik ketika menghitung gradien. Ini terlihat seperti sebuah pohon.
Sehingga anda akan sering mendengar daun pohon ini adalah masukan tensors dan root adalah output tensor.
Gradien dihitung dengan tracing grafik dari akar ke daun dan mengalikan setiap gradien dalam cara menggunakan aturan rantai.