16.3 Elméleti és effektív recepciós mező

16.3.1 Cél, előismeret és induló becslés

Ez az egység a konvolúciós hálózatok egyik legfontosabb, de gyakran félreértett szerkezeti fogalmát vizsgálja: mekkora bemeneti területet lát egy kimeneti neuron? A kérdés nem csupán elméleti; a tervezés során abból indulunk ki, hogy a modellnek akkora kontextust kell kapnia, amekkorát a feladat megkíván. A szükséges előismeret a 16.2. Pooling, downsampling és aliasing alfejezetben tárgyalt pooling és stride fogalma, valamint a 4.3. Jacobi-mátrix, láncszabály és VJP alfejezetben bevezetett VJP és a 15.3. Transposed convolution mint adjungált alfejezetben tárgyalt lineáris operátoros leírás; a 12.3. Sanity check és kis mintára túlillesztés alfejezetből a gradiensalapú érzékenységvizsgálat szemlélete tér vissza.

Induló becslés: egy 4 rétegű, mindenhol 3×33\times3-as, stride 1 konvolúciót használó hálózat kimenetének egyetlen neuronja hány pixelből álló bemeneti négyzetet lát? A kézenfekvő válasz 1+2+2+2+2=91+2+2+2+2=9, azaz 9×99\times9; a pontos érvelést és az ettől eltérő eseteket ebben az egységben dolgozzuk ki.

16.3.2 Definíciók: elméleti recepciós mező, jump és effektív mező

A következő fogalmakat 1D-ben definiáljuk, majd a 2D kiterjesztést adjuk meg. Az 1D jelölés a térbeli dimenziókat világosabban mutatja, és a 2D eredmény téglalap kernel esetén dimenziónként szeparálható.

Elméleti recepciós mező (receptive field, RF). Legyen adott egy LL rétegből álló soros hálózat, amelyben minden réteg egyetlen térbeli dimenzión konvolúciót, poolingot vagy más, kernelablakkal dolgozó műveletet végez. Az ll réteg kimenetének egy rögzített pozíciójához tartozó elméleti recepciós mező FlF_l az eredeti bemeneten azon pozíciók legkisebb befoglaló intervallumának hossza, amelyek értékétől a kimenet függhet. A kezdeti réteg a bemenet maga: F0=1F_0=1. A befoglaló intervallumot azért használjuk, mert dilation esetén a ténylegesen hozzáférhető pontok nem feltétlenül alkotnak kontiguus halmazt.

Egy fontos finomság: FlF_l a hozzáférhetőség felső határa, nem a ténylegesen megvalósuló hatás leírása. Ha egy súly nulla, a hozzá tartozó bemeneti pozíció nem befolyásolja a kimenetet, de az architektúra által elvileg elérhető marad.

Jump (lépésköz). A JlJ_l lépésköz azt adja meg, hogy az ll réteg kimenetén két szomszédos pozícióhoz tartozó bemeneti koordináták az eredeti bemeneti rácson mekkora távolságra vannak egymástól. Kezdetben J0=1J_0=1, mert a bemeneti rács két szomszédos pixele egy egységnyire van. A jump a kimeneti rács tényleges ritkábbodását írja le, ezért a stride-ok szorzata jelenik meg benne.

Kötelező jelölések. Az ll réteg kernelmérete klk_l, stride-ja sls_l, dilationje dld_l; mind pozitív egész. A padding plp_l nemnegatív egész, de a RF nagyságába nem szól bele, mert a zero padding virtuális, és nem szállít valódi bemeneti értéket. A bias ugyancsak térbelileg konstans, ezért nem változtatja a mezőt. A csatornákra szorítkozva a standard groups=1groups=1 esetet használjuk; a térbeli RF a csatornaszámtól független, mert a bemeneti csatornák ugyanazt a térbeli régiót osztják meg.

