19.1 Depthwise separable és pointwise réteg

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

Ebben az alfejezetben a nn.Conv2d két korlátozott rokonát definiáljuk: a depthwise (csatornánkénti, mélységi) és a pointwise (1×11\times1-es, pontonkénti) réteget, majd belőlük a depthwise separable (csatornaszétválasztott) blokkot. A cél az, hogy a teljes konvolúció egyszerre végzett térbeli és csatornakeverését szétválasszuk, és a paraméter-, illetve MAC-költséget pontosan, meghatározott alakokra kiszámoljuk. A szükséges előismeret a 14.4. Csoportos és depthwise konvolúció alfejezetből a groups paraméter értelmezése és oszthatósági feltétele, a 17.4. Architektúra összehasonlítása kontrollált keretben alfejezetből a költségkeretek egyeztetésének szükségessége, a 15.1. Súly- és biasgradiens alfejezetből a súlymegosztásból következő gradiens-összegzés. A [D10] dokumentáció szerint a PyTorch Conv2d térbeli cross-correlationt számol kernelmegfordítás nélkül; a depthwise és pointwise változatok is ezt teszik, tehát a „konvolúció” elnevezés ellenére ebben a fejezetben végig cross-correlationt definiálunk.

Induló becslés. Legyen Cin=3C_{in}=3, Cout=4C_{out}=4, kh=kw=3k_h=k_w=3, stride 1, padding 0, 1×5×51\times5\times5 bemenet. A teljes réteg súlyszáma 4⋅3⋅9=1084\cdot3\cdot9=108. A separable blokk depthwise súlya 3⋅9=273\cdot9=27, pointwise súlya 4⋅3=124\cdot3=12, összesen 3939, tehát a súlyarány 39/108=13/36≈0,36139/108=13/36\approx0{,}361. A levezetés után látni fogjuk, hogy ez nem véletlen: bias nélkül az arány mindig 1Cout+1khkw\frac1{C_{out}}+\frac1{k_hk_w}.

19.1.2 Definíciók: depthwise, pointwise, separable

Legyen a bemeneti képbatch X∈ℝN×Cin×H×WX\in\mathbb R^{N\times C_{in}\times H\times W}, NCHW elrendezésben.

1. definíció (depthwise konvolúció). A depthwise konvolúció olyan cross-correlation, amelyben groups = C_in, tehát minden bemeneti csatornához külön csatornacsoport tartozik. A kernelsúly alakja

D∈ℝCin×m×kh×kw,D\in\mathbb R^{C_{in}\times m\times k_h\times k_w},

ahol m∈ℤ>0m\in\mathbb Z_{>0} a depthwise multiplier: egy bemeneti csatornához mm darab kimeneti szűrő tartozik. A kimeneti csatornák száma emiatt Cmid=mCinC_{mid}=mC_{in}. Zéró alapú indexeléssel a kimenetet Y(1)∈ℝN×mCin×Hout×WoutY^{(1)}\in\mathbb R^{N\times mC_{in}\times H_{out}\times W_{out}} jelöli, és a kimeneti oo csatornához egyértelműen tartozik c=⌊o/m⌋c=\lfloor o/m\rfloor és μ=omodm\mu=o\bmod m. Adott stride ss, zero padding pp és dilation dd mellett

Y(1)[n,o,i,j]=b(1)[o]+∑α=0kh−1∑β=0kw−1D[⌊o/m⌋,omodm,α,β]X[n,⌊o/m⌋,is−p+αd,js−p+βd],Y^{(1)}[n,o,i,j] \;=\; b^{(1)}[o]+\sum_{\alpha=0}^{k_h-1}\sum_{\beta=0}^{k_w-1} D\!\left[\lfloor o/m\rfloor,\;o\bmod m,\;\alpha,\;\beta\right] X\!\left[n,\;\lfloor o/m\rfloor,\; is-p+\alpha d,\;js-p+\beta d\right],

