Topik ini menerapkan autograd untuk meminimalkan sebuah fungsi secara utuh tanpa kelas optimizer sama sekali. Fungsi tujuannya sengaja dipilih sederhana, yaitu , sehingga setiap langkah dapat diperiksa dengan hitungan tangan. Prosedur yang disusun di sini, mulai dari tahap forward hingga pembaruan parameter, adalah versi manual dari perulangan pelatihan yang kelak dirangkum oleh optimizer.
Fungsi tujuan dan aliran satu iterasi#
Fungsi memiliki nilai minimum 0 di titik , dengan turunan analitik . Jawabannya sudah diketahui sejak awal, sehingga keberhasilan prosedur otomatis dapat diukur secara jelas, yaitu bergerak menuju 4 sambil menurunkan loss menuju 0. Pemilihan fungsi kuadrat satu variabel ini memang disengaja agar mekanismenya tidak tertutupi kerumitan model.
Setiap iterasi terdiri atas tiga tahap yang berulang. Diagram berikut menunjukkan alirannya:
Panah biru ke depan membentuk graf dari w menuju loss, panah merah berlabel backward() mengisi w.grad, dan panah putus-putus memperbarui w sebelum siklus dimulai lagi. Tiga tahap itulah yang dieksekusi oleh program pada bagian berikutnya, dengan w berperan sebagai satu-satunya parameter yang dicari.
Arah gradien menentukan arah langkah#
Rumus pembaruan pada topik penyegaran turunan, yaitu , bekerja otomatis mengikuti tanda gradien. Apabila gradiennya negatif, pembaruan menaikkan w, dan sebaliknya apabila gradiennya positif. Program berikut menguji tanda gradien pada tiga titik:
import torch
for nilai in (1.0, 4.0, 6.0):
w = torch.tensor(nilai, requires_grad=True)
loss = (w - 4) ** 2
loss.backward()
print(f"w = {nilai:.1f}: gradien = {w.grad.item():+.1f}")w = 1.0: gradien = -6.0
w = 4.0: gradien = +0.0
w = 6.0: gradien = +4.0Di titik , gradiennya negatif sehingga fungsi menurun ke arah kanan dan pembaruan menaikkan w. Di titik berlaku kebalikannya, yaitu gradien positif dan pembaruan menurunkan w. Di titik gradiennya nol, sehingga pembaruan tidak menggerakkan apa pun dan titik itu menjadi titik henti yang diharapkan.
Perulangan pembaruan parameter#
Program berikut merangkai semuanya menjadi delapan iterasi lengkap, dengan titik awal dan learning rate 0,1, yakni ukuran langkah pada setiap pembaruan:
import torch
w = torch.tensor(0.0, requires_grad=True) # titik awal
learning_rate = 0.1
for iterasi in range(8):
loss = (w - 4) ** 2 # fungsi tujuan: f(w) = (w - 4)^2
loss.backward()
print(f"iterasi {iterasi}: w = {w.item():.4f} | loss = {loss.item():.4f}"
f" | gradien = {w.grad.item():+.4f}")
with torch.no_grad():
w -= learning_rate * w.grad # pembaruan parameter
w.grad = None # kosongkan gradien untuk iterasi berikutnyaiterasi 0: w = 0.0000 | loss = 16.0000 | gradien = -8.0000
iterasi 1: w = 0.8000 | loss = 10.2400 | gradien = -6.4000
iterasi 2: w = 1.4400 | loss = 6.5536 | gradien = -5.1200
iterasi 3: w = 1.9520 | loss = 4.1943 | gradien = -4.0960
iterasi 4: w = 2.3616 | loss = 2.6844 | gradien = -3.2768
iterasi 5: w = 2.6893 | loss = 1.7180 | gradien = -2.6214
iterasi 6: w = 2.9514 | loss = 1.0995 | gradien = -2.0972
iterasi 7: w = 3.1611 | loss = 0.7037 | gradien = -1.6777Loss turun dari 16.0000 menjadi 0.7037 dalam delapan iterasi, dan w bergerak dari 0.0000 menuju 3.1611, mendekati titik minimum 4. Setiap baris keluaran menunjukkan pola yang sama, yaitu jarak w ke 4 menyusut menjadi 80 persen dari iterasi sebelumnya karena besarnya langkah proporsional terhadap jarak itu sendiri. Apabila perulangan diperpanjang, nilai w terus mendekati 4 dan loss menuju nol.
Tiga detail pada program ini layak digarisbawahi. Pertama, graf dibangun ulang setiap iterasi dari nilai w terkini, sehingga gradien selalu mengikuti posisi terbaru. Kedua, pembaruan w -= learning_rate * w.grad dilakukan di dalam torch.no_grad() karena perubahan parameter bukan bagian dari perhitungan yang perlu dicatat, dan operasi in-place pada tensor leaf terlacak memang ditolak di luar konteks itu. Ketiga, w.grad = None membersihkan gradien sebelum iterasi berikutnya agar sisa akumulasi dari graf sebelumnya tidak ikut terhitung.
Pilihan learning rate 0,1 pada contoh ini bukan angka sembarangan. Nilai yang terlalu besar membuat w melampaui titik minimum lalu memantul dengan jarak yang makin lebar, sedangkan nilai yang terlalu kecil membuat kemajuan antara iterasi nyaris tidak terlihat. Pada fungsi kuadrat seperti contoh ini, batas amannya dapat dihitung, sedangkan pada model nyata nilainya ditemukan melalui percobaan, dan itulah sebabnya learning rate menjadi salah satu pengaturan yang paling sering disetel.
Kelima langkah yang dirangkum optimizer#
Perulangan manual di atas sebenarnya terdiri atas lima langkah yang selalu muncul dalam urutan yang sama, yaitu:
- menghitung keluaran model dari masukan, yang lazim disebut tahap forward,
- menghitung loss dari perbandingan keluaran dengan target,
- memanggil
loss.backward()untuk mengisi gradien seluruh parameter, - mengosongkan gradien lama sebelum iterasi berikutnya,
- memperbarui parameter dengan
w = w - learning_rate * gradien.
Kelas optimizer pada PyTorch membungkus langkah keempat dan kelima menjadi optimizer.zero_grad() dan optimizer.step(), sedangkan tiga langkah pertama tetap ditulis manual pada setiap perulangan pelatihan. Dengan demikian, perulangan pelatihan penuh yang digunakan dalam praktiknya, yaitu zero_grad, forward, loss, backward, dan step, sebenarnya adalah prosedur yang baru saja dikerjakan secara manual di topik ini. Pemahaman atas versi manualnya menjadikan setiap baris pada versi optimizer terasa wajar, bukan sekadar ritual yang ditiru.
Kesalahan umum#
Kesalahan pertama adalah memperbarui parameter di luar torch.no_grad(). Autograd menolak operasi in-place pada tensor leaf terlacak dengan pesan “a leaf Variable that requires grad is being used in an in-place operation”, sehingga program berhenti pada iterasi pertama. Perbaikannya adalah membungkus baris pembaruan dengan konteks tersebut, sebagaimana program di atas.
Kesalahan kedua adalah lupa mengosongkan w.grad antara iterasi. Gradien terakumulasi antara panggilan backward(), sehingga langkah pembaruan membesar dari yang seharusnya dan jalur penurunan menjadi tidak terkendali. Perbaikannya adalah menetapkan w.grad = None segera setelah pembaruan, atau menggunakan optimizer.zero_grad() ketika optimizer sudah digunakan.
Kesalahan ketiga adalah menulis w = w - learning_rate * w.grad di dalam no_grad() sebagai pengganti operasi in-place. Penugasan itu membuat w menunjuk ke tensor baru yang tidak terlacak, sehingga iterasi berikutnya tidak lagi mengisi gradien dan backward() pada iterasi itu gagal dengan pesan “does not require grad”. Perbaikannya adalah mempertahankan tensor yang sama melalui operasi in-place seperti w -= ..., atau mengaktifkan kembali pelacakan dengan w.requires_grad_(True) setelah penugasan.
Ringkasan#
- Penurunan gradien manual terdiri atas siklus forward,
backward(), dan pembaruanw -= learning_rate * gradiendi dalamtorch.no_grad(). - Tanda gradien menentukan arah langkah, sehingga pembaruan bergerak otomatis menuju titik minimum fungsi tujuan.
w.gradwajib dinolkan antara iterasi agar akumulasi tidak merusak besarnya langkah pembaruan.- Lima langkah manual tersebut, yaitu zero_grad, forward, loss, backward, dan step, dirangkum oleh optimizer pada perulangan pelatihan sungguhan.
Referensi#
- Deep Learning with PyTorch: A 60 Minute Blitz — PyTorch
— Tutorial resmi autograd yang mencontohkan pembaruan bobot manual di dalam
torch.no_grad(). - PyTorch documentation — PyTorch — Rujukan API resmi PyTorch untuk kelas-kelas optimizer yang merangkum langkah pembaruan parameter.