8.3 Kapacitás, regularizálás és modellválasztás

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

Ez az alfejezet a 8.2. Véges hipotézisosztály egyenletes korlátja véges hipotézisosztályra adott egyenletes hibakorlátját ülteti át gyakorlati döntési keretbe. A kérdés: ha több modellt tanítunk, és a legjobbat a validációs halmazon választjuk, mit mondhatunk a végső teszteredményről? Az előismeret: a Hoeffding-korlát és az uniókorlát (8.2. Véges hipotézisosztály egyenletes korlátja), a loss-szerződések (7.3. Bináris, multilabel és regressziós cél), valamint a gradiensalapú tanítás (4.3. Jacobi-mátrix, láncszabály és VJP). Induló becslés: tíz modellből a legjobb validációs pontosság várhatóan mennyivel haladja meg a valós pontosságot, ha mindegyik modell valódi pontossága 0,50{,}5?

8.3.2 Kapacitás és bias–variance

Legyen DD tanítóhalmaz, f̂D\hat f_D a belőle tanított modell, és ff a valódi regressziós cél. Egy rögzített xx pontban, ahol y=f(x)+εy=f(x)+\varepsilon, 𝔼[ε]=0\mathbb E[\varepsilon]=0, 𝕍[ε]=σ2\mathbb V[\varepsilon]=\sigma^2, és f̂D\hat f_D független a zajtól, a négyzetes hiba várható értéke három tagra bontható:

𝔼D[(f̂D(x)−y)2]=(𝔼D[f̂D(x)]−f(x))2+𝕍D[f̂D(x)]+σ2.\mathbb E_D[(\hat f_D(x)-y)^2] = (\mathbb E_D[\hat f_D(x)] - f(x))^2 + \mathbb V_D[\hat f_D(x)] + \sigma^2.

Az első tag a bias², a második a variance, a harmadik az irreducibilis zaj. Ez a felbontás csak négyzetes hibára érvényes; cross-entropyra nem ugyanez a képlet. A bias a modellcsalád átlagos közelítési hibája, a variance pedig a modell érzékenysége a konkrét tanítómintára.

A capacity a hipotézisosztály kifejezőképessége. A 8.2. Véges hipotézisosztály egyenletes korlátja jelölésében |ℋ|=M|\mathcal H|=M. A nagyobb MM általában csökkenti a bias-t, mert jobb közelítő függvény kerülhet a készletbe, de növeli a statisztikai hibát: az uniókorlát log(2M/δ)/(2n)\sqrt{\log(2M/\delta)/(2n)} sugara MM-mel nő. A kapacitás nem azonos a paraméterszámmal, és nem ad önmagában számszerű jóslatot a teszthibára.

8.3.3 Regularizálás: penalty és early stopping

A penalty explicit korlátozást ad a veszteséghez. L2-regularizálás esetén a minimalizált cél

J(W)=1N∑i=1Nℓ(f(xi;W),yi)+λ2∥W∥F2.J(W) = \frac1N\sum_{i=1}^N \ell(f(x_i;W), y_i) + \frac{\lambda}{2}\|W\|_F^2.

A gradiens ∇WJ=∇WR̂(W)+λW\nabla_W J = \nabla_W \hat R(W) + \lambda W. Ez a 4.3. Jacobi-mátrix, láncszabály és VJP alfejezetbeli láncszabály szerint az affin rétegekben ugyanúgy továbbterjed; a penalty hatása az, hogy nulla felé húzza a súlyokat, így szűkíti az elérhető függvények terét, azaz csökkenti az effektív kapacitást. Az AdamW súlycsökkenése nem azonos a loss-ba írt L2 Adam alatti hatásával; itt a közönséges SGD–L2 esetet tárgyaljuk.

Az early stopping implicit regularizálás: a tanítást a validációs hiba növekedése előtt leállítjuk. A modell nem éri el a tanítóhalmaz teljes illeszkedését, ezért a ténylegesen elért paramétertér-tartomány kisebb, mint amit a modellcsalád elvileg megengedne. Nincs zárt képlete, és a leállítási pont maga is a validációs halmaztól függ.