Effektív recepciós mező (ERF). Az effektív recepciós mező az input pixelek mért érzékenységének eloszlása egy adott kimeneti neuronra nézve. Mérhetjük például a loss bemeneti gradiensének abszolút értékével:

Gij=|∂L∂X:,:,i,j|,G_{ij} = \left|\frac{\partial L}{\partial X_{:, :, i, j}}\right|,

ahol LL egy választott kimeneti neuron értéke. Az ERF nem az elméleti RF automatikus tulajdonsága: a gradiens eloszlása a konkrét súlyoktól és a bemenettől is függhet.

16.3.3 Tétel: a RF és a jump rekurziója

A következő állítás a soros rétegek recepciós mezőjének alapegyenlete. A bizonyítás elemi indukció, ezért a tankönyv teljes levezetéssel adja.

Tétel (soros RF-rekurzió). Legyenek l=1,…,Ll=1,\dots,L soros 1D rétegek, rendre (kl,dl,sl)(k_l,d_l,s_l) paraméterekkel. Legyen F0=1F_0=1 és J0=1J_0=1. Ekkor minden l≥1l\ge 1 esetén

Jl=Jl−1sl,Fl=Fl−1+(kl−1)dlJl−1.J_l = J_{l-1}\,s_l, \qquad F_l = F_{l-1} + (k_l-1)\,d_l\,J_{l-1}.

A padding a befoglaló hossz rekurziójában nem szerepel; a stride csak a jump-on keresztül hat a következő réteg mezőjére.

Bizonyítás. A jump-ra vonatkozó állítás közvetlen: az ll réteg kernelét két szomszédos kimeneti pozíció esetén az előző réteg kimenetén sls_l rácslépés választja el. Az előző réteg kimenetének egy rácslépése az eredeti bemeneti rácson Jl−1J_{l-1} egységnek felel meg, így a kimeneti rács szomszédos elemeihez tartozó bemeneti koordináták különbsége slJl−1s_l J_{l-1}. Tehát Jl=Jl−1slJ_l = J_{l-1}s_l.

A mezőhöz tekintsük az ll réteg kernelét. A kernel az előző réteg kimenetéből klk_l darab pozíciót használ, éspedig 0,dl,2dl,…,(kl−1)dl0,d_l,2d_l,\ldots,(k_l-1)d_l offsettel a kernel kezdőpontjához képest. Minden ilyen előző kimeneti pozíció az eredeti bemeneten egy legfeljebb Fl−1F_{l-1} hosszúságú befoglaló intervallumtól függ. Két szomszédos mintavételezett előző pozíció között dld_l darab előző kimeneti rácslépés van, tehát a két befoglaló intervallum kezdőpontjának távolsága az eredeti bemeneti rácson dlJl−1d_l J_{l-1}. A legkisebb befoglaló intervallum hossza ezért

Fl−1+(kl−1)(dlJl−1),F_{l-1} + (k_l-1)\,(d_l J_{l-1}),

mert a kernel (kl−1)(k_l-1) darab ilyen távolságnyi szakasszal bővíti a kiinduló Fl−1F_{l-1} hosszú intervallumot. Ez éppen a kívánt rekurzió. ∎

A tétel feltételei közt a rétegek soros elrendezése szerepel; skip-connection esetén a mező a két ág uniója, ezért az itteni egyszerű rekurzió nem alkalmazható változatlanul.

Következmény (zárt képlet). Mivel Jl−1=∏m=1l−1smJ_{l-1} = \prod_{m=1}^{l-1}s_m, az LL rétegű soros hálózat RF-je

FL=1+∑l=1L(kl−1)dl∏m=1l−1sm.F_L = 1 + \sum_{l=1}^{L} (k_l-1)\,d_l \prod_{m=1}^{l-1}s_m.

A bizonyítás teleszkópikus összeg: Fl−Fl−1=(kl−1)dlJl−1F_l-F_{l-1}=(k_l-1)d_lJ_{l-1}, és Jl−1J_{l-1} a stride-ok szorzata.

