requires_grad

Mekanisme graf komputasi dan pelacakan operasi melalui atribut requires_grad.

Daftar isi

Topik ini membahas atribut requires_grad, yaitu saklar yang menentukan apakah operasi pada sebuah tensor dicatat oleh autograd. Pembahasan mencakup graf komputasi (computational graph) yang terbentuk secara otomatis, atribut grad_fn pada hasil operasi, pelacakan bawaan pada nn.Parameter, serta cara mengubah status pelacakan setelah tensor dibuat. Dengan memahami saklar ini, kasus gradien yang tidak terisi atau keluaran yang tidak terlacak dapat ditelusuri penyebabnya sampai ke tensor yang menyusunnya.

Graf komputasi yang terbentuk secara otomatis#

Autograd bekerja berdasarkan graf komputasi, yaitu jaringan yang merekam setiap operasi tensor beserta hubungan antara operasinya. Setiap kali sebuah operasi melibatkan tensor yang terlacak, PyTorch menambahkan simpul operasi itu ke graf pada saat operasi dijalankan. Tidak ada tahap kompilasi terpisah dan tidak ada penulisan graf secara manual, sehingga graf yang terbentuk selalu mencerminkan kode yang benar-benar berjalan.

Graf inilah peta yang dilalui aturan rantai ketika gradien dihitung mundur. Diagram berikut membandingkan rantai operasi yang terlacak dengan rantai serupa yang tidak terlacak:

arequires_grad = Truea × 2b = a × 2grad_fn = MulBackward0b + 1y = b + 1grad_fn = AddBackward0crequires_grad = Falsec × 2 + 1d = c × 2 + 1tanpa grad_fn
Pelacakan mengikuti requires_grad: hanya rantai atas yang membentuk graf komputasi

Rantai atas dimulai dari tensor a yang pelacakannya aktif, sehingga setiap hasil operasinya membawa grad_fn dan menjadi bagian graf. Rantai bawah dibangun dari tensor c yang tidak dilacak, sehingga hasilnya tidak memiliki grad_fn dan tidak menyumbang apa pun pada perhitungan gradien. Perbedaan keduanya hanya berasal dari satu atribut, yaitu requires_grad pada tensor awal.

requires_grad sebagai saklar pelacakan#

Atribut requires_grad bernilai False secara bawaan pada tensor yang dibuat langsung, misalnya melalui torch.tensor. Apabila nilainya disetel menjadi True, tensor itu berperan sebagai akar yang perlu diisi gradien, dan seluruh hasil operasi yang bergantung padanya ikut terlacak. Kebalikannya juga berlaku, yaitu operasi di antara tensor yang tidak terlacak sama sekali tidak menghasilkan catatan apa pun.

Program berikut membandingkan kedua kelompok tensor itu, termasuk cara requires_grad_() mengaktifkan pelacakan pada tensor yang sudah ada:

python pelacakan-operasi.py
import torch

a = torch.tensor(2.0, requires_grad=True)
b = a * 2
y = b + 1

c = torch.tensor(2.0)
d = c * 2 + 1

e = torch.tensor(5.0)
e.requires_grad_(True)      # mengaktifkan pelacakan setelah tensor dibuat
f = e * 2 + 1

print("a.is_leaf =", a.is_leaf, "| a.requires_grad =", a.requires_grad)
print("y.grad_fn =", type(y.grad_fn).__name__)
print("d.grad_fn =", d.grad_fn)
print("e.requires_grad =", e.requires_grad, "| f.grad_fn =", type(f.grad_fn).__name__)
text Keluaran
a.is_leaf = True | a.requires_grad = True
y.grad_fn = AddBackward0
d.grad_fn = None
e.requires_grad = True | f.grad_fn = AddBackward0

Tensor a adalah tensor leaf, yakni tensor yang ditulis langsung oleh pengguna dan bukan hasil operasi autograd, sehingga nilai is_leaf-nya adalah True. Hasil operasi seperti y bukan leaf dan membawa grad_fn.

Baris ketiga keluaran menunjukkan perilaku yang paling sering membingungkan pemula, yaitu d.grad_fn bernilai None. Tidak ada yang rusak pada perhitungan d, tetapi tensor itu lahir dari c yang tidak terlacak, sehingga tidak ada riwayat yang dapat dicatat. Baris terakhir memperlihatkan sisi lainnya, yaitu pelacakan yang diaktifkan pada e membuat hasil operasinya langsung membawa grad_fn.

nn.Parameter dan pelacakan bawaan#

