Machine Learning Academy · บทเรียน

วงรอบการฝึก: ค่าความสูญเสีย ตัวปรับปรุง และยุคการฝึก

ผู้เรียนจะเขียนวงรอบการฝึก PyTorch ได้แก่ zero_grad, forward คำนวณ CrossEntropyLoss, backward, optimizer.step และติดตามค่าความสูญเสียกับความแม่นยำตลอดแต่ละยุค

บทเรียน 4 จาก 413 ขั้นตอน

วงรอบการฝึก: ค่าความสูญเสีย ตัวปรับปรุง และยุคการฝึก เป็นบทเรียน Machine Learning Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Machine Learning Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน

สี่ขั้นตอนของลูปการฝึกทุกแบบ

ลูปการฝึกของ PyTorch มีสี่ขั้นตอนที่ต้องทำซ้ำสำหรับทุกชุดข้อมูล ได้แก่ (1) ล้างแกรเดียนต์ (2) การส่งข้อมูลไปข้างหน้า (3) การส่งข้อมูลย้อนกลับ และ (4) ขั้นตอนของตัวเพิ่มประสิทธิภาพ การข้ามหรือสลับลำดับขั้นตอนเหล่านี้จะทำให้ได้ผลลัพธ์ผิดโดยอาจไม่แสดงข้อผิดพลาดอย่างชัดเจน เช่น แกรเดียนต์สะสม พารามิเตอร์ถูกอัปเดตไม่ถูกต้อง หรือเกิดหน่วยความจำรั่ว การทำความเข้าใจรูปแบบนี้จนคุ้นเคยเป็นนิสัยที่สำคัญที่สุดสำหรับการฝึกเครือข่ายประสาทเทียมด้วย PyTorch

import torch
import torch.nn as nn
import torch.optim as optim

model = nn.Linear(2, 1)
optimizer = optim.SGD(model.parameters(), lr=0.01)
criterion = nn.MSELoss()

X = torch.randn(20, 2)
y = torch.randn(20, 1)

for step in range(1):
    optimizer.zero_grad()           # (1) zero grads
    y_pred = model(X)               # (2) forward
    loss = criterion(y_pred, y)     # (2) loss
    loss.backward()                 # (3) backward
    optimizer.step()                # (4) update
    print('Loss:', loss.item())

ฟังก์ชันการสูญเสีย: การเลือกเกณฑ์ที่เหมาะสม

ฟังก์ชันการสูญเสียใช้วัดว่าการคาดการณ์ของโมเดลคลาดเคลื่อนมากเพียงใด โมดูล nn ของ PyTorch มีฟังก์ชันประเภทนี้อยู่หลายแบบ ได้แก่ nn.MSELoss สำหรับการถดถอย (ค่าคลาดเคลื่อนกำลังสองเฉลี่ย), nn.CrossEntropyLoss สำหรับการจำแนกประเภทหลายกลุ่ม (รวมลอจิกซอฟต์แมกซ์กับ NLL) และ nn.BCEWithLogitsLoss สำหรับการจำแนกประเภทแบบทวิภาค (รวมซิกมอยด์กับครอสเอนโทรปีแบบทวิภาค) การใช้ฟังก์ชันการสูญเสียไม่ตรงกับงานเป็นข้อผิดพลาดที่ผู้เริ่มต้นมักทำ ซึ่งทำให้โมเดลไม่สามารถเรียนรู้ได้

import torch
import torch.nn as nn

# Regression
mse = nn.MSELoss()
y_pred = torch.tensor([2.5, 3.0])
y_true = torch.tensor([2.0, 3.5])
print('MSE:', mse(y_pred, y_true).item())

# Multi-class: logits (raw scores), not softmax
ce = nn.CrossEntropyLoss()
logits = torch.tensor([[2.0, 0.5, 1.0]])
labels = torch.tensor([0])
print('CE:', ce(logits, labels).item())

ตัวเพิ่มประสิทธิภาพ: SGD, Adam และ AdamW

