18.2 Batch normalization train és eval módban

18.2.1 Cél, előismeret és induló kérdés

A 18.1. Reziduális blokk és identitásút egységben a reziduális blokkot y=x+F(x)y=x+F(x) alakban definiáltuk, és láttuk, hogy a shortcut identitás a gradiens terjedését segíti. A gyakorlatban a reziduális főág egyik leggyakoribb eleme a konvolúció utáni batch normalizálás. Ennek az egységnek a célja annak pontos szétválasztása, ami a BatchNorm-ban statisztikailag számított, ami tanulható paraméter, és ami pufferállapot, különösen a train és az eval mód eltérő viselkedésén keresztül.

Előismeret: a 14.2. Több bemeneti és kimeneti csatorna alfejezetben bevezetett NCHW alak és csatornaszerkezet, valamint a 6.2. Konvexitás és sima optimalizálási határ alfejezetben tárgyalt optimalizálási szemlélet. A dropout train/eval kapcsolóját a 17.2. AlexNet és a kísérleti kontextus AlexNet-kontextusában említettük; a BatchNorm ugyanezt a kapcsolót más okból igényli.

Induló kérdés: egy BN-t tartalmazó hálózatot egyetlen tesztképpel futtatunk úgy, hogy elfelejtettük az eval() módot. A BatchNorm az egyetlen kép csatornájából számít átlagot és varianciát. Miért sérül ezzel az inference-szerződés akkor is, ha gradiensláépést egyáltalán nem végzünk?

18.2.2 Definíciók, jelölések és alakok

Legyen a réteg bemenete X∈ℝN×C×H×WX\in\mathbb R^{N\times C\times H\times W}, az NCHW konvenció szerint. A BatchNorm2d minden cc kimeneti/bemeneti csatornához külön statisztikát és külön affin paraméterpárt rendel. A batch-méret a csatornán belüli összes megfigyelés:

M=N⋅H⋅W.M = N\cdot H\cdot W.

A cc csatorna batch-átlaga:

μc=1M∑n=1N∑h=1H∑w=1Wxn,c,h,w.\mu_c = \frac{1}{M}\sum_{n=1}^{N}\sum_{h=1}^{H}\sum_{w=1}^{W} x_{n,c,h,w}.

A cc csatorna batch-varianciája a torzított, azaz 1/M1/M-es konvencióval:

σc2=1M∑n,h,w(xn,c,h,w−μc)2.\sigma_c^2 = \frac{1}{M}\sum_{n,h,w}\bigl(x_{n,c,h,w}-\mu_c\bigr)^2.

A PyTorch BatchNorm2d ezt a torzított varianciát használja; ez a torch.var(..., unbiased=False) konvenció [D12]. Ez nem statisztikai becslés az 5.2. Várható érték, variancia és likelihood értelmében, ahol a Bessel-korrekció az 1/(M−1)1/(M-1)-es mintavarianciát adja. Itt a cél normalizálás, nem a populációvariancia torzítatlan becslése; a két konvenció megkülönböztetése numerikus eltérést okoz.

A tanulható affin paraméterek csatornánként egy skalárpár:

γc∈ℝ,βc∈ℝ.\gamma_c\in\mathbb R,\qquad \beta_c\in\mathbb R.

A PyTorch-objektumban ezek a weight és a bias attribútumok, mindkettő CC hosszú vektor. Az eps paraméter ε>0\varepsilon>0 numerikus stabilizátor, alapértelmezése 10−510^{-5}.

18.2.3 A train mód forwardja

A train mód képlete három lépésből áll: számítás, normalizálás, affin transzformáció.

Definíció 1 (BatchNorm train forward). Legyen ε>0\varepsilon>0, γc,βc∈ℝ\gamma_c,\beta_c\in\mathbb R. A train módú normalizált érték

x̂n,c,h,w=xn,c,h,w−μcσc2+ε,\hat x_{n,c,h,w} = \frac{x_{n,c,h,w}-\mu_c}{\sqrt{\sigma_c^2+\varepsilon}},