Kelas nn.Parameter adalah pembungkus tensor yang menyetel requires_grad=True secara otomatis. Seluruh bobot pada layer bawaan PyTorch, misalnya nn.Linear, disimpan sebagai nn.Parameter, sehingga model langsung siap dilatih tanpa penyetelan tambahan. Sebaliknya, data masukan dan label dibuat sebagai tensor biasa tanpa pelacakan karena keduanya bukan besaran yang nilainya dicari.

Program berikut menunjukkan perbedaan status tersebut:

python nn-parameter.py
import torch
import torch.nn as nn

torch.manual_seed(0)

param = nn.Parameter(torch.randn(3))
bias = nn.Parameter(torch.zeros(1))
biasa = torch.randn(3)          # tensor biasa, bukan parameter

print("param.requires_grad    =", param.requires_grad)
print("bias.requires_grad     =", bias.requires_grad)
print("biasa.requires_grad    =", biasa.requires_grad)
text Keluaran
param.requires_grad    = True
bias.requires_grad     = True
biasa.requires_grad    = False

Baris terakhir menegaskan bahwa tensor biasa yang dibuat dengan torch.randn tidak terlacak. Pemisahan peran ini menjaga graf tetap ramping, yaitu hanya menyimpan simpul yang relevan untuk memperbarui parameter, sementara data yang hanya melewati perhitungan tidak diberi beban pencatatan.

Mengubah status pelacakan setelahnya#

Method requires_grad_() mengubah status pelacakan pada tensor yang sudah dibuat. Bentuk yang paling lazim justru mematikan pelacakan, misalnya param.requires_grad_(False) untuk membekukan layer tertentu agar bobotnya tidak diperbarui, praktik yang digunakan pada transfer learning. Pada model besar, pembekuan dilakukan secara selektif, misalnya hanya layer pengekstrak ciri yang dibekukan, sedangkan layer klasifikasi tetap terlacak. Kebalikannya, requires_grad_(True) berguna untuk tensor yang dibuat tanpa pelacakan lalu digunakan sebagai variabel pencarian, seperti tensor e pada program pertama di atas.

Perlu dicatat bahwa perubahan status ini berlaku untuk operasi yang akan datang. Mematikan pelacakan pada sebuah tensor tidak menghapus graf yang sudah terbentuk sebelumnya, dan mengaktifkan pelacakan pada hasil operasi tidak membuat riwayat lamanya terekam. Kebutuhan untuk memutus riwayat yang sudah ada ditangani oleh detach(), yang dibahas pada topik no_grad dan detach.

Kesalahan umum#

Kesalahan pertama adalah mengubah tensor leaf yang terlacak melalui operasi in-place, yaitu operasi yang mengubah isi tensor asalnya secara langsung, seperti add_(). Autograd menolaknya karena nilai leaf yang sudah tercatat di graf tidak boleh berubah tanpa sepengetahuan mekanisme pencatatan:

python leaf-in-place.py
import torch

a = torch.tensor(2.0, requires_grad=True)

try:
    a.add_(1.0)     # operasi in-place pada tensor leaf
except RuntimeError as e:
    print("RuntimeError:", e)
text Keluaran
RuntimeError: a leaf Variable that requires grad is being used in an in-place operation.

Perbaikannya tergantung maksudnya. Apabila perubahan memang bagian dari pembaruan parameter, bungkus operasinya di dalam torch.no_grad(), pola yang dipraktikkan pada topik penurunan gradien manual. Apabila yang dibutuhkan adalah nilai tanpa riwayat pelacakan, gunakan detach() sebagaimana dibahas pada topik no_grad dan detach.

Kesalahan kedua adalah menyalin tensor dengan torch.tensor(...) atau memanggil .item() dengan anggapan riwayat ikut tersalin. Keduanya menghasilkan data baru yang sama sekali tidak terhubung ke graf, sehingga operasi setelahnya tidak lagi terhubung ke parameter asalnya. Apabila riwayat perlu dipertahankan, gunakan operasi tensor secara langsung, dan gunakan .item() hanya pada titik yang memang menjadi ujung perhitungan, misalnya untuk ditampilkan.

Ringkasan#

  • Atribut requires_grad menentukan apakah operasi pada sebuah tensor dicatat ke graf komputasi, dan hasil operasi pada tensor terlacak membawa grad_fn.
  • Tensor tanpa pelacakan tidak membentuk graf apa pun, sehingga gradien tidak pernah mengalir melaluinya.
  • nn.Parameter menyetel requires_grad=True secara otomatis, dan itulah sebabnya bobot model siap dilatih tanpa penyetelan tambahan.
  • requires_grad_() mengubah status pelacakan untuk operasi berikutnya, sedangkan operasi in-place pada tensor leaf yang terlacak ditolak oleh autograd.

Referensi#