ตัวปรับค่าการเรียนรู้ใช้เกรเดียนต์ที่คำนวณได้เพื่ออัปเดตพารามิเตอร์ของโมเดล SGD (การลดลงตามเกรเดียนต์แบบสุ่ม) เป็นตัวปรับค่าการเรียนรู้แบบดั้งเดิม การเพิ่ม momentum จะช่วยเร่งการลู่เข้า Adam จะปรับอัตราการเรียนรู้แยกตามพารามิเตอร์ โดยใช้ค่าประมาณโมเมนต์อันดับที่หนึ่งและสอง จึงมักลู่เข้าได้เร็วกว่าในทางปฏิบัติ AdamW เพิ่มการลดค่าน้ำหนักที่เหมาะสม (การทำให้เป็นระเบียบแบบ L2) และเป็นตัวเลือกเริ่มต้นสำหรับโมเดลทรานส์ฟอร์เมอร์ ตัวปรับค่าการเรียนรู้ทั้งหมดอยู่ใน torch.optim

import torch.optim as optim
import torch.nn as nn

model = nn.Linear(4, 2)

# Stochastic Gradient Descent with momentum
sgd = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# Adam: adaptive learning rate
adam = optim.Adam(model.parameters(), lr=0.001,
                  betas=(0.9, 0.999))

# AdamW: Adam + proper weight decay
adamw = optim.AdamW(model.parameters(), lr=0.001,
                    weight_decay=0.01)

วนซ้ำตามยุคและชุดข้อมูลย่อย

โดยทั่วไป การฝึกจะทำงานหลายยุค ซึ่งหมายถึงการประมวลผลชุดข้อมูลฝึกครบหนึ่งรอบ ภายในแต่ละยุค คุณจะวนซ้ำผ่านชุดข้อมูลย่อย ซึ่งเป็นส่วนย่อยของข้อมูล การใช้ DataLoader จะจัดการสับเปลี่ยนลำดับและแบ่งชุดข้อมูลโดยอัตโนมัติ การติดตามค่าการสูญเสียเฉลี่ยต่อยุคช่วยให้คุณตรวจสอบได้ว่าโมเดลกำลังลู่เข้าหรือไม่ การพิมพ์ผลทุกยุค (หรือทุก ๆ N ชุดข้อมูลย่อย) ช่วยให้เห็นความคืบหน้าของการฝึก

import torch
from torch.utils.data import TensorDataset, DataLoader
import torch.nn as nn
import torch.optim as optim

X = torch.randn(200, 4)
y = torch.randn(200, 1)
dataset = TensorDataset(X, y)
loader = DataLoader(dataset, batch_size=32, shuffle=True)

model = nn.Linear(4, 1)
optimizer = optim.Adam(model.parameters())
criterion = nn.MSELoss()

for epoch in range(3):
    total_loss = 0
    for X_batch, y_batch in loader:
        optimizer.zero_grad()
        pred = model(X_batch)
        loss = criterion(pred, y_batch)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    print(f'Epoch {epoch}: avg_loss={total_loss/len(loader):.4f}')

DataLoader: การแบ่งและสับเปลี่ยนข้อมูล

DataLoader ห่อหุ้มชุดข้อมูลและจัดเตรียมตัววนซ้ำที่ส่งคืนชุดข้อมูลย่อย พารามิเตอร์สำคัญ ได้แก่ batch_size ซึ่งกำหนดจำนวนตัวอย่างต่อการอัปเดตเกรเดียนต์ shuffle=True ซึ่งสุ่มลำดับใหม่ในแต่ละยุค (สำคัญอย่างยิ่งต่อการฝึก) และ num_workers ซึ่งเปิดใช้การโหลดข้อมูลแบบขนาน สำหรับชุดข้อมูลที่กำหนดเอง ให้สร้างคลาสย่อยจาก torch.utils.data.Dataset และใช้งาน __len__ กับ __getitem__

import torch
from torch.utils.data import Dataset, DataLoader

class MyDataset(Dataset):
    def __init__(self, X, y):
        self.X = X
        self.y = y

    def __len__(self):
        return len(self.X)

    def __getitem__(self, idx):
        return self.X[idx], self.y[idx]

