Kode asli yang tidak saya temukan di situs web PyTorch lagi.
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)
Masalah dengan kode di atas tidak ada fungsi berdasarkan apa yang menghitung gradien. Ini berarti kita tidak tahu berapa banyak parameter (argumen yang dibutuhkan fungsi) dan dimensi parameter.
Untuk sepenuhnya memahami ini, saya membuat contoh yang mirip 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])
Saya berasumsi fungsi kami adalah y=3*a + 2*b*b + torch.log(c)
dan parameternya adalah tensor dengan tiga elemen di dalamnya.
Anda bisa menganggap yang gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
seperti ini adalah akumulator.
Seperti yang mungkin Anda dengar, perhitungan sistem autograd PyTorch setara dengan produk Jacobian.
Jika Anda memiliki fungsi, seperti yang kami lakukan:
y=3*a + 2*b*b + torch.log(c)
Jacobian akan menjadi [3, 4*b, 1/c]
. Namun, Jacobian ini bukanlah cara PyTorch melakukan sesuatu untuk menghitung gradien pada titik tertentu.
PyTorch menggunakan penerusan maju dan diferensiasi otomatis mode mundur (AD) secara bersamaan.
Tidak ada matematika simbolik yang terlibat dan tidak ada diferensiasi numerik.
Diferensiasi numerik adalah menghitung δy/δb
, untuk b=1
dan di b=1+ε
mana ε kecil.
Jika Anda tidak menggunakan gradien di y.backward()
:
Contoh 2
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 Anda a
, b
, c
tensor awalnya.
Hati-hati bagaimana Anda menginisialisasi Anda a
, b
, c
:
Contoh 3:
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 torch.empty()
dan tidak menggunakan pin_memory=True
Anda mungkin memiliki hasil yang berbeda setiap saat.
Juga, gradien catatan seperti akumulator jadi nolkan mereka saat diperlukan.
Contoh 4:
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.)
Beberapa tip terakhir tentang istilah yang digunakan PyTorch:
PyTorch membuat grafik komputasi dinamis saat menghitung gradien dalam lintasan maju. Ini terlihat seperti pohon.
Jadi anda akan sering mendengar daun pohon ini adalah input tensor dan root adalah output tensor .
Gradien dihitung dengan menelusuri grafik dari akar ke daun dan mengalikan setiap gradien dengan menggunakan aturan rantai . Pengalikan ini terjadi pada gerakan mundur.
Penjelasan
Untuk jaringan saraf, kami biasanya menggunakan
loss
untuk menilai seberapa baik jaringan telah belajar untuk mengklasifikasikan gambar masukan (atau tugas lain). Theloss
Istilah ini biasanya nilai skalar. Untuk memperbarui parameter jaringan, kita perlu menghitung gradienloss
wrt ke parameter, yang sebenarnya adaleaf node
dalam grafik komputasi (omong-omong, parameter ini sebagian besar merupakan bobot dan bias dari berbagai lapisan seperti Konvolusi, Linear dan seterusnya).Menurut aturan rantai, untuk menghitung gradien
loss
wrt ke simpul daun, kita dapat menghitung turunan dariloss
wrt beberapa variabel perantara, dan gradien variabel perantara wrt ke variabel daun, lakukan perkalian titik dan jumlahkan semuanya.The
gradient
argumen dariVariable
'sbackward()
metode yang digunakan untuk menghitung jumlah tertimbang dari setiap elemen dari Variabel wrt Variable daun . Bobot ini hanyalah turunan dariloss
wrt akhir setiap elemen variabel menengah.Contoh konkret
Mari kita ambil contoh konkret dan sederhana untuk memahami ini.
Dalam contoh di atas, hasil dari yang pertama
print
adalahyang persis merupakan turunan dari z_1 wrt ke x.
Hasil kedua
print
adalah:yang merupakan turunan dari z_2 wrt ke x.
Sekarang jika menggunakan bobot [1, 1, 1, 1] untuk menghitung turunan dari z wrt ke x, hasilnya adalah
1*dz_1/dx + 1*dz_2/dx + 1*dz_3/dx + 1*dz_4/dx
. Jadi tidak mengherankan jika keluaran dari ke-3print
adalah:Perlu dicatat bahwa vektor bobot [1, 1, 1, 1] persis turunan dari
loss
wrt ke z_1, z_2, z_3 dan z_4. Turunan dariloss
wrt tox
dihitung sebagai:Jadi output ke-4
print
sama dengan yang ke-3print
:sumber
gradient
argumen dengan lebih baik. Terima kasih atas jawaban anda.[1, 1, 1, 1]
persis turunan dariloss
wrt untukz_1
,z_2
,z_3
danz_4
." Saya pikir pernyataan ini benar-benar kunci jawabannya. Saat melihat kode OP, tanda tanya besar adalah dari mana asal angka - angka (ajaib) untuk gradien ini. Dalam contoh konkret Anda, saya pikir akan sangat membantu untuk menunjukkan hubungan antara[1, 0, 0 0]
tensor eg danloss
fungsi segera sehingga orang dapat melihat bahwa nilainya tidak sembarangan dalam contoh ini.loss = z.sum(dim=1)
, itu akan menjadiloss = z_1 + z_2 + z_3 + z_4
. Jika Anda mengetahui kalkulus sederhana, Anda akan mengetahui bahwa turunan dariloss
wrt toz_1, z_2, z_3, z_4
adalah[1, 1, 1, 1]
.Biasanya, grafik komputasi Anda memiliki satu keluaran skalar
loss
. Kemudian Anda dapat menghitung gradien dariloss
wrt the weights (w
) denganloss.backward()
. Di mana argumen defaultbackward()
adalah1.0
.Jika keluaran Anda memiliki beberapa nilai (misalnya
loss=[loss1, loss2, loss3]
), Anda dapat menghitung gradien kerugian dengan bobotloss.backward(torch.FloatTensor([1.0, 1.0, 1.0]))
.Selanjutnya, jika Anda ingin menambah bobot atau kepentingan kerugian yang berbeda, Anda dapat menggunakan
loss.backward(torch.FloatTensor([-0.1, 1.0, 0.0001]))
.Artinya menghitung
-0.1*d(loss1)/dw, d(loss2)/dw, 0.0001*d(loss3)/dw
secara bersamaan.sumber
grad_tensors
bukanlah untuk menimbangnya secara berbeda tetapi mereka adalah gradien dari setiap elemen tensor yang sesuai.Di sini, keluaran dari forward (), yaitu y adalah aa 3-vektor.
Ketiga nilai tersebut adalah gradien pada keluaran jaringan. Mereka biasanya disetel ke 1.0 jika y adalah keluaran akhir, tetapi dapat memiliki nilai lain juga, terutama jika y adalah bagian dari jaringan yang lebih besar.
Misalnya. jika x adalah masukan, y = [y1, y2, y3] adalah keluaran antara yang digunakan untuk menghitung keluaran akhir z,
Kemudian,
Jadi di sini, tiga nilai mundur adalah
dan kemudian mundur () menghitung dz / dx
sumber