2D kiterjesztés. Téglalap kernel esetén két külön rekurziót futtatunk a magasságra és a szélességre. A HH dimenzióra kh,dh,shk_h,d_h,s_h, a WW dimenzióra kw,dw,swk_w,d_w,s_w paraméterekkel az FhF_h és FwF_w értékeket a fenti képlettel számoljuk, a teljes elméleti befoglaló téglalap pedig Fh×FwF_h\times F_w. Az itt használt konvolúciós implementáció szimmetrikus zero padding mellett cross-correlationt számol, ezért a RF számítása ugyanaz, mint a megfordított kernelű matematikai konvolúcióé.

16.3.4 Kézi kis példa és ellenőrzés

Tekintsünk három réteget:

  1. réteg: k1=3,d1=1,s1=1k_1=3,d_1=1,s_1=1;
  2. réteg: k2=2,d2=1,s2=2k_2=2,d_2=1,s_2=2 (pl. maxpool);
  3. réteg: k3=3,d3=2,s3=1k_3=3,d_3=2,s_3=1.

A rekurzió lépésről lépésre:

A harmadik réteg kimenetének egy neuronja tehát a bemenet egy 12 hosszúságú intervallumától függhet, a kimeneti rács pedig minden második bemeneti pixelen mintavételez. A dilation a 3. rétegben 88 egységgel növelte a mezőt, pedig a kernel fizikailag csak 33 együtthatót tartalmaz.

16.3.5 Labor: három architektúra RF-e és gradiensalapú érzékenység

A labor három kis konvolúciós hálózat RF-ét számítja ki a rekurzióval, majd a gradiens befoglaló dobozának méretét hasonlítja az elmélethez. Minden modell egyetlen bemeneti és kimeneti csatornával, bias nélkül, ReLU nélkül készül, hogy a lineáris map gradiensét vizsgálhassuk.

A munkakönyvtár legyen lab/erf/. A következő kódot mentsük erf_lab.py néven, és futtassuk a

python erf_lab.py

paranccsal. A kód CPU-n fut, float32 dtype-pal, torch.manual_seed(7) inicializálással; a device cpu.

import torch
import torch.nn as nn

torch.manual_seed(7)
device = torch.device("cpu")

def rf_from_spec(spec):
    """spec: list of (kernel, dilation, stride) 1D/négyzetes esetre."""
    F = 1
    J = 1
    for k, d, s in spec:
        F = F + (k - 1) * d * J
        J = J * s
    return F, J

def build_layer(k, d, s):
    return nn.Conv2d(1, 1, kernel_size=k, dilation=d,
                     stride=s, padding=1, bias=False)

specs = {
    "A": [(3, 1, 1)] * 4,                     # négy 3x3, stride 1
    "B": [(3, 1, 2)] * 3,                     # három 3x3, stride 2
    "C": [(3, 1, 1), (3, 2, 1), (3, 4, 1)],  # dilation 1,2,4
}

for name, spec in specs.items():
    F, J = rf_from_spec(spec)
    model = nn.Sequential(*[build_layer(*p) for p in spec]).to(device)

    x = torch.ones(1, 1, 32, 32, requires_grad=True)
    out = model(x)
    cy, cx = out.shape[2] // 2, out.shape[3] // 2
    loss = out[0, 0, cy, cx]
    loss.backward()

    g = x.grad[0, 0].detach().abs()
    nz = (g > 1e-8).nonzero()
    ymin, xmin = nz.min(dim=0).values
    ymax, xmax = nz.max(dim=0).values
    mh, mw = int(ymax - ymin + 1), int(xmax - xmin + 1)

    # a gradiens befoglaló dobozának középső 3x3 blokkja
    cy_eff, cx_eff = (ymin + ymax) // 2, (xmin + xmax) // 2
    mid = g[cy_eff - 1:cy_eff + 2, cx_eff - 1:cx_eff + 2].sum().item()
    total = g.sum().item()

    print(f"{name}: elmeleti RF=({F},{F}), jump=({J},{J}), "
          f"mert doboz=({mh},{mw}), kozep3x3 arany={mid/total:.3f}")

