DataLens

Fungsi loss dan optimizer

Pilih loss yang tepat untuk masalah regresi, biner, dan multi-kelas, pahami logit dan BCEWithLogitsLoss, dan biarkan optimizer seperti SGD atau Adam memperbarui bobot.

Level: Menengah · 7 menit baca

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.

Idenya

Training butuh dua bagian lagi:

PyTorch menyediakan keduanya, sehingga langkah training menyusut menjadi beberapa baris standar.

Loss untuk setiap jenis masalah

MasalahOutput modelLossTarget
regresisatu angka per contohnn.MSELoss() (atau nn.L1Loss() untuk MAE)nilai float
klasifikasi binersatu logit per contohnn.BCEWithLogitsLoss()float 0.0 / 1.0
multi-kelas (k kelas)k logit per contohnn.CrossEntropyLoss()indeks kelas 0..k−1 (int64)
import torch
from torch import nn

pred = torch.tensor([52.0, 61.0, 44.0])
actual = torch.tensor([50.0, 65.0, 44.0])
print(nn.MSELoss()(pred, actual), nn.L1Loss()(pred, actual))
tensor(6.6667) tensor(2.)

Objek loss dibuat sekali, lalu dipanggil seperti fungsi: loss_fn(predictions, targets).

Logit dan BCEWithLogitsLoss

Untuk masalah biner, model mengeluarkan skor mentah (logit), dan loss-nya sendiri yang menerapkan sigmoid:

logits = torch.tensor([2.0, -1.0, 0.5])      # raw model outputs
targets = torch.tensor([1.0, 0.0, 0.0])
loss_fn = nn.BCEWithLogitsLoss()
print(loss_fn(logits, targets))

probs = torch.sigmoid(logits)
manual = -(targets * torch.log(probs) + (1 - targets) * torch.log(1 - probs)).mean()
print(manual)
tensor(0.4714)
tensor(0.4714)

Log loss yang sama seperti di track ML. Kenapa tidak menerapkan sigmoid di model lalu memakai nn.BCELoss pada probabilitas? Karena untuk prediksi yang sangat yakin, log(sigmoid(z)) kehilangan presisi (probabilitas dibulatkan menjadi tepat 1.0, dan log(0) muncul). BCEWithLogitsLoss menggabungkan kedua langkah itu dengan cara yang stabil secara numerik. Aturannya: model mengembalikan logit; loss menerima logit.

Multi-kelas: CrossEntropyLoss

Untuk k kelas (misalnya, ulasan ini membahas yang mana dari 5 kategori produk), model mengembalikan k logit per contoh, dan target-nya adalah indeks kelas yang benar:

logits = torch.tensor([[2.0, 0.5, -1.0],      # example 1: class 0 looks likely
                       [0.1, 0.2, 3.0]])      # example 2: class 2 looks likely
targets = torch.tensor([0, 2])                # correct class indices (int64)
print(nn.CrossEntropyLoss()(logits, targets))
print(torch.softmax(logits, dim=1).round(decimals=3))
tensor(0.1755)
tensor([[0.7860, 0.1750, 0.0390],
        [0.0490, 0.0540, 0.8960]])

CrossEntropyLoss menerapkan softmax (yang mengubah k logit menjadi k probabilitas berjumlah 1) dan log loss dalam satu langkah yang stabil. Sekali lagi: tidak ada softmax di model.

Optimizer

Optimizer memegang parameter-parameter model dan memperbaruinya dari .grad masing-masing:

torch.manual_seed(0)
model = nn.Linear(1, 1)
optimizer = torch.optim.SGD(model.parameters(), lr=0.05)
x = torch.tensor([[1.0], [2.0], [3.0]])
y = torch.tensor([[3.0], [5.0], [7.0]])
loss_fn = nn.MSELoss()

for step in range(3):
    optimizer.zero_grad()            # 1. clear old gradients
    loss = loss_fn(model(x), y)      # 2. forward pass + loss
    loss.backward()                  # 3. compute gradients
    optimizer.step()                 # 4. update parameters
    print(step, round(loss.item(), 3))
0 22.744
1 4.525
2 0.911

Empat baris itu adalah jantung dari setiap training loop PyTorch. Bandingkan dengan modul autograd: zero_grad() menggantikan panggilan manual .grad.zero_(), dan step() menggantikan update di dalam no_grad().

Optimizer yang mana?

for name, opt_class in [("SGD", torch.optim.SGD), ("Adam", torch.optim.Adam)]:
    torch.manual_seed(0)
    model = nn.Linear(1, 1)
    optimizer = opt_class(model.parameters(), lr=0.05)
    for _ in range(200):
        optimizer.zero_grad()
        loss = loss_fn(model(x), y)
        loss.backward()
        optimizer.step()
    print(name, round(loss.item(), 5), round(model.weight.item(), 3), round(model.bias.item(), 3))
SGD 0.00014 1.986 1.031
Adam 0.04756 1.743 1.57

SGD mencapai w = 2, b = 1 dalam 200 langkah; Adam, dengan learning rate yang sama, masih dalam perjalanan. Ukuran langkah per parameter milik Adam bersinar di masalah besar dan berantakan dengan banyak parameter, bukan di mainan berbobot satu, dan setiap optimizer punya rentang learning rate yang baik masing-masing. Learning rate tetap pengaturan yang paling penting, apa pun optimizer-nya.

Ide utama

Pilih loss dari jenis masalahnya (MSE untuk angka, BCEWithLogits untuk ya/tidak, CrossEntropy untuk k kelas), berikan logit, dan jalankan training dengan zero_grad → loss → backward → step.

Mengapa ini penting untuk kode yang bersih

Loss dan optimizer adalah konfigurasi, bukan logika: buat sekali, di dekat model, dari pengaturan yang jelas (lr, weight_decay). Ketidakcocokan adalah bug senyap yang klasik: softmax di model dan di CrossEntropyLoss (training tetap jalan, tetapi lebih buruk), target integer untuk BCE, target float untuk CrossEntropy. Menjaga konvensi "logit masuk, loss keluar" di mana-mana mencegahnya.

Rangkuman

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.

Berikutnya: Training loop, langkah demi langkah →