a kimenet pedig

yn,c,h,w=γcx̂n,c,h,w+βc.y_{n,c,h,w}=\gamma_c\,\hat x_{n,c,h,w}+\beta_c.

A μc\mu_c és σc2\sigma_c^2 a fenti, az aktuális batchből számított statisztikák. Minden mennyiség a cc csatornán osztozik; a (γ,β)(\gamma,\beta) a térbeli pozíciók és a batch fölé broadcastolódik.

A shape-ellenőrzés: μ,σ2,γ,β∈ℝC\mu,\sigma^2,\gamma,\beta\in\mathbb R^C; az XX, X̂\hat X, YY mind ℝN×C×H×W\mathbb R^{N\times C\times H\times W}.

Lemma 1 (a normalizált batch statisztikái). Ha M≥1M\ge 1, akkor train módban x̂\hat x batch-átlaga minden cc csatornán 00. Ha σc2>0\sigma_c^2>0, akkor x̂\hat x torzított batch-varianciája σc2/(σc2+ε)\sigma_c^2/(\sigma_c^2+\varepsilon).

Bizonyítás. Az összegzés linearitása miatt a normalizált értékek átlaga

1M∑n,h,wx̂n,c,h,w=1σc2+ε⋅1M∑n,h,w(xn,c,h,w−μc)=1σc2+ε⋅0=0.\frac{1}{M}\sum_{n,h,w}\hat x_{n,c,h,w} =\frac{1}{\sqrt{\sigma_c^2+\varepsilon}}\cdot \frac{1}{M}\sum_{n,h,w}(x_{n,c,h,w}-\mu_c) =\frac{1}{\sqrt{\sigma_c^2+\varepsilon}}\cdot 0=0.

A varianciához használjuk, hogy a konstans (σc2+ε)−1/2(\sigma_c^2+\varepsilon)^{-1/2} szorzó a négyzetes eltérésekből kiemelhető:

1M∑n,h,wx̂n,c,h,w2=1σc2+ε⋅1M∑n,h,w(xn,c,h,w−μc)2=σc2σc2+ε.\frac{1}{M}\sum_{n,h,w}\hat x_{n,c,h,w}^2 =\frac{1}{\sigma_c^2+\varepsilon}\cdot\frac{1}{M}\sum_{n,h,w}(x_{n,c,h,w}-\mu_c)^2 =\frac{\sigma_c^2}{\sigma_c^2+\varepsilon}.

Mivel a normalizált átlag nulla, ez a második kifejezés éppen a torzított variancia. ▫\square

Két következmény. Először, ha σc2≫ε\sigma_c^2\gg\varepsilon, a normalizált batch varianciája közel 11; ha σc2=0\sigma_c^2=0, akkor x̂=0\hat x=0. Másodszor, az affin lépés után a batch-átlag βc\beta_c, a torzított variancia γc2⋅σc2/(σc2+ε)\gamma_c^2\cdot\sigma_c^2/(\sigma_c^2+\varepsilon).

18.2.4 Running statisztikák és a momentum paraméter

A train mód minden forwardja frissíti a running buffert, ha a track_running_stats=True alapértelmezést használjuk. A normalizálás és a pufferfrissítés két különböző varianciát használ. Jelölje

vcbiased=σc2=1M∑n,h,w(xn,c,h,w−μc)2,vcunbiased=MM−1vcbiased(M>1).v_c^{\mathrm{biased}}=\sigma_c^2=\frac1M\sum_{n,h,w}(x_{n,c,h,w}-\mu_c)^2,\qquad v_c^{\mathrm{unbiased}}=\frac{M}{M-1}\,v_c^{\mathrm{biased}}\quad(M>1).

