Thuta Learning
Computer Vision
ExercisesAIintermediate

Exercise: Vision Training Pipeline ကို Debug လုပ်ခြင်း

ဒီခန်းပြီးရင် ဘာတတ်သွားမလဲ

  • Exercise: Vision Training Pipeline ကို Debug လုပ်ခြင်း concept ကို နားလည်ရှင်းပြနိုင်ရန်
  • နမူနာ code ကို ကိုယ်တိုင် run ပြီး output စစ်နိုင်ရန်
  • Tutorial Platform project နှင့် production scenario တွင် မှန်ကန်စွာအသုံးချနိုင်ရန်

နားလည်ထားရမယ့် အချက်

Vision pipeline တစ်ခုမှာ bug တွေက tensor shape error လို ချက်ချင်း crash ဖြစ်တဲ့ အမျိုးအစားနဲ့၊ code က run ပြီး loss ကျသလိုလိုနဲ့ model က တကယ်တော့ ဘာမှ မကောင်းတဲ့ silent failure နှစ်မျိုးရှိတယ်။ Shape mismatch (Conv output feature map ကို Linear layer ရဲ့ expected input size နဲ့ မကိုက်ညီတဲ့ Flatten) ဟာ ပထမအမျိုးအစားဖြစ်ပြီး၊ error message ကိုယ်တိုင်က ရှာဖွေဖို့ လမ်းညွှန်ပေးတယ်။ ဒါပေမဲ့ model.train()/model.eval() mode mix up, validation data ပေါ်မှာ augmentation ကို မှားထည့်ခြင်း၊ ImageNet normalization statistics ကို မှားရိုက်ခြင်းစတာတွေက error တစ်ခုမှ မထုတ်ဘဲ training curve ကို subtle ဖြစ်စေတယ် — accuracy က ရနိုင်ပေမယ့် expected ထက် နိမ့်နေတာ၊ ဒါမှမဟုတ် validation metric တွေက အနည်းငယ် misleading ဖြစ်နေတာမျိုး ဖြစ်တတ်တယ်။

လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်

Tutorial Platform ရဲ့ 'Code Review Mode' feature ကို သုံးပြီး ဒီ script ကို line-by-line annotate လုပ်နိုင်တယ် — bug တွေ့တဲ့နေရာမှာ comment tag ချိတ်ပြီး 'why this breaks' explanation ရေးထားတဲ့ note attach လုပ်လို့ရတယ်၊ ပြီးရင် platform ရဲ့ reference solution note နဲ့ side-by-side compare ပြပေးတယ်။

အတူတူ စမ်းရေးကြည့်မယ်

python
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision.transforms import v2
from torch.utils.data import Dataset, DataLoader

torch.manual_seed(0)

# --- Preprocessing: "ImageNet normalization" ---
train_transform = v2.Compose([
    v2.RandomHorizontalFlip(),
    v2.RandomCrop(224, padding=4),
    v2.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),
])

val_transform = v2.Compose([
    v2.RandomHorizontalFlip(),
    v2.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),
])

class SyntheticImageDataset(Dataset):
    # Stands in for a real folder of labeled photos (e.g. torchvision's
    # ImageFolder) so this script is fully self-contained and runnable.
    def __init__(self, num_samples, num_classes, transform):
        self.num_samples = num_samples
        self.num_classes = num_classes
        self.transform = transform

    def __len__(self):
        return self.num_samples

    def __getitem__(self, idx):
        image = torch.rand(3, 224, 224)  # fake RGB photo
        label = torch.randint(0, self.num_classes, (1,)).item()
        return self.transform(image), label

train_set = SyntheticImageDataset(num_samples=64, num_classes=10, transform=train_transform)
val_set = SyntheticImageDataset(num_samples=32, num_classes=10, transform=val_transform)

train_loader = DataLoader(train_set, batch_size=32, shuffle=True)
val_loader = DataLoader(val_set, batch_size=32, shuffle=False)

class SimpleCNN(nn.Module):
    def __init__(self, num_classes=10):
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 16, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(16, 32, kernel_size=3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
        )
        # 224x224 input -> two 2x2 pools -> 56x56 feature map, 32 channels
        self.classifier = nn.Sequential(
            nn.Flatten(),
            nn.Linear(32 * 28 * 28, 128),
            nn.ReLU(),
            nn.Linear(128, num_classes),
        )

    def forward(self, x):
        x = self.features(x)
        x = self.classifier(x)
        return x

model = SimpleCNN(num_classes=train_set.num_classes)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-3)

def train_one_epoch():
    for images, labels in train_loader:
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

def evaluate():
    model.eval()
    correct, total = 0, 0
    with torch.no_grad():
        for images, labels in val_loader:
            outputs = model(images)
            preds = outputs.argmax(dim=1)
            correct += (preds == labels).sum().item()
            total += labels.size(0)
    return correct / total

for epoch in range(5):
    train_one_epoch()
    acc = evaluate()
    print(f"Epoch {epoch+1}: val accuracy = {acc:.4f}")