A három modell elméleti értéke:

A kód elvárt ellenőrzése: a gradiens befoglaló dobozának mérete rendre (9,9)(9,9), (15,15)(15,15) és (15,15)(15,15) kell hogy legyen; a pontos pozíció a padding miatt eltolódhat, de a méret nem. A középső 3×33\times3-as blokk energiaaránya a seed függvénye; tipikusan határozottan nagyobb, mint a szélső régiók egyenlő méretű blokkjaié, de a konkrét arányt csak futtatás után szabad állítani. Az alábbi táblázat a várt szerkezetet mutatja, nem mért futásból:

Architektúra Elméleti RF Jump Gradiens dobozmérete
A 9×99\times9 11 9×99\times9
B 15×1515\times15 88 15×1515\times15
C 15×1515\times15 11 15×1515\times15

16.3.6 Gyakori tévedés és ellenpélda

A leggyakoribb hiba azt állítani, hogy az elméleti RF nagysága önmagában garantálja a mező minden pixelének egyenlő vagy legalább érdemi hatását. Ez hamis.

Ellenpélda. Vegyük az A architektúrát (négy 3×33\times3-os konvolúció, stride 1), amelynek elméleti RF-je 9×99\times9. Mindegyik rétegben állítsuk a kernel középső elemét 11-re, az összes többi együtthatót 00-ra. Az 1-es padding mellett minden réteg 1×11\times1-es konvolúcióvá degenerálódik, tehát a modell kimenete az input ugyanazon pozícióját adja vissza (bias nélkül). A kimenet középső neuronjának gradiens-térképe egyetlen input pixelen nemnulla, annak ellenére, hogy az architekturális RF 9×99\times9. Az elméleti RF tehát a hozzáférhetőség felső határa, nem a ténylegesen gyakorolt hatás leírása.

16.3.7 Feladatok

F1 (fogalmi, nehézség 1). Magyarázza el a különbséget az elméleti recepciós mező és az effektív recepciós mező között. Adjon egy konkrét súlykonfigurációt, amelyben a kettő jelentősen eltér. Az átadandó eredmény: saját szavakkal írt definíció, mérési mód, és egy kis numerikus példa a fenti labor valamely modelljén.

F2 (levezetési, nehézség 2). Számítsa ki a recepciós mezőt és a jump-ot a következő 1D soros hálózatra: Conv(k=5,d=1,s=1k=5,d=1,s=1), MaxPool(k=2,s=2k=2,s=2), Conv(k=3,d=2,s=2k=3,d=2,s=2). A megoldásban minden réteg utáni FlF_l és JlJ_l érték szerepeljen, a rekurzió indoklásával együtt. Elvárt végeredmény: F=14F=14, J=4J=4.

F3 (implementációs, nehézség 2). Írjon Python függvényt, amely specifikáció-listából kiszámítja az FF és JJ értékeket 1D/négyzetes esetre, és legalább két assertteszttel ellenőrizze. Az átadandó eredmény: futtatható kód, tesztesetek és azok kimenete.

F4 (hibakeresési, nehézség 2). Tekintse a következő hibás rekurziót:

def rf_wrong(spec):
    F = 1
    J = 1
    for k, d, s in spec:
        J = J * s
        F = F + (k - 1) * d * J   # a frissített J-t használja
    return F, J

Magyarázza el, miért hibás, milyen következménye van, és javítsa. Ellenőrizze a javítást egyetlen k=3,s=2k=3,s=2 rétegen: a helyes F=3F=3, a hibás F=5F=5. Az átadandó eredmény: hibaelemzés, javított kód, kontrollfutás.