A train forward a torzított vcbiasedv_c^{\mathrm{biased}}-szel normalizál (Definíció 1), a futó variancia viszont a torzítatlan vcunbiasedv_c^{\mathrm{unbiased}} becslést kapja [D12]. Legyen a frissítés előtti futó átlag μ‾c\bar\mu_c, a frissítés előtti futó variancia σ‾c2\bar\sigma_c^2, és legyen a momentum α∈(0,1]\alpha\in(0,1]. Az egy batch utáni új értékek:

μ‾c←(1−α)μ‾c+αμc,σ‾c2←(1−α)σ‾c2+αvcunbiased.\bar\mu_c\leftarrow (1-\alpha)\,\bar\mu_c+\alpha\,\mu_c,\qquad \bar\sigma_c^2\leftarrow (1-\alpha)\,\bar\sigma_c^2+\alpha\,v_c^{\mathrm{unbiased}}.

M=1M=1 esetén (egyetlen elem csatornánként) a torzítatlan becslés nem értelmezett; a PyTorch ilyenkor train módban hibát jelez.

A PyTorch alapértelmezett α=0,1\alpha=0{,}1. Ez exponenciális mozgóátlag: a régi puffer 1−α1-\alpha, az aktuális batch α\alpha súlyt kap. A buffer a running_mean és running_var attribútumban él, és nem kap gradienst; a state_dict() menti, az optimizáló viszont nem frissíti. A running_var varianciát tárol, nem szórást, ezért a forwardban gyököt kell vonni belőle.

A sorozat frissítése tt batch után, α=0,1\alpha=0{,}1 mellett gyorsan elfelejti a múltat: az első batch α\alpha, a második α(1−α)=0,09\alpha(1-\alpha)=0{,}09 súlyt kap. Ha α\alpha-t növeljük, a buffer érzékenyebb az aktuális minibatch zajára; ha csökkentjük, a konvergencia lassul. A momentum=None opció a dokumentáció szerint az 1/num_batches_tracked1/\text{num\_batches\_tracked} kumulatív átlagot használja [D12]; a főútban mi a rögzített α=0,1\alpha=0{,}1 változatot tárgyaljuk.

18.2.5 Eval mód és a két út különbsége

Az eval() mód a BatchNorm számára azt jelenti, hogy a batchstatisztikát nem számoljuk, és a buffert nem frissítjük. Ha a running statisztika rendelkezésre áll, akkor a normalizálás a futó értékekkel történik:

yn,c,h,w=γcxn,c,h,w−μ‾cσ‾c2+ε+βc.y_{n,c,h,w} =\gamma_c\,\frac{x_{n,c,h,w}-\bar\mu_c}{\sqrt{\bar\sigma_c^2+\varepsilon}}+\beta_c.

Definíció 2 (BatchNorm eval forward). Eval módban, track_running_stats=True mellett, a BatchNorm2d a fenti képletet használja, ahol μ‾c\bar\mu_c és σ‾c2\bar\sigma_c^2 a train során felhalmozott futó statisztika. A γc,βc\gamma_c,\beta_c ugyanazok a tanulható paraméterek, mint train módban.

A train/eval különbség formálisan abban áll, hogy train módban a statisztika a minibatch függvénye és a forward mellékhatással frissíti a buffert, eval módban pedig a statisztika konstans, a forwardnak nincs mellékhatása. Ez nem az autograd beállítása, hanem a modul állapota: a torch.inference_mode() a gradiensszámítást kapcsolja ki, de önmagában nem váltja át a BatchNormot.

Az eval mód azért szükséges, mert az inference alatt a kimenetnek nem szabad függnie attól, hogy egy képet egyedül vagy más képekkel egy batchben értékelünk ki. A batchstatisztika egyetlen képen is számolható, ha H⋅W>1H\cdot W>1, de akkor minden kép önmagához normalizálódik, nem a tanítási populációhoz; kis batchben pedig a statisztika varianciája nagy. A running puffer a train alatt látott csatornaeloszlás exponenciális mozgóátlagát közelíti, és így egy előre rögzített normalizálási konstanst ad az inference-hez.

18.2.6 Kézi kis példa

Legyen N=2N=2, C=1C=1, H=W=2H=W=2, tehát M=8M=8. A bemenet

