Key Concept: การเรียนรู้จากความผิดพลาด
ตอนนี้เรามีโมเดลและข้อมูลแล้ว ถึงเวลาฝึกให้โมเดลของเราทำนายได้อย่างแม่นยำ กระบวนการนี้เรียกว่า Optimization (การปรับปรุงพารามิเตอร์) ซึ่งทำงานคล้ายกับนักเรียนที่กำลังทำข้อสอบ:
1. ทำนาย (Predict)
โมเดลลองทายคำตอบจากรูปภาพที่ได้รับ (Forward Pass)
2. ตรวจข้อสอบ (Loss)
ใช้ Loss Function เพื่อวัดว่าโมเดลทายผิดไปจากคำตอบจริงมากแค่ไหน
3. ปรับปรุง (Optimize)
ใช้ Optimizer และสมองกล Autograd ขยับน้ำหนัก (Weights) เพื่อให้คราวหน้าทายแม่นขึ้น
ตั้งค่าเริ่มต้น (Prerequisite Code)
เราจะโหลดโค้ดจากบทก่อนๆ ทั้ง Dataset, DataLoader และโครงสร้าง Neural Network มาไว้ด้วยกันก่อน
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor
# 1. โหลด Dataset
training_data = datasets.FashionMNIST(root="data", train=True, download=True, transform=ToTensor())
test_data = datasets.FashionMNIST(root="data", train=False, download=True, transform=ToTensor())
# 2. สร้าง DataLoader
train_dataloader = DataLoader(training_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)
# 3. กำหนดโมเดล
class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28*28, 512), nn.ReLU(),
nn.Linear(512, 512), nn.ReLU(),
nn.Linear(512, 10),
)
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
model = NeuralNetwork()
Hyperparameters (ตัวแปรควบคุมการเทรน)
ไฮเปอร์พารามิเตอร์ คือค่าพารามิเตอร์ที่เราเป็นคนตั้งขึ้นเอง (ปรับจูนได้) ก่อนที่จะเริ่มรันการฝึกสอน ซึ่งจะส่งผลโดยตรงกับความเร็วและคุณภาพของการเรียนรู้
- Number of Epochs - จำนวนรอบที่โมเดลจะได้เห็นข้อมูลทั้งหมดใน Dataset
- Batch Size - จำนวนข้อมูลที่ดึงมาป้อนโมเดลต่อ 1 ครั้งก่อนคำนวณปรับค่าน้ำหนัก
- Learning Rate - อัตราการเรียนรู้ (ความก้าวร้าวในการปรับน้ำหนัก) ค่าน้อยโมเดลเรียนรู้ช้าแต่ละเอียด ค่ามากโมเดลเรียนรู้เร็วแต่ค่าอาจจะแกว่ง
learning_rate = 1e-3
batch_size = 64
epochs = 5
Optimization Loop
ในแต่ละ Epoch จะประกอบด้วย 2 ลูปหลักๆ คือ:
- The Train Loop - ลูปการเทรน โมเดลเรียนรู้เพื่อลดค่าความสูญเสีย (Loss)
- The Validation/Test Loop - ลูปทดสอบ ลองนำข้อมูลใหม่ที่โมเดลไม่เคยเห็นมาให้มันทำนาย เพื่อดูว่าประสิทธิภาพดีขึ้นหรือไม่
Loss Function
เมื่อเริ่มต้นเทรน โมเดลอาจจะให้คำตอบที่แย่มากๆ Loss function คือตัววัดระดับ "ความแย่" นั้น เป้าหมายของการเทรนคือทำให้ค่า Loss นี้น้อยที่สุด ในงาน Classification เรามักใช้ nn.CrossEntropyLoss
# Initialize the loss function
loss_fn = nn.CrossEntropyLoss()
Optimizer
Optimization คือกระบวนการปรับจูนพารามิเตอร์เพื่อลดความผิดพลาด ในตัวอย่างนี้เราจะใช้ Stochastic Gradient Descent (SGD) โดย PyTorch มีอัลกอริทึมให้เลือกหลายแบบ (เช่น ADAM, RMSProp)
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
ภายใน Training Loop, Optimizer จะทำ 3 ขั้นตอนเสมอ:
optimizer.zero_grad(): ล้างค่า Gradients จากรอบที่แล้วทิ้งไป ไม่ให้มันสะสมปนกันloss.backward(): สั่งให้ Autograd คำนวณ Gradients จาก Loss ย้อนกลับไปหาตัวแปรทุกตัวoptimizer.step(): นำค่า Gradients ที่ได้มาอัปเดตน้ำหนักของโมเดล
Full Implementation (ประกอบร่าง)
เรามากำหนดฟังก์ชัน train_loop และ test_loop ตามหลักการที่อธิบายไปด้านบนกัน
def train_loop(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
model.train() # ตั้งโหมดโมเดลเป็นการเทรน
for batch, (X, y) in enumerate(dataloader):
# คำนวณการทำนายและ Loss
pred = model(X)
loss = loss_fn(pred, y)
# Backpropagation (ปรับน้ำหนัก)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# ปรินต์ความคืบหน้าทุกๆ 100 batch
if batch % 100 == 0:
loss, current = loss.item(), (batch + 1) * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")
def test_loop(dataloader, model, loss_fn):
model.eval() # ตั้งโหมดโมเดลเป็นการประเมิน
size = len(dataloader.dataset)
num_batches = len(dataloader)
test_loss, correct = 0, 0
with torch.no_grad(): # ไม่ต้องจำ Gradients
for X, y in dataloader:
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
correct /= size
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
เริ่มรันการเทรน 5 Epochs!
epochs = 5
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train_loop(train_dataloader, model, loss_fn, optimizer)
test_loop(test_dataloader, model, loss_fn)
print("Done!")
-> คุณสามารถลองกด Start Training Simulation ที่บอร์ดจำลองด้านขวา เพื่อดูตัวอย่างผลลัพธ์ที่ได้จากโค้ดชุดนี้ได้เลยครับ