A 21.3. Dropout, súlyregularizálás és augmentáció egység három regularizáló eszközt választ szét: a dropoutot, a súlyregularizálást (weight decay) és az adataugmentációt, valamint tárgyalja a hozzájuk kapcsolódó label smoothingot. A három mechanizmus eltérő helyen avatkozik be: a dropout a modell belső aktivációit zajosítja, a weight decay determinisztikus büntetőtagot ad a célfüggvényhez, az augmentáció pedig a bemeneti eloszlást módosítja. Előismeret a 21.2. Learning rate és ütemezés lépésméret- és ütemezésfogalma, a 7.2. Softmax és többosztályos cross-entropy softmax/cross-entropy célja, valamint a 20.3. Preprocessing, domain shift és súlylicenc input-szerződés. Induló kérdés: adott egy aktivációvektor és megtartási valószínűség. Ha train módban a maszk , mi az inverted dropout kimenete? Eval módban mi a kimenet, és miért?
Legyen az aktivációtensor , ahol a batchméret, az adott réteg kimeneti dimenziója. A dropout megtartási valószínűsége , kihagyási valószínűsége . A dropout maszk minden eleme egymástól független Bernoulli-eloszlású:
A
tehát annak valószínűsége, hogy egy elemet megtartunk; a
dropout rate a
kihagyási valószínűség. A PyTorch nn.Dropout(p) argumentuma
a kihagyási valószínűség: p
,
és train módban a megtartott elemeket
-pel
szorozza [D12]. A két konvenció összekeverése gyakori hiba;
nemszimmetrikus kontroll:
-hoz
nn.Dropout(0.2) tartozik, a várható nullaarány 20%, a
megtartott elemek szorzója
.
A
határeset nn.Dropout(0).
Inverted dropout esetén a kimenetet a maszk mellett -pel osztjuk:
elemenkénti szorzással. A határeset az identitás; a kizárt, mert nullával osztanánk. Az a Hadamard-szorzat, alakja .
Tétel (inverted dropout feltételes torzítatlansága). Legyen rögzített aktivációtensor, és legyenek a maszk elemei független változók, függetlenek -tól. Ekkor minden indexpárra
Bizonyítás. A feltételes várható érték linearitását használjuk. Mivel a feltételben rögzített, és független tőle:
Az utolsó lépés a Bernoulli-eloszlás várható értékét használja.
A tétel jelentése: az inverted dropout a train módban sem torzítja el a réteg kimenetének várható értékét, csak zajt ad hozzá. A klasszikus, inverted nélküli dropout train alatt -t számol, eval alatt pedig -t; az inverted változat ezt a skálakülönbséget train módba hozza, így eval mód nem igényel külön szorzást.
A train/eval viselkedés tehát: train módban minden
forwardnál friss, független maszk generálódik; eval módban a modell a
determinisztikus
aktivációt adja, ami az inverted skálázás miatt éppen a feltételes
várható értéknek felel meg. A nn.Module
train() és eval() állapota vezérli ezt. A
BatchNorm szintén train/eval módot vált, de ott az ok a
statisztikakezelés: a normalizáló réteg eval alatt futó átlagot és
varianciát használ, a dropout viszont egyszerűen eltávolítja a
véletlent. A kettő nem ugyanaz a mechanizmus, és nem szabad
összemosni.
A dropout célja heurisztikus: minden neuron kénytelen más neuronokkal együttműködve hasznos reprezentációt adni, mert bármelyik társa véletlenszerűen hiányozhat. Ez redundáns, kevésbé egyedi tanulópéldára támaszkodó reprezentációt ösztönöz. A dropout nem növeli a hipotézisosztály expresszivitását; az approximációs kérdés (9.3. Expresszivitás és approximációs állítások) és a tanítási pálya itt is különválik.
A feltételes variancia egy rövid kiegészítő levezetéssel megmutatja, mekkora zajt visz a dropout a forwardba. Mivel ,
Minél kisebb
,
azaz minél nagyobb a PyTorch p argumentuma, annál nagyobb a
relatív zaj. Ez magyarázza, miért válik zajossá a train loss dropout
alatt.
A weight decay a loss-hoz adott négyzetes büntetőtag. Legyen a regularizálandó súlyparaméterek halmaza; a bias-okat tipikusan kihagyjuk. A teljes célfüggvény
ahol a súlycsökkentési együttható, a Frobenius-norma. A tag gradiense minden -re , ezért a sima SGD frissítése
Ez a lépés kis relatív arányban zsugorítja a súlyt, ezért nevezik weight decaynek.
Torch környezetben az SGD(..., weight_decay=λ) a fenti
L2-tagot valósítja meg. Az Adam és AdamW között azonban lényegi
különbség van. Ha a
gradienst az Adam adaptív normalizálásán küldjük keresztül, a
regularizáló tag hatása paraméterenként és időben változó; nem egyenlő
azzal, mintha a súlyt minden lépésben
tényezővel szoroznánk. A decoupled weight decay ezt a
zsugorítást leválasztja az adaptív gradiensfrissítésről:
A [P02] szerzői ezt a szétválasztást javasolják, és az így kapott AdamW-t mutatják be. A mechanizmusbeli különbség magából az Adam frissítési szabályából és a fenti definícióból levezethető, ezért azt a könyv itt bizonyított állításként kezeli; azt, hogy a decoupled változat mely feladatokon és mennyivel jobb, empirikus állításként nem terjesztjük ki.
A
tipikus keresési tartománya gyakorlati heurisztikaként
és
között szokott lenni, de ez nem tétel: a megfelelő érték adattól és
modelltől függ. A PyTorch torch.optim aktuális
argumentumait a használt könyvtárverzió dokumentációjához és a
telepített implementációhoz kell igazítani [D06].
A label smoothing a többosztályos tanítási célt lágyítja. Az int64 osztálycímke egy-hot vektora . A simított cél
ahol . Ellenőrzés: az elemek nemnegatívak, és
tehát valószínűségeloszlás. A cross-entropy cél , ahol a logitsokból számolt predikció. Az határeset a szokásos cross-entropy az int64 cél felett; a modell kimenete továbbra is logits, a [D07] loss-szerződésnek megfelelően.
A smoothing hatása heurisztikus: a degenerált egy-hot célhoz tartozó
veszteség akkor lenne nulla, ha a helyes logit minden másik fölé
korlátlanul kinőne. A simított cél ezt megakadályozza, mert a helyes
osztályhoz tartozó
,
a többi osztályra pedig
;
a minimumhoz a logitoknak véges különbséget kell tartaniuk. Ez gyakran
nyugodtabb kalibrációt ad, de nem bizonyított, hogy minden adatkészleten
javít; heurisztikaként kell kezelni. A torch
CrossEntropyLoss újabb kiadása label_smoothing
argumentumot is kínál; a fogalom implementálásához azonban elég a fenti
képlet, így a levezetés nem függ az API-tól.
A data augmentation a tanítási bemenetek véletlen, címkemegőrző transzformációja. A feltétel a label-megőrzés: a transzformált képhez ugyanaz az cél tartozik, mint az eredetihez. Ez a 22.2. Címkemegőrző transzformációk szerződés közvetlen alkalmazása. GlyphLab osztályozásnál a címke az orientáció, ezért például enyhe eltolás, kis Gauss-zaj vagy fényességskálázás megengedett, a -os forgatás viszont nem címkemegőrző: a vertical és horizontal osztályt felcseréli. A diagonal osztály ráadásul a generátorszerződés szerint csak az egyik ferde irányt tartalmazza, így a tükrözés is új célértelmezést igényelne.
Az augmentáció tehát a data oldalon bővíti az effektív mintát; a dropout a modell belső aktivációit zajosítja; a weight decay determinisztikus paraméterbüntetést ad. Validációs és teszt spliten a kiértékeléshez nem alkalmazunk véletlen augmentációt, mert a metrikának reprodukálhatónak és a kiértékelt modellhez kötöttnek kell lennie.
Vegyük az induló kérdés vektorát, mellett. Ha , akkor az inverted dropout kimenete
Egy másik maszkkal, esetén . A két realizáció átlaga , ami nem egyezik a várható értékkel; a várható érték nem egyetlen minta átlaga, hanem az eloszlás feletti átlag. A negyedik elem mindkét esetben nulla, mert ; a dropout a nulla aktivációt nem tudja zajossá tenni, ami a varianciaképlettel is összhangban van.
A minimalista NumPy-ellenőrzés:
import numpy as np
rng = np.random.default_rng(20261020)
h = np.array([2.0, -1.0, 3.0, 0.0], dtype=np.float32)
p_keep = np.float32(0.5) # megtartási valószínűség
mask = (rng.random(h.shape, dtype=np.float32) < p_keep).astype(np.float32)
out = mask * h / p_keep
print(f"mask={mask}, out={out}")
# Ellenőrzés: a 4. elem mindig 0, a skála 1/p_keep = 2.
# PyTorch-megfelelő: torch.nn.Dropout(p=1 - p_keep), mert ott p a kihagyás.A seed, dtype és a p_keep numerikus típusa együttesen
rögzíti a reprodukálhatóságot; más NumPy-verzió bitazonosságot nem ígér,
ugyanúgy, ahogy 20.3. Preprocessing, domain shift és
súlylicenc alfejezetben az input-szerződésnél láttuk.
A labor célja a három mechanizmus szétválasztása GlyphLab kis CPU-s
környezetben. A rendszer: data/images.npy alakja
float32, data/labels.npy int64, a split a
data/metadata.csv-ből jön. A modell egy kis CNN:
A bemenet kizárólag a képtensor; a maszk és doboz nem bemenet. A kód a következő munkakönyvtárból futtatható:
# munkakönyvtár: lab/
# futtatás: python lab_n083_ablation.py
import numpy as np, torch, torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset
torch.manual_seed(20261020)
rng = np.random.default_rng(20261020)
device = torch.device("cpu")
images = np.load("data/images.npy").astype(np.float32) # (360,1,24,24)
labels = np.load("data/labels.npy").astype(np.int64) # (360,)
meta = np.genfromtxt("data/metadata.csv", delimiter=",", dtype=None, names=True)
train_idx = np.where(meta["split"] == "train")[0]
val_idx = np.where(meta["split"] == "val")[0]
Xtr = torch.from_numpy(images[train_idx])
ytr = torch.from_numpy(labels[train_idx])
Xva = torch.from_numpy(images[val_idx])
yva = torch.from_numpy(labels[val_idx])
class TinyCNN(nn.Module):
def __init__(self, p_drop=0.0): # p_drop = nn.Dropout argumentuma
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 16, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(16, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2))
self.head = nn.Sequential(nn.Flatten(), nn.Linear(32*6*6, 3))
self.drop = nn.Dropout(p_drop) if p_drop > 0 else nn.Identity()
def forward(self, x):
z = self.features(x)
z = self.drop(z)
return self.head(z)
def evaluate(model, X, y):
model.eval()
with torch.no_grad():
out = model(X)
return (out.argmax(1) == y).float().mean().item()
def train_one(cfg, Xtr, ytr, Xva, yva):
# cfg: (p_drop, use_adamw, wd, label_smooth, use_aug)
model = TinyCNN(p_drop=cfg[0]).to(device)
opt = (torch.optim.AdamW if cfg[1] else torch.optim.Adam)(
model.parameters(), lr=1e-3, weight_decay=cfg[2])
lossf = nn.CrossEntropyLoss(label_smoothing=cfg[3])
ds = TensorDataset(Xtr, ytr)
for ep in range(15):
model.train()
for xb, yb in DataLoader(ds, batch_size=32, shuffle=True):
if cfg[4]:
xb = xb + 0.02 * torch.randn_like(xb) # kis zaj, címkemegőrző
sh = np.random.randint(-2, 3, size=2)
xb = torch.roll(xb, shifts=tuple(sh), dims=(2, 3))
opt.zero_grad()
loss = lossf(model(xb), yb)
loss.backward()
opt.step()
return evaluate(model, Xva, yva)
configs = {
"baseline": (0.0, False, 0.0, 0.0, False),
"+dropout": (0.5, False, 0.0, 0.0, False),
"+weight_decay": (0.0, True, 1e-4, 0.0, False),
"+label_smooth": (0.0, False, 0.0, 0.1, False),
"+augment": (0.0, False, 0.0, 0.0, True),
}
for name, cfg in configs.items():
acc = train_one(cfg, Xtr, ytr, Xva, yva)
print(f"{name:14s} val_acc={acc:.3f}")A kiértékelés a legjobb validációs checkpoint nélkül, a 15. epoch végi paramétereivel történik; ez csak mechanizmus-probának való, nem modellválasztásnak. Az alábbi táblázat jelölt szemléltetés, nem ebben a kézirati lépésben elvégzett futás; a tényleges méréshez a fenti szkriptet kell futtatni és a nyers val_acc értéket naplózni.
| Konfiguráció | val_acc (jelölt) | Értelmezés |
|---|---|---|
| baseline | 0,62 | gyenge, zajos kis modell |
| +dropout | 0,63–0,68 | erős túlillesztésnél javulhat |
| +weight_decay | 0,64 | közepes regularizáló |
| +label_smooth | 0,65 | cél lágyítása |
| +augment | 0,66–0,70 | adatoldali bővítés; nem bitazonos |
A corrupt tesztet itt nem használjuk: a modellválasztás a val spliten történik, a corrupt teszt csak befagyasztott modell után értékelhető, ahogy a GlyphLab-szerződés előírja.
F1 (fogalmi, nehézség 1). Magyarázza el, miért nem ugyanaz a train/eval viselkedés oka a dropoutnál és a BatchNormnál. Adjon egy-egy konkrét példát a viselkedésre. Átadandó: legfeljebb 15 soros magyarázat, a két állapot különválasztott okaival.
F2 (levezetési, nehézség 2). Adott rögzített vektor, . Vezesse le az inverted dropout kimenet feltételes varianciáját: . Nevezze meg a felhasznált varianciatulajdonságot, és ellenőrizze, hogy esetén a variancia nulla. Átadandó: minden lépés, feltételek és szélsőeset-kontroll.
F3 (implementációs, nehézség 1). Írjon saját
inverted_dropout(x, p_keep, rng) függvényt NumPy-ban, amely
float32 bemenetet,
megtartási valószínűséget és seedelt Generator objektumot
fogad, maszkot generál, elvégzi az
skálázást, és shape-asserttel ellenőrzi a kimenetet. Tesztelje a
,
példán; a seed legyen 42. Adja meg azt is, milyen argumentumú
nn.Dropout felel meg a függvénynek. Átadandó:
teljes függvénykód, futási kimenet, shape-ellenőrzés, magyarázat a
határeset viselkedéséről.
F4 (hibakeresési, nehézség 2). Az alábbi kódrészlet egy hibás dropout-implementációt mutat. Azonosítsa a hibát, mondja meg, milyen következménye van train és eval módban, javítsa, és adja meg a javítás utáni ellenőrző kimenetet a , esetre.
class WrongDropout:
def __init__(self, p_keep):
self.p_keep = p_keep
def forward(self, x, rng):
mask = (rng.random(x.shape) < self.p_keep).astype(float)
return mask * xÁtadandó: hiba oka, következmény, javított kód, a javítás utáni egy konkrét kimenet.
F5 (kísérleti/transzfer, nehézség 3). Tervezzen olyan ablatív kísérletet GlyphLab-on, amely a dropout, a weight decay és az augmentáció hatását egyenként méri anélkül, hogy a corrupt tesztet modellválasztásra használná. Határozza meg a baseline modellt, a megfigyelési egységet, a splitet, a seedet, a metrikát, a rögzített tényezőket és az érvényességi korlátot. Átadandó: protokollterv és indoklás, legfeljebb 20 sor.
F1. A dropout train módban friss Bernoulli-maszkot alkalmaz, és az inverted skálázással a feltételes várható értéket torzítatlanul hagyja; eval módban a maszkot eltávolítja, mert a determinisztikus éppen a várható érték. A BatchNorm viszont train módban a minibatch átlagával és varianciájával normalizál, és futó statisztikát frissít; eval módban ezeket a futó statisztikákat használja, hogy a kimenet ne függjön a batch összetételétől. A közös pont a modulállapot-váltás, az ok és a mechanizmus azonban különböző: véletlen eltávolítás, szemben a statisztikai normalizálás batchfüggetlenítésével.
F2. A varianciatulajdonság: konstans mellett. Itt , , . A Bernoulli-variancia . Ezért
Szélsőeset: mellett , a variancia nulla, a maszk konstans 1, a kimenet determinisztikus. Feltételek: , Bernoulli(), független a feltételtől. Az speciális esetben a variancia nulla, a nulla aktiváció nem zajosodik.
F3. Függvény:
import numpy as np
def inverted_dropout(x, p_keep, rng):
assert x.dtype == np.float32, "float32 bemenet kötelező"
assert isinstance(p_keep, float) and 0.0 < p_keep <= 1.0
mask = (rng.random(x.shape, dtype=np.float32) < np.float32(p_keep)).astype(np.float32)
out = mask * x / np.float32(p_keep)
assert out.shape == x.shape and out.dtype == np.float32
return out
rng = np.random.default_rng(42)
x = np.array([2.0, -1.0, 3.0, 0.0], dtype=np.float32)
print(inverted_dropout(x, 0.5, rng))
# lab-profil (NumPy 2.3.5) kimenete: [ 4. -0. 0. 0.]; a -0. a -1*0 float-előjeleA p_keep paraméter float, a bemenet float32; a
PyTorch-megfelelő nn.Dropout(p=1 - p_keep); az osztás
float32-ben végzett, ezért shape és dtype garantált. A
határesetben (PyTorchban nn.Dropout(0)) a maszk minden
eleme 1, a kimenet azonos a bemenettel, de a maszkgenerálás költsége
megmarad; implementációban érdemes lehet
esetén rövidre zárni, ez azonban hatékonysági döntés, nem helyességi
feltétel.
F4. A hiba: a függvény nem skáláz
-pel.
Következmény: train módban a kimenet várható értéke
lesz, nem
,
ezért eval módban a determinisztikus
torzítatlan ugyan, de a train alatti várható aktivációk skálája eltér az
eval módétól; a tanult súlyok a lefojtott skálához igazodnak, és eval
alatt a réteg kimenetei túl nagyok lesznek. Javítás:
return mask * x / self.p_keep. Ellenőrzés a
,
-vel:
ha
,
a javított kimenet
;
a hibás kimenet
lett volna, amelynek várható értéke
.
F5. Tervvázlat: a baseline a labor TinyCNN-je, Adam
lr
,
seed 20261020, batch 32, 15 epoch, metrika a val split accuracy. A
megfigyelési egység a val képszám, de modellválasztásnál a val loss a
checkpoint-kritérium. Rögzített tényezők: split a metadata.csv-ből,
input NCHW float32 [0,1], nincs corrupt teszt a választásban. Egyetlen
tényező változik futásonként: dropout nn.Dropout(0.5), azaz
,
vagy AdamW
,
vagy zaj/eltolás augmentáció. Mindegyik futást legalább 3 seeddel
ismételve, az eredményt seedenkénti pontosság-mediánnal és szórással
jelentjük. Korlát: a GlyphLab toy adat, az eredmény nem általánosít
természetes képre; a corrupt tesztet csak a kiválasztott befagyasztott
modell páros kiértékelésére használjuk.
A gyakori tévedés: „A dropout mindig javítja a validációt.” Ez nem igaz. A dropout csökkenti az effektív kapacitást és növeli a tanítójel zaját, ezért ha a modell eleve underfit, a hozzáadás tovább ront. Szemléltető ellenpélda: GlyphLab-on egyetlen lineáris fej közvetlenül a pixeleken, 64 rejtett neuron nélkül, mindössze paraméterrel; a train accuracy is alacsony, a modell nem overfit. Ha erre dropoutot kapcsolunk -tel, a train and val accuracy is csökken, mert a tanítójelet is elfojtjuk, miközben nem volt redundáns kapacitás, amit regularizálni kellett volna. A dropout tehát modellkapacitáshoz és adatskálához mért eszköz; a „mindig segít” állítás cáfolata már az underfit eset.
Ellenőrizze a tétel lépéseit: (1) a feltételes várható érték
linearitása alkalmazható-e, ha a maszk független a feltételtől? (2) Az
eredmény
alakú-e mindkét oldalon? (3) A varianciaképletben
(nn.Dropout(0)) esetén a maszk szórása nulla, a kimenet
determinisztikus? (4) A weight decay célfüggvényében a
konvenció gradiense valóban
?
(5) A label smoothing célvektor összege 1 marad-e minden
esetén? Ha bármelyik kérdésre nemleges a válasz, a megfelelő
levezetéshez térjen vissza, és keresse meg az indexhibát.
Korábbi fogalom visszahívása: a 9.3. Expresszivitás és approximációs állítások approximációs tételből azt láttuk, hogy az expresszivitás nem ígér taníthatóságot. A dropout és a weight decay az optimalizálási pályát és az effektív hipotézisteret alakítja, nem az approximációs kapacitás elméleti maximumát; a kettő különválasztása itt is kötelező.
A dropout elemenkénti Bernoulli-maszkkal nulláz aktivációkat train módban, és az inverted skálázás révén a feltételes várható érték torzítatlan marad; eval módban a maszk eltűnik. A weight decay a loss-hoz adott tag, amelynek gradiense ; az AdamW decoupled változata ezt a zsugorítást leválasztja az adaptív lépésről. A label smoothing a célvektort keveri az egyenletes eloszlással, az augmentáció címkemegőrző véletlen transzformációkkal bővíti a bemenetet. A három mechanizmus a modell belsejében, a célfüggvényben és a data oldalon hat; hatásuk nem univerzális törvény, hanem kísérletileg ellenőrizendő heurisztika.
A 21.4. Osztályarány, súlyozás és céleloszlás egység az osztályarány és céleloszlás kérdését tárgyalja: ott a label smoothing fogalma a súlyozott cross-entropy és a kiegyensúlyozatlan célok elemzéséhez kapcsolódik.