နားလည်ထားရမယ့် အချက်
Image တစ်ခုကို filter လုပ်ခြင်းဆိုသည်မှာ kernel ကိန်းသေးငယ်တစ်ခုကို image ပေါ်တွင် slide လုပ်ပြီး position တစ်ခုစီတွင် အောက်ရှိ pixel များ၏ weighted sum ကို တွက်ချက်ခြင်းသာ ဖြစ်ပြီး — ၎င်းသည် သင်အသိရှိပြီးသား convolution ဟုခေါ်သော sliding-window operation အတိအကျပင် ဖြစ်သည်။ filter တစ်ခုနှင့်တစ်ခု ကွာခြားသည့်အချက်မှာ kernel ၏ weight များသာ ဖြစ်သည် — positive value သေးငယ်ညီညီများသော kernel တစ်ခုသည် blur အဖြစ် လုပ်ဆောင်ပေးသည် (neighborhood တစ်ခု၏ average ကို ယူခြင်း)၊ တစ်ဖက်တွင် negative weight ရှိပြီး တစ်ဖက်တွင် positive weight ရှိသော Sobel kernel ကဲ့သို့ kernel တစ်ခုကတော့ ထိုဦးတည်ချက်တွင် intensity သွက်လက်စွာ ပြောင်းလဲသည့်နေရာ — edge — တွင်သာ output ကြီးမားစွာ ထုတ်ပေးသည်။ Sobel kernel များသည် horizontal နှင့် vertical အတွဲအဖြစ် ရှိကြပြီး၊ image တစ်ခုတည်းအပေါ် နှစ်ခုစလုံးကို apply လုပ်ပြီး ရလဒ်များကို ပေါင်းစပ်ခြင်း (square-root-of-sum-of-squares ဖြင့် ပုံမှန်) သည် ဦးတည်ချက် မည်သည့်ဘက်ရှိ edge ပြင်းထန်ရာတွင်မဆို light up ဖြစ်စေသော gradient-magnitude map တစ်ခု ပေးသည်။
ဤသင်ခန်းစာအတွက် အဓိက အသိအမြင်မှာ ၎င်းသည် CNN ၏ Conv2d layer လုပ်ဆောင်သည့်အရာနှင့် operation ကွဲပြားခြင်း မဟုတ်ပါ — F.conv2d သည် Conv2d module တစ်ခုက internal အနေနှင့် ခေါ်ယူသုံးသော function အတိအကျပင် ဖြစ်သည်။ လက်ဖြင့်ဒီဇိုင်းဆွဲထားသော Sobel filter တစ်ခုနှင့် training စတင်ချိန်ရှိ ကျပန်း initialize လုပ်ထားသော Conv2d layer တစ်ခုကြား ခြားနားချက်တစ်ခုတည်းမှာ weight များ ဘယ်ကလာသလဲဆိုတာသာ ဖြစ်သည် — တစ်ခုကို edge geometry နားလည်သူတစ်ဦးက ရွေးချယ်ခဲ့ပြီး၊ အခြားတစ်ခုကတော့ ကျပန်းမှ စတင်ကာ loss တစ်ခုကို လျှော့ချရန် gradient descent မှ ပုံသွင်းပေးခြင်း ဖြစ်သည်။ တကယ်တော့ trained image classifier တစ်ခု၏ ပထမဆုံး convolutional layer အမှန်တကယ် ဘာကို သင်ယူခဲ့သလဲဟု researcher များ visualize လုပ်ကြည့်သောအခါ လက်ဖြင့်ဒီဇိုင်းဆွဲထားသော Sobel/Gabor-like edge, blob detector များနှင့် အံ့သြစရာကောင်းလောက်အောင် ဆင်တူနေသည်ကို မကြာခဏ တွေ့ရသည် — network သည် classical computer vision engineer များ လက်ဖြင့် တွေ့ရှိခဲ့သော primitive အသုံးဝင်များအတူတူပင်ကို data မှသာ ပြန်တွေ့ရှိပြန်ခြင်း ဖြစ်သည်၊ insight မဟုတ်ဘဲ။
လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Tutorial Platform ၏ exercise walkthrough screenshot uploader သည် image တစ်ခုကို လက်ခံမီ ဈေးသက်သာသော blur check တစ်ခု run လုပ်သည် — upload လုပ်လိုက်သော screenshot ကို (ဒီသင်ခန်းစာ code အတိုင်းပင်) Sobel-style filter ဖြင့် apply လုပ်ပြီး average gradient magnitude ကို ကြည့်သည် — ရှင်းလင်းသော၊ focus ကျသော code screenshot တစ်ခုတွင် စာသား edge ထက်ထက်များစွာ ရှိသဖြင့် score မြင့်ပြီး၊ မတော်တဆ မှုန်ဝါးသွားသော (သို့) heavily compress ဖြစ်သွားသော upload တစ်ခုတွင် edge များ မှေးမှိန်နေသဖြင့် score နိမ့်ကာ image သည် သင်ခန်းစာနှင့် တွဲမတိုင်မီ 'ဒါမှုန်ဝါးနေပုံပေါ်တယ်၊ ပြန် upload ချင်ပါသလား' ဆိုသော သတိပေးချက် ပေါ်လာစေသည်။
အတူတူ စမ်းရေးကြည့်မယ်
import torch
import torch.nn.functional as F
torch.manual_seed(0)
# A synthetic single-channel "image" -- think of it as a grayscale
# screenshot, batch of 1, 1 channel, 16x16 pixels.
image = torch.rand(1, 1, 16, 16)
# Sobel kernels: hand-designed weights that respond strongly to
# vertical and horizontal intensity changes (edges).
sobel_x = torch.tensor([[-1., 0., 1.],
[-2., 0., 2.],
[-1., 0., 1.]]).view(1, 1, 3, 3)
sobel_y = torch.tensor([[-1., -2., -1.],
[ 0., 0., 0.],
[ 1., 2., 1.]]).view(1, 1, 3, 3)
# torch.nn.functional.conv2d is the exact same op a Conv2d layer
# uses internally -- we're just supplying the weights ourselves
# instead of letting backprop learn them.
edges_x = F.conv2d(image, sobel_x, padding=1)
edges_y = F.conv2d(image, sobel_y, padding=1)
print("edges_x shape:", edges_x.shape)
print("edges_y shape:", edges_y.shape)
# Combine both directions into a single gradient-magnitude map.
magnitude = torch.sqrt(edges_x ** 2 + edges_y ** 2)
print("gradient magnitude shape:", magnitude.shape)
print("mean edge strength is positive:", (magnitude.mean() > 0).item())ဤသို့ print ထုတ်သည်: edges_x shape: torch.Size([1, 1, 16, 16])၊ edges_y shape: torch.Size([1, 1, 16, 16]) (padding=1 ကြောင့် spatial size မပြောင်းလဲပါ)၊ gradient magnitude shape: torch.Size([1, 1, 16, 16])၊ နောက်ဆုံးတွင် mean edge strength is positive: True — magnitude သည် squared value များ၏ square root မှ တည်ဆောက်ထားသောကြောင့် negative ဘယ်တော့မှ မဖြစ်နိုင်၍ mean သည် positive ဖြစ်ရန် အာမခံသလိုပင်ဖြစ်ပြီး၊ ကျပန်းနှင့် constant မဟုတ်သော input အတွက် သုညထက် တိကျစွာ ကြီးနေမည် ဖြစ်သည်။၅ မိနစ် စမ်းကြည့်
sobel_x ကို nn.Conv2d(1, 1, kernel_size=3, padding=1, bias=False) layer တစ်ခု၏ weight အဖြစ် wrap လုပ်ပါ (.weight = nn.Parameter(sobel_x) ဖြင့် assign လုပ်ပါ)၊ .weight.requires_grad သည် default အားဖြင့် True ဖြစ်ကြောင်း စစ်ဆေးပါ၊ ဤ layer ကို loss အစစ်တစ်ခုနှင့် train နေသော model တစ်ခုအတွင်း ထားလိုက်ပါက weight များကို ဘာဖြစ်လာနိုင်သလဲ ဆိုတာကို comment တစ်ခုတွင် ရှင်းပြပါ — Sobel structure ကျန်ရှိနေဦးမလား။
သတိလေးတစ်ချက်
3x3 kernel တစ်ခုတွင် padding=1 ထည့်ရန် မေ့လျော့ခြင်း — output spatial size ကို ကျုံ့စေသည် (input 16x16 သည် output 14x14 ဖြစ်သွားသည်) — ရလာသော edge map သည် original image နှင့် overlay တင်ကြည့်လျှင် pixel-for-pixel ကိုက်ညီတော့မည် မဟုတ်ပါ။
PyTorch ၏ F.conv2d သည် true mathematical convolution (kernel ကို flip လုပ်သော) ဟု ယူဆခြင်း — PyTorch က cross-correlation (flip မလုပ်) ကို အမှန်တကယ် implement လုပ်ထားသည် — learned layer တစ်ခုအတွက် ဂရုမစိုက်ရသော်လည်း (network က weight ကို ဘယ်လိုပဲဖြစ်ဖြစ် ချိန်ညှိပေးမည်ဖြစ်၍) textbook (သို့) library တစ်ခုမှ true convolution ဖြင့် သတ်မှတ်ထားသော classical filter တစ်ခုကို port လုပ်နေလျှင်တော့ ကိုက်ညီစေရန် kernel ကို လက်ဖြင့် flip လုပ်ပေးရန် လိုအပ်သည်။
Wikipedia — Edge detection — Computer Vision