8.3.4 Validáció és beágyazott választás

A validáció a modellválasztáshoz használt, a tanításból kizárt adatrész. A beágyazott választás két ciklust jelent: a belső ciklus adott hiperparaméterrel tanít, és a belső validáció dönt az early stoppingról; a külső ciklus a hiperparamétereket a külső validációs pontszám alapján választja. A zárótesztet csak a legvégén, egyszer, a már rögzített modellen értékeljük. Ha a tesztet a keresés közben akár egyszer is használjuk, adaptív torzítást viszünk a végső becslésbe.

8.3.5 Ellenpélda: a legjobb validációs pontszám torzítása

Állítás (cáfolandó). Ha MM modell közül a validációs halmazon legjobb pontosságút választjuk, akkor a kiválasztott modell validációs pontossága torzítatlan becslése a tesztpontosságnak.

Ellenpélda. Legyen M=10M=10 modell, és mindegyik valós pontossága p=0,5p=0{,}5 bármely iid tesztmintán. A validációs halmaz nval=1n_{val}=1 elemű. Minden hih_i modell predikciója ezen az egy mintán Xi∼Bernoulli(0,5)X_i \sim \mathrm{Bernoulli}(0{,}5), és az XiX_i változók függetlenek. A kiválasztott modell ĥ=argmaxiXi\hat h = \arg\max_i X_i.

A kiválasztott modell validációs pontossága maxiXi\max_i X_i. Várható értéke

𝔼[maxiXi]=ℙ(maxiXi=1)=1−ℙ(mind Xi=0)=1−0,510=1023/1024≈0,9990.\mathbb E[\max_i X_i] = \mathbb P(\max_i X_i = 1) = 1 - \mathbb P(\text{mind } X_i=0) = 1 - 0{,}5^{10} = 1023/1024 \approx 0{,}9990.

A tesztpontosság ezzel szemben minden modellre 0,50{,}5 várható értékű, mert a modell valós pontossága 0,50{,}5, és a tesztminta független a validációs mintától. Tehát a kiválasztott modell validációs pontossága várhatóan 0,99900{,}9990, míg a tesztpontosság várhatóan 0,50{,}5. A különbség 0,49900{,}4990; ez a kiválasztási folyamat által okozott felfelé torzítás. A cáfolandó állítás hamis. A torzítás forrása nem a modellek hibája, hanem az, hogy a maximum operátor kiválasztja a validációs zaj kedvező irányú ingadozását.

8.3.6 Kézi számpélda és ellenőrző kód

Kisebb eset: M=3M=3, nval=2n_{val}=2, p=0,5p=0{,}5. Minden modell validációs pontossága Yi∼Binom(2,0,5)/2Y_i \sim \mathrm{Binom}(2, 0{,}5)/2, lehetséges értékei 00, 0,50{,}5, 11, rendre 1/41/4, 1/21/2, 1/41/4 valószínűséggel. A maximum eloszlása:

Ezért 𝔼[maxYi]=1⋅37/64+0,5⋅26/64=50/64=0,78125\mathbb E[\max Y_i] = 1 \cdot 37/64 + 0{,}5 \cdot 26/64 = 50/64 = 0{,}78125, szemben a 0,50{,}5 valós értékkel. A torzítás 0,281250{,}28125.

Az alábbi minimális kód ugyanezt a kézi számítást ellenőrzi közvetlen eloszlással; nem mért kimenet, hanem a fenti képletből számított érték.

# munkakonyvtar: labs/n031
# Nem futtatott ellenorzes; a szamitas a fenti kezzel levezetett ertekeket adja vissza.
from fractions import Fraction
from math import comb

M, n_val, p = 3, 2, Fraction(1, 2)

def binom_prob(n, k):
    return Fraction(comb(n, k)) * p**k * (1 - p)**(n - k)