X=[[1234][2468]]∈ℝ2×1×2×2.X=\begin{bmatrix} \begin{bmatrix}1&2\\3&4\end{bmatrix}\\[4pt] \begin{bmatrix}2&4\\6&8\end{bmatrix} \end{bmatrix} \in\mathbb R^{2\times1\times2\times2}.

A nyolc pixel: 1,2,3,4,2,4,6,81,2,3,4,2,4,6,8. Az összeg 3030, így

μ=308=3,75.\mu=\frac{30}{8}=3{,}75.

A négyzetes eltérések összege 7,5625+3,0625+0,5625+0,0625+3,0625+0,0625+5,0625+18,0625=37,57{,}5625+3{,}0625+0{,}5625+0{,}0625+3{,}0625+0{,}0625+5{,}0625+18{,}0625=37{,}5, tehát

σ2=37,58=4,6875.\sigma^2=\frac{37{,}5}{8}=4{,}6875.

ε=10−5\varepsilon=10^{-5} mellett 4,68751≈2,1651\sqrt{4{,}68751}\approx2{,}1651. A normalizált x̂\hat x értékek:

1−3,752,1651=−1,2702,2−3,752,1651=−0,8083,3−3,752,1651=−0,3464,4−3,752,1651=0,1155.\frac{1-3{,}75}{2{,}1651}=-1{,}2702,\quad \frac{2-3{,}75}{2{,}1651}=-0{,}8083,\quad \frac{3-3{,}75}{2{,}1651}=-0{,}3464,\quad \frac{4-3{,}75}{2{,}1651}=0{,}1155.

A második kép 2,4,6,82,4,6,8 értékei rendre −0,8083-0{,}8083, 0,11550{,}1155, 1,03921{,}0392, 1,96291{,}9629. Ha az affin paraméter (γ,β)=(2,1)(\gamma,\beta)=(2,1), akkor y=2x̂+1y=2\hat x+1:

xx x−μx-\mu x̂\hat x y=2x̂+1y=2\hat x+1
1 −2,75-2{,}75 −1,2702-1{,}2702 −1,5404-1{,}5404
2 −1,75-1{,}75 −0,8083-0{,}8083 −0,6166-0{,}6166
3 −0,75-0{,}75 −0,3464-0{,}3464 0,30720{,}3072
4 0,250{,}25 0,11550{,}1155 1,23101{,}2310
6 2,252{,}25 1,03921{,}0392 3,07843{,}0784
8 4,254{,}25 1,96291{,}9629 4,92584{,}9258

A második kép 2-je és 4-ese a táblázat 2. és 4. sorával azonos x̂\hat x-et és yy-t ad, mert a statisztika mind a nyolc pixelből készül.

Most a running frissítés egyetlen forward után, α=0,1\alpha=0{,}1, kezdeti μ‾=0\bar\mu=0, σ‾2=1\bar\sigma^2=1 mellett. A pufferbe a torzítatlan variancia kerül: vunbiased=87⋅4,6875=37,57≈5,357142857v^{\mathrm{unbiased}}=\frac{8}{7}\cdot4{,}6875=\frac{37{,}5}{7}\approx5{,}357142857. Így

μ‾=0,9⋅0+0,1⋅3,75=0,375,σ‾2=0,9⋅1+0,1⋅5,357142857≈1,435714286.\bar\mu=0{,}9\cdot0+0{,}1\cdot3{,}75=0{,}375, \qquad \bar\sigma^2=0{,}9\cdot1+0{,}1\cdot5{,}357142857\approx1{,}435714286.

Ha ugyanez a batch másodszor is megérkezik, a buffer μ‾=0,9⋅0,375+0,1⋅3,75=0,7125\bar\mu=0{,}9\cdot0{,}375+0{,}1\cdot3{,}75=0{,}7125 és σ‾2=0,9⋅1,435714286+0,1⋅5,357142857≈1,827857143\bar\sigma^2=0{,}9\cdot1{,}435714286+0{,}1\cdot5{,}357142857\approx1{,}827857143 lesz. Aki a torzított 4,68754{,}6875-öt írná a pufferbe, 1,368751{,}36875-öt, illetve 1,7006251{,}700625-öt kapna; a különbség kis MM mellett jelentős.

