A 36.1. Állításból kísérleti terv egységben rögzített kísérleti terv most kapja meg a mérési bizonytalanság részét. A cél annak eldöntése, hogy két konfiguráció különbsége valódi hatás-e, vagy csupán a tanítási véletlen, azaz a seedek ingadozása. Szükséges előismeret a preregisztrált terv fogalma, a hypothesis, control és változó tényező megkülönböztetése. Induló becslés: öt seeddel futtatott kis CNN-en a legjobb és legrosszabb validációs pontosság különbsége gyakran több százalékpont; ha ennél kisebb hatást várunk, egyetlen futás nem dönt.
Egy seed-futás (seed run) egy teljes tanítási folyamat egy rögzített seeddel, változatlan kóddal, adatsplit-tel és hardveren. Az ismétlés független egysége (independent unit) itt a futás: a seedek egymástól független véletlen állapotokat indítanak, ezért az eredményeket egy közös „seed-populáció” mintájának tekintjük. Ez a populáció idealizáció: az adott hardveren, adaton és kódon értelmes; más hardveren más populációról beszélünk.
A GlyphLab scene_id-je itt nem a független egység, mert
a train/val/test split rögzített. A scene-alapú újramintavételezés az
adatbizonytalanságot mérné; a seed-ismétlés a tanítási véletlent. A
kettőt a szerződés szerint külön kell jelölni: a jelen egység csak a
seed-szórást vizsgálja, a prediktív bizonytalanság és a bootstrap más
fogalom.
Két konfiguráció legyen és . Párosított seedeken (paired seeds) azt értjük, hogy ugyanazt a seedet használjuk mindkét konfigurációhoz, így az -edik pár közös véletlen környezetet kap. A különbség
A mintavételi modell feltételei:
A párosítás előnye a varianciaképletből látszik. Ha a páron belüli korreláció, akkor
A párosított átlag becsült szórásnégyzete ezért , míg független minták különbségénél állna. Pozitív esetén — ami gyakori, mert egy „nehéz” seed mindkét konfigurációt rontja — a párosított becslés varianciája kisebb.
A becslők:
Tétel (párosított hatásintervallum, normális modell). Ha független minta, akkor
ahol a -kvantilist jelöli: . Következésképpen a hatásra vonatkozó -os konfidenciaintervallum
Bizonyítási státusz: a tétel standard valószínűségszámítási eredmény; a t-eloszlás a normális átlag és a független -eloszlású varianciabecslés hányadosából származik. A feltételeket és az ismételt mintavételi értelmezést a [S02] módszertani oldal tárgyalja. A normalitás itt közelítés, mert a pontosságkülönbség korlátos; kis -re az intervallumot nem szabad precíziós garanciaként kezelni.
Az ismételt mintavételi értelmezés: ha a teljes, seedes kísérletet sokszor megismételnénk új seedhalmazokkal, a kiszámított intervallumok körülbelül része tartalmazná -t. Azt nem állítja, hogy az igazi hatás valószínűséggel éppen a most kapott konkrét intervallumban van.
Legyen
a súlyregularizálás nélküli,
az AdamW weight_decay=1e-4 beállítású futás; a metrika
validációs pontosság arányban. Az öt párosított seed eredménye
szemléltető számítás, nem mért futás:
| seed | |||
|---|---|---|---|
| 1 | 0.80 | 0.81 | |
| 2 | 0.78 | 0.83 | |
| 3 | 0.84 | 0.85 | |
| 4 | 0.82 | 0.82 | |
| 5 | 0.81 | 0.84 |
A különbségvektor eleme:
| 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|
Átlaga . Az eltérések , négyzetösszegük , így , . A standard hiba . A kritikus értékkel a -os hatásintervallum
A különbség mértékegysége százalékpontban ugyanez: és százalékpont között. Az intervallum tartalmazza a -t, tehát ez negatív eredmény az előre rögzített „ jobb, mint ” hipotézisre nézve: a hatást ezzel az öt seeddel nem tudjuk megkülönböztetni a seed-zajtól. A felső határ körülbelül százalékpont: e küszöbnél nagyobb pozitív hatások nem szerepelnek a közölt 95%-os konfidenciaintervallumban a modellfeltevések mellett. Ugyanakkor a minta a százalékpontos javulást sem zárja ki.
A negatív eredmény (negative result) definíciója: az előre specifikált hatásirányra a konfidenciaintervallum tartalmazza a nullát, ezért a nullhipotézist nem vetjük el. Ez hiányzó bizonyíték (absence of evidence), nem a hatás hiányának bizonyítéka (evidence of absence). Ha a gyakorlatban csak a küszöbnél nagyobb javulás érdekes, akkor ekvivalencia-intervallumot vagy a CI és összevetését kell protokollba foglalni; a fenti intervallum például nem zárja ki a hatást sem.
A negatív eredményt ugyanúgy rögzíteni kell, mint a pozitívat: nyers táblázat, CI, kód és környezet. A kísérleti naplóban a negatív eredmény nem kudarc, hanem a keresési tér egy pontjának korrekt kiértékelése.
Ha konfigurációt vagy több, utólag kiválasztott hipotézist hasonlítunk, és a legkedvezőbb eredményt emeljük ki, a nyers intervallum már nem érvényes kiválasztáskorrekció nélkül. A seedek mint ismétlések száma önmagában nem jelent többszörös hipotézistesztet; akkor lép fel kiválasztási torzítás, ha a legkedvezőbb seed eredményét választjuk ki. A torzítás oka: a kiválasztás maga is véletlen változó. Ugyanez a helyzet, ha több hipotézist tesztelünk ugyanazon a kiértékelő halmazon. A családi hibavalószínűség annak valószínűsége, hogy legalább egy igaz nullhipotézist tévesen elvetünk.
Lemma (Boole–Bonferroni). Tetszőleges eseményekre
Bizonyítás. Két eseményre , mert a metszet valószínűsége nemnegatív; -ra teljes indukcióval. Ha minden egyedi teszt szintje , akkor az unió valószínűsége legfeljebb .
Példa: ha összehasonlítást végzünk és családi szintet akarunk, az egyedi intervallumhoz tartozik. A kézi példában , tehát a korrigált intervallum
A Bonferroni-korrekció konzervatív, de garantált felső korlát. A helyes gyakorlat a fő összehasonlítás előzetes kijelölése; a többi elemzés feltáró jellegét külön kell jelenteni.
A labor a 36.1. Állításból kísérleti terv
tervét követi: a változó tényező a súlyregularizálás, a kontroll
a weight_decay=0, a vizsgált
a weight_decay=1e-4; a metrika validációs pontosság; a
döntési szabály a fenti hatásintervallum. A seedlista előre rögzített:
20261020, 20261021, 20261022, 20261023, 20261024. A hardver
főút: CPU, float32, NCHW [0,1] bemenet,
int64 címke. A compute budget:
seed
konfiguráció
epoch, kis CPU-n néhány perc.
Inputok: data/images.npy, data/labels.npy,
data/metadata.csv. Futtatás előtt a
python quickcheck.py ellenőrzi a hash-t, alakot és splitet.
A következő szkript munkakönyvtára lab/:
# munkakönyvtár: lab/
# Futtatás: python n142_seed_repeats.py --seeds 20261020,20261021,20261022,20261023,20261024
import argparse, csv
from pathlib import Path
import numpy as np
import torch
from torch import nn
from torch.utils.data import DataLoader, Subset, TensorDataset
from scipy.stats import t as student_t
DATA = Path("data")
def load_split():
tr, va = [], []
with open(DATA / "metadata.csv", newline="") as f:
for row in csv.DictReader(f):
i = int(row["index"])
if row["split"] == "train":
tr.append(i)
elif row["split"] == "val":
va.append(i)
return np.asarray(tr, dtype=np.int64), np.asarray(va, dtype=np.int64)
class TinyCNN(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(
nn.Conv2d(1, 8, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(8, 16, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.Flatten(), nn.Linear(16 * 6 * 6, 3))
def forward(self, x):
return self.net(x)
def train_eval(seed, X, y, tr_idx, va_idx, weight_decay, epochs=5, lr=1e-3):
torch.manual_seed(seed) # CPU float32 főút; ez adja a párosítást
model = TinyCNN()
opt = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=weight_decay)
ds = TensorDataset(torch.from_numpy(X), torch.from_numpy(y))
dl = DataLoader(Subset(ds, tr_idx), batch_size=16, shuffle=True)
for _ in range(epochs):
model.train()
for xb, yb in dl:
opt.zero_grad()
loss = nn.functional.cross_entropy(model(xb), yb)
loss.backward()
opt.step()
model.eval()
with torch.no_grad():
xv = torch.from_numpy(X[va_idx])
yv = torch.from_numpy(y[va_idx])
acc = (model(xv).argmax(1) == yv).float().mean().item()
return acc
def paired_ci(diffs, alpha=0.05):
diffs = np.asarray(diffs, dtype=np.float64)
m = diffs.size
mean_d = float(diffs.mean())
sd = float(diffs.std(ddof=1))
se = sd / np.sqrt(m)
tcrit = float(student_t.ppf(1 - alpha / 2, df=m - 1))
return mean_d, se, mean_d - tcrit * se, mean_d + tcrit * se, m - 1
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--seeds", default="20261020,20261021,20261022,20261023,20261024")
ap.add_argument("--epochs", type=int, default=5)
ap.add_argument("--alpha", type=float, default=0.05)
ap.add_argument("--out", default="")
args = ap.parse_args()
seeds = [int(s) for s in args.seeds.split(",")]
X = np.load(DATA / "images.npy").astype(np.float32) # (360,1,24,24)
y = np.load(DATA / "labels.npy").astype(np.int64) # (360,)
tr_idx, va_idx = load_split()
rows = []
for s in seeds:
a = train_eval(s, X, y, tr_idx, va_idx, weight_decay=0.0, epochs=args.epochs)
b = train_eval(s, X, y, tr_idx, va_idx, weight_decay=1e-4, epochs=args.epochs)
rows.append((s, a, b, b - a))
print(f"seed={s} A={a:.4f} B={b:.4f} d={b-a:+.4f}")
mean_d, se, low, high, df = paired_ci([r[3] for r in rows], args.alpha)
print(f"mean d={mean_d:+.4f} SE={se:.4f} df={df} CI=[{low:.4f},{high:.4f}]")
if args.out:
with open(args.out, "w", newline="") as f:
w = csv.writer(f)
w.writerow(["seed", "A_acc", "B_acc", "d_B_minus_A"])
w.writerows(rows)
if __name__ == "__main__":
main()A következő kimeneti táblázat jelölt szemléltetés, nem elvégzett futás; a számok a kézi példát ismétlik a kimeneti forma bemutatására:
seed=20261020 A=0.8000 B=0.8100 d=+0.0100
seed=20261021 A=0.7800 B=0.8300 d=+0.0500
seed=20261022 A=0.8400 B=0.8500 d=+0.0100
seed=20261023 A=0.8200 B=0.8200 d=+0.0000
seed=20261024 A=0.8100 B=0.8400 d=+0.0300
mean d=+0.0200 SE=0.0089 df=4 CI=[-0.0048,0.0448]
Értelmezés: a nyers táblázat mind az öt sort közli, nem csak a legjobb seedet. A CI tartalmazza a nullát, tehát a weight decay hatása ezzel a protokollal nem különböztethető meg a seed-zajtól; a közölt 95%-os intervallum a százalékpontnál nagyobb javulást nem tartalmazza, miközben a mérsékelt javulás és a nulla hatás is összeegyeztethető vele a feltevések mellett. A hardver szerepe itt rögzített: a 24.2. CPU/GPU profiling és helyes időmérés alfejezetben tanult mérési logikához hasonlóan a hardver a protokoll része, és a CPU/GPU vagy AMP-váltás nem a seed-szórás része, hanem külön környezeti tényező, amelyet külön mátrixban kell jelenteni.
F1 (fogalmi, nehézség 1). A GlyphLab train splitje 120 jelenetből származó 240 képet tartalmaz, és egy kísérlet öt seeddel tanít ugyanazon a spliten. Mi a független egység a seed-ismétlésben, és miért nem a kép vagy a jelenet? Átadandó: két-három mondatos indoklás a három jelölt megkülönböztetésével.
F2 (levezetési, nehézség 2). Adott párosított seed különbsége, :
| 1 | 2 | 3 | 4 | 5 | 6 | |
|---|---|---|---|---|---|---|
Számítsa ki a -os hatásintervallumot, és döntsön a „ jobb, mint ” előre rögzített hipotézisről. Átadandó: , , , -kritikus érték, CI és egy mondatos döntés.
F3 (implementációs, nehézség 2). Írjon egy
paired_effect(diffs, alpha) függvényt, amely
float64 bemenetből az átlagot, standard hibát és a
kétoldali CI határait adja vissza; a t-kvantilishez használhatja a
scipy.stats.t.ppf függvényt. Ellenőrizze az F2 példáján.
Átadandó: futtatható kód, a visszatérési értékek,
shape-ellenőrzés: diffs alakja (m,), az
eredmény négy skalár, a df m-1.
F4 (hibakeresési, nehézség 2). Valaki ezt a kódot írja:
sd = np.std(diffs) # a population-szórás
se = sd / np.sqrt(len(diffs))Mi a hiba, mi a következménye a CI szélességére, és hogyan javítandó? Átadandó: a hiba oka, iránya és a javított sor, majd a visszaellenőrzés az F2 adatain.
F5 (kísérleti/transzfer, nehézség 3). Tervezze meg három konfiguráció — baseline, dropout , weight decay — összehasonlítását öt párosított seeddel a GlyphLab-on. Adja meg a fő összehasonlítást, a többszörös összehasonlítás kezelését, a negatív eredmény definícióját és a nyers átadandó táblázatot. Átadandó: protokoll-leírás, indoklás és következtetési korlát.
F1. A független egység a seed-futás, mert az
ismétlés a tanítási véletlent változtatja, miközben a split rögzített. A
kép nem független, mert minden futás ugyanazokat a képeket látja; a
jelenet sem, mert a scene-struktúra az adatmintavétel egysége lenne, de
itt nem sorsolunk új splitet. Ha új splitet is sorsolnánk, a független
egység a (seed, split) pár lenne.
F2. Részletes számítás:
Az eltérések rendre , , , , , ; négyzetösszegük . Így
A standard hiba . A kritikus érték . A CI:
A CI nem tartalmazza a -t, ezért a „ jobb, mint ” hipotézis itt éppen elvethető: a jelölt irány szerint , és a teljes intervallum negatív, tehát a minta szerint szignifikánsan rosszabb ebben a szemléltető példában.
F3. Egy lehetséges megoldás:
import numpy as np
from scipy.stats import t as student_t
def paired_effect(diffs, alpha=0.05):
d = np.asarray(diffs, dtype=np.float64) # alak: (m,)
m = d.shape[0] # skalár
mean_d = d.mean() # skalár
sd = d.std(ddof=1) # skalár
se = sd / np.sqrt(m) # skalár
tcrit = student_t.ppf(1 - alpha / 2, df=m - 1)
return mean_d, se, mean_d - tcrit * se, mean_d + tcrit * se
diffs = [-0.02, -0.01, 0.00, -0.03, -0.01, -0.04]
mean_d, se, low, high = paired_effect(diffs)
print(mean_d, se, low, high)
# -0.018333... 0.006009... -0.03378 -0.00288Ellenőrzés: diffs hossza
,
a df
;
a négy visszatérési érték skalár; a CI határai
abszolút toleranciával egyeznek az F2 értékeivel.
F4. Az np.std alapértelmezett
ddof=0 értéke a populációs szórást adja, amely
-es
osztást használ; a mintából becsült szóráshoz
osztás kell. Következmény: a szórás és a standard hiba kisebb a
szükségesnél, ezért a CI túl szűk, és a fals pozitív arány megnő.
Javítás: sd = np.std(diffs, ddof=1). Visszaellenőrzés az F2
adatain: ddof=0 esetén
,
ddof=1 esetén
;
a helyes CI szélesebb.
F5. Protokollminta: a fő összehasonlítás a dropout és a baseline között párosított seedekkel, öt előre rögzített seeddel; a weight decay csak másodlagos feltáró elem. A három összehasonlításhoz a Bonferroni-korrekció egyedi szintet ad, tehát a fő CI -os. Az átadandó nyers táblázat minden seedre három pontosságot és a fő különbséget tartalmazza. Negatív eredmény: a fő CI tartalmazza a nullát, tehát a dropout hatását nem tudjuk megkülönböztetni a seed-zajtól. Következtetési korlát: a GlyphLab adat nem természetes képi benchmark, és a hardver CPU/float32; GPU-ra vagy más adatra az eredmény nem vihető át bizonyítás nélkül.
Gyakori hiba, hogy tíz seedből csak a legjobbat jelentik, és azt állítják: „a módszer pontossága ”. Ellenpélda: a tíz nyers pontosság legyen ; a legjobb , de az átlag , és a tapasztalati szórás alapján a seed-átlag CI-ja nem tartalmazza a -et. A kiválasztott futás a maximum statisztikája, amelynek eloszlása felfelé torzított; a stabil teljesítmény jellemzéséhez az átlagot és a hatásintervallumot kell közölni.
A kézi számítás ellenőrzése: a df mindig , az ötös példában ; a CI szélessége növelésével -szeres ütemben szűkül; a -kritikus érték nagyobb a normális -nál kis -re. A 35.2. Magyarázat sanity check alfejezetben tanult randomizált kontroll logikája itt a seed-randomizálásban tér vissza: a kontroll nem bizonyítja a hatás mechanizmusát, csak a modellfüggőséget teszteli. A 32.2. Scaled dot-product attention alfejezetben használt alakellenőrzés itt is kötelező: a különbségvektor alakja , a standard hiba skalár. A 24.2. CPU/GPU profiling és helyes időmérés alfejezetben rögzített mérési fegyelem szerint a hardvert expliciten rögzítjük, és a hardverváltást nem számoljuk bele a seed-szórásba.
A seed-ismétlés független egysége a teljes futás, nem a kép vagy a jelenet. Párosított seedekkel azonos véletlen környezetben mérjük a két konfigurációt, és a páronkénti különbségek átlagát, standard hibáját, valamint -alapú hatásintervallumát közöljük. A nulla befoglalása negatív eredmény: hiányzó bizonyíték, nem a hatás hiányának bizonyítéka. Több összehasonlítás esetén a családi hiba a Boole–Bonferroni korláttal kontrollálható. A labor öt előre rögzített seeddel, CPU/float32 főúton tanít kis CNN-t, és a nyers futásokat teljes táblázatban adja át.
A 36.3. Szakirodalmi reprodukció és attribúció a szakirodalmi reprodukciót és attribúciót vizsgálja: a „reprodukáltuk” állítás ott csak akkor lesz megalapozott, ha a cikk protokollja mellett a seed-ismétlést, a nyers futásokat és a hatásintervallumot is közöljük a forrás pontos megjelölésével.