# P(max <= v) = P(Y <= v)^M, v itt a pontossag (0, 0.5, 1)
def cdf_max(v):
    return sum(binom_prob(n_val, k) for k in range(int(v * n_val) + 1)) ** M

cdf_0 = cdf_max(0)                 # P(max = 0)
cdf_half = cdf_max(Fraction(1, 2)) # P(max <= 0.5)
cdf_1 = cdf_max(1)                 # P(max <= 1) = 1

p_0 = cdf_0
p_half = cdf_half - cdf_0
p_1 = cdf_1 - cdf_half
expected_max = p_0 * 0 + p_half * Fraction(1, 2) + p_1 * 1
print(p_0, p_half, p_1, expected_max, float(expected_max))
# Vart: 1/64, 26/64, 37/64, 50/64=0.78125

8.3.7 Labor: rögzített költségű modellválasztás érintetlen záróteszttel

A GlyphLab adatokon a feladat egy rögzített költségű keresés megtervezése. Az adat: data/images.npy (360,1,24,24)(360,1,24,24) float32 NCHW, data/labels.npy int64, data/metadata.csv a split oszloppal. A train/val/test halmazok jelenetszinten diszjunktak, azaz egy scene_id minden képe ugyanabba a részhalmazba kerül: 240/60/60 kép.

Protokoll (terv, nem mért eredmény):

  1. Rögzített keresési tér: rejtett méret {16,32}\{16, 32\}, L2-λ∈{0,10−4,10−3}\lambda \in \{0, 10^{-4}, 10^{-3}\}, összesen 6 konfiguráció.
  2. Belső ciklus: minden konfigurációt 30 epochig tanítunk a train halmazon, batch méret 32, SGD tanulási ráta 0,010{,}01, seed 2026102020261020. A belső validáció minden epoch végén a val halmazon számol pontosságot, és a belső legjobb epoch súlyát őrizzük meg.
  3. Külső választás: a 6 konfiguráció közül a belső legjobb val pontosság szerint választunk. Ha holtverseny van, a kisebb λ\lambda nyer.
  4. Érintetlen záróteszt: a kiválasztott konfiguráció belső legjobb súlyával egyszer kiértékeljük a test halmaz pontosságát. A test halmazt a keresés során semmilyen lépésben nem használjuk.
  5. Jelentés: a jegyzőkönyvbe kerül mind a 6 belső val érték, a kiválasztott konfiguráció, a test pontosság, valamint a seed és a környezet verziója.

Az alábbi vázlat a protokollt rögzíti; a tényleges futtatás a hallgató feladata, ezért itt nem közlünk mért kimenetet.

# munkakonyvtar: labs/n031
# Terv, nem lefuttatott ellenorzes. A hallgato a GlyphLab adatokkal futtathatja.
import numpy as np
import torch
import torch.nn as nn
from torch.utils.data import TensorDataset, DataLoader

seed = 20261020
torch.manual_seed(seed)
np.random.seed(seed)
device = torch.device("cpu")
dtype = torch.float32

images = np.load("../data/images.npy").astype(np.float32)
labels = np.load("../data/labels.npy").astype(np.int64)
meta = np.loadtxt("../data/metadata.csv", delimiter=",", skiprows=1, dtype=str)
# A metadata oszlopai: index, scene_id, view_id, label, split, xmin, ymin, xmax, ymax
# split oszlop indexe 4
train_idx = np.where(meta[:, 4] == "train")[0]
val_idx = np.where(meta[:, 4] == "val")[0]
test_idx = np.where(meta[:, 4] == "test")[0]

X_train = torch.tensor(images[train_idx], dtype=dtype, device=device)
y_train = torch.tensor(labels[train_idx], dtype=torch.long, device=device)
X_val = torch.tensor(images[val_idx], dtype=dtype, device=device)
y_val = torch.tensor(labels[val_idx], dtype=torch.long, device=device)
X_test = torch.tensor(images[test_idx], dtype=dtype, device=device)
y_test = torch.tensor(labels[test_idx], dtype=torch.long, device=device)