18.2.7 Labor: kézi számítás és bufferfrissítés

A munkakönyvtár lab/. A szkript bn_manual.py; futtatás:

python bn_manual.py

A bemenetet float32-ben, CPU-n adjuk meg, a főút szerint:

import torch
import torch.nn as nn

torch.manual_seed(20261020)  # a BN inicializálása determinisztikus; a seed a szerződést rögzíti
dtype = torch.float32
device = "cpu"

X = torch.tensor(
    [[[[1.0, 2.0], [3.0, 4.0]]],
     [[[2.0, 4.0], [6.0, 8.0]]]],
    dtype=dtype, device=device
)  # (2,1,2,2)

bn = nn.BatchNorm2d(
    num_features=1, eps=1e-5, momentum=0.1,
    affine=True, track_running_stats=True
).to(device)

# Kézi statisztika a (N,H,W) dimenziókon, ugyanazzal a torzított varianciával:
mu = X.mean(dim=(0, 2, 3), keepdim=True)         # (1,1,1,1)
var = X.var(dim=(0, 2, 3), unbiased=False, keepdim=True)

bn.train()
Y = bn(X)

manual = (X - mu) / torch.sqrt(var + 1e-5)       # gamma=1, beta=0
print("max_abs_diff train:", (Y - manual).abs().max().item())

# Kézi pufferfrissítés: a futó variancia a torzítatlan becslést kapja (M=8).
M = X.numel() // X.shape[1]
var_unbiased = var * M / (M - 1)
rm_manual = 0.9 * 0.0 + 0.1 * mu.flatten()
rv_manual = 0.9 * 1.0 + 0.1 * var_unbiased.flatten()
print("running_mean:", bn.running_mean.item(), "kézi:", rm_manual.item())
print("running_var:", bn.running_var.item(), "kézi:", rv_manual.item())
assert torch.allclose(bn.running_mean, rm_manual) and torch.allclose(bn.running_var, rv_manual)
# Kézi levezetés: running_mean = 0.375, running_var = 37.5/70 + 0.9 = 1.435714...

A kézi és a könyvtári forward közötti eltérés a fenti, M=8M=8 elemű példán float32-ben legfeljebb 10−510^{-5} nagyságrendű abszolút hiba, mert a képletek ugyanazok; a labor ezt max_abs_diff formában írja ki. A futtatás után a bufferek a fenti, torzítatlan varianciával számított értékeket adják; a szkript ezt assert-tel ellenőrzi. Lab-profilban (PyTorch 2.14.1+cpu) mért kimenet: running_mean 0,3750{,}375, running_var ≈1,4357142\approx1{,}4357142, a train-forward eltérése a kézi képlettől gépi pontosságú.

Az eval-út ellenőrzése ugyanabban a szkriptben folytatódik:

bn.eval()
Y_eval = bn(X)

manual_eval = (X - rm_manual.view(1, -1, 1, 1)) / torch.sqrt(rv_manual.view(1, -1, 1, 1) + 1e-5)
print("max_abs_diff eval:", (Y_eval - manual_eval).abs().max().item())
assert torch.allclose(Y_eval, manual_eval, atol=1e-5)

A bn.eval() hívás után a forward már a buffert használja. Az x=1x=1 pixel eval-normalizált értéke (1−0,375)/1,435724286≈0,5216(1-0{,}375)/\sqrt{1{,}435724286}\approx0{,}5216, az x=8x=8 pixelé (8−0,375)/1,435724286≈6,3636(8-0{,}375)/\sqrt{1{,}435724286}\approx6{,}3636; a lab-profilban a könyvtári eval-forward mind a nyolc pixelre ezt adta. A kimeneti összevetés akkor igazolja az eval utat, ha a könyvtár és a kézi képlet mind a 8 pixelre egyezik.

