နားလည်ထားရမယ့် အချက်
အလုပ်လုပ်တဲ့ image classifier တစ်ခုဆိုတာ လှည့်ကွက်တစ်ခုတည်းနဲ့ မရဘူး — အဆင့်တိုင်းက ရှေ့အဆင့်ရဲ့ output ပုံစံ (shape) ကို မှန်ကန်စွာ လက်ခံနိုင်ဖို့ မှီခိုနေတဲ့ pipeline တစ်ခုလုံးပါ။ ဒီ project က အကုန်လုံးကို ဆက်စပ်ပေးထားတယ် — label ပါတဲ့ synthetic image တွေကို ထုတ်ပေးတဲ့ Dataset class (အပေါ်ပိုင်းလင်း အောက်ပိုင်းမှောင် pattern တွေနဲ့ class ခွဲခြားထားတာ real class ကွာခြားချက်တွေရဲ့ ကိုယ်စား), batch လုပ်ပြီး shuffle လုပ်ပေးတဲ့ DataLoader, spatial size ကို တဖြည်းဖြည်းလျှော့ပြီး channel depth ကို တိုးပေးတဲ့ Conv2d+ReLU+MaxPool block နှစ်ခုပါတဲ့ CNN သေးလေး၊ ပြီးတော့ နောက်ဆုံး feature map ကို class score တွေအဖြစ် ပြောင်းပေးတဲ့ Linear head တစ်ခု။ Training loop က CrossEntropyLoss နဲ့ Adam သုံးပြီး ဒါတွေအပေါ် loop လှည့်ပြီး၊ evaluation ကတော့ gradient ပိတ်ထားတဲ့ held-out data အပေါ် forward pass အတူတူ run တာပါပဲ။ Naive အနေနဲ့ pixel တွေကို တန်းပြီး Linear layer stack ထဲ ထည့်တာက image ကို image ဖြစ်စေတဲ့ 2D spatial structure ကို စွန့်ပစ်လိုက်တာပါ — CNN ရဲ့ convolution တွေက frame ထဲမှာ ဘယ်နေရာရောက်ရောက် local pattern (edge, blob) တွေကို ရှာတွေ့နိုင်တယ်၊ pooling ကလည်း pattern နည်းနည်းရွှေ့သွားလည်း အဲဒီ recognition ကို ဆက်ထိန်းပေးထားနိုင်တယ်။ synthetic generator ကို CIFAR-10 ဒါမှမဟုတ် ImageNet loading နဲ့ အစားထိုးလိုက်ရုံနဲ့ pipeline ထဲက ဘာမှ ပြောင်းစရာမလိုဘူး — ဒါက ဒီလိုတည်ဆောက်ခြင်းရဲ့ အဓိကအချက်ပါပဲ။
လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
ဒီ pipeline အတိုင်းအတာအတိုင်းပဲ Tutorial Platform ရဲ့ 'lesson thumbnail အကြံပြုချက်' ဒါမှမဟုတ် 'diagram အမျိုးအစား auto-tag' feature တစ်ခုကို ပံ့ပိုးပေးနိုင်ပါတယ် — lesson content ထဲက screenshot တွေ ဒါမှမဟုတ် diagram image တွေကို CNN တစ်ခုကနေဖြတ်ပြီး ('code screenshot' vs 'architecture diagram' vs 'chart' စသည်) auto-tag လုပ်ပေးနိုင်တယ်၊ search filter အတွက်လည်း အသုံးဝင်တယ်။ ဒီမှာရှိတဲ့ Dataset/DataLoader/train/evaluate ဖွဲ့စည်းပုံက real feature တစ်ခုမှာ သုံးမယ့်အတိုင်းအတာနဲ့ တူတူပါပဲ — image source ကို synthetic tensor ကနေ upload လုပ်ထားတဲ့ lesson image တွေနဲ့ အစားထိုးရုံ၊ class တွေကို toy pattern နှစ်ခုကနေ platform အလိုရှိတဲ့ content category အစစ်တွေနဲ့ အစားထိုးရုံပါပဲ။
အတူတူ စမ်းရေးကြည့်မယ်
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
class SyntheticImageDataset(Dataset):
def __init__(self, n_samples=200, size=16):
self.data, self.labels = [], []
for i in range(n_samples):
label = i % 2
img = torch.rand(1, size, size) * 0.3
if label == 1:
img[:, :size // 2, :] += 0.6
else:
img[:, size // 2:, :] += 0.6
self.data.append(img)
self.labels.append(label)
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
return self.data[idx], self.labels[idx]
class SmallCNN(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(1, 8, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(8, 16, kernel_size=3, padding=1)
self.pool = nn.MaxPool2d(2, 2)
self.fc = nn.Linear(16 * 4 * 4, 2)
def forward(self, x):
x = self.pool(torch.relu(self.conv1(x))) # 16 -> 8
x = self.pool(torch.relu(self.conv2(x))) # 8 -> 4
x = x.view(x.size(0), -1)
return self.fc(x)
train_loader = DataLoader(SyntheticImageDataset(200), batch_size=16, shuffle=True)
test_loader = DataLoader(SyntheticImageDataset(40), batch_size=16)
model = SmallCNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)
for epoch in range(5):
total_loss = 0.0
for images, labels in train_loader:
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f"Epoch {epoch+1}, Loss: {total_loss / len(train_loader):.4f}")
model.eval()
correct, total = 0, 0
with torch.no_grad():
for images, labels in test_loader:
preds = model(images).argmax(dim=1)
correct += (preds == labels).sum().item()
total += labels.size(0)
print(f"Test accuracy: {correct/total:.2%}")Epoch တစ်ခုစီအတွက် Loss တန်ဖိုးက 5 epoch အတွင်း တဖြည်းဖြည်းကျသွားပြီး၊ နောက်ဆုံးမှာ held-out test set အပေါ် Test accuracy ရာခိုင်နှုန်းတစ်ခု (ဥပမာ 90%+) print ထုတ်ပြပါလိမ့်မယ်။၅ မိနစ် စမ်းကြည့်
SmallCNN ကို conv1 output channel 8 ကနေ 32 လိုပြင်ပြီး၊ epoch အရေအတွက်ကို 10 အထိ တိုးကြည့်ပါ — accuracy ဘယ်လိုပြောင်းလဲသွားလဲ။ ပြီးရင် bright pattern ကို ဘယ်ဘက်/ညာဘက် ခွဲထားတဲ့ ပုံစံသစ်တစ်ခု (top/bottom အစား left/right) ဖန်တီးပြီး model က အလွယ်တကူ သင်ယူနိုင်လားစမ်းကြည့်ပါ။
သတိလေးတစ်ချက်
Evaluation အချိန် model.eval() (နဲ့ torch.no_grad()) ကို မမေ့ရဘူး — မထားရင် dropout/batchnorm က training mode အတိုင်း ဆက်လုပ်နေမှာဖြစ်ပြီး၊ ဘယ်တော့မှမသုံးမည့် gradient တွေကိုပါ memory ထဲ ခြေရာခံနေမှာပါ။
conv/pool layer တွေပြီးနောက် ပထမဆုံး Linear layer ထဲ ထည့်မယ့် flattened feature size ကို မှားတွက်တာ — pooling ပြီးနောက် spatial dimension ဘယ်လောက်ကျန်တယ်ဆိုတာ မှားရေတွက်တာက CNN shape-mismatch bug တွေထဲမှာ အများဆုံးတွေ့ရတဲ့ error တစ်ခုပါ။
PyTorch Examples — MNIST — Deep Learning