နားလည်ထားရမယ့် အချက်
Deep network တစ်ခု train လုပ်နေတဲ့အခါ early layer တွေရဲ့ parameter တွေက update တိုင်း ပြောင်းလဲနေတယ်၊ ဒါက later layer တွေထဲ ဝင်လာတဲ့ activation တွေရဲ့ distribution ကို ဆက်တိုက် ပြောင်းလဲစေတယ် — ဒါကို internal covariate shift လို့ခေါ်တယ်။ Later layer တွေက stable mapping တစ်ခု သင်ယူမယ့်အစား ရွေ့လျားနေတဲ့ target ကို အမြဲ ပြန်လိုက်ညှိနေရလို့ convergence နှေးသွားပြီး learning rate မြင့်တဲ့အခါ training ကို မတည်ငြိမ်စေနိုင်တယ်။ Batch normalization က ဒီပြဿနာကို တိုက်ရိုက် ဖြေရှင်းတယ် — feature တစ်ခုစီအတွက် current batch ပေါ်က mean ကို နှုတ်၊ standard deviation နဲ့ စား၊ ပြီးမှ layer ကို ဘယ် distribution မဆို ကိုယ်စားပြုနိုင်ဖို့ learnable scale/shift ကို apply ပြန်လုပ်ပေးတယ်။ ပြဿနာကတော့ batch normalization ရဲ့ statistics တွေက batch composition အပေါ် မူတည်နေတယ် — batch size သေးသေးလေးဆိုရင် (သို့) sequence model တွေမှာ batch entry တွေရဲ့ length မတူညီပြီး padding ရှိတဲ့အခါ statistics တွေက noisy ဖြစ်သွားနိုင်တယ်။ Layer normalization ကတော့ batch dimension အစား sample တစ်ခုတည်းရဲ့ feature တွေအပေါ်ပဲ normalize လုပ်လို့ ဒီပြဿနာကို ရှောင်နိုင်တယ် — ဒါကြောင့် statistics တွေက batch size (သို့) batch ထဲ ဘယ် example တွေ ပါနေလဲဆိုတာအပေါ် မူတည်တော့ဘူး၊ ဒါကြောင့် transformer တွေမှာ default choice ဖြစ်နေတာပဲ။
လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Tutorial Platform ရဲ့ sentiment classifier က review text ကို batch အလိုက် process လုပ်တယ်၊ ဒါပေမယ့် real traffic မှာတော့ batch size က တအားကွာနိုင်တယ် — quiet hour တစ်ခုမှာ request တစ်ခုတည်း၊ launch တစ်ခုမှာတော့ ရာနဲ့ချီ။ Batch normalization layer တွေက ဘယ် batch ရောက်လာလာ ဒါကနေ mean/std ကို တွက်မှာဖြစ်လို့ review တစ်ခုတည်းပါတဲ့ batch က review 200 ပါတဲ့ batch နဲ့ ယှဉ်ရင် statistics မယုံကြည်ရနိုင်ဘူး၊ prediction တွေကလည်း မတည်ငြိမ်ဖြစ်နိုင်တယ်။ Classifier က transformer-based ဖြစ်နေတဲ့အတွက် layer normalization က ပိုကိုက်ညီတယ် — review တစ်ခုစီရဲ့ token feature တွေကို batch ထဲက အခြား review တွေနဲ့ သီးခြားစီ normalize လုပ်တာဖြစ်လို့ ညဉ့်ခင်း 2 နာရီမှာ review တစ်ခုတည်း ဝင်လာလည်း review 200 ပါတဲ့ batch ထဲမှာ ဝင်သလိုပဲ တူညီစွာ normalize ဖြစ်တယ်။
အတူတူ စမ်းရေးကြည့်မယ်
import torch
import torch.nn as nn
torch.manual_seed(0)
batch_size, num_features = 4, 6
x = torch.randn(batch_size, num_features) * 5 + 3
bn = nn.BatchNorm1d(num_features)
ln = nn.LayerNorm(num_features)
bn_out = bn(x)
ln_out = ln(x)
print("input mean/std:", round(x.mean().item(), 3), round(x.std().item(), 3))
print("batchnorm per-feature (column) mean:", bn_out.mean(dim=0))
print("batchnorm per-feature (column) std:", bn_out.std(dim=0, unbiased=False))
print("layernorm per-sample (row) mean:", ln_out.mean(dim=1))
print("layernorm per-sample (row) std:", ln_out.std(dim=1, unbiased=False))input mean/std: 3.xxx 5.xxx
batchnorm per-feature (column) mean: tensor([~0, ~0, ~0, ~0, ~0, ~0])
batchnorm per-feature (column) std: tensor([~1, ~1, ~1, ~1, ~1, ~1])
layernorm per-sample (row) mean: tensor([~0, ~0, ~0, ~0])
layernorm per-sample (row) std: tensor([~1, ~1, ~1, ~1])
BatchNorm1d က feature (column) တစ်ခုစီကို batch ရဲ့ sample 4 ခုပေါ် normalize လုပ်လို့ column တစ်ခုစီရဲ့ mean/std က 0/1 နီးနီးဖြစ်တယ်။ LayerNorm ကတော့ sample (row) တစ်ခုစီကို feature 6 ခုပေါ် normalize လုပ်လို့ row တစ်ခုစီရဲ့ mean/std က 0/1 နီးနီးဖြစ်တယ် — dimension လုံးဝ ကွာခြားတယ်။၅ မိနစ် စမ်းကြည့်
batch_size ကို 4 ကနေ 1 ကို လျှော့ပြီး ပြန် run ကြည့်ပါ — BatchNorm1d မှာ error တက်လား၊ LayerNorm မှာလား စစ်ဆေးပါ။ batch_size=1 မှာ ဘာလို့ ဒီလို ဖြစ်ရသလဲ concept paragraph ကို ပြန်ကြည့်ပြီး ရှင်းပြပါ။
သတိလေးတစ်ချက်
BatchNorm1d ကို batch_size=1 နဲ့ train mode မှာ run ရင် variance ကို sample တစ်ခုတည်းကနေ တွက်လို့ 0 ဖြစ်သွားပြီး error တက်တတ်တယ် — LayerNorm မှာတော့ ဒီပြဿနာ မရှိဘူး
BatchNorm layer တွေကို eval() mode ကို ပြောင်းဖို့ မေ့တတ်ကြတယ် — train mode မှာ running mean/std ကို batch statistics အသစ်နဲ့ update လုပ်နေတယ်၊ eval mode မှာမှ stored running statistics ကို သုံးပြီး inference တစ်ခုချင်းစီမှာ တသမတ်တည်း output ထွက်တာဖြစ်တယ်
Wikipedia — Batch normalization — Deep Learning