Setiap proyek deep learning dengan PyTorch berputar di sekitar satu struktur yang sama, yaitu perulangan pelatihan (training loop), kode yang menggerakkan model menelusuri data berulang kali sampai prediksinya membaik. Topik ini membedah anatomi struktur tersebut, mulai dari lima baris inti yang membentuk satu iterasi (iteration), yakni satu kali pemrosesan satu kelompok data, sampai skrip pelatihan pertama yang lengkap. Setelah membaca topik ini, bentuk dasar perulangan pelatihan dapat ditulis dari ingatan, dan fungsi setiap baris dapat dijelaskan.
Lima baris inti satu iterasi#
Satu iterasi perulangan pelatihan memproses satu batch, yaitu kelompok kecil sampel yang diproses bersama dalam satu langkah, dan selalu tersusun dari lima baris yang sama dalam urutan yang sama. Urutan ini bersifat kanonik, sehingga begitu dikenali pada satu proyek, struktur tersebut dapat ditemukan kembali pada hampir semua kode PyTorch lainnya. Kelima baris tersebut ditulis sebagai berikut.
# tidak-dijalankan: fragmen merujuk variabel yang didefinisikan pada skrip lengkap di bawah
optimizer.zero_grad() # (1) kosongkan gradien lama
y_pred = model(x_batch) # (2) forward, model menghitung prediksi
loss = criterion(y_pred, y_batch) # (3) hitung loss
loss.backward() # (4) backward, gradien dihitung
optimizer.step() # (5) perbarui bobotBaris (1) mengosongkan nilai gradien (gradient), yaitu arah dan besar perubahan bobot yang dihitung PyTorch, sebelum perhitungan baru dimulai. Baris (2) menjalankan operasi maju (forward pass), yakni memasukkan batch masukan ke model untuk memperoleh prediksi. Baris (3) menghitung loss, angka tunggal yang mengukur seberapa jauh prediksi menyimpang dari target, menggunakan fungsi loss yang disimpan pada variabel criterion. Baris (4) menjalankan operasi mundur (backward pass) yang mengisi gradien setiap bobot model dari loss tersebut. Baris (5) meminta optimizer menggunakan gradien itu untuk memperbarui bobot model.
Diagram berikut menunjukkan siklus tersebut beserta jalan baliknya ke batch berikutnya.
Kelima baris dijalankan untuk setiap batch dalam dataset. Setelah batch terakhir diproses, satu epoch, yaitu satu penelusuran penuh atas seluruh data pelatihan, dianggap selesai, dan perulangan luar kemudian memulai epoch berikutnya dari baris (1) lagi.
Skrip perulangan pelatihan pertama#
Skrip berikut menerapkan kelima baris itu secara utuh. Datanya sintetis: 64 titik diambil dari hubungan linear yang diberi sedikit derau, sehingga jawaban yang benar sudah diketahui dan hasil pelatihan dapat dinilai secara langsung. TensorDataset membungkus pasangan masukan dan target menjadi satu dataset, sedangkan DataLoader memotongnya menjadi batch berisi delapan sampel dan mengacak urutannya pada setiap epoch. Model yang digunakan adalah nn.Linear(1, 1), fungsi lossnya nn.MSELoss(), dan optimizernya torch.optim.SGD dengan learning rate 0.5.
import torch
import torch.nn as nn
from torch.utils.data import TensorDataset, DataLoader
torch.manual_seed(0)
# Data sintetis: regresi linear y = 2x + 1 dengan sedikit derau
n = 64
x = torch.linspace(0.0, 1.0, n).unsqueeze(1)
y = 2.0 * x + 1.0 + 0.05 * torch.randn(n, 1)
dataset = TensorDataset(x, y)
loader = DataLoader(dataset, batch_size=8, shuffle=True)
model = nn.Linear(1, 1) # model yang akan dilatih
criterion = nn.MSELoss() # fungsi loss
optimizer = torch.optim.SGD(model.parameters(), lr=0.5)
for epoch in range(5):
total = 0.0
for x_batch, y_batch in loader:
optimizer.zero_grad() # (1) kosongkan gradien lama
y_pred = model(x_batch) # (2) forward
loss = criterion(y_pred, y_batch) # (3) hitung loss
loss.backward() # (4) backward
optimizer.step() # (5) perbarui bobot
total += loss.item()
print(f"epoch {epoch + 1}: loss rata-rata {total / len(loader):.4f}")
print("bobot akhir:", model.weight.item())
print("bias akhir :", model.bias.item())epoch 1: loss rata-rata 0.5150
epoch 2: loss rata-rata 0.0187
epoch 3: loss rata-rata 0.0050
epoch 4: loss rata-rata 0.0041
epoch 5: loss rata-rata 0.0044
bobot akhir: 1.9852105379104614
bias akhir : 0.9896457195281982Perulangan luarnya berjalan lima epoch, sedangkan perulangan dalamnya menelusuri loader batch demi batch. Di dalam perulangan dalam itulah kelima baris inti dieksekusi, satu kali untuk setiap batch. Angka loss pada setiap epoch diakumulasi dari seluruh batch, lalu dibagi len(loader), yaitu jumlah batch dalam satu epoch, sehingga nilai yang dicetak merupakan rata-rata loss epoch tersebut. torch.manual_seed(0) di awal skrip membuat pengacakan data dan inisialisasi bobot tetap sama, sehingga keluarannya dapat direproduksi.
Membaca keluaran skrip#
Loss turun dari 0.5150 pada epoch pertama menjadi sekitar 0.004 pada epoch keempat dan kelima. Penurunan besar terjadi pada epoch kedua, kemudian kurvanya mendatar dekat nilai 0.004. Perbandingan ini penting: derau yang ditanamkan pada data sebesar 0.05 menetapkan lantai teoretis untuk fungsi loss mean squared error (MSE) yang menghitung rata-rata kuadrat selisih prediksi dan target,
Kuadrat derau tersebut, , adalah nilai loss terbaik yang masih dapat dicapai model linear mana pun pada data ini, sehingga kurva yang mendatar dekat angka itu justru menandakan pelatihan sehat. Angka epoch terakhir yang sedikit naik dari 0.0041 menjadi 0.0044 bukan gejala gangguan, melainkan fluktuasi wajar karena urutan batch diacak dan rata-rata dihitung dari sampel yang berbeda di setiap epoch.
Dua baris terakhir keluaran menegaskan hasilnya. Bobot model berakhir di 1.985 dan biasnya di 0.990, dua angka yang menghampiri dua dan satu, yaitu koefisien yang ditanamkan saat data dibuat. Model memang tidak pernah menemukan nilai tersebut secara persis karena sampel pelatihan berau, tetapi arah pembaruan tetap benar dan selisihnya terus menyempit.
Kesalahan umum#
Tiga kesalahan berikut paling sering muncul saat perulangan pelatihan pertama ditulis.
- Lupa membagi akumulasi loss dengan
len(loader). Angka yang dicetak menjadi total loss seluruh batch, bukan rata-ratanya, sehingga angka itu tidak sebanding apabila jumlah batch berubah. Perbaikannya: bagitotaldenganlen(loader)sebelum dicetak. - Menambahkan
loss.item()tanpa alasan yang jelas atau justru mencetak objeklossmentah. Mencetaklossmentah memuat pembungkus tensor beserta graf komputasinya, sedangkan.item()mengambil angka Python biasa yang ringan untuk disimpan ke dalam daftar. - Meletakkan
optimizer.zero_grad()di luar perulangan batch. Gradien kemudian terakumulasi lintas batch, dan baris kelima menerima informasi yang tercampur dari banyak batch sekaligus. Gejalanya tidak berupa pesan error, melainkan loss yang sulit menetap.
Ringkasan#
- Satu iterasi perulangan pelatihan tersusun dari lima baris berurutan:
optimizer.zero_grad(), forward, penghitungan loss,loss.backward(), danoptimizer.step(). - Perulangan dalam menelusuri batch demi batch, sedangkan perulangan luar menghitung epoch. Rata-rata loss per epoch diperoleh dengan membagi akumulasi loss oleh
len(loader). - Loss yang mendatar di dekat kuadrat derau data menandakan pelatihan sudah mendekati batas terbaik yang mungkin, bukan berarti pelatihan gagal.
Referensi#
- PyTorch documentation — PyTorch
— Rujukan utama modul
torch.nn, optimizer, dan API pelatihan yang digunakan pada skrip. - Deep Learning with PyTorch: A 60 Minute Blitz — PyTorch — Tutorial resmi yang memperkenalkan tensor, autograd, dan perulangan pelatihan pertama.
- PyTorch data documentation — PyTorch
— Dokumentasi
TensorDatasetdanDataLoaderuntuk batching serta pengacakan urutan batch.