X = torch.randn(100, 5)
y = torch.randint(0, 3, (100,))
dataset = MyDataset(X, y)
loader = DataLoader(dataset, batch_size=16, shuffle=True)

X_batch, y_batch = next(iter(loader))
print(X_batch.shape)   # torch.Size([16, 5])

CrossEntropyLoss: ลอจิตและดัชนีคลาส

CrossEntropyLoss ต้องการลอจิตดิบ (คะแนนที่ยังไม่ทำให้เป็นมาตรฐาน) ไม่ใช่ความน่าจะเป็นจากซอฟต์แมกซ์ ภายในจะใช้ลอ็กซอฟต์แมกซ์และคำนวณค่าความน่าจะเป็นติดลบแบบลอการิทึม ป้ายกำกับเป้าหมายควรเป็นดัชนีคลาสจำนวนเต็ม (ไม่ใช่เวกเตอร์แบบวันฮอต) นี่คือฟังก์ชันการสูญเสียที่เหมาะสมสำหรับการจำแนกหลายคลาส และมีเสถียรภาพเชิงตัวเลขมากกว่าการใช้ซอฟต์แมกซ์แล้วตามด้วย NLLLoss ด้วยตนเอง ชั้นสุดท้ายของโมเดลไม่ควรมีการทำงานของซอฟต์แมกซ์เมื่อใช้ฟังก์ชันการสูญเสียนี้

import torch
import torch.nn as nn

criterion = nn.CrossEntropyLoss()

# Batch of 4 samples, 3 classes
logits = torch.tensor([
    [2.1, 0.5, 0.3],
    [0.1, 3.0, 0.2],
    [0.8, 0.9, 2.0],
    [1.5, 0.1, 0.4]
])

# True labels as class indices (not one-hot)
labels = torch.tensor([0, 1, 2, 0])

loss = criterion(logits, labels)
print('Loss:', loss.item())

ติดตามความแม่นยำระหว่างการฝึก

การที่ค่าการสูญเสียลดลงยืนยันว่าโมเดลกำลังเรียนรู้ แต่ความแม่นยำจะบอกว่าการทำนายนั้นถูกต้องจริงหรือไม่ สำหรับการจำแนกหลายคลาส ให้แปลงลอจิตเป็นคลาสที่ทำนายด้วย torch.argmax ตามมิติของคลาส แล้วเปรียบเทียบกับป้ายกำกับจริง การติดตามทั้งค่าการสูญเสียและความแม่นยำระหว่างการฝึก รวมถึงความแม่นยำในการตรวจสอบความถูกต้องหากต้องการ จะให้ภาพรวมที่ครบถ้วนของพลวัตการเรียนรู้

import torch

def compute_accuracy(logits, labels):
    preds = torch.argmax(logits, dim=1)
    correct = (preds == labels).sum().item()
    return correct / len(labels)

logits = torch.tensor([
    [2.0, 0.1, 0.3],
    [0.1, 0.2, 3.5],
    [1.0, 0.5, 0.2]
])
labels = torch.tensor([0, 2, 0])

print('Accuracy:', compute_accuracy(logits, labels))
# 1.0 (all three correct)

วงรอบตรวจสอบความถูกต้อง: ประเมินโดยไม่อัปเดต

หลังจากแต่ละยุคของการฝึก ให้เรียกใช้วงรอบตรวจสอบความถูกต้องเพื่อประเมินประสิทธิภาพกับข้อมูลที่ไม่เคยเห็นมาก่อน ห่อการทำงานด้วย torch.no_grad() เพื่อปิดการคำนวณเกรเดียนต์ และเรียกใช้ model.eval() เพื่อปิดความไม่แน่นอนแบบสุ่มของ Dropout และ BatchNorm การเปรียบเทียบค่าการสูญเสียระหว่างการฝึกกับการตรวจสอบความถูกต้องเป็นเครื่องมือหลักในการตรวจจับการเรียนรู้เกินพอดี เมื่อค่าการสูญเสียในการตรวจสอบความถูกต้องเพิ่มขึ้น ขณะที่ค่าการสูญเสียในการฝึกยังลดลง แสดงว่าโมเดลเรียนรู้ชุดฝึกเกินพอดี

