Optimizer mengubah gradien menjadi pembaruan parameter, sehingga loss dapat ditekan iterasi demi iterasi. Topik ini memperkenalkan tiga optimizer bawaan torch.optim, yaitu SGD, Adam, dan AdamW, beserta learning rate, yakni besarnya langkah pembaruan yang menjadi hyperparameter paling menentukan. Kode di akhir topik memperlihatkan loss yang turun dalam lima iterasi pada model kecil, sehingga peran setiap baris terlihat secara konkret.
Peran optimizer dan learning rate#
Setiap optimizer menyimpan rujukan ke parameter model. Ketika optimizer.step() dipanggil, optimizer membaca atribut .grad pada setiap parameter dan memperbaruinya mengikuti aturan tertentu. Untuk SGD, aturannya adalah penurunan searah gradien dengan langkah sebesar :
dengan menyatakan parameter, menyatakan learning rate, dan menyatakan gradien loss terhadap parameter. Learning rate termasuk hyperparameter, yaitu nilai yang ditetapkan sebelum pelatihan dan tidak dipelajari dari data. Nilai yang terlalu besar membuat pelatihan tidak stabil, bahkan divergen, sedangkan nilai yang terlalu kecil membuat perubahan loss nyaris tidak terlihat.
Method lain yang perlu dikenal mulai sekarang adalah optimizer.zero_grad(). Method itu mengosongkan gradien yang tersimpan karena backward() bersifat akumulatif, bukan menimpa. Tanpa pengosongan, gradien dari beberapa iterasi tercampur menjadi satu. Kedua method tersebut diperkenalkan sekilas di sini, sedangkan perulangan pelatihan yang merangkai semuanya dibahas utuh pada topik Anatomi perulangan.
SGD, Adam, dan AdamW#
Ketiga optimizer berikut dibuat dengan API yang seragam, yaitu parameter model diberikan sebagai argumen pertama dan learning rate diberikan melalui lr. Pada PyTorch 2.15, Adam dan AdamW memiliki learning rate bawaan 0.001, sedangkan SGD menuntut lr diberikan secara eksplisit. Apa pun optimizernya, nilainya hampir selalu ditetapkan eksplisit karena sangat menentukan hasil.
import torch
import torch.nn as nn
torch.manual_seed(0)
model = nn.Linear(4, 3)
sgd = torch.optim.SGD(model.parameters(), lr=0.01)
adam = torch.optim.Adam(model.parameters(), lr=0.001)
adamw = torch.optim.AdamW(model.parameters(), lr=0.001)
print(type(sgd).__name__, type(adam).__name__, type(adamw).__name__)SGD Adam AdamWKetiganya berbeda pada aturan pembaruannya, dan ringkasannya dirangkum pada tabel berikut.
| Optimizer | Ide inti | Catatan penggunaan |
|---|---|---|
SGD | Langkah searah gradien dengan learning rate yang sama untuk semua parameter. | Sederhana dan mudah dianalisis, serta sering dipadukan dengan momentum. |
Adam | Menyimpan rata-rata bergerak gradien dan kuadrat gradien, sehingga besarnya langkah menyesuaikan tiap parameter. | Pilihan awal yang umum karena bekerja baik pada rentang learning rate yang lebar. |
AdamW | Adam dengan weight decay yang diterapkan langsung pada bobot, terpisah dari gradien. | Lazim menjadi standar untuk model berskala besar. |
Istilah pada tabel itu dijelaskan sebagai berikut. Momentum, yaitu akumulasi kecepatan dari beberapa langkah sebelumnya, membuat arah pembaruan lebih stabil ketika gradien berfluktuasi. Sifat adaptif Adam berasal dari pembagian langkah dengan akar rata-rata kuadrat gradien, sehingga langkah pada parameter dengan gradien besar menjadi lebih kecil dan sebaliknya. Weight decay, yaitu penalti yang mendorong bobot tetap kecil, pada Adam versi lama tercampur ke dalam gradien. AdamW memisahkannya, sehingga regularisasi bekerja pada bobot secara langsung. Perbedaan ketiganya tampak pada kecepatan konvergensi dan kualitas model akhir, bukan pada API-nya, karena ketiganya digunakan dengan pola kode yang sama persis.
Lima iterasi pembaruan#
File berikut merangkai komponen-komponen pada modul ini menjadi satu perulangan mini. Data berupa regresi sintetis dengan empat fitur dan dua target. Modelnya Linear(4, 2) dengan loss MSELoss, sedangkan optimizernya SGD dengan learning rate 0.05. Setiap iterasi menjalankan zero_grad(), forward, backward(), lalu step().
import torch
import torch.nn as nn
torch.manual_seed(0)
# data sintetis regresi: y = x @ W + b
x = torch.randn(32, 4) # (N, in_features) = (32, 4)
W = torch.tensor([[1.0, -1.0], [0.5, 2.0], [-0.5, 0.25], [2.0, 0.0]])
b = torch.tensor([0.1, -0.2])
y = x @ W + b # (N, out_features) = (32, 2)
model = nn.Linear(4, 2)
loss_fn = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.05)
for i in range(5):
optimizer.zero_grad() # kosongkan gradien dari iterasi sebelumnya
prediksi = model(x) # forward
loss = loss_fn(prediksi, y)
loss.backward() # hitung gradien
optimizer.step() # perbarui parameter
print(f"iterasi {i + 1}: loss = {loss.item():.4f}")iterasi 1: loss = 5.9632
iterasi 2: loss = 5.2088
iterasi 3: loss = 4.5603
iterasi 4: loss = 4.0019
iterasi 5: loss = 3.5199Loss turun dari 5.9632 menjadi 3.5199 dalam lima iterasi, dengan penurunan yang stabil pada setiap langkah. Perlu dicatat bahwa nilai loss yang dicetak dihitung sebelum step() pada iterasi yang sama diterapkan, sehingga deret itu menyatakan kemajuan dari pembaruan sebelumnya. Perulangan pelatihan yang lengkap, termasuk pemrosesan per batch dan mode train/eval, dibahas pada topik perulangan pelatihan.
Memilih learning rate#
Peran learning rate paling mudah dilihat ketika tiga nilai yang jauh berbeda diberikan pada masalah yang sama. Kode berikut melatih model yang sama dengan inisialisasi yang sama, hanya learning ratenya yang diubah.
import torch
import torch.nn as nn
torch.manual_seed(0)
x = torch.randn(32, 4)
W = torch.tensor([[1.0, -1.0], [0.5, 2.0], [-0.5, 0.25], [2.0, 0.0]])
b = torch.tensor([0.1, -0.2])
y = x @ W + b
def latih(lr):
torch.manual_seed(0) # inisialisasi model yang identik
model = nn.Linear(4, 2)
loss_fn = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=lr)
nilai = []
for _ in range(5):
optimizer.zero_grad()
loss = loss_fn(model(x), y)
loss.backward()
optimizer.step()
nilai.append(loss.item())
return nilai
for lr in (0.00001, 0.05, 2.0):
deret = " ".join(f"{v:.4f}" for v in latih(lr))
print(f"lr={lr:>8}: {deret}")lr= 1e-05: 5.6564 5.6563 5.6562 5.6560 5.6559
lr= 0.05: 5.6564 5.0004 4.4313 3.9363 3.5050
lr= 2.0: 5.6564 16.0180 89.1739 563.2015 3700.5664Tiga baris keluaran itu memperlihatkan tiga perilaku yang berbeda. Learning rate 0.00001 membuat loss nyaris diam karena langkah pembaruannya terlalu kecil. Nilai 0.05 menurunkan loss secara stabil sampai 3.5050. Nilai 2.0 justru menaikkan loss dari 5.6564 menjadi 3700.5664, karena setiap langkah melampaui lembah yang hendak dituju. Inilah alasan learning rate disebut hyperparameter paling menentukan: satu angka itu memengaruhi jalannya pelatihan lebih besar daripada perbedaan antara optimizer.
Ringkasan#
- Optimizer membaca
.gradpada setiap parameter dan memperbaruinya saatstep(), sementarazero_grad()wajib dipanggil karenabackward()bersifat akumulatif. SGDmenggunakan langkah seragam searah gradien,Adammenyesuaikan langkah per parameter melalui rata-rata bergerak, danAdamWmenambahkan weight decay yang terpisah dari gradien.- Learning rate menentukan besarnya langkah pembaruan: terlalu besar membuat loss divergen dan terlalu kecil membuat pelatihan lambat, sehingga nilainya hampir selalu ditetapkan eksplisit.
Referensi#
- Deep Learning with PyTorch: A 60 Minute Blitz — PyTorch
— Tutorial resmi yang memperkenalkan
torch.optimdan perulangan pelatihan pertama. - PyTorch Documentation — PyTorch
— Dokumentasi resmi
torch.optimuntukSGD,Adam, danAdamW.