Az egység célja, hogy a programozói adatkezelést pontos megfigyelési egységgel, csoportos felosztással és ellenőrizhető szivárgásdefinícióval kapcsolja össze. Előismeretként csak az 1.2. Szakmailag megalapozott modellezési állítások állítástípusait és bizonyítékjegyzékét használjuk; haladó valószínűségszámításra nincs szükség.
Induló becslés. A GlyphLab adatbázis 360 darab -es szürke képet tartalmaz, de ezek 180 jelenetből (scene) készültek, jelenetenként két zajos nézettel (view). Hány független megfigyelésünk van: 360 vagy 180? Ha valaki képszintű train/validation/test felosztást készít, pontosan milyen hibát követ el? Tippeljen, és a labor végén vesse össze a levezetett értékkel.
Megfigyelési egység (observation unit). Az az elemi rekord, amelyről a modell egy előrejelzést ad. A GlyphLabban ez egy kép, tehát a modell bemenete egy tensor; a kezdőadatban , , float32, intenzitás. A hozzá tartozó cél , int64 osztályindex.
Scene és view. A scene az a rejtett, közös
képződmény, amelyből a képek keletkeznek: ugyanaz a geometriai
elrendezés, alakzatvastagság és pozíció. A view ennek egy
zajos, önálló képi megfigyelése. A metadata.csv minden
sorához scene_id és view_id tartozik; egy
scene mindkét view-ja ugyanabba a splitbe kerül.
Csoport (group). Egy megfigyeléscsoport azon rekordok halmaza, amelyek közös rejtett véletlen forrásból származnak. Formálisan legyen az rekord csoportazonosítója; a GlyphLabban . Az érvényes felosztás feltétele:
A kép a predikció és a képenkénti metrika megfigyelési egysége, míg a
scene_id a split és a csoportos bizonytalanságbecslés
egysége. A scene_id tehát a független mintavételi egység:
ha a tesztkészletből új jelenetekre akarunk következtetni, akkor a
felosztást jelenetekre, nem képekre kell elvégezni.
Train/validation/test. A train a paraméterek illesztésére, a validation a modell- és hiperparaméterválasztásra, a test a rögzített protokoll végén, egyszeri, független értékelésre szolgál. A GlyphLab split 120, 30, 30 független jelenetet, azaz 240, 60, 60 képet tartalmaz. A két view nem növeli a független jelenetek számát.
Transzformáció. Az a leképezés, amely a nyers
rekordból a modell bemenetét állítja elő:
.
Ha a transzformáció adaptív paramétereket tanul, például globális
standardizálást vagy PCA-alapú redukciót, akkor ezeket csak a train
felosztáson illesztjük; a teszt statisztikája nem szivároghat a trainbe.
A GlyphLab corrupted_test.npy állománya a rögzített split
után alkalmazott teszt-transzformáció, ezért nem
befolyásolja a tanítást.
Adatszivárgás (data leakage). Két fő formája van. Az egyik a csoportszintű átszivárgás: ugyanazon scene képei különböző splitbe kerülnek, így a tesztben olyan rejtett jelenet szerepel, amelynek egy másik megfigyelését a train már látta. A másik a preprocessing-átszivárgás: a felosztás elvégzése előtt a teljes adaton számolunk statisztikát, alkalmazunk imputációt vagy választunk hiperparamétert. Mindkettő torzítja az általánosítási becslést.
A függetlenség formális valószínűségi definícióját az 5.1. Esemény, feltétel és véletlen változó egységben építjük fel; itt az elemi gyakorisági kritériummal dolgozunk: két megfigyelés akkor független, ha az együttes relatív gyakoriság a peremgyakoriságok szorzata. A következő lemmát saját, teljesen diszkrét generatív modellel bizonyítjuk.
Lemma (közös rejtett jelenetből származó nézetek függősége). Legyen rejtett jelenet, . Minden nézet egy zajos csatornán halad át: ha , a nézet értéket ad valószínűséggel és értéket valószínűséggel; ha , a szerepek felcserélődnek. A két csatorna zajai adott mellett függetlenek. Ekkor a két nézet és nem független.
Bizonyítás. Először a peremeloszlást számítjuk. Az feltételeit összegezve:
és ugyanígy . A szimmetria miatt ugyanez igaz -re.
Most az együttes eloszlást írjuk fel. Ha a két csatorna adott mellett független, akkor a helyes–helyes együttes valószínűség , a hibás–hibás . A két -érték együttesen:
Ha és függetlenek lennének, akkor a peremek szorzatának kellene teljesülnie:
Mivel , a két nézet nem független. ∎
A bizonyításban a feltételes függetlenség és a perem-összegzés szerepét érdemes külön látni: adott mellett a két zajdobás független, de a közös rejtett miatt a megfigyelések összekapcsolódnak. Ha a csatorna hibája lenne, az együttes tömeg volna, tehát maximális függést kapnánk. Ha a csatorna teljesen informatív zajt adna, vagyis a kimenet független lenne -től, akkor a nézetek is függetlenné válnának; a függés forrása tehát a közös jel.
Ugyanezt a generatív modellt egy háromjelenetes, kétnézetes miniatűr adatbázison szemléltetjük, hogy a csoportos split feltétele látható legyen.
| scene_id | view_id | megfigyelt osztály |
|---|---|---|
| 1 | 1 | a |
| 1 | 2 | a |
| 2 | 1 | b |
| 2 | 2 | b |
| 3 | 1 | a |
| 3 | 2 | b |
A fenti táblában a scene 1 és 2 nézetei determinisztikusan azonosak, a scene 3 nézetei zajosak. Ha képszintű felosztást készítenénk, például a páratlan sorokat trainbe, a párosakat testbe tennénk, akkor a scene 1 és 2 egyik nézete a trainben, másik a testben lenne; a tesztben szereplő kép a trainből ismert jelenetet mutatná. A csoportos split ezzel szemben teljes scene-eket oszt be: az egyik lehetséges érvényes kimenet train = {scene 1, scene 2}, test = {scene 3}. Ekkor a teszt minden képe olyan jelenetből származik, amelyet a modell a trainben nem látott.
Input és szerződés. A munkakönyvtár a
lab/; a bemenet data/metadata.csv, amelynek
scene_id, view_id, label és
split oszlopa int64, a split string értékű
(train, val, test). A labor nem
tölti be a képtensort, nem használ GPU-t, és nem végez lebegőpontos
műveletet; a dtype-egyezés a CSV-ből olvasott oszlopokon értendő.
Futtatási parancs. A lab/
könyvtárból:
python n003_split_check.pyKód.
import math
import numpy as np
import pandas as pd
from pathlib import Path
DATA_DIR = Path("data")
meta = pd.read_csv(DATA_DIR / "metadata.csv")
def violating_scenes(df: pd.DataFrame, split_col: str) -> list[int]:
"""Azon scene_id-k, amelyek több különböző splitben szerepelnek."""
nunique = df.groupby("scene_id")[split_col].nunique()
return nunique[nunique > 1].index.astype(int).tolist()
def scene_counts(df: pd.DataFrame, split_col: str) -> dict[str, int]:
return df.groupby(split_col)["scene_id"].nunique().to_dict()
# 1. Jó split ellenőrzése a gyártó szerint
bad_good = violating_scenes(meta, "split")
counts_good = scene_counts(meta, "split")
print("Jó split:")
print(" split-számláló scene-ekre:", counts_good)
print(" szabálytalan scene-ek száma:", len(bad_good))
# 2. Szándékosan hibás, képszintű split
rng = np.random.default_rng(12345) # a hibás split seedje
idx = rng.permutation(len(meta))
n_train, n_val = 240, 60
bad_split = np.full(len(meta), "unused", dtype="<U5")
bad_split[idx[:n_train]] = "train"
bad_split[idx[n_train:n_train + n_val]] = "val"
bad_split[idx[n_train + n_val:]] = "test"
meta_bad = meta.copy()
meta_bad["split_bad"] = bad_split
bad_bad = violating_scenes(meta_bad, "split_bad")
counts_bad = scene_counts(meta_bad, "split_bad")
print("Hibás split:")
print(" split-számláló scene-ekre:", counts_bad)
print(" szabálytalan scene-ek száma:", len(bad_bad))
# 3. Várható szabálytalan scene-szám a hibás splithez
C = math.comb # Python 3.8+: pontos egész binomiális együttható
p_same = (C(240, 2) + C(60, 2) + C(60, 2)) / C(360, 2)
print(f"Egy scene együtt maradásának valószínűsége: {p_same:.4f}")
print(f"Várható szabálytalan scene-szám: {180 * (1 - p_same):.2f}")Elvárt eredmény és értelmezés. A jó splitre a
violating_scenes üres lista, és a scene-számláló
train: 120, val: 30, test: 30, ahogyan a GlyphLab
szerződése rögzíti. A szándékosan hibás felosztásban ezzel szemben a
scene_id tudat nélkül permutáltunk képeket, ezért sok scene
két view-ja különböző splitbe kerül.
A hibás splithez tartozó várható szabálytalan scene-szám levezethető elemi kombinatorikával. Egy rögzített scene két view-ja akkor marad együtt, ha mindkettő ugyanabba a szegmensbe esik:
Ezért a várhatóan szabálytalan scene-ek száma
A kód által kiírt tényleges szám a 12345 seeddel ettől
néhánnyal eltérhet; az ellenőrzés kritériuma az, hogy a hibás splitre
pozitív, a jóra nulla legyen. Ez a labor éppen a csoportos split
feltételét teszteli: a jó felosztásban soha nem lép át scene, a hibásban
várhatóan 180-ból körülbelül 90 jelenet igen.
F1 fogalmi (1-es nehézség). Határozza meg a
scene és a view különbségét, és indokolja
három mondatban, miért nem helyettesítheti a 360 képet 360 független
jelenetnek. Elvárt eredmény: pontos fogalmi megkülönböztetés és a közös
rejtett okra hivatkozó indoklás.
F2 levezetési (2-es nehézség). Tekintse az egyenletes eloszlású rejtett jelenetet. Az egyes nézetek az értékét valószínűséggel helyesen adják, a másik két értékre egyenként – valószínűséggel tévednek; a két nézet adott mellett független. Számítsa ki értékét, és mutassa meg, miért nem független a két nézet. Elvárt eredmény: levezetett és a függetlenségi összehasonlítás -dal.
F3 implementációs (2-es nehézség). Írjon
split_integrity(df, split_col) függvényt, amely visszaadja
azon scene_id-k listáját, amelyek több különböző splitben
szerepelnek. Tesztelje a data/metadata.csv-n a
split oszlopra, majd egy mesterségesen megcserélt
split_bad oszlopra. Elvárt eredmény: futtatható kód, üres
lista a jó, nem üres a rossz oszlopra.
F4 hibakeresési (2-es nehézség). Az alábbi kód képszintű splitet készít. Azonosítsa a hibát, írja le a teszt-accuracyra gyakorolt következményét, és adja meg a scene-szintű javítást, valamint annak ellenőrzését.
def split_by_view(meta, rng):
idx = rng.permutation(len(meta))
split = np.full(len(meta), "train", dtype="<U5")
split[idx[240:300]] = "val"
split[idx[300:]] = "test"
meta["split"] = split
return metaElvárt eredmény: a hiba lokalizálása, a torzítás irányának indoklása,
valamint a javított függvény és a violating_scenes
ellenőrzés futási kritériuma.
F5 kísérlettervezési/transzfer (3-as nehézség). A GlyphLab bővített változatában jelenetenként 10 time-lapse nézetet készítünk, és a felhasználási cél ismeretlen jelenetek osztályozása. Tervezzen protokollt: mi a megfigyelési egység, hogyan választja szét a train/validation/test készleteket, mi legyen a baseline, és milyen metrikával, illetve ellenőrzéssel mutatná ki az esetleges szivárgást? Elvárt eredmény: egy lehetséges terv, annak korlátjaival; alternatív terv megadása esetén az eltérő döntés indoklása.
F1 megoldás. A scene a közös rejtett geometriai elrendezés, a view ennek egy zajos képi vetülete. Két view ugyanarról a scene-ről nem cserélhető fel két független jelenettel, mert az egyik nézet alapján a másikra jobb előrejelzés adható, mint a peremeloszlásból. Ezért a független mintavételi egység a scene; a képek száma csak a modellbemenetek számát adja, nem a statisztikai bizonyíték erejét.
F2 megoldás. Adott mellett a két csatorna azonos válaszának valószínűsége az esélyek négyzetösszege:
Mivel nem függ -től,
A peremeloszlás egyenletes marad: tetszőleges -re
Ha a két nézet független lenne, akkor volna. Mivel , a nézetek nem függetlenek; a közös rejtett az együttes eloszlást a peremek szorzatától eltéríti.
F3 megoldás. A laborban szereplő
violating_scenes függvény közvetlenül használható. Nem elég
teljes jelenetek splitjét megváltoztatni: az nem sérti a csoportszintű
feltételt. A teszthez két kiválasztott jelenetnek csak egy-egy
nézetét kell az eredetitől eltérő splitbe tenni:
meta_test = meta.copy()
meta_test["split_bad"] = meta_test["split"]
selected = meta_test["scene_id"].unique()[:2]
for sid in selected:
row_id = meta_test.index[meta_test["scene_id"] == sid][0]
old_split = meta_test.loc[row_id, "split_bad"]
meta_test.loc[row_id, "split_bad"] = (
"test" if old_split != "test" else "train"
)
# A hallgató saját split_integrity függvénye megegyezik a laborbeli
# violating_scenes működésével.
bad = violating_scenes(meta_test, "split_bad")
assert set(bad) == set(selected) and len(bad) == 2Az ellenőrzés típusa halmaz-egyezés, nem lebegőpontos tolerancia: a
jó oszlopra a lista üres, a hibásra pontosan a két módosított
scene_id jelenik meg.
F4 megoldás. A hiba az, hogy a
np.random.permutation a 360 képet függetlenül sorsolja,
ezért a scene_id-t nem veszi figyelembe: ugyanazon scene
két view-ja különböző splitbe kerülhet. Következmény: a testben olyan
jelenetek jelennek meg, amelyek egy másik nézete a trainben szerepel; a
teszt-accuracy felfelé torzul, mert a modell ismert geometriákra
válaszol, nem új jelenetekre.
Javítás: először a scene-ekből kell permutációt készíteni, majd a scene-hez tartozó összes view-t együtt kell beosztani. Egy lehetséges vázlat:
def split_by_scene(meta, rng):
scenes = meta["scene_id"].unique()
perm = rng.permutation(len(scenes))
split_map = {}
for s in scenes[perm[:120]]:
split_map[s] = "train"
for s in scenes[perm[120:150]]:
split_map[s] = "val"
for s in scenes[perm[150:]]:
split_map[s] = "test"
meta["split_fixed"] = meta["scene_id"].map(split_map)
return metaEllenőrzés: a violating_scenes(meta, "split_fixed")
eredményének üresnek, a scene-számlálónak pedig
train: 120, val: 30, test: 30 értékűnek kell lennie.
F5 megoldásminta. A megfigyelési egység továbbra is a scene, mert a time-lapse sorozat tagjai közös jelenetből erednek. A felosztást scene-szintű osztály-rétegzett permutációval végeznénk, például 120/30/30 jelenettel; egy scene összes nézete egy splitbe kerülne. Baseline-ként egy olyan modellt választanánk, amely a train-osztályok relatív gyakoriságát jósolja, vagy egy korábbi kis CNN-t; mert a kérdés az, hogy a jeleneten belüli plusz nézetek javítják-e az új jelenetekre való általánosítást.
Metrika: scene-szintű átlagos accuracy és per-kép accuracy, valamint
páros ellenőrzés, hogy a testben nem szerepel olyan scene, amelynek
bármely view-ja a trainben vagy a valben van. A szivárgás detektálására
a split_integrity függvényt futtatnánk a végső
metadata.csv-n. Fontos korlát: a per-kép accuracy felfelé
torzíthat, ha a test sok nézetet tartalmaz ugyanarról a jelenetről;
ezért a fő metrika a scene-szintű átlag, amely minden jelenetet egyenlő
súllyal vesz.
A leggyakoribb tévedés: a több kép több független megfigyelést jelent. A GlyphLab ellenpéldája: a 360 kép 180 jelenetből áll; ha képszintű splitet készítünk, várhatóan körülbelül 90 jelenetnek az egyik nézete a trainbe, a másik a testbe kerül. A teszt-accuracy ekkor olyan jeleneteken is mér, amelyeket a modell a trainből részben ismer; a magas érték nem az ismeretlen jelenetre való általánosítást, hanem a szivárgást mutatja. A képek darabszáma tehát a számítási költséget és a modellbemenetek számát jellemzi, nem a független bizonyítékok számát.
view_id-t használná?violating_scenes függvény
visszatérési listája?Az 1.2. Szakmailag megalapozott modellezési
állítások visszahívása: az empirikus állítás típusa megköveteli az
adatot, a splitet és a számítási protokollt. A most bevezetett
scene_id azt a hiányzó protokoll-összetevőt adja meg, amely
nélkül a pontossági számítás nem minősülhet megalapozott empirikus
állításnak.
A megfigyelési egység nem mindig azonos a modell bemenetével: a
GlyphLabban a bemenet a kép, de a független egység a
scene_id. A train/validation/test felosztás érvényességi
feltétele, hogy egy csoport minden rekordja ugyanabba a splitbe
kerüljön; ennek megsértése csoportszintű adatszivárgást okoz. A zajos
nézetek függőségét diszkrét generatív modellel bizonyítottuk: a közös
rejtett jelenet miatt az együttes eloszlás nem a peremek szorzata. A
labor a jó splitre nulla, a képszintű hibás splitre várhatóan körülbelül
90 szabálytalan jelenetet mutat. A feladatok a fogalmi
megkülönböztetést, a levezetést, az ellenőrző kódot, a hibás felosztás
javítását és egy time-lapse transzferprotokollt fedik le.
Következő alkalmazás. Az 1.4. Tanulási diagnózis és kísérleti napló egységben a tanulási diagnózist és a kísérleti naplót építjük fel; a mostani split-ellenőrzés lesz a napló első kötelező rovata.
Források
ELLENORZES.md helyi
laborriportja alapján; a jelen egység kimenetei a kód futtatása nélkül,
a szerződésben rögzített elvárt értékek és a levezetett várható érték
szerint jelöltek.