DataLens

Training loop, langkah demi langkah

Tulis training loop lengkap dengan epoch, mini-batch, tahap validasi dalam mode eval, dan pencatatan loss, serta pahami fungsi setiap barisnya.

Level: Menengah · 7 menit baca

Latihan modul ini

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

Idenya

Tidak seperti satu panggilan fit() di scikit-learn, PyTorch menyerahkan training loop untuk kamu tulis sendiri. Kodenya memang lebih banyak, tetapi kamu juga mendapat kendali penuh: kamu yang memutuskan bagaimana batch diambil, apa yang dicatat, kapan evaluasi, dan kapan berhenti. Setiap proyek PyTorch punya loop dengan kerangka yang sama, jadi begitu kamu memahaminya, kamu bisa membaca kode training siapa pun.

for each epoch (a full pass over the training data):
    model.train()
    for each mini-batch:
        zero gradients → forward → loss → backward → optimizer step
    model.eval()
    with no gradients: compute validation loss
    log both losses

Datanya

Lagi-lagi permintaan kopi: 4 fitur, prediksi unit yang terjual. Standarkan input-nya (training berbasis gradient butuh skala yang sebanding), dan sisihkan 66 hari terakhir untuk validasi:

import numpy as np
import pandas as pd
import torch
from torch import nn

demand = pd.read_csv("daily_demand.csv")
FEATURES = ["temperature", "weekend", "promo", "ad_spend"]
X = demand[FEATURES].to_numpy(dtype=np.float32)
y = demand["units"].to_numpy(dtype=np.float32).reshape(-1, 1)

mean, std = X[:300].mean(axis=0), X[:300].std(axis=0)     # statistics from training rows only
X = (X - mean) / std
X_train, y_train = torch.from_numpy(X[:300]), torch.from_numpy(y[:300])
X_val, y_val = torch.from_numpy(X[300:]), torch.from_numpy(y[300:])
print(X_train.shape, y_train.shape, X_val.shape)
torch.Size([300, 4]) torch.Size([300, 1]) torch.Size([66, 4])

Loop-nya

Ini training loop lengkap untuk data permintaan: jaringan kecil, optimizer, loss function, dan 200 putaran atas data latih dalam batch berisi 32. Setiap proyek PyTorch yang akan kamu lihat punya loop berbentuk seperti ini:

torch.manual_seed(0)
model = nn.Sequential(nn.Linear(4, 16), nn.ReLU(), nn.Linear(16, 1))
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
loss_fn = nn.MSELoss()
batch_size = 32

for epoch in range(1, 201):
    model.train()
    order = torch.randperm(len(X_train))              # shuffle every epoch
    for start in range(0, len(X_train), batch_size):
        idx = order[start:start + batch_size]
        optimizer.zero_grad()
        loss = loss_fn(model(X_train[idx]), y_train[idx])
        loss.backward()
        optimizer.step()

    model.eval()
    with torch.no_grad():
        train_loss = loss_fn(model(X_train), y_train).item()
        val_loss = loss_fn(model(X_val), y_val).item()
    if epoch in (1, 10, 50, 100, 200):
        print(f"epoch {epoch:3d}  train MSE {train_loss:8.2f}  val MSE {val_loss:8.2f}")
epoch   1  train MSE  3105.28  val MSE  3449.84
epoch  10  train MSE   863.41  val MSE   641.93
epoch  50  train MSE    28.19  val MSE    36.46
epoch 100  train MSE    24.25  val MSE    29.97
epoch 200  train MSE    23.10  val MSE    28.22

Baris demi baris:

MSE turun dari ribuan (bobot acak yang memprediksi asal-asalan) ke sekitar 25, sejalan dengan regresi linear dari track ML (RMSE ≈ 5 unit). Pada data yang hampir linear ini, network-nya menyamai regresi linear; ia tidak bisa secara ajaib mengalahkan noise.

Membaca kurvanya

PolaArtiTindakan
kedua loss turun, lalu mendatar berdekatansudah mempelajari apa yang bisa dipelajariberhenti; mungkin tambahkan fitur
training turun, validasi mendatar lalu naikoverfittingberhenti lebih awal, regularisasi (modul 12)
keduanya tetap tinggiunderfitting atau ada bugmodel lebih besar, epoch lebih banyak, cek data dan learning rate
loss melompat-lompat atau menjadi nanlearning rate terlalu tinggi, atau input tidak diskalakanturunkan lr, standarkan

Membuat prediksi

Setelah training, lakukan prediksi dalam mode eval tanpa gradient, lalu konversi kembali ke NumPy:

model.eval()
with torch.no_grad():
    preds = model(X_val).squeeze().numpy()
mae = np.mean(np.abs(preds - y_val.squeeze().numpy()))
print(preds[:5].round(1), round(float(mae), 2))
[76.9 46.1 67.9 47.  53.8] 4.39

MAE validasinya sebanding dengan regresi linear di track ML: sanity check yang bagus bahwa loop-nya berfungsi.

Ide utama

Setiap training loop adalah: untuk setiap epoch, mode train(), acak, loop atas mini-batch dengan zero_grad → forward → loss → backward → step; lalu mode eval() dan no_grad() untuk validasi; catat kedua loss.

Mengapa ini penting untuk kode yang bersih

Training loop terus bertambah fitur seiring waktu: logging, checkpoint, early stopping, metrik. Mulailah dari kerangka bersih di atas, dan saat ia membesar, ekstrak fungsi train_one_epoch(model, loader, optimizer, loss_fn) dan evaluate(model, loader, loss_fn). Masing-masing lalu muat dalam satu layar dan bisa dites dengan dataset kecil. Modul struktur proyek membangun persis itu.

Rangkuman

Latihan modul ini

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

Berikutnya: Dataset dan DataLoader →