18.2.8 Gyakori tévedés: a mechanizmus és a motiváció

Az eredeti tanulmány címe az internal covariate shift-et, azaz a rétegek bemeneti eloszlásának eltolódását nevezi meg motivációként [P07]. A PMLR-rekord és az absztrakt ellenőrzött; a cikk teljes mechanizmus-érvelése azonban ebben a kéziratban nem teljes szakaszolvasásból származik. A későbbi munka absztraktja szerint a BatchNorm javulása nem elsősorban az eloszlásstabilitáson, hanem az optimalizálási felület simításán keresztül magyarázható [P08]. Ebből nem következik, hogy az ICS-érv hamis, és az sem, hogy a P08-magyarázat minden architektúrára érvényes. A 6.2. Konvexitás és sima optimalizálási határ alfejezetben bevezetett LL-simaság lokális feltétel; a BN hálózatglobális konvergenciát vagy jobb generalizációt önmagában nem garantál. A helyes állításforma:

További gyakori hiba a momentum összekeverése a 6.4. Momentum és adaptív optimizálók optimalizáló-momentumával. Az ottani momentum a gradienslépés tehetetlensége; a BN momentum a futó statisztika exponenciális simításának α\alpha súlya. A két paraméter egymástól független, és a state_dict()-ben sem érintkeznek.

18.2.9 Önellenőrzés

18.2.10 Feladatok

F1 (fogalmi, nehézség 1). Magyarázza el, miért nem használjuk a batchstatisztikát egyetlen tesztképre, és mit ad helyette a running puffer. Térjen ki arra az esetre is, amikor N=1N=1, de H⋅W=576H\cdot W=576 a GlyphLab 24×2424\times24-es képén. Elvárt eredmény: saját, három-négy mondatos érvelés, amely megkülönbözteti a batchstatisztikát a running statisztikától.

F2 (levezetési, nehézség 2). A fenti labor batchétől független új esetben legyen X∈ℝ2×1×2×2X\in\mathbb R^{2\times1\times2\times2} értéke [[[1,3],[5,7]]][[[1,3],[5,7]]] és [[[2,6],[10,14]]][[[2,6],[10,14]]], γ=2\gamma=2, β=−1\beta=-1, ε=10−5\varepsilon=10^{-5}. Számítsa ki μ\mu, σ2\sigma^2 értékét a torzított konvencióval, majd mind a nyolc yn,c,h,wy_{n,c,h,w} kimenetet. Elvárt eredmény: minden lépés, a shape megadása és a nyolc kimeneti érték két tizedesre kerekítve.

F3 (implementációs, nehézség 2). Írjon batchnorm_forward_manual(X, gamma, beta, eps) függvényt, amely a train forwardot a Definition 1 képleteivel számolja, a statisztikát a (0,2,3)(0,2,3) dimenziókon, unbiased=False varianciával képezi, és a batchstat visszatérési értékben visszaadja a (μ,σ2)(\mu,\sigma^2) párt is. Verifikálja a beépített nn.BatchNorm2d train kimenetén a labor XX batchén, γ=2\gamma=2, β=−1\beta=-1 beállítással. Elvárt átadandó: teljes kód, a maximális abszolút eltérés és a használt tolerancia.

F4 (hibakeresési, nehézség 2). Az alábbi töredék a labor modelljét egy tesztlistán futtatja:

best = SmallCNN()
best.load_state_dict(torch.load("best.pt", weights_only=True))
best.train()  # a tanítási állapot megőrzése
preds = [best(x.unsqueeze(0)).argmax().item() for x in test_images]

Azonosítsa a hibát, mondja ki a következményét a BatchNorm statisztikáira, és adja meg a javítást. Elvárt eredmény: a hiba oka, a következmény, a javított kódblokk és annak ellenőrzése, hogy két eltérő sorrendű tesztlistán azonos predikciók születnek.

