နားလည်ထားရမယ့် အချက်
Deep Learning with PyTorch သင်ခန်းစာမှာ CNN တစ်ခုကို တည်ဆောက်ပြီး train လုပ်ပြီးသားဖြစ်၍ ဤသင်ခန်းစာသည် Conv2d နှင့် MaxPool2d ကို အစအဆုံး ပြန်ရှင်းပြခြင်း မဟုတ်ဘဲ image များအတွက် ဘာကြောင့် ၎င်းတို့ကို အသုံးပြုသင့်သလဲဆိုသည်ကိုသာ ဦးတည်ပြီး recap ပြန်လုပ်ခြင်း ဖြစ်သည်။ အဓိက property မှာ weight sharing ဖြစ်သည် — filter သေးငယ်တစ်ခု (RGB input အတွက် ဆိုလျှင် 3x3x3) ကို image တစ်ခုလုံးရှိ spatial position တိုင်းတွင် ပြန်လည် အသုံးပြုသည် — fully-connected layer တစ်ခုကဲ့သို့ pixel position တစ်ခုစီအတွက် လုံးဝ သီးခြား weight တစ်ခုစီ သင်ယူသည့်နည်းမျိုး မဟုတ်ပါ။ ၎င်းသည် vision အတွက် သီးသန့် အရေးကြီးသော အကျိုးဆက်နှစ်ခုကို ပေးသည် — ပထမတစ်ခုမှာ ဈေးသက်သာစွာဖြစ်စေခြင်း — 32x32 image ပေါ်ရှိ 3x3 conv filter တစ်ခုသည် image သည် 32x32 ဖြစ်ဖြစ် 3200x3200 ဖြစ်ဖြစ် parameter count တူညီစွာ သေးငယ်နေမည် ဖြစ်ပြီး၊ dense layer တစ်ခု၏ parameter များကတော့ image size နှင့်အတူ ကျယ်ပြန့်စွာ တိုးလာမည် ဖြစ်သည်။ ဒုတိယ၊ ပိုအရေးကြီးသောအချက်မှာ network ကို translation equivariance ပေးခြင်းဖြစ်သည် — filter တစ်ခုက detect လုပ်ရန် သင်ယူထားသော pattern (edge, texture) တစ်ခုသည် weight အတူတူပင် နေရာတိုင်း slide ဝင်သောကြောင့် image ထဲ ဘယ်နေရာ ပေါ်ပေါ် detect ဖြစ်နိုင်သည် — network သည် ဘယ်ဘက်အပေါ်ထောင့်နှင့် ညာဘက်အောက်ထောင့်အတွက် 'edge' ကို သီးခြားစီ ပြန်သင်ယူစရာ မလိုပါ။
Pooling (ဤနေရာတွင် MaxPool2d) သည် equivariance အပေါ်တွင် ထိန်းချုပ်ထားသော local translation invariance ပမာဏတစ်ခု ထပ်ပေါင်းထည့်ခြင်းဖြင့် weight sharing ကို ပြည့်စုံစေသည် — window သေးငယ်တစ်ခုစီ၏ max ကို ယူခြင်းက input ကို pixel တစ်ခု နှစ်ခု ရွှေ့လိုက်ခြင်းသည် pooled output ကို မပြောင်းလဲစေတတ်ကြောင်း ဆိုလိုသည် — အကြောင်းမှာ activation အပြင်းဆုံးအတူတူပင် window အတွင်း ကျန်ရှိနေတတ်သောကြောင့် ဖြစ်သည်။ conv+pool block များကို stack လုပ်ခြင်းသည် effective receptive field ကို ဈေးသက်သာစွာ ကြီးထွားစေသည် — pooled layer တစ်ခုစီက နောက် convolution ၏ kernel သေးငယ်တစ်ခုကို original image ၏ ဧရိယာ ပိုမိုကြီးမားသော အချိုးအစားတစ်ခုကို 'မြင်' စေသည် — ထို့ကြောင့် deep stack များသည် kernel ကြီးတစ်ခုတည်း လုံးဝ မလိုအပ်ဘဲ local pattern သေးငယ်များ (edge) ရှာဖွေခြင်းမှ structure ပိုကြီးများ (ပုံသဏ္ဍာန်၊ ထို့နောက် object အစိတ်အပိုင်းများ) ရှာဖွေခြင်းဆီ တဖြည်းဖြည်း တည်ဆောက်သွားသည်။ image ကို 1D vector အဖြစ် flatten လုပ်ပြီး 2D spatial structure အားလုံးကို ပစ်ချလိုက်သော plain MLP နှင့် နှိုင်းယှဉ်ကြည့်ပါ — pixel အနီးစပ်နှစ်ခုသည် ဆက်စပ်နေသည်ဆိုသော idea လုံးဝ မရှိပါ — ထို့ကြောင့်ပင် image data ပမာဏတူညီစွာဖြင့် CNN များသည် MLP များထက် ပိုမို ကောင်းစွာ generalize လုပ်နိုင်ခြင်း ဖြစ်သည်။
လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
upload လုပ်လိုက်သော lesson image တစ်ခုစီကို သင်ခန်းစာထဲ ထည့်မတိုင်မီ 'diagram', 'code screenshot', 'photo' ဟု label တပ်ပေးသော Tutorial Platform ၏ auto-tagging feature သည် ဤကဲ့သို့ Conv2d+MaxPool2d feature extractor သေးငယ်တစ်ခုကို ပထမအဆင့်အဖြစ် အတိအကျ run လုပ်သည် — code screenshot ကို upload လုပ်ထားသော image ၏ ဘယ်ဘက်အပေါ်ထောင့်တွင်ဖြစ်စေ ညာဘက်အောက်ထောင့်တွင်ဖြစ်စေ ကပ်ထည့်ထားသည်ဖြစ်စေ 'monospace text block' detector အတူတူပင် fire ဖြစ်စေနိုင်သည်မှာ weight sharing ကြောင့်ပင် ဖြစ်ပြီး၊ ဖြစ်နိုင်ချေရှိသော position တိုင်းအတွက် detector များကို သီးခြားစီ train လုပ်ရန် မလိုအပ်ပါ။
အတူတူ စမ်းရေးကြည့်မယ်
import torch
import torch.nn as nn
torch.manual_seed(0)
# Fake batch of 4 RGB "lesson images" the model would see during
# auto-tagging: diagram vs code-screenshot vs photo classification.
images = torch.randn(4, 3, 32, 32)
feature_extractor = nn.Sequential(
nn.Conv2d(in_channels=3, out_channels=8, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2), # 32x32 -> 16x16
nn.Conv2d(in_channels=8, out_channels=16, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2), # 16x16 -> 8x8
)
features = feature_extractor(images)
print("input shape:", images.shape)
print("feature map shape:", features.shape)
# The same 3x3 conv weights are reused at every spatial position --
# count the parameters to see how cheap that is compared to a dense
# layer over the same input.
conv1_params = sum(p.numel() for p in feature_extractor[0].parameters())
print("params in first conv layer:", conv1_params)input shape: torch.Size([4, 3, 32, 32]) ကို print ထုတ်ပြီး၊ ထို့နောက် feature map shape: torch.Size([4, 16, 8, 8]) ကို ထုတ်သည် — MaxPool2d(kernel_size=2) layer နှစ်ခုစီသည် H, W ကို ထက်ဝက်စီ လျှော့ချသည် (32 → 16 → 8)၊ channel count ကတော့ Conv2d layer များအတိုင်း လိုက်သည် (3 → 8 → 16)။ နောက်ဆုံးတွင် params in first conv layer: 224 ကို print ထုတ်သည် — (output channel 8 × input channel 3 × 3 × 3 weight) + bias 8 = 216 + 8 ဟု အတိအကျ တွက်ချက်ထားခြင်း ဖြစ်သည်။၅ မိနစ် စမ်းကြည့်
feature_extractor ထဲသို့ တတိယ nn.Conv2d(16, 32, kernel_size=3, padding=1) + nn.ReLU() + nn.MaxPool2d(kernel_size=2) block ထပ်ထည့်ပါ၊ run မလုပ်မီ မျှော်လင့်ထားသော output spatial size ကို (8x8 မှ စတင်၍) လက်ဖြင့် တွက်ချက်ကြည့်ပါ၊ ထို့နောက် code ကို run ပြီး features.shape သည် သင့် prediction နှင့် ကိုက်ညီမကိုက်ညီ စစ်ဆေးပါ။
သတိလေးတစ်ချက်
input သေးငယ်တစ်ခုပေါ်တွင် MaxPool2d layer အလွန်အကျွံ stack လုပ်ခြင်းသည် feature map ကို တိတ်တဆိတ် ဘာမျှမကျန်အောင် ကျုံ့စေတတ်သည် — ဤ 32x32 input သည် 1x1 သို့ ရောက်ခြင်း (သို့) kernel သည် ကျန်ရှိနေသည့်အရာထက် ကြီးနေချိန် runtime error ဖြစ်ခြင်းမတိုင်မီ /2 downsampling နှစ်ခန့်သာ ခံနိုင်နိုင်သည်။
weight sharing သည် translation invariance နှင့်အတူ rotation (သို့) scale invariance ကိုပါ ပေးသည်ဟု ယူဆခြင်း — မပေးပါ — upright screenshot များပေါ်တွင်သာ train လုပ်ထားသော CNN တစ်ခုသည် screenshot အတူတူကိုပင် 90 degree rotate လုပ်ထားလျှင် (သို့) zoom level များစွာ ကွဲပြားပြသထားလျှင် fail ဖြစ်နိုင်ဆဲဖြစ်သည် — ထို invariance များသည် convolution တစ်ခုတည်းမှ မဟုတ်ဘဲ augmentation (transforms သင်ခန်းစာကို ကြည့်ပါ) (သို့) architecture အထူးမှသာ ရရှိနိုင်သည်။
Wikipedia — Convolutional neural network — Computer Vision