Model tidak mempelajari seluruh dataset sekaligus; dataset dipotong menjadi batch yang digilirkan melalui forward, backward, dan pembaruan parameter. Tiga istilah pada proses itu — batch, iterasi, epoch — sering tertukar padahal maknanya berbeda, dan ukuran batch menyimpan trade-off yang memengaruhi kecepatan, memori, hingga kualitas gradien. Chapter ini memetakan ketiganya, membedah trade-offnya, lalu membuktikannya dengan training identik pada batch 8, 32, dan 128.
Batch, Iterasi, dan Epoch #
- Batch adalah potongan data yang diproses model sebelum satu pembaruan parameter; ukurannya disebut batch size.
- Iterasi adalah satu putaran forward–backward–
step()pada satu batch. - Epoch adalah satu putaran penuh menelusuri seluruh data latih.
Aritmetikanya lurus: dataset 600 sampel dengan batch size 32 menghasilkan 19 iterasi per epoch — 18 batch penuh ditambah satu batch sisa berisi 24 sampel, karena DataLoader tidak membuang sisa yang tidak genap. Lima epoch berarti model telah melihat setiap sampel tepat lima kali.
Full Batch, Mini-Batch, dan Stochastic #
| Mode | Ukuran batch | Karakteristik |
|---|---|---|
| Full batch | seluruh data latih | gradien paling halus (eksak), satu pembaruan per epoch, memori besar |
| Mini-batch | 16–512 (umumnya) | kompromi industri: gradien cukup stabil, pembaruan cukup sering |
| Stochastic (online) | 1 sampel | pembaruan paling sering, gradien paling bergejolak, tidak efisien pada komputasi paralel |
Full-batch gradient descent yang kita hitung manual di chapter Gradient Descent memakai gradien eksak seluruh data; mini-batch menggantinya dengan perkiraan dari potongan data, dan variasi antar batch itu justru berguna — membantu model lolos dari titik jenuh dan kerap menghasilkan generalisasi lebih baik daripada gradien eksak.
Trade-off Ukuran Batch #
| Aspek | Batch kecil | Batch besar |
|---|---|---|
| Kualitas gradien | bergejolak antar iterasi | semakin halus dan mendekati gradien eksak |
| Pembaruan per epoch | banyak (600/8 = 75) | sedikit (600/128 = 5) |
| Memori per iterasi | kecil | besar, bisa melebihi kapasitas GPU |
| Waktu per epoch | lebih lama (iterasi banyak) | lebih cepat (paralelisme efektif) |
| Kemajuan per epoch | cenderung lebih jauh | cenderung lebih pendek pada epoch sama |
Dua baris terakhir tabel tampak saling bertentangan dan memang demikian adanya: batch kecil mendapat lebih banyak kesempatan memperbaiki bobot dalam satu epoch, sedangkan batch besar menikmati gradien yang lebih dapat dipercaya. Tidak ada pemenang mutlak — perlu diukur.
Contoh: Batch 8, 32, dan 128 #
Berkas banding_batch.py melatih model yang identik tiga kali: dataset make_moons 600 sampel, MLP [2, 16, 2], SGD lr=0.1, 30 epoch, inisialisasi bobot sama. Satu-satunya variabel yang berubah adalah batch size:
"""Perbandingan batch size 8, 32, dan 128 pada training yang sama.
Dataset make_moons 600 sampel, MLP [2, 16, 2], SGD lr=0.1, 30 epoch.
Hanya batch size yang berubah. Diamati: jumlah iterasi per epoch, laju
penurunan loss, getaran loss antar batch, akurasi akhir, dan waktu.
Semua contoh diuji pada CPU (torch 2.14.1+cpu).
"""
import time
import torch
import torch.nn as nn
from sklearn.datasets import make_moons
from torch.utils.data import DataLoader, TensorDataset
torch.manual_seed(42)
# ---------- 1. Dataset dan komponen yang disamakan ----------
X, y = make_moons(n_samples=600, noise=0.20, random_state=42)
X_t = torch.tensor(X, dtype=torch.float32)
y_t = torch.tensor(y, dtype=torch.long)
JUMLAH_EPOCH = 30
EPOCH_CETAK = (1, 10, 20, 30)
def buat_model():
"""Model dengan inisialisasi bobot identik untuk tiap batch size."""
torch.manual_seed(7)
return nn.Sequential(
nn.Linear(2, 16),
nn.ReLU(),
nn.Linear(16, 2),
)
def latih(batch_size):
"""Latih model dengan batch size tertentu, kembalikan ringkasan."""
model = buat_model()
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
dataset = TensorDataset(X_t, y_t)
loader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=True,
generator=torch.Generator().manual_seed(42),
)
mulai = time.perf_counter()
jejak_loss = {}
batch_terakhir = None
loss_per_batch = None
for epoch in range(1, JUMLAH_EPOCH + 1):
if epoch == JUMLAH_EPOCH:
loss_per_batch = [] # getaran batch pada epoch terakhir
total_loss = 0.0
for X_batch, y_batch in loader:
optimizer.zero_grad()
loss = loss_fn(model(X_batch), y_batch)
loss.backward()
optimizer.step()
total_loss += loss.item()
batch_terakhir = len(y_batch)
if loss_per_batch is not None:
loss_per_batch.append(loss.item())
if epoch in EPOCH_CETAK:
jejak_loss[epoch] = total_loss / len(loader)
waktu = time.perf_counter() - mulai
with torch.no_grad():
akurasi = (model(X_t).argmax(dim=1) == y_t).float().mean().item()
getaran = torch.tensor(loss_per_batch).std().item()
return {
"iterasi": len(loader),
"terakhir": batch_terakhir,
"jejak": jejak_loss,
"akhir": jejak_loss[JUMLAH_EPOCH],
"akurasi": akurasi,
"getaran": getaran,
"waktu": waktu,
}
# ---------- 2. Jalankan tiga konfigurasi ----------
print("data : make_moons 600 sampel | MLP [2, 16, 2] | SGD lr=0.1")
print("epoch :", JUMLAH_EPOCH, "| satu-satunya variabel: batch size")
print()
for batch_size in (8, 32, 128):
h = latih(batch_size)
jejak = " -> ".join(f"{h['jejak'][e]:.4f}" for e in EPOCH_CETAK)
print(f"batch {batch_size:3d} | {h['iterasi']:2d} iterasi/epoch "
f"| batch terakhir {h['terakhir']:3d}")
print(f" loss epoch 1/10/20/30 : {jejak}")
print(f" loss akhir {h['akhir']:.4f} | akurasi {h['akurasi']:.3f} | "
f"getaran loss antar batch {h['getaran']:.4f} | "
f"waktu {h['waktu']:.2f} s")
print()
print("catatan: angka waktu bervariasi antar mesin dan eksekusi;")
print("getaran = simpangan baku loss antar batch pada epoch terakhir.")Output yang Dihasilkan:
data : make_moons 600 sampel | MLP [2, 16, 2] | SGD lr=0.1
epoch : 30 | satu-satunya variabel: batch size
batch 8 | 75 iterasi/epoch | batch terakhir 8
loss epoch 1/10/20/30 : 0.4410 -> 0.2486 -> 0.1627 -> 0.1290
loss akhir 0.1290 | akurasi 0.963 | getaran loss antar batch 0.1424 | waktu 8.52 s
batch 32 | 19 iterasi/epoch | batch terakhir 24
loss epoch 1/10/20/30 : 0.5479 -> 0.2921 -> 0.2722 -> 0.2588
loss akhir 0.2588 | akurasi 0.895 | getaran loss antar batch 0.0902 | waktu 4.49 s
batch 128 | 5 iterasi/epoch | batch terakhir 88
loss epoch 1/10/20/30 : 0.6132 -> 0.3809 -> 0.3155 -> 0.2988
loss akhir 0.2988 | akurasi 0.875 | getaran loss antar batch 0.0612 | waktu 1.52 s
catatan: angka waktu bervariasi antar mesin dan eksekusi;
getaran = simpangan baku loss antar batch pada epoch terakhir.Contoh di atas diuji nyata dengan PyTorch 2.14.1+cpu pada CPU. Mari kita telaah kode di atas baris per baris:
- Baris 19-21 (data): 600 sampel
make_moonsdikonversi sekali ke tensor dan dipakai bersama oleh ketiga pelatihan. - Baris 27-34 (
buat_model): seed7dipanggil ulang tiap pelatihan sehingga ketiga konfigurasi memulai dari bobot identik. - Baris 43-49 (loader):
shuffle=Truedengan generator ber-seed memberi urutan data acak yang sama untuk ketiganya. - Baris 55-69 (loop): pelatihan standar;
jejak_lossmencatat rata-rata loss per epoch, dan pada epoch terakhir setiap loss batch disimpan untuk mengukur getaran. - Baris 70-75 (metrik): waktu diukur dengan
time.perf_counter(); getaran = simpangan baku loss antar batch pada epoch terakhir, ukuran kebisingan gradien mini-batch. - Baris 91-100 (perbandingan): hasil ketiga konfigurasi dicetak berdampingan.
Keluaran mengubah tabel menjadi angka. Batch 8 menghasilkan 75 iterasi per epoch dan menuntaskan loss sampai 0.1290 (akurasi 0.963); batch 128 hanya mendapat 5 iterasi dan berhenti di 0.2988 (0.875) — pada 30 epoch yang sama, frekuensi pembaruan menentukan seberapa jauh model maju. Arah sebaliknya tampak pada getaran: simpangan baku loss antar batch turun 0.1424 → 0.0902 → 0.0612 seiring batch membesar — gradien semakin halus. Waktu per epoch memihak batch besar (8.52 s → 1.52 s) karena 75 iterasi kecil menanggung biaya tetap Python jauh lebih sering daripada 5 iterasi besar.
Jumlah iterasi per epoch kini jelas; besaran berikutnya menentukan seberapa jauh tiap iterasi menggeser parameter. Learning rate — pengatur tunggal yang paling sering memisahkan training mulus dari training gagal — adalah topik chapter berikutnya.