F5 (kísérleti/transzfer, nehézség 3). Tervezzen kísérletet a következő kérdésre: egy adott, már betanított CNN predikciója a kép teljes elméleti RF-jét használja-e, vagy csak egy jóval kisebb központi tartományra érzékeny? Adja meg a protokollt: rögzített modell és adat, split, gradiens- vagy perturbációalapú mérés, küszöb, metrika, ismétlések száma, és a következtetés érvényességi korlátja. Az átadandó eredmény: protokollterv, nem szükséges futtatni.

16.3.8 Megoldások és indoklás

F1 megoldás. Az elméleti RF az architektúrából számított maximális bemeneti halmaz, amelytől egy kimeneti neuron függhet; az effektív RF a ténylegesen megvalósuló súlyozott érzékenység. Utóbbit a választott kimeneti neuronra vonatkozó loss bemeneti gradiensének abszolút értékével mérjük. Konkrét ellenpélda: az A modellben minden kernel középső eleme 1, a többi 0. Ekkor az elméleti RF 9×99\times9, de a középső kimeneti neuron gradiense csak az input középső pixelén nemnulla, tehát a mért hatás 1×11\times1.

F2 megoldás. A rekurzióval:

  1. réteg: k=5,d=1,s=1k=5,d=1,s=1: F1=1+(5−1)⋅1⋅1=5F_1=1+(5-1)\cdot 1\cdot 1=5, J1=1⋅1=1J_1=1\cdot 1=1.
  2. réteg: pooling k=2,d=1,s=2k=2,d=1,s=2: F2=5+(2−1)⋅1⋅1=6F_2=5+(2-1)\cdot 1\cdot 1=6, J2=1⋅2=2J_2=1\cdot 2=2.
  3. réteg: k=3,d=2,s=2k=3,d=2,s=2: F3=6+(3−1)⋅2⋅2=6+8=14F_3=6+(3-1)\cdot 2\cdot 2=6+8=14, J3=2⋅2=4J_3=2\cdot 2=4.

Tehát a végső RF 14, a jump 4. Ez azt jelenti, hogy a kimenet minden negyedik eredeti bemeneti pixelen mintavételez, és egyetlen kimeneti neuron egy 14 hosszú intervallumtól függhet. A levezetés a tétel mindkét rekurziójának közvetlen alkalmazása.

F3 megoldás. A függvény és a tesztek:

def rf_from_spec(spec):
    """spec: list of (kernel, dilation, stride)."""
    F = 1
    J = 1
    for k, d, s in spec:
        F = F + (k - 1) * d * J
        J = J * s
    return F, J

# teszt 1: négy 3x3-as, stride 1: RF=9
assert rf_from_spec([(3, 1, 1)] * 4) == (9, 1)

# teszt 2: egy stride-2 réteg, majd egy stride-1
assert rf_from_spec([(3, 1, 2)]) == (3, 2)
assert rf_from_spec([(3, 1, 2), (3, 1, 1)]) == (7, 2)

A második tesztben az első réteg után J1=2J_1=2, a második réteg hozzáadása F=3+(3−1)⋅1⋅2=7F=3+(3-1)\cdot 1\cdot 2=7, a jump változatlan: J2=2⋅1=2J_2=2\cdot 1=2. A 𝚛𝚎𝚝𝚞𝚛𝚗\texttt{return} sorrend (F,J)(F,J) konzisztens a szövegbeli jelöléssel.

F4 megoldás. A hiba a sorrendben van: a réteg stride-ja a következő réteg mezőjét befolyásolja, nem a saját rétegét. A kód a JJ frissítése utáni értéket használja, ezért a saját kernel hozzájárulását már a megnövelt jump-tal szorozza. Egyetlen k=3,d=1,s=2k=3,d=1,s=2 rétegen a helyes F=1+(3−1)⋅1⋅1=3F=1+(3-1)\cdot 1\cdot 1=3, a hibás F=1+(3−1)⋅1⋅2=5F=1+(3-1)\cdot 1\cdot 2=5; a hibás kód még a kernel tényleges méretét is túlbecsüli. Javítás: a JJ frissítése a mezőszámítás után következzen, ahogyan a tétel bizonyítása is teszi. A javított kód a F3 megoldás függvénye.