F5 (kísérleti/transzfer, nehézség 3). Tervezzen kísérletet a GlyphLab adaton arra a kérdésre, hogy a BatchNorm beillesztése a kis CNN főágába javítja-e a validációs loss-t a normalizálás nélküli baseline-hoz képest. Adjon protokollt: független split, osztályonkénti jelenet-resampling nélkül, három seed, a val loss alapú checkpoint-választás, a záróteszt a corrupted_test.npy-n csak a kiválasztás után, páros összehasonlítás. Elvárt eredmény: A hipotézis, a változó tényező, a metrika, az érvényességi korlátok és annak kimondása, hogy a kis toy adaton mért különbség nem általános mechanizmusbizonyíték.

18.2.11 Megoldások és indoklás

F1. A batchstatisztika az adott minibatch függvénye. Egyetlen tesztkép esetén N=1N=1, így a cc csatorna átlaga és varianciája az adott kép H⋅WH\cdot W pixeléből készülne: minden kép saját középértékéhez normalizálódna, nem a tanítás során látott csatornaeloszláshoz. A 576576 pixel elegendő lenne a számításhoz, de a normalizálás jelentése megváltozik: az inference kimenet attól függne, mely képek vannak éppen a batchben, és egy kép saját kontrasztja eltűnne. A running puffer az exponenciális mozgóátlaggal a train alatt megfigyelt statisztikát rögzíti, és rögzített, batchfüggetlen normalizálást ad az eval módhoz.

F2. A nyolc pixel: 1,3,5,7,2,6,10,141,3,5,7,2,6,10,14. Összegük 4848, tehát

μ=488=6.\mu=\frac{48}{8}=6.

Az eltérések és négyzeteik: −5,25;−3,9;−1,1;1,1;−4,16;0,0;4,16;8,64-5,25;\ -3,9;\ -1,1;\ 1,1;\ -4,16;\ 0,0;\ 4,16;\ 8,64. Az összegük 132132, így a torzított variancia

σ2=1328=16,5.\sigma^2=\frac{132}{8}=16{,}5.

A nevező 16,5+10−5≈4,0620\sqrt{16{,}5+10^{-5}}\approx4{,}0620. A kimenet y=2x̂−1y=2\hat x-1:

x=1:−54,0620=−1,2310,y=−3,4620;x=1:\ \frac{-5}{4{,}0620}=-1{,}2310,\quad y=-3{,}4620; x=3:−34,0620=−0,7386,y=−2,4772;x=3:\ \frac{-3}{4{,}0620}=-0{,}7386,\quad y=-2{,}4772; x=5:−14,0620=−0,2462,y=−1,4924;x=5:\ \frac{-1}{4{,}0620}=-0{,}2462,\quad y=-1{,}4924; x=7:y=−0,5076;x=7:\ y=-0{,}5076; x=2:y=−2,9696;x=2:\ y=-2{,}9696; x=6:y=−1;x=6:\ y=-1; x=10:y=0,9696;x=10:\ y=0{,}9696; x=14:84,0620=1,9695,y=2,9390.x=14:\ \frac{8}{4{,}0620}=1{,}9695,\quad y=2{,}9390.

A kimeneti tensor shape-je (2,1,2,2)(2,1,2,2). A x=6x=6 eset azért ad pontosan −1-1-et, mert x=μx=\mu, tehát x̂=0\hat x=0.

F3. Egy lehetséges teljes megoldás:

import torch
import torch.nn as nn

def batchnorm_forward_manual(X, gamma, beta, eps):
    mu = X.mean(dim=(0, 2, 3), keepdim=True)
    var = X.var(dim=(0, 2, 3), unbiased=False, keepdim=True)
    xhat = (X - mu) / torch.sqrt(var + eps)
    Y = gamma.view(1, -1, 1, 1) * xhat + beta.view(1, -1, 1, 1)
    return Y, (mu, var)