You should see
Script ကို run လိုက်ရင် ပထမဆုံး crash ဖြစ်မှာက Linear layer size bug ကြောင့်ဖြစ်တယ် — `nn.Linear(32 * 28 * 28, ...)` ကို 224x224 input အတွက် ရေးထားပေမယ့် two 2x2 MaxPool တွေဆီက output က 56x56 (28x28 မဟုတ်ဘူး) ဖြစ်နေလို့ `RuntimeError: mat1 and mat2 shapes cannot be multiplied` ဆိုတဲ့ error ထွက်လာမယ်။ ဒါကို ပြင်လိုက်ရင်တောင်, `optimizer.zero_grad()` ကို train_one_epoch() ထဲက ချန်ထားလို့ gradient တွေက batch တစ်ခုစီအလိုက် ပေါင်းစုနေမှာဖြစ်ပြီး loss က မမှန်ကန်တဲ့နည်းနဲ့ ကျသွားလိမ့်မယ် (accuracy တက်ပေမယ့် သိပ်ကောင်းမလာဘူး)။ ထပ်ပြီး val_transform ထဲမှာ RandomHorizontalFlip ပါနေလို့ validation accuracy တစ်ခေါက်ချင်းစီမှာ flip random ကြောင့် ခပ်လှုပ်လှုပ် ပြောင်းနေမယ်။

၅ မိနစ် စမ်းကြည့်

Code ကို run မလုပ်မီ ဖတ်ပြီး bug သုံးခုကို ရှာပါ — တစ်ခုစီအတွက် ဘယ်နေရာမှာလဲ၊ ဘာကြောင့် ပြဿနာဖြစ်လဲ၊ ဒါက error တစ်ခုချက်ချင်းထုတ်လား ဒါမှမဟုတ် training result ကို silent ဖျက်ဆီးနေလားဆိုတာ ရေးပြီး ရှင်းပြပါ။

သတိလေးတစ်ချက်

Shape error ကိုပဲ ရှာတွေ့ပြီး fix လုပ်ပြီး ရပ်တန့်သွားတတ်တယ် — အခြား silent bug နှစ်ခုကို လျစ်လျူရှုမိတယ်။

zero_grad() ပျောက်နေတာကို 'style issue' လို့ထင်ပြီး လျစ်လျူရှုတတ်တယ်၊ ဒါပေမဲ့ training dynamics ကို တကယ်ပျက်စီးစေတယ်။

PyTorch Tutorials — Training a Classifier (CIFAR10)Computer Vision

ဒီနေရာမှာ လူအများမှားတတ်တယ်

  • Shape error ကိုပဲ ရှာတွေ့ပြီး fix လုပ်ပြီး ရပ်တန့်သွားတတ်တယ် — အခြား silent bug နှစ်ခုကို လျစ်လျူရှုမိတယ်။
  • zero_grad() ပျောက်နေတာကို 'style issue' လို့ထင်ပြီး လျစ်လျူရှုတတ်တယ်၊ ဒါပေမဲ့ training dynamics ကို တကယ်ပျက်စီးစေတယ်။
  • နမူနာ code ကို production system ပေါ် တိုက်ရိုက်မစမ်းဘဲ local/test environment တွင် အရင်အတည်ပြုပါ။

လေ့ကျင့်ခန်း

Code ကို run မလုပ်မီ ဖတ်ပြီး bug သုံးခုကို ရှာပါ — တစ်ခုစီအတွက် ဘယ်နေရာမှာလဲ၊ ဘာကြောင့် ပြဿနာဖြစ်လဲ၊ ဒါက error တစ်ခုချက်ချင်းထုတ်လား ဒါမှမဟုတ် training result ကို silent ဖျက်ဆီးနေလားဆိုတာ ရေးပြီး ရှင်းပြပါ။

You'll know it worked when: Script ကို run လိုက်ရင် ပထမဆုံး crash ဖြစ်မှာက Linear layer size bug ကြောင့်ဖြစ်တယ် — `nn.Linear(32 * 28 * 28, ...)` ကို 224x224 input အတွက် ရေးထားပေမယ့် two 2x2 MaxPool တွေဆီက output က 56x56 (28x28 မဟုတ်ဘူး) ဖြစ်နေလို့ `RuntimeError: mat1 and mat2 shapes cannot be multiplied` ဆိုတဲ့ error ထွက်လာမယ်။ ဒါကို ပြင်လိုက်ရင်တောင်, `optimizer.zero_grad()` ကို train_one_epoch() ထဲက ချန်ထားလို့ gradient တွေက batch တစ်ခုစီအလိုက် ပေါင်းစုနေမှာဖြစ်ပြီး loss က မမှန်ကန်တဲ့နည်းနဲ့ ကျသွားလိမ့်မယ် (accuracy တက်ပေမယ့် သိပ်ကောင်းမလာဘူး)။ ထပ်ပြီး val_transform ထဲမှာ RandomHorizontalFlip ပါနေလို့ validation accuracy တစ်ခေါက်ချင်းစီမှာ flip random ကြောင့် ခပ်လှုပ်လှုပ် ပြောင်းနေမယ်။

Exercise: Vision Training Pipeline ကို Debug လုပ်ခြင်း | Thuta Learning