import torch

def validate(model, val_loader, criterion):
    model.eval()
    total_loss = 0
    with torch.no_grad():
        for X_batch, y_batch in val_loader:
            logits = model(X_batch)
            loss = criterion(logits, y_batch)
            total_loss += loss.item()
    model.train()   # restore training mode
    return total_loss / len(val_loader)

# Usage inside training loop:
# val_loss = validate(model, val_loader, criterion)
# print(f'Val loss: {val_loss:.4f}')

การจัดตารางอัตราการเรียนรู้

อัตราการเรียนรู้คงที่มักทำให้การลู่เข้าช้าหรือเกิดการแกว่งใกล้ค่าต่ำสุด ตัวจัดตารางอัตราการเรียนรู้จะปรับ LR โดยอัตโนมัติระหว่างการฝึก StepLR ลด LR ด้วยตัวคูณทุก ๆ N ยุค CosineAnnealingLR ลดค่าลงอย่างราบรื่นจนเกือบเป็นศูนย์ตามเส้นโคไซน์ และ ReduceLROnPlateau ลด LR เมื่อค่าการสูญเสียในการตรวจสอบความถูกต้องหยุดปรับปรุง โดยทั่วไปจะเรียกใช้ตัวจัดตารางหลังตัวปรับค่าการเรียนรู้ โดยมักเรียกหนึ่งครั้งต่อยุค

import torch.optim as optim
import torch.nn as nn

model = nn.Linear(4, 2)
optimizer = optim.Adam(model.parameters(), lr=0.01)

# Decay LR by 0.5 every 2 epochs
scheduler = optim.lr_scheduler.StepLR(
    optimizer, step_size=2, gamma=0.5
)

for epoch in range(6):
    # ... training code ...
    scheduler.step()
    print(f'Epoch {epoch}: LR={scheduler.get_last_lr()[0]}')
# LR: 0.01, 0.01, 0.005, 0.005, 0.0025, 0.0025

บันทึกจุดตรวจสอบระหว่างการฝึก

การฝึกอาจใช้เวลาหลายชั่วโมงหรือหลายวัน การบันทึกจุดตรวจสอบเป็นระยะช่วยป้องกันการสูญเสียความคืบหน้าเมื่อโปรแกรมขัดข้อง และทำให้กลับมาทำต่อจากจุดที่ดีที่สุดได้ จุดตรวจสอบที่ดีจะเก็บพจนานุกรมสถานะของโมเดล พจนานุกรมสถานะของตัวปรับค่าการเรียนรู้ (ซึ่งมีพจน์โมเมนตัม) หมายเลขยุค และเมตริกการตรวจสอบความถูกต้องที่ดีที่สุด การกู้คืนสถานะของตัวปรับค่าการเรียนรู้ทำให้การฝึกดำเนินต่อจากจุดเดิมได้อย่างแม่นยำ รวมถึงบัฟเฟอร์โมเมนตัมที่ส่งผลต่อการอัปเดตครั้งถัดไป

import torch

def save_checkpoint(model, optimizer, epoch, loss, path):
    torch.save({
        'epoch': epoch,
        'model_state_dict': model.state_dict(),
        'optimizer_state_dict': optimizer.state_dict(),
        'loss': loss
    }, path)

def load_checkpoint(model, optimizer, path):
    ckpt = torch.load(path)
    model.load_state_dict(ckpt['model_state_dict'])
    optimizer.load_state_dict(ckpt['optimizer_state_dict'])
    return ckpt['epoch'], ckpt['loss']

วงรอบการฝึกฉบับสมบูรณ์: นำทุกส่วนมาประกอบกัน