def evaluate(model, X, y):
    model.eval()
    with torch.no_grad():
        logits = model(X)
        pred = logits.argmax(dim=1)
        return (pred == y).float().mean().item()

# A keresesi ter 6 konfiguracio; itt csak a szerkezet latszik.
for hidden in [16, 32]:
    for lam in [0.0, 1e-4, 1e-3]:
        # modellt epiteni, tanitani, belso val legjobbat menteni
        # A reszletek: n044 tanitasi ciklus es n046 checkpoint.
        pass
# A kivalasztott modellt a test halmazon egyszer kiertekelni.

8.3.8 Feladatok

F1 (fogalmi, nehézség 1). Mi a különbség a validációs és a teszt halmaz szerepe között a beágyazott modellválasztásban? Adj egy konkrét forgatókönyvet, ahol a teszt halmaz keresés közbeni használata torzítja a végső pontosságbecslést. Átadandó: saját megfogalmazású, legalább öt mondatos válasz.

F2 (levezetési, nehézség 2). Vezesd le az M=5M=5, nval=3n_{val}=3, p=0,5p=0{,}5 esetre a legjobb validációs pontosság várható értékét, és hasonlítsd össze a 0,50{,}5 valós értékkel. Minden lépést indokolj. Átadandó: az eloszlás, a várható érték képlete és a numerikus eredmény.

F3 (implementációs, nehézség 2). Írj olyan Python-szkriptet, amely M=20M=20 modell, nval=5n_{val}=5 validációs minta, p=0,5p=0{,}5 esetén 1000010\,000 ismétléssel szimulálja a fenti kiválasztást, és kiírja a kiválasztott modell átlagos validációs pontosságát, valamint a tesztpontosság becsült átlagát. A scriptben seed, importok, dtype és futási parancs szerepeljen. Átadandó: a kód és a várható kimenet magyarázattal.

F4 (hibakeresési, nehézség 2). Az alábbi pszeudokód a legjobb konfigurációt keresi:

for config in grid:
    model = train(config, train_data)
    val_acc[config] = evaluate(model, val_data)
best_config = argmax(val_acc)
test_acc = evaluate(train(best_config, train_data + val_data), test_data)

Hibás-e? Ha igen, hol, mi a következmény, és hogyan javítod? Átadandó: a hiba oka, a torzítás mechanizmusa és a javított pszeudokód.

F5 (kísérleti/transzfer, nehézség 3). Tervezd meg a GlyphLab adatokra a modellválasztást úgy, hogy a keresési tér három modellcsaládot tartalmazzon: MLP 32 rejtett egységgel, MLP 64 rejtett egységgel, és egy kis CNN egy konvolúciós réteggel. Mindegyikhez L2-λ∈{10−4,10−2}\lambda \in \{10^{-4}, 10^{-2}\}. Határozd meg a splitet, a választási kritériumot, a teszt időzítését, és indokold, miért jelenetfüggetlen a felosztás. Átadandó: a protokoll szöveges leírása, a keresési tér táblázata, és az érvényességi korlát.

8.3.9 Megoldások és indoklás

F1. A validáció arra való, hogy a keresés során döntéseket hozzunk: hiperparamétert, epochot, modellcsaládot választunk. A teszt halmaz ezzel szemben a már lezárt modell egyszeri, torzítatlan külső értékelése. Ha a tesztet a kereséshez használjuk, a keresés adaptívan illeszkedik a tesztminta zajához; a kiválasztott modell tesztpontossága felfelé torzított becslés lesz a valódi általánosítási hibára. Példa: száz hiperparaméter-beállítást próbálunk, és minden körben a tesztpontosság alapján döntünk; a maximális tesztpontosság várhatóan a zaj miatt nagyobb a valódi pontosságnál.