azzal a konvencióval, hogy a [0,H−1]×[0,W−1][0,H-1]\times[0,W-1] indexen kívüli bemenet nulla. Az m=1m=1 esetben o=co=c, tehát egy bemeneti csatornából pontosan egy köztes csatorna lesz. A depthwise groups=C_in beállítás miatt az oszthatósági feltétel automatikusan teljesül, a gyakorlatban azonban a PyTorch a groups értéket csak akkor fogadja el, ha CinC_{in} és CoutC_{out} egyaránt osztható groups értékkel; itt Cout=mCinC_{out}=mC_{in} ezt garantálja.

2. definíció (pointwise konvolúció). A pointwise konvolúció 1×11\times1-es kernelű, groups=1 csatornakeverő cross-correlation:

P∈ℝCout×Cmid×1×1,Z[n,q,i,j]=b(2)[q]+∑c′=0Cmid−1P[q,c′,0,0]Y(1)[n,c′,i,j].P\in\mathbb R^{C_{out}\times C_{mid}\times 1\times 1},\qquad Z[n,q,i,j] \;=\; b^{(2)}[q]+\sum_{c'=0}^{C_{mid}-1}P[q,c',0,0]\;Y^{(1)}[n,c',i,j].

Mivel a kernel térbeli kiterjedése 1, stride 1 és padding 0 esetén a térbeli felbontás változatlan: a pointwise csak az egyazon (i,j)(i,j) pozícióban lévő csatornákat keveri (channel mixing). A teljes konvolúció ezzel szemben minden kimeneti skalárhoz az összes bemeneti csatornát és az összes kernelpozíciót egyszerre használja.

3. definíció (depthwise separable blokk). A depthwise separable blokk a két réteg kompozíciója:

Z=PW(DW(X)).Z \;=\; \mathrm{PW}\!\left(\mathrm{DW}(X)\right).

A térbeli szűrés és a csatornakeverés tehát szekvenciálisan, külön operátorokkal történik. A „separable” szó itt nem a matematikai tenzorszorzat-szeparálhatóságot jelenti, hanem a térbeli és csatorna-feladat szétválasztását; ezt a fogalmi különbséget az F1 feladat vizsgálja.

19.1.3 Levezetés: paraméter- és MAC-arány

4. állítás (saját levezetés, elemi leszámlálás). Legyen X∈ℝN×Cin×H×WX\in\mathbb R^{N\times C_{in}\times H\times W}, kh,kw≥1k_h,k_w\ge1, stride s≥1s\ge1, padding p≥0p\ge0, dilation d≥1d\ge1, és tegyük fel, hogy a teljes konvolúció (groups=1, kimeneti csatornaszám CoutC_{out}) és a separable blokk (m=1m=1 depthwise + pointwise) azonos Hout×WoutH_{out}\times W_{out} térbeli kimenetet ad. A MAC definíciója: egy kimeneti skalárhoz tartozó egy szorzás-plusz-akkumulálás; a bias-hozzáadás nem MAC. Ekkor bias nélkül a súlyparaméterek aránya, és mindig a MAC-ek aránya

PsepPfull=MsepMfull=1Cout+1khkw.\frac{P_{sep}}{P_{full}}\;=\;\frac{M_{sep}}{M_{full}}\;=\;\frac{1}{C_{out}}+\frac{1}{k_hk_w}.

Bizonyítás. A teljes réteg egyetlen kimeneti skalárjához CinkhkwC_{in}k_hk_w súly–bemenet szorzat tartozik, tehát

Mfull=NCoutHoutWoutCinkhkw.M_{full}=N\, C_{out}\, H_{out}W_{out}\, C_{in}\, k_hk_w.

A depthwise réteg (m=1m=1) kimeneti skalárjaihoz Cin/g=Cin/Cin=1C_{in}/g = C_{in}/C_{in}=1 bemeneti csatorna tartozik, tehát egy kimeneti skalár khkwk_hk_w MAC-et igényel; a kimeneti skalárok száma NCinHoutWoutN\,C_{in}H_{out}W_{out}, ezért

MDW=NCinHoutWoutkhkw=1CoutMfull.M_{DW}=N\, C_{in}\, H_{out}W_{out}\, k_hk_w=\frac{1}{C_{out}}M_{full}.

A pointwise réteg egy kimeneti skalárja CinC_{in} szorzatot igényel, a kimeneti skalárok száma NCoutHoutWoutN\,C_{out}H_{out}W_{out}, így

MPW=NCoutHoutWoutCin=1khkwMfull.M_{PW}=N\,C_{out}\,H_{out}W_{out}\,C_{in}=\frac{1}{k_hk_w}M_{full}.

A separable blokk MAC-je a kettő összege, mert a pointwise a depthwise kimenetén dolgozik, és a két réteg költsége additív:

Msep=MDW+MPW=(1Cout+1khkw)Mfull.M_{sep}=M_{DW}+M_{PW} =\left(\frac{1}{C_{out}}+\frac{1}{k_hk_w}\right)M_{full}.

A bias nélküli súlyparaméterekre ugyanez a három szorzat jelenik meg: Pfull=CoutCinkhkwP_{full}=C_{out}C_{in}k_hk_w, PDW=CinkhkwP_{DW}=C_{in}k_hk_w, PPW=CoutCinP_{PW}=C_{out}C_{in}, tehát az arány azonos. ◼\blacksquare

Megjegyzések.

  1. Bias esetén a teljes konvolúciónak CoutC_{out}, a depthwise rétegnek CinC_{in}, a pointwise rétegnek CoutC_{out} biasa van: Pfull=CoutCinkhkw+CoutP_{full}=C_{out}C_{in}k_hk_w+C_{out}, Psep=Cinkhkw+Cin+CoutCin+CoutP_{sep}=C_{in}k_hk_w+C_{in}+C_{out}C_{in}+C_{out}. Az arány ekkor már nem egyezik meg a MAC-aránnyal, és a különbség CinC_{in} növelésével sem tűnik el, mert a depthwise biasok száma is CinC_{in}-nel nő. Rögzített CoutC_{out} és k2=khkwk^2=k_hk_w mellett

limCin→∞PsepPfull=k2+Cout+1Coutk2,MsepMfull=k2+CoutCoutk2,\lim_{C_{in}\to\infty}\frac{P_{sep}}{P_{full}}=\frac{k^2+C_{out}+1}{C_{out}k^2},\qquad \frac{M_{sep}}{M_{full}}=\frac{k^2+C_{out}}{C_{out}k^2},

a különbség 1/(Coutk2)1/(C_{out}k^2). Például k2=9k^2=9, Cout=4C_{out}=4 esetén a két érték 14/3614/36 és 13/3613/36. Aki paraméterköltséget közöl, mondja meg, számol-e bias-t. 2. Multiplier esetén m>1m>1-re Cmid=mCinC_{mid}=mC_{in}, így MDWM_{DW} mm-szeres, a pointwise pedig mCinmC_{in} bemeneti csatornán dolgozik, ezért

Msep(m)Mfull=mCinkhkw+mCoutCinCoutCinkhkw=m(1Cout+1khkw).\frac{M_{sep}^{(m)}}{M_{full}}=\frac{m\,C_{in}k_hk_w+m\,C_{out}C_{in}}{C_{out}C_{in}k_hk_w} =m\left(\frac1{C_{out}}+\frac1{k_hk_w}\right).

19.1.4 Kézi kis példa és ellenőrző munkamenet

Példánkban N=1N=1, Cin=3C_{in}=3, Cout=4C_{out}=4, H=W=5H=W=5, kh=kw=3k_h=k_w=3, s=1s=1, p=0p=0, d=1d=1, ezért Hout=Wout=⌊(5+0−0−1)/1⌋+1=3H_{out}=W_{out}=\lfloor(5+0-0-1)/1\rfloor+1=3.

Operátor Súly+bias MAC
Teljes Conv2d(3,4,3) 108+4=112108+4=112 1⋅4⋅9⋅3⋅9=9721\cdot4\cdot9\cdot3\cdot9=972
Depthwise Conv2d(3,3,3,groups=3) 27+3=3027+3=30 1⋅3⋅9⋅1⋅9=2431\cdot3\cdot9\cdot1\cdot9=243
Pointwise Conv2d(3,4,1) 12+4=1612+4=16 1⋅4⋅9⋅3=1081\cdot4\cdot9\cdot3=108
Separable összeg 39+7=4639+7=46 351351

Bias nélkül a súlyarány 39/108=0,361139/108=0{,}3611, a MAC-arány 351/972=0,3611351/972=0{,}3611, pontosan 14+19\frac14+\frac19. A bias-t is tartalmazó paraméterarány 46/112≈0,41146/112\approx0{,}411, tehát a bias elhanyagolása itt nem ártalmatlan.

19.1.5 Labor: kis blokk és kézi költségszámolás

A labor egyetlen függvénnyel számolja ki tetszőleges nn.Conv2d paraméter- és MAC-költségét a fenti képletekből, és a bemeneti térbeli méretből. A kód a lab/n073_lab.py fájlba kerül; a gyökérkönyvtár a fejezet lab mappája.

# lab/n073_lab.py
# Futtatás: python n073_lab.py
# CPU, float32; a kimenet a képletekből számolt kontroll, nem futásidő-mérés.
import math
import torch
from torch import nn

def out_len(L, p, d, k, s):
    return math.floor((L + 2*p - d*(k-1) - 1)/s) + 1

def count_conv(conv, N, H, W):
    # Csak forward cross-correlation Conv2d; transposed conv nem tartozik ide.
    assert conv.in_channels % conv.groups == 0
    cin_per_group = conv.in_channels // conv.groups
    Ho = out_len(H, conv.padding[0], conv.dilation[0], conv.kernel_size[0], conv.stride[0])
    Wo = out_len(W, conv.padding[1], conv.dilation[1], conv.kernel_size[1], conv.stride[1])
    params = sum(p.numel() for p in conv.parameters())  # súly + bias
    mac = N * conv.out_channels * Ho * Wo * cin_per_group * conv.kernel_size[0] * conv.kernel_size[1]
    return params, mac, (Ho, Wo)

device = torch.device("cpu")
dtype = torch.float32

full = nn.Conv2d(3, 4, 3, stride=1, padding=0, dilation=1, groups=1, bias=True).to(device)
dw   = nn.Conv2d(3, 3, 3, stride=1, padding=0, dilation=1, groups=3, bias=True).to(device)
pw   = nn.Conv2d(3, 4, 1, stride=1, padding=0, dilation=1, groups=1, bias=True).to(device)

pF, mF, shapeF = count_conv(full, 1, 5, 5)
pD, mD, _ = count_conv(dw, 1, 5, 5)
pP, mP, _ = count_conv(pw, 1, 5, 5)
print("full      ", pF, mF, shapeF)
print("dw        ", pD, mD)
print("pw        ", pP, mP)
print("sep ossz  ", pD+pP, mD+mP)
print("MAC arany ", (mD+mP)/mF)
print("sulyarany bias nelkul ", (3*9 + 4*3)/(4*3*9))

with torch.no_grad():
    Y = pw(dw(torch.zeros(1, 3, 5, 5, dtype=dtype, device=device)))
print("output shape:", tuple(Y.shape))

Várható, képletből számolt kimenet (a kézirat ezt nem futtatta; a tanulólabor futtatja és jegyzi a tényleges értékeket):

full       (112, 972, (3, 3))
dw         (30, 243)
pw         (16, 108)
sep ossz   (46, 351)
MAC arany  0.3611111111111111
sulyarany bias nelkul  0.3611111111111111
output shape: (1, 4, 3, 3)

Ellenőrzés és értelmezés. A két arány bias nélkül az ötödik tizedesjegyig egyezik a 14+19\frac14+\frac19 értékkel; a bias-os paraméterarány különbözik, ahogy a megjegyzés mondta. Az output shape (1,4,3,3)(1,4,3,3) megegyezik a teljes réteg kimenetével, tehát a térbeli illesztés teljesül. A számítás nem futásidő-mérés: a count_conv csak a zárt képleteket ismétli meg, így a numerikus egyezés a levezetés belső konzisztenciáját ellenőrzi, nem a könyvtár optimalizálását.

19.1.6 Feladatok

F1 — fogalmi (nehézség 1). Adja meg saját szavaival, miben korlátozott a depthwise réteg a teljes konvolúcióhoz képest, miért nevezzük a 1×11\times1-es réteget channel mixingnek, és miért nem „szeparálható” a szó matematikai tenzorszorzat-értelmében. Adjon ellenpéldát: 1×11\times1-es kernel groups=2 beállítással mely csatornák keverednek, melyek nem. Átadandó: legfeljebb egy oldal, képletekkel.

F2 — levezetési/bizonyítási (nehézség 2). Vezesse le a depthwise multiplier mm esetére a MAC-arányt, és határozza meg: kh=kw=3k_h=k_w=3 és Cout=16C_{out}=16 mellett mi a legkisebb pozitív egész mm, amelyre a separable blokk már nem csökkenti a MAC-et a teljes réteghez képest. Átadandó: lépésről lépésre levezetés és az mm értéke.

F3 — implementációs (nehézség 2). Egészítse ki a labor count_conv függvényét úgy, hogy hibát dobjon, ha in_channels % groups != 0, majd tesztelje három esettel: a labor full, dw, pw rétegén kívül egy Conv2d(6, 4, 3, groups=2) rétegen is, N=2N=2, H=W=10H=W=10 bemenettel. Átadandó: futtatható kód, assert-ekkel, és a várt egész MAC-értékek.

F4 — hibakeresési (nehézség 2). Az alábbi érvelés hibás: „A 3×33\times3-as separable blokk a teljes konvolúcióhoz képest 1/91/9-ére csökkenti a számítást, mert a pointwise 1×11\times1 elhanyagolható.” Lokalizálja a hibát, mutassa meg a fenti Cin=3C_{in}=3, Cout=4C_{out}=4 példán a tényleges arányt, és adjon olyan szélsőesetet (Cout=1C_{out}=1), ahol a separable blokk MAC-je nagyobb a teljesnél. Átadandó: az ok, a következmény és a javított állítás.

F5 — kísérleti/transzfer (nehézség 3). Tervezzen GlyphLab-protokollt, amely egy teljes konvolúciós blokk és egy depthwise separable blokk hatását hasonlítja össze egyeztetett MAC-keret mellett, a 17.4. Architektúra összehasonlítása kontrollált keretben matched-recipe elvét követve. Írja elő a hipotézist, a modellfejek azonos tartalmát, a scene_id szerinti splitet, a seed-készletet, a best-val-loss választást, a záró clean/korrupt tesztet és a következtetési határt. Futtatás nem elvárt. Átadandó: egyoldalas protokoll.

19.1.7 Megoldások és indoklás

F1. A teljes konvolúció kimeneti skalárja ∑c∑α,βK[q,c,α,β]X[…]\sum_c\sum_{\alpha,\beta}K[q,c,\alpha,\beta]X[\dots], tehát a csatorna- és térbeli indexek egyszerre, tetszőlegesen összekapcsolódnak. A depthwise rétegben az összegzés csak α,β\alpha,\beta szerint fut, és minden kimeneti csatorna pontosan egy bemeneti csatornához kötődik; a groups=C_in beállítás ezt a blokk-diagonális kapcsolatot valósítja meg. A pointwise 1×11\times1-es réteg ezzel szemben ugyanazon (i,j)(i,j) pozíció összes csatornáját keveri, de térben nem hat, ezért nevezzük csatornakeverésnek. A „separable” elnevezés itt operátorok szekvenciális szétválasztását jelenti, nem azt, hogy a 3×33\times3-as kernel két 3×13\times1+1×31\times3 kernelszorzatként állna elő; utóbbi tenzorszorzat-szeparálhatóság esetén a kernel rangja 1 volna. Ellenpélda: Conv2d(6, 4, 1, groups=2) a bemenetet két háromcsatornás csoportra osztja; a 0–2. csatornák keveredhetnek egymással, a 3–5. csatornák egymással, de a két csoport között nincs út, tehát ez nem teljes channel mixing.

F2. Az mm-es depthwise kimeneti csatornaszáma mCinmC_{in}, MAC-je N⋅mCin⋅HoutWout⋅khkwN\cdot mC_{in}\cdot H_{out}W_{out}\cdot k_hk_w. A pointwise bemenete mCinmC_{in} csatorna, MAC-je N⋅Cout⋅HoutWout⋅mCinN\cdot C_{out}\cdot H_{out}W_{out}\cdot mC_{in}. A teljes réteg MAC-je változatlan NCoutCinHoutWoutkhkwN\,C_{out}C_{in}H_{out}W_{out}k_hk_w. A hányadosból N,HoutWout,CinN,H_{out}W_{out},C_{in} kiesik:

Msep(m)Mfull=mCinkhkw+mCoutCinCoutCinkhkw=m(1Cout+1khkw).\frac{M_{sep}^{(m)}}{M_{full}} =\frac{mC_{in}k_hk_w+mC_{out}C_{in}}{C_{out}C_{in}k_hk_w} =m\left(\frac1{C_{out}}+\frac1{k_hk_w}\right).

A feltétel m(1/16+1/9)≥1m(1/16+1/9)\ge1, azaz m⋅25/144≥1m\cdot25/144\ge1, tehát m≥144/25=5,76m\ge144/25=5{,}76. A legkisebb pozitív egész megoldás m=6m=6. m=6m=6 esetén az arány 6⋅25/144=25/24>16\cdot25/144=25/24>1, tehát a separable változat több MAC-et igényel, mint a teljes réteg. Ez a szélsőeset mutatja, hogy a depthwise separable nem minden beállításban takarékos.

F3. A teljes függvény:

# lab/n073_f3.py — futtatás: python n073_f3.py
import math
import torch
from torch import nn

def out_len(L, p, d, k, s):
    return math.floor((L + 2*p - d*(k-1) - 1)/s) + 1

def count_conv(conv, N, H, W):
    if conv.in_channels % conv.groups != 0:
        raise ValueError("in_channels nem osztható groups értékkel")
    cin_per_group = conv.in_channels // conv.groups
    Ho = out_len(H, conv.padding[0], conv.dilation[0], conv.kernel_size[0], conv.stride[0])
    Wo = out_len(W, conv.padding[1], conv.dilation[1], conv.kernel_size[1], conv.stride[1])
    mac = N * conv.out_channels * Ho * Wo * cin_per_group * conv.kernel_size[0] * conv.kernel_size[1]
    return mac

full = nn.Conv2d(3, 4, 3); dw = nn.Conv2d(3, 3, 3, groups=3); pw = nn.Conv2d(3, 4, 1)
assert count_conv(full, 1, 5, 5) == 972
assert count_conv(dw,   1, 5, 5) == 243
assert count_conv(pw,   1, 3, 3) == 108
g2 = nn.Conv2d(6, 4, 3, groups=2)
# H=W=10, k=3, p=0, s=1, d=1 -> Hout=Wout=8; N=2; out=4; cin/group=3
assert count_conv(g2, 2, 10, 10) == 2*4*8*8*3*9
try:
    nn.Conv2d(5, 4, 3, groups=2)
except ValueError:
    print("group-oszthatósági hiba helyesen elkapva")
print("minden assert lefutott")

A várt MAC a grouped esetre 2⋅4⋅8⋅8⋅3⋅9=138242\cdot4\cdot8\cdot8\cdot3\cdot9=13824. A konstruktor már a modul létrehozásakor hibát dob a 5 % 2 esetben, ezért a count_conv assertje a közvetlen modulépítés előtti védőháló.

F4. A hiba a pointwise tag elhagyása: az érvelés csak a depthwise 1/khkw1/k_hk_w szorzóját nézi, és csendben CoutC_{out}-t a levezetés nélkül kezeli. A példában a teljes MAC 972, a depthwise 243, a pointwise további 108, így a tényleges arány 351/972=0,3611351/972=0{,}3611, nem pedig 1/9≈0,1111/9\approx0{,}111. A következmény túlzott megtakarítási ígéret. Cout=1C_{out}=1 esetén a teljes réteg MAC 1⋅1⋅9⋅1⋅3⋅9=2431\cdot1\cdot9\cdot1\cdot3\cdot9=243, a separable pedig 243+1⋅1⋅9⋅3=270243+1\cdot1\cdot9\cdot3=270? Várjunk: Cout=1C_{out}=1, pointwise 1×11\times1 MAC N⋅Cout⋅HoWo⋅Cin=1⋅1⋅9⋅3=27N\cdot C_{out}\cdot H_oW_o\cdot C_{in}=1\cdot1\cdot9\cdot3=27, tehát 243+27=270243+27=270; az arány 270/243=10/9>1270/243=10/9>1. A javított állítás: a separable blokk akkor és csak akkor csökkenti a MAC-et az m=1m=1 esetben, ha 1Cout+1khkw<1\frac1{C_{out}}+\frac1{k_hk_w}<1, ami Cout>1C_{out}>1 és khkw>1k_hk_w>1 mellett teljesül. Az F4 hibakeresési megoldás tehát a hiányzó pointwise tételt azonosítja.

F5 lehetséges protokoll (terv, nem futás). Hipotézis: azonos MAC-keretben a depthwise separable blokk validációs cross-entropyja nem marad el szisztematikusan a teljes konvolúciós blokkétól a GlyphLab háromosztályos feladatán. Felépítés: közös stem Conv2d(1,8,3,stride=2,padding=1); majd A blokk: depthwise separable, B blokk: teljes conv, úgy választva csatornaszámokat, hogy a stem és a közös fej kivételével count_conv szerinti MAC-keret 5%-on belül egyezzen; fej mindkettőn azonos AvgPool+lineáris 3 logit. Adat: GlyphLab, train/val/test a megadott split szerint, mintavételi egység scene_id; augmentáció és egyszerű flip kizárt vagy mindkét ágon azonos. Választás: 5 seed (20261020, +1, +2, +3, +4), batch 64, AdamW, 30 epoch, early-stop a best val lossra checkpointol; a tesztet csak a választott checkpointon futólag értékeljük, clean és páros corrupt kimenettel. Metrika: per-image accuracy és macro-tényezős 95% CI a scene-szintű bootstrapből (lásd 5.4. Függő képek, seedek és resampling). Következtetési határ: a toy adat és a kis CPU-s környezet miatt az eredmény nem általánosítható természetes képekre vagy GPU-kernel-hatékonyságra.

19.1.8 Tipikus tévedés, önellenőrzés és visszahívás

A leggyakoribb tévedés: „Kevesebb MAC automatikusan kisebb valós futási időt jelent.” A MAC-arány a fenti levezetésből következik, a futásidő viszont a hardver, kernelimplementáció, memória-hozzáférés és batchméret függvénye. Ellenpélda-váz: képzeljünk el egyetlen csatornán, nagy térbeli képen egy naiv Python-listás depthwise hurkot, mellette egy 64 csatornás pointwise 1x1-et, amelyet optimalizált GEMM hív meg; a depthwise MAC-száma lehet sokkal kisebb, a valós futás mégis a rossz aritmetikai intenzitású depthwise hurokban telhet el. Ez gondolatkísérlet, nem a jelen kéziratban mért állítás; a 24.2. CPU/GPU profiling és helyes időmérés mérési protokollja dönti el a konkrét gépen. A helyes állítás tehát megfordítva sem igaz: a MAC-arány csak számítási keret, nem sebességgarancia.

Önellenőrző kérdés és válasz. Milyen CoutC_{out} és kernelméret mellett nem csökken a MAC? A 4.4. állítás alapján nem csökken, ha 1Cout+1khkw≥1\frac1{C_{out}}+\frac1{k_hk_w}\ge1. Pozitív egészekre ez pontosan a Cout=1C_{out}=1 eset; ekkor a depthwise + pointwise összeg nagyobb, mert a pointwise új költséget ad a csatornakeveréshez, miközben a teljes réteg a kevés kimeneti csatorna miatt eleve olcsó. Aki az arányt Cout=1C_{out}=1 mellett is megtakarításként közli, azonnal ellenőrizhető hibát követ el.

Visszahívás. A 15.1. Súly- és biasgradiens alfejezetben levezetett súlygradiens-összegzés a depthwise blokkban is érvényes: minden kimeneti csatorna pontosan egy bemeneti csatornán dolgozik, de a súlygradienshez a batch és térbeli felhasználási helyek szerint továbbra is összeadódnak a hozzájárulások; az osztás hiba volna. A 18.1. Reziduális blokk és identitásút reziduális blokkja miatt, ha a separable blokkot shortcut mellett használjuk, a kimeneti csatornaszám illesztésére adott esetben 1×11\times1-es projekció kell, ami további pointwise költség. Végül a 7.1. Entrópia, cross-entropy és KL cross-entropy felbontása emlékeztet arra, hogy a modellválasztást a validációs H(p,q)H(p,q) dönti el; a paraméter- vagy MAC-megtakarítás önmagában nem minőségi garancia.

19.1.9 Rövid összefoglaló

A depthwise konvolúció groups=C_in beállítással minden bemeneti csatornát külön szűr, mm multiplier esetén mCinmC_{in} köztes csatornát adva. A pointwise 1×11\times1-es réteg azonos térbeli pozíció csatornáit keveri; a kettő kompozíciója a depthwise separable blokk, amely a térbeli és csatornakeverést szétválasztja. A levezetett arány bias nélkül mind paraméterekre, mind MAC-re 1Cout+1khkw\frac1{C_{out}}+\frac1{k_hk_w}, mm esetén ennek mm-szerese. A példában ez 13/36≈0,36113/36\approx0{,}361; Cout=1C_{out}=1 esetén az arány meghaladja az 1-et, tehát a separable forma nem mindig takarékos. A MAC-megtakarítás nem bizonyít futásidő-csökkenést. A kódos ellenőrzés a képletek konzisztenciáját mutatja, a tényleges teljesítményt csak külön mérés igazolhatja.

19.1.10 Következő alkalmazás

A 19.2. MobileNet és inverted residual a MobileNetV2 inverted residual-blokkját építi erre a separable alapra: ott a pointwise réteg először növeli, majd a kimeneti pointwise csökkenti a csatornaszámot, lineáris bottleneck-et hagyva; a [P09] tanulmány MobileNetV2-tervezési elvei ebben a kontextusban jelennek meg. A 19.2. MobileNet és inverted residual ezekből oktatási célú, egyszerűsített blokkot épít.

19.1.11 Felhasznált források

A 4. állítás és a példák saját levezetések és saját számítások; a labor kimenete a képletekből előre számolt kontroll, nem a szerző által elvégzett futtatás.