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 ?
Legyen tanítóhalmaz, a belőle tanított modell, és a valódi regressziós cél. Egy rögzített pontban, ahol , , , és független a zajtól, a négyzetes hiba várható értéke három tagra bontható:
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 . A nagyobb á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 sugara -mel nő. A kapacitás nem azonos a paraméterszámmal, és nem ad önmagában számszerű jóslatot a teszthibára.
A penalty explicit korlátozást ad a veszteséghez. L2-regularizálás esetén a minimalizált cél
A gradiens . 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.
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.
Állítás (cáfolandó). Ha 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 modell, és mindegyik valós pontossága bármely iid tesztmintán. A validációs halmaz elemű. Minden modell predikciója ezen az egy mintán , és az változók függetlenek. A kiválasztott modell .
A kiválasztott modell validációs pontossága . Várható értéke
A tesztpontosság ezzel szemben minden modellre várható értékű, mert a modell valós pontossága , é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 , míg a tesztpontosság várhatóan . A különbség ; 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.
Kisebb eset: , , . Minden modell validációs pontossága , lehetséges értékei , , , rendre , , valószínűséggel. A maximum eloszlása:
Ezért , szemben a valós értékkel. A torzítás .
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.78125A GlyphLab adatokon a feladat egy rögzített költségű keresés
megtervezése. Az adat: data/images.npy
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):
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.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 , , esetre a legjobb validációs pontosság várható értékét, és hasonlítsd össze a 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 modell, validációs minta, esetén 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-. 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.
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 . Lehetséges értékek: , valószínűségek . A maximum eloszlása esetén:
Ebből: - , - , - , - .
Várható érték:
Numerikusan: , , . Így
A torzítás . A maximum várható értéke tehát messze a valós fölött van. Alakellenőrzés: a valószínűségek összege , a várható érték -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 fölött, a tesztpontosság átlaga 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 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:
metadata.csv
train/val/test oszlopa jelenetfüggetlen: egy jelenet mindkét nézete
azonos splitben van. Ezért a modellválasztás során a validation
pontosság független megfigyelési egysége a jelenet, nem a kép; a
bootstrap és a CI is jelenetszintű.| Modellcsalád | L2- | Konfigurációk |
|---|---|---|
| MLP 32 | 2 | |
| MLP 64 | 2 | |
| Kis CNN | 2 |
„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: mintán egy paraméterű, erős L2-regularizálással tanított modell lehet alulillesztett, míg egy 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ő.
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 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 tag közvetlenül hozzáadódik a VJP-hez.
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: , , esetén a várható maximum , míg a tesztpontosság . Ezért a tesztet csak a keresés lezárása után, egyszer értékeljük.