Dataset, DataLoader & Klasifikasi Angka Tulisan Tangan
Part 2 membahas cara memuat data real, memproses dalam batch, dan membangun classifier yang bisa mengenali angka tulisan tangan (MNIST) dengan akurasi 97%+ β lengkap dengan visualisasi arsitektur network dan proses training.
Dataset MNIST β 70.000 gambar angka tulisan tangan
Transforms β Preprocessing gambar sebelum masuk model
DataLoader β Batch, shuffle, parallel loading
Membangun Classifier β Neural network untuk 10 kelas angka
Training Loop Lengkap β Train + evaluate + visualisasi loss
Evaluasi & Prediksi β Akurasi, confusion, dan prediksi real
Ringkasan & Preview Part 3
π
1. Recap Part 1
Fondasi yang sudah kita kuasai
Di Part 1, kita sudah belajar: Tensor (array multi-dimensi), Autograd (hitung gradient otomatis), dan membuat neural network pertama yang belajar y = 2x + 1 dari data. Sekarang kita naik level β dari data dummy ke data real: gambar tulisan tangan.
πΌοΈ
2. Mengenal Dataset MNIST
70.000 gambar angka 0-9, masing-masing 28Γ28 pixel grayscale
MNIST (Modified National Institute of Standards and Technology) adalah dataset benchmark paling terkenal di machine learning β berisi 70.000 gambar angka tulisan tangan (0-9), masing-masing berukuran 28Γ28 pixel dalam grayscale.
πΌοΈ Contoh Gambar MNIST β Angka 0 sampai 9
π Training Set
60.000 gambar + label. Digunakan untuk melatih model. Data di-shuffle setiap epoch.
π§ͺ Test Set
10.000 gambar + label. Tidak pernah dilihat model saat training. Mengukur akurasi sebenarnya.
π
3. Transforms β Preprocessing Data
Konversi gambar β tensor, normalisasi nilai pixel
Sebelum gambar bisa masuk ke neural network, kita perlu transform: mengubah gambar PIL menjadi tensor dan normalisasi agar training lebih stabil.
05_transforms.py β Preprocessing Pipeline
import torchvision.transforms as transforms
# Pipeline preprocessing: jalankan berurutan
transform = transforms.Compose([
transforms.ToTensor(), # PIL Image β Tensor [0, 1]
transforms.Normalize(
(0.1307,), # mean MNIST
(0.3081,) # std MNIST
)
])
# Apa yang terjadi:# 1. ToTensor(): gambar 28Γ28 pixel (0-255)# β Tensor shape [1, 28, 28] dengan nilai [0.0, 1.0]# 2. Normalize(): (pixel - mean) / std# β Nilai terpusat di 0, spread Β±1# β Training lebih stabil & cepat converge
π Mengapa Normalisasi?
Tanpa normalisasi, pixel bernilai 0-255 β range yang terlalu besar. Gradient bisa meledak atau menghilang. Normalisasi membuat semua input dalam range yang seragam (~-0.4 sampai ~2.8 untuk MNIST), sehingga optimizer bekerja jauh lebih efisien. Nilai 0.1307 dan 0.3081 adalah mean dan std yang sudah dihitung dari seluruh dataset MNIST.
π¦
4. Dataset & DataLoader
Muat data, bagi ke batch, shuffle, parallel loading
π DataLoader Pipeline β Dari Dataset ke Batch
06_dataset_dataloader.py β Muat MNIST
import torch
from torch.utils.data import DataLoader
import torchvision
import torchvision.transforms as transforms
# ===========================# 1. Transform pipeline# ===========================
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
# ===========================# 2. Download & muat dataset# ===========================
train_dataset = torchvision.datasets.MNIST(
root='./data',
train=True, # Training set (60K)
download=True, # Download jika belum ada
transform=transform
)
test_dataset = torchvision.datasets.MNIST(
root='./data',
train=False, # Test set (10K)
download=True,
transform=transform
)
print(f"Training: {len(train_dataset)} gambar")
print(f"Test: {len(test_dataset)} gambar")
# Training: 60000 gambar# Test: 10000 gambar# ===========================# 3. Buat DataLoader# ===========================
train_loader = DataLoader(
train_dataset,
batch_size=64, # 64 gambar per batch
shuffle=True# Acak setiap epoch
)
test_loader = DataLoader(
test_dataset,
batch_size=64,
shuffle=False# Test: tidak perlu acak
)
# ===========================# 4. Intip satu batch# ===========================
images, labels = next(iter(train_loader))
print(f"Batch images: {images.shape}")
print(f"Batch labels: {labels.shape}")
# Batch images: torch.Size([64, 1, 28, 28])# βbatch βchannel βheight βwidth# Batch labels: torch.Size([64])# β64 angka (0-9)
π Kenapa Pakai Batch?
Melatih 60.000 gambar sekaligus = terlalu berat untuk memory. Satu gambar saja = terlalu noisy (gradient tidak stabil). Mini-batch (64) = sweet spot: cukup stabil untuk gradient yang baik, cukup kecil untuk muat di memory. Model melihat 64 gambar, hitung rata-rata error, update parameter sekali. Ulangi 937 kali = 1 epoch (semua data terlihat sekali).
π§
5. Membangun Digit Classifier
Neural network dengan 2 hidden layers β input 784, output 10 kelas
import torch
import torch.nn as nn
classMNISTClassifier(nn.Module):
def__init__(self):
super().__init__()
self.flatten = nn.Flatten() # [1,28,28] β [784]
self.layers = nn.Sequential(
nn.Linear(784, 256), # Hidden 1
nn.ReLU(), # Aktivasi
nn.Linear(256, 128), # Hidden 2
nn.ReLU(), # Aktivasi
nn.Linear(128, 10) # Output (10 kelas)
)
defforward(self, x):
x = self.flatten(x) # Flatten gambar
x = self.layers(x) # Forward through layersreturn x
model = MNISTClassifier()
# Hitung total parameters
total = sum(p.numel() for p in model.parameters())
print(f"Total parameters: {total:,}")
# Total parameters: 235,146
π Apa Itu ReLU?
ReLU (Rectified Linear Unit) = max(0, x). Jika input positif β loloskan. Jika negatif β jadikan 0. Ini "fungsi aktivasi" yang membuat network bisa belajar pola non-linear (bukan cuma garis lurus). Tanpa ReLU, network sekompleks apapun hanya bisa menghitung fungsi linear β yang tidak cukup untuk mengenali gambar.
ποΈ
6. Training Loop Lengkap
Train 10 epoch + evaluasi setiap epoch + track loss
π 97.8% Akurasi! Dari 10.000 gambar test, model kita benar mengenali 9.780 gambar. Hanya salah 220 β dan ini hanya dengan 2 hidden layers sederhana. Di Part 3 kita akan naik ke 99%+ dengan CNN (Convolutional Neural Network).
π
7. Evaluasi & Prediksi
Simpan model + prediksi gambar baru
09_evaluate_predict.py β Prediksi & Save
# ===========================# 1. Prediksi gambar individual# ===========================# Ambil satu gambar dari test set
image, true_label = test_dataset[0]
# Prediksi
model.eval()
with torch.no_grad():
output = model(image.unsqueeze(0)) # Tambah batch dimension
probs = torch.nn.functional.softmax(output, dim=1)
pred = output.argmax(dim=1).item()
conf = probs[0][pred].item() * 100print(f"True label: {true_label}")
print(f"Predicted: {pred}")
print(f"Confidence: {conf:.1f}%")
# True label: 7# Predicted: 7# Confidence: 99.8% β # ===========================# 2. Simpan model untuk nanti# ===========================
torch.save(model.state_dict(), 'mnist_model.pth')
print("Model tersimpan! πΎ")
# Muat kembali:
loaded_model = MNISTClassifier()
loaded_model.load_state_dict(torch.load('mnist_model.pth'))
loaded_model.eval()
print("Model dimuat kembali! β ")
π
8. Ringkasan Part 2
Konsep baru yang kita kuasai
Konsep
Apa Itu
Kode Kunci
Dataset
Koleksi data + label. MNIST: 70K gambar angka.
datasets.MNIST(root, train, transform)
Transform
Pipeline preprocessing: gambar β tensor β normalize
transforms.Compose([ToTensor(), Normalize()])
DataLoader
Bagi data ke batch, shuffle, parallel loading
DataLoader(dataset, batch_size=64, shuffle=True)
Flatten
Ubah gambar 2D β vektor 1D untuk masuk ke Linear
nn.Flatten() # [1,28,28] β [784]
CrossEntropyLoss
Loss untuk klasifikasi multi-kelas (10 angka)
nn.CrossEntropyLoss()
Adam Optimizer
Optimizer adaptif β lebih baik dari SGD untuk kebanyakan kasus
optim.Adam(model.parameters(), lr=0.001)
model.train()
Aktifkan mode training (dropout, batchnorm aktif)
model.train()
model.eval()
Mode evaluasi (dropout off, batchnorm freeze)
model.eval()
torch.save()
Simpan model ke file untuk dipakai nanti
torch.save(model.state_dict(), 'model.pth')
softmax
Konversi output raw β probabilitas (jumlah = 1.0)