F5 megoldás. Protokollterv: rögzítsünk egy betanított modellt és a GlyphLab teszt splitet (a legjobb checkpoint már kiválasztott, a tesztet nem használtuk választásra). Minden képre számítsuk ki a középső kimeneti logit gradiensét az inputra, majd az abszolút gradiensből keressük meg azt a legkisebb középpontú négyzetet, amely a teljes gradiensenergia legalább 95 százalékát tartalmazza. A metrika ennek a négyzetnek a mérete az elméleti RF méretéhez viszonyítva. Ismételjük legalább 30 független tesztképen; az átlagos négyzetméret és annak szórása a jelentendő mennyiség. Baseline: az elméleti RF. Korlát: ReLU-k esetén a gradiens inputfüggő, ezért több inputon átlagolunk, és az eredmény csak a rögzített modellre, erre a feladatra és erre a mérési definícióra érvényes; a perturbációs módszer nagy bemeneti változásokra nemlineáris, ezért a gradiens csak lokális érzékenységet mér.

16.3.9 Önellenőrzés és visszahívás

Önellenőrző kérdések: (1) Miért nem befolyásolja a padding a recepciós mező hosszát? (2) Egy s>1s>1 réteg után miért növekszik a rákövetkező rétegek RF-je gyorsabban? (3) A gradiens befoglaló dobozának mérete mindig egyenlő az elméleti RF-fel?

Válaszok: (1) a padding virtuális nulla, nem eredeti bemenet; (2) mert a jump nő, így a következő kernel ugyanannyi mintája nagyobb bemeneti tartományt fog át; (3) nem, csak az elérhető tartomány felső határa, és lineáris aktiváció nélkül a gradiens akár nulla is lehet a mező egy részén, ahogyan az F1 ellenpéldája mutatta.

Korábbi fogalom visszahívása: a 4.3. Jacobi-mátrix, láncszabály és VJP alfejezetben levezetett VJP szerint a gradiens az inputra nézve Jf⊤eJ_f^\top e, ahol ee a választott kimeneti neuron egységvektora. A jelen labor ezt a Jacobi-sort vizsgálja térbeli térképen. A 16.2. Pooling, downsampling és aliasing alfejezetből tudjuk, hogy a pooling ablak és stride ugyanezen rekurzióval kezelhető; a maxpool gradiens-térképe azonban csak az aktív útvonalat mutatja.

16.3.10 Rövid összefoglaló

A recepciós mező azt a bemeneti tartományt jelöli, amelytől egy kimeneti neuron elvileg függhet. Soros rétegek esetén a jump Jl=Jl−1slJ_l=J_{l-1}s_l, a mező pedig Fl=Fl−1+(kl−1)dlJl−1F_l=F_{l-1}+(k_l-1)d_lJ_{l-1}; a zárt képletben a stride-ok szorzata gyorsítja a növekedést. A padding és a bias a hosszt nem változtatja. Az effektív recepciós mező ezzel szemben a gradienssel mért tényleges érzékenység, és messze lehet az elméleti határtól. A labor három architektúrán ellenőrizte, hogy a gradiens befoglaló mérete rendre 9×99\times9, 15×1515\times15 és 15×1515\times15, miközben az energiaeloszlás nem egyenletes.

16.3.11 Következő alkalmazás

A 16.4. IV. ellenőrző pont: a CNN-operátor teljes megértése IV. ellenőrző pont a CNN-operátor teljes megértését méri: ott a recepciós mező mellett az eltolási equivariance/invariance határfeltételeit, a stride-részcsoportokat és a gradiensellenőrzést is együttesen kell alkalmazni. Az itt levezetett rekurzió a csoportosított architektúrák és a transzponált konvolúció reverse-map elemzésében is alapeszköz.

16.3.12 Felhasznált források