วงรอบการฝึกที่มีคุณภาพระดับใช้งานจริงจะรวมทุกส่วนเข้าด้วยกัน ได้แก่ DataLoader สำหรับแบ่งชุดข้อมูล การอัปเดตสี่ขั้นตอนต่อชุดข้อมูลย่อย การตรวจสอบความถูกต้องในแต่ละยุค การจัดตารางอัตราการเรียนรู้ การติดตามค่าการสูญเสียและความแม่นยำ และการบันทึกจุดตรวจสอบ โค้ดด้านล่างแสดงรูปแบบทั้งหมดด้วยโมเดลจำแนกอย่างง่าย การปรับแม่แบบนี้ให้ใช้กับปัญหาการเรียนรู้แบบมีผู้สอนใด ๆ ต้องเปลี่ยนเพียงโมเดล ชุดข้อมูล และฟังก์ชันการสูญเสีย

import torch, torch.nn as nn, torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader

X_tr = torch.randn(160, 4); y_tr = torch.randint(0, 3, (160,))
X_val = torch.randn(40, 4); y_val = torch.randint(0, 3, (40,))
tr_loader = DataLoader(TensorDataset(X_tr, y_tr), 32, shuffle=True)
val_loader = DataLoader(TensorDataset(X_val, y_val), 32)

model = nn.Sequential(nn.Linear(4, 16), nn.ReLU(), nn.Linear(16, 3))
optimizer = optim.Adam(model.parameters())
criterion = nn.CrossEntropyLoss()

for epoch in range(5):
    model.train()
    for Xb, yb in tr_loader:
        optimizer.zero_grad()
        loss = criterion(model(Xb), yb)
        loss.backward(); optimizer.step()
    model.eval()
    with torch.no_grad():
        val_loss = sum(criterion(model(Xb), yb).item()
                       for Xb, yb in val_loader) / len(val_loader)
    print(f'Epoch {epoch}: val_loss={val_loss:.3f}')

ตรวจสอบความเข้าใจ

ทดสอบความเข้าใจแนวคิดการเรียนรู้ของเครื่องด้วย Python จากบทเรียนนี้

สรุปบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า วงรอบการฝึกสี่ขั้นตอน (zero_grad, forward, backward, step) เป็นพื้นฐานของการฝึกด้วย PyTorch ทุกแบบ DataLoader จัดการการแบ่งและสับเปลี่ยนข้อมูลโดยอัตโนมัติ และ CrossEntropyLoss ที่ใช้กับลอจิตเป็นตัวเลือกมาตรฐานสำหรับการจำแนก ลำดับถัดไป เราจะสำรวจการจัดตารางอัตราการเรียนรู้และผลกระทบของอัตราการเรียนรู้ต่อพลวัตการฝึก

เริ่มต้นได้ฟรี

เรียนรู้ Python ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
30
บทเรียน
120

คำถามที่พบบ่อย

บทเรียน “วงรอบการฝึก: ค่าความสูญเสีย ตัวปรับปรุง และยุคการฝึก” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “วงรอบการฝึก: ค่าความสูญเสีย ตัวปรับปรุง และยุคการฝึก” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Machine Learning Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Machine Learning Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “วงรอบการฝึก: ค่าความสูญเสีย ตัวปรับปรุง และยุคการฝึก”

ผู้เรียนจะเขียนวงรอบการฝึก PyTorch ได้แก่ zero_grad, forward คำนวณ CrossEntropyLoss, backward, optimizer.step และติดตามค่าความสูญเสียกับความแม่นยำตลอดแต่ละยุค คุณปฏิบัติ Machine Learning Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Machine Learning Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Machine Learning Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “วงรอบการฝึก: ค่าความสูญเสีย ตัวปรับปรุง และยุคการฝึก” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Machine Learning Academy นี้ได้ไหม

ได้ บทเรียน Machine Learning Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เทนเซอร์ PyTorch: การสร้าง การดำเนินการ และการถ่ายโอนไปยัง GPU
  2. Autograd: การหาอนุพันธ์อัตโนมัติสำหรับการแพร่ย้อนกลับ
  3. การสร้างเครือข่ายแบบป้อนไปข้างหน้าด้วย nn.Module
  4. วงรอบการฝึก: ค่าความสูญเสีย ตัวปรับปรุง และยุคการฝึก
← กลับไปที่ Machine Learning Academy