F2. Minden modell validációs pontossága Yi∼Binom(3,0,5)/3Y_i \sim \mathrm{Binom}(3, 0{,}5)/3. Lehetséges értékek: 0,1/3,2/3,10, 1/3, 2/3, 1, valószínűségek 1/8,3/8,3/8,1/81/8, 3/8, 3/8, 1/8. A maximum eloszlása M=5M=5 esetén:

Ebből: - ℙ(max=0)=1/32768\mathbb P(\max = 0) = 1/32768, - ℙ(max=1/3)=(1/32)−(1/32768)=1023/32768\mathbb P(\max = 1/3) = (1/32) - (1/32768) = 1023/32768, - ℙ(max=2/3)=(16807/32768)−(1/32)=16807/32768−1024/32768=15783/32768\mathbb P(\max = 2/3) = (16807/32768) - (1/32) = 16807/32768 - 1024/32768 = 15783/32768, - ℙ(max=1)=1−16807/32768=15961/32768\mathbb P(\max = 1) = 1 - 16807/32768 = 15961/32768.

Várható érték:

𝔼[maxYi]=0⋅p0+13p1/3+23p2/3+1⋅p1.\mathbb E[\max Y_i] = 0 \cdot p_0 + \frac13 p_{1/3} + \frac23 p_{2/3} + 1 \cdot p_1.

Numerikusan: p1/3=1023/32768≈0,03122p_{1/3} = 1023/32768 \approx 0{,}03122, p2/3=15783/32768≈0,48166p_{2/3} = 15783/32768 \approx 0{,}48166, p1=15961/32768≈0,48712p_1 = 15961/32768 \approx 0{,}48712. Így

𝔼[maxYi]≈0,01041+0,32111+0,48712=0,81860.\mathbb E[\max Y_i] \approx 0{,}01041 + 0{,}32111 + 0{,}48712 = 0{,}81860.

A torzítás 0,81860−0,5=0,318600{,}81860 - 0{,}5 = 0{,}31860. A maximum várható értéke tehát messze a valós 0,50{,}5 fölött van. Alakellenőrzés: a valószínűségek összege 11, a várható érték [0,1][0,1]-ben van.

F3. Példakód:

# munkakonyvtar: labs/n031
# Szimulacio: M=20, n_val=5, p=0.5, 10000 ismetles.
# Futas: python sim_validation_bias.py
import numpy as np

rng = np.random.default_rng(20261020)
M, n_val, p, reps = 20, 5, 0.5, 10_000
val_max = np.empty(reps, dtype=np.float64)
test_acc = np.empty(reps, dtype=np.float64)

for r in range(reps):
    # validation predikciok: M x n_val, Bernoulli(p)
    pred = rng.random((M, n_val), dtype=np.float64) < p
    val_acc = pred.mean(axis=1)          # shape (M,)
    best = int(np.argmax(val_acc))       # a legjobb modell
    val_max[r] = val_acc[best]
    # tesztpontossag: egy ujabb Bernoulli(p) minta a kivalasztott modellre
    test_acc[r] = rng.binomial(1, p)

print("atlagos legjobb validation accuracy:", val_max.mean())
print("atlagos test accuracy:", test_acc.mean())

Várható kimenet: a validációs átlag körülbelül 0,80{,}8 fölött, a tesztpontosság átlaga 0,50{,}5 körül. A pontos érték függ a szimulációtól, de a torzítás iránya egyértelmű. Tolerancia: a tesztátlag 0,5±20,25/10000=0,5±0,010{,}5 \pm 2\sqrt{0{,}25/10\,000} = 0{,}5 \pm 0{,}01 intervallumban mozoghat nagy valószínűséggel.