X = torch.tensor(
    [[[[1.0, 2.0], [3.0, 4.0]]],
     [[[2.0, 4.0], [6.0, 8.0]]]], dtype=torch.float32
)

bn = nn.BatchNorm2d(1, eps=1e-5, momentum=0.1)
bn.weight.data.copy_(torch.tensor([2.0]))
bn.bias.data.copy_(torch.tensor([-1.0]))
bn.train()

Y_ref = bn(X)
Y_man, (mu, var) = batchnorm_forward_manual(
    X, bn.weight, bn.bias, 1e-5
)
print("mu =", mu.view(-1).tolist())       # [3.75]
print("var =", var.view(-1).tolist())     # [4.6875]
print("max abs diff =", (Y_ref - Y_man).abs().max().item())

A várt max abs diff float32-ben kisebb, mint 2⋅10−52\cdot10^{-5}; a laborban az atol=1e-4 értéknél szigorúbb, atol=1e-5 tűrést érdemes használni, mert a képlet és a könyvtár ugyanazt a torzított varianciát számolja.

F4. A hiba a best.train() hívás a kiértékelés előtt. A BatchNorm train módban az aktuális tesztbatchből számol statisztikát, és forwardonként frissíti a running puffert. Következmény: a predikció batch-összetétel-függő lesz, a bejárási sorrend megváltoztatása más logitokat adhat, és a mentett modell running állapota felülíródik. A javítás:

best.eval()
with torch.inference_mode():
    preds = [best(x.unsqueeze(0)).argmax().item() for x in test_images]

Az ellenőrzés: a tesztlistát két különböző permutációban futtatva eval() módban a predikciós lista a megfelelő indexeléssel azonos. A torch.inference_mode() a gradiensszámítást kapcsolja ki; önmagában nem váltja át a BatchNorm eval állapotát, ezért a kettőt együtt kell használni.

F5. A protokoll rögzítése a futás előtt: a kérdés az, hogy a BN a GlyphLab val loss-át csökkenti-e a normalizálás nélküli azonos architektúrához képest. A megfigyelési egység a független scene_id; a train/val/test splitet a generátor rögzíti, a bootstrap vagy újraosztás nem keveri a nézeteket. Mindkét modellt három seeddel tanítjuk, azonos inicializálási és optimalizáló-beállításokkal. A modellek a BN jelenlétében térnek el; a val loss alapján választunk legjobb checkpointot, a tesztet csak ezután, a párosított clean és corrupt változaton értékeljük ki. A fő metrika a val loss, jelentésre a test accuracy is megadható. A korlátok: a GlyphLab 240 tanítóképe nem elegendő a mechanizmus általános igazolására; a három seed csak a training zaj egy keskeny szórását mutatja; a P08 optimalizálási magyarázatát ez a kísérlet nem erősíti vagy cáfolja, mert csupán egy kis, egy feladatú adathalmazon mér.

18.2.12 Rövid összefoglaló

A BatchNorm2d train módban minden csatornára kiszámítja a batch átlagát és torzított, 1/M1/M-es varianciáját, normalizál, majd a tanulható γ\gamma és β\beta affin transzformációt alkalmazza. A forward mellékhatásként α\alpha momentummal frissíti a futó átlag- és varianciabuffert. Eval módban a batchstatisztika helyett ez a rögzített running puffer normalizál, így az inference nem függ a batch összetételétől. A P07 ICS-motivációja és a P08 optimalizálási vizsgálata külön státuszú állítás; a bizonyított rész csupán a normalizált batch nulla átlagáról és közel egységnyi varianciájáról szól.

18.2.13 Következő alkalmazás

A 18.3. Pre-activation, kis batch és alternatív normalizálás egység a pre-activation elrendezést, a kis batch viselkedését és a BatchNorm alternatíváit tárgyalja. Ehhez itt azt visszük tovább, hogy a normalizálás helye a reziduális főágban nem közömbös: a shortcut megkerülheti a normalizálást, ezért a pre-activation és a post-activation változat statisztikai útja eltér.

18.2.14 Felhasznált források