F4. A kód hibás. Az utolsó sorban a train_data + val_data egyesített halmazon újratanítja a legjobb konfigurációt, majd a tesztet értékeli. Az első hiba: a tesztet nem a keresés során kiválasztott, rögzített modellen méri, hanem egy újratanított változaton; ez megsérti az érintetlen záróteszt elvét. A második hiba: a val_data tanításhoz való hozzáadása után a modell már nem ugyanaz, amelyet a validáció kiválasztott, tehát a tesztpontosság nem a kiválasztott modellre vonatkozik. A torzítás mechanizmusa: a teszt kiértékelése nem a validáció által kiválasztott állapoton történik, ezért a jelentett pontosság nem a kiválasztási protokoll végén rögzített modellé. Javítás: a keresés során minden konfigurációhoz mentsük a legjobb súlyt a belső validáció alapján, majd a választott konfiguráció mentett súlyát egyszer értékeljük a test halmazon. Javított pszeudokód:

for config in grid:
    model, best_state = train_with_early_stopping(config, train_data, val_data)
    val_acc[config] = evaluate(model, val_data)
    states[config] = best_state
best_config = argmax(val_acc)
test_acc = evaluate(states[best_config], test_data)

F5. A protokoll:

Modellcsalád L2-λ\lambda Konfigurációk
MLP 32 {10−4,10−2}\{10^{-4}, 10^{-2}\} 2
MLP 64 {10−4,10−2}\{10^{-4}, 10^{-2}\} 2
Kis CNN {10−4,10−2}\{10^{-4}, 10^{-2}\} 2

8.3.10 Gyakori tévedés

„A nagyobb kapacitású modell tesztpontossága rosszabb, mint a kisebbé, mert a nagy kapacitás mindig túlilleszt.” Ez nem következik. A kapacitás önmagában nem ad számszerű jóslatot a teszthibára; a tényleges hiba a minta méretétől, a loss típusától, a regularizálástól és az optimalizálástól is függ. Ellenpélda: n=10n=10 mintán egy 10610^6 paraméterű, erős L2-regularizálással tanított modell lehet alulillesztett, míg egy 55 paraméterű, regularizálatlan modell is túlilleszthet, ha a loss erősen hajtja. A 8.2. Véges hipotézisosztály egyenletes korlátja uniókorlátja csak a statisztikai hiba felső becslését növeli a kapacitással; ez nem jelenti azt, hogy a tényleges hiba szükségképpen nő.

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

Ellenőrizze, hogy az ellenpélda minden feltevése kimondott-e: a modellek valós pontossága, a validációs minták Bernoulli-eloszlása, a függetlenség, a maximum-kiválasztás. Ha bármelyik feltételt elhagyjuk, a cáfolat nem érvényes. Visszahívás a 8.2. Véges hipotézisosztály egyenletes korlátja uniókorlátjából: a 2Me−2nϵ22Me^{-2n\epsilon^2} tag mutatja, miért nő a statisztikai hiba a kapacitással; a mostani torzítás ennek a jelenségnek a véges validációs mintán megfigyelt párja. A 7.3. Bináris, multilabel és regressziós cél loss-szerződései arra emlékeztetnek, hogy a bias–variance felbontás négyzetes hibára szól, cross-entropyra más elemzés kell. A 4.3. Jacobi-mátrix, láncszabály és VJP láncszabálya a regularizált loss gradiensét adja meg: a λW\lambda W tag közvetlenül hozzáadódik a VJP-hez.

8.3.12 Rövid összefoglaló

A kapacitás a hipotézisosztály kifejezőképessége, amely a bias²–variance felbontásban a variance oldalt növeli. A penalty és az early stopping az effektív kapacitást korlátozza; a validáció a modellválasztás döntési eszköze. A beágyazott választás a belső tanítási és a külső keresési ciklust szétválasztja, a tesztet pedig érintetlenül hagyja. Az ellenpélda megmutatta, hogy sok próbából a legjobb validációs pontszám felfelé torzított becslése a tesztpontosságnak: M=10M=10, nval=1n_{val}=1, p=0,5p=0{,}5 esetén a várható maximum 0,9990{,}999, míg a tesztpontosság 0,50{,}5. Ezért a tesztet csak a keresés lezárása után, egyszer értékeljük.

8.3.13 Források