Egy előtanított modell helyes használatához három, egymástól
független kérdést kell külön megválaszolni. (1) Kompatibilis
előfeldolgozás: a bemenet reprezentációja (méret,
crop, normalizálás, csatornarend, értéktartomány) megegyezik-e azzal,
amit a súlycsomag elvár — ez dokumentációból ellenőrizhető szerződés.
(2) Adatdomén-hasonlóság: mennyire hasonlít a saját
adat a forrás tanítóadatához — ez nem garantálható, csak vizsgálható.
(3) A target teljesítmény igazolása: a modell a saját
adaton, külön target-domain értékeléssel mérve elég jó-e. Az első
feltétel teljesülése nem jelenti a forrás- és a céladat azonos
eloszlását, és az eloszláseltérés önmagában nem teszi szabálytalanná a
transzfert; csak azt jelenti, hogy a (3) mérés nem hagyható ki. Ez az
alfejezet ezt a preprocessing-szerződést járja körbe:
resize/crop, normalizálás, csatornarend, a súlycsomag enumja és a
felhasználási licenc. Előismeret a 20.2.
Finomhangolás és tanulási ráta finomhangolási anyaga: a
state_dict, a fagyasztott paraméterek és a
BatchNorm-pufferek kezelése. A 19.3. EfficientNet és
architektúraskálázás alfejezetben tárgyalt architektúra-skálázás és
a 16.3. Elméleti és effektív recepciós mező
alfejezetben levezetett recepciós mező itt abban tér vissza, hogy a
bemeneti felbontás változtatása a háló belső aktivációinak térbeli
méretét is megváltoztatja. Induló kérdés: Milyen konkrét
ellenőrzésekkel dokumentálható, hogy a letöltött súlycsomag a mi
adatunkon a várt bemeneti reprezentációt kapja, milyen korlátozott
target-domain validáció kell a teljesítmény igazolásához, és
megengedett-e jogilag a felhasználás?
Legyen a nyers képadat batch, a tanító adateloszlás (source), a felhasználáskori eloszlás (target). Preprocessing-szerződésnek nevezzük azt a leképezést, amely a nyers pixelekből a háló által várt normalizált bemenetet állítja elő. Ez legalább négy komponenst tartalmaz:
Domain shift az az állapot, amikor
.
Ez nem önmagában hiba, hanem mérhető eltérés: az adateloszlások
különbözősége miatt a modell a target eloszláson rosszabb teljesítményt
mutathat. A súlycsomag enumja a közzétett
súlyváltozatok azonosítója (pl. IMAGENET1K_V1,
DEFAULT). A licenc a súlyok felhasználási
feltételeit rögzítő jogi dokumentum; a letölthető súly megléte nem
jelenti azt, hogy tetszőleges célra felhasználható.
A torchvision dokumentációja [D13] a modellek betöltéséhez
weights enum értékeket használ; a DEFAULT az
adott könyvtárverzió ajánlott súlyát jelöli. A [D09] oktatóanyag a saját
modell mentését és betöltését tárgyalja; ezt a saját kísérleti
checkpointra alkalmazzuk. A [P06] a ResNet-reziduális blokkokat vezeti
be; az olvasott 3.1–3.2 szakasz a
rövidítést bizonyítja, de a cikk licencfeltételeire nem terjed ki.
Tegyük fel, hogy egy előtanított modell első rétege egy lineáris projekció alakban, ahol egy bemeneti sorvektor, , . A modell készítője a normalizálást értékekkel végezte, így a háló bemenete . A felhasználó ezt elhagyja, és nyers -et ad be. Ekkor a háló által számított érték , míg a szerződés szerint , ahol a -dimenziós csupa egyes oszlopvektor. A különbség:
Ez általában nulla, csak ha éppen a konstans vektorral egyenlő. Legyen például , , , és . Ekkor , míg . A modell más logitot ad, holott a bemenet ugyanaz a kép. Ez az ellenpélda mutatja: a normalizálás elhagyása nem egyszerűen skálázza a kimenetet, hanem a bias és a súly interakciója miatt el is tolja.
Vegyünk egy
méretű színképet, azaz
,
.
A csatornák sorrendje PyTorchban NCHW: a tensor
[1, 3, 2, 2] alakú. Egy másik könyvtárból érkező adat lehet
NHWC, [1, 2, 2, 3]. Ha a felhasználó az NHWC tensort
NCHW-ként adja be, akkor a [1, 2, 2, 3] alakot a háló úgy
értelmezi, mint
,
,
,
bemenetet. Ez egyrészt shape-hiba, másrészt ha a csatornák száma
véletlenül egybeesik (például egy RGB kép és egy BGR kép esetén
mindkettő
),
akkor a shape egyezik, de a csatornák sorrendje fel van cserélve. Legyen
az eredeti RGB pixel:
.
A BGR sorrendben ugyanez a pixel
.
A modell első konvolúciós rétegének súlyai az RGB csatornákra vannak
tanítva; a BGR sorrendben beadott bemenet esetén az első csatorna súlyai
a kék intenzitást látják, a harmadiké a vöröset. A kimeneti aktivációk
megváltoznak, mégpedig nem pusztán a csatornák felcserélésével, mert a
rákövetkező rétegek súlyai is fixek. Az elemszám (3 csatorna) és a
tensor mérete azonos, de a szemantikai tartalom hibás. Ez a példa azt
igazolja, hogy a csatornarend nem redukálható a csatornák
darabszámára.
Tekintsünk egy méretű, 3 csatornás képet: . A szerződés szerint a normalizálás , . Számoljuk ki a normalizált értékeket:
Python-ellenőrzés (a művelet egyszerű, NumPy-val vagy PyTorch-kal is
elvégezhető; az alábbi kód futtatható a lab/
munkakönyvtárból, de e kéziratban a kimenet kézzel számított):
# lab/preprocess_check.py
import numpy as np
x = np.array([0.8, 0.4, 0.6], dtype=np.float32)
mu = np.array([0.485, 0.456, 0.406], dtype=np.float32)
sigma = np.array([0.229, 0.224, 0.225], dtype=np.float32)
x_norm = (x - mu) / sigma
print(x_norm) # [1.3755..., -0.25, 0.8622...]Ha a felhasználó a normalizálást kihagyja, és a nyers
-t
adja be, az első réteg lineáris transzformációja eltér a várttól, ahogy
az 1. ellenpéldában láttuk. A csatornarend ellenőrzésére hasonlóan: ha a
képet NHWC-ból NCHW-ba konvertáljuk, ügyelni kell arra, hogy a
transpose ne cserélje fel a színcsatornákat. Egy RGB → BGR
hiba reprodukálásához elegendő a csatornák indexelését megfordítani:
x_bgr = x[::-1]. A két vektor elemszáma azonos, de a kép
szemantikailag más.
A labor célja egy súly-adat-preprocessing
eredetjegyzék elkészítése a GlyphLab saját adataira és egy
lehetséges külső súlycsomagra. A GlyphLab adatok a 20.3. Preprocessing, domain shift és súlylicenc
előtti fejezetekben már ellenőrzöttek: data/images.npy
alakja (360, 1, 24, 24), float32, intenzitás
,
grayscale. Mivel a saját modellünk ezen az adaton tanult, a
preprocessing-szerződés a következő:
Ezt a szerződést a lab/preprocessing_ledger.md fájlban
rögzítjük. A fájl tartalma:
# Preprocessing eredetjegyzék – GlyphLab
| Mező | Érték | Ellenőrzés |
|---|---|---|
| Adatfájl | data/images.npy | quickcheck.py |
| Alak | (360, 1, 24, 24) | kézi |
| dtype | float32 | kézi |
| Intenzitás tartomány | [0, 1] | min/max |
| Normalizálás | nincs | – |
| Csatornarend | NCHW | – |
| Súly forrása | saját training, seed 20261020 | state_dict |
| Licenc | saját, oktatási célra | – |A licencellenőrzéshez a külső súlyok esetén a [D13] és [P06] forrásokat kell használni. Az előtanított súlyok felhasználási feltételei modell- és súlyváltozatonként eltérhetnek; a pontos licencet a modellkatalógus és a súlyok eredeti forrása alapján, még letöltés vagy továbbadás előtt kell rögzíteni. A puszta katalógusbeli elérhetőség nem jelent korlátlan újrafelhasználási jogosultságot. A [P06] cikk esetében a licenc a preprintben nem szerepel; az arXiv-rekord nem jogi licencnyilatkozat. A labor átadandó eredménye tehát:
preprocessing_ledger.md fájl elkészítése.license_checks.md fájl, amely rögzíti: (a) a
GlyphLab saját súlyainak oktatási felhasználása; (b) a torchvision
modellkatalógus [D13] felhasznált súlyváltozatának licencfeltételeit;
(c) a [P06] licenc hiányának megjelölését.Fontos: a felhasználó a saját modelljének súlyát szabadon használhatja oktatási célra, de a külső súlyokra vonatkozó állításokat csak a forrás tényleges elolvasása után tehet. A labor kódja nem igényel külső letöltést; a GlyphLab adatok helyben elérhetők. Az alábbi ellenőrző kód a preprocessing-szerződés betartását teszteli:
# lab/check_preprocessing.py
import numpy as np
from pathlib import Path
images = np.load(Path("data/images.npy"))
assert images.dtype == np.float32
assert images.shape == (360, 1, 24, 24)
assert images.min() >= 0.0 and images.max() <= 1.0
print("Preprocessing-szerződés teljesül: [0,1], float32, NCHW, alak (360,1,24,24)")Ez a kód a lab/ könyvtárból futtatható:
python check_preprocessing.py. Az output a fenti kiírás;
mivel a kéziratban nem futtattuk, az állítást a
quickcheck.py korábbi ellenőrzött jelentésére
alapozzuk.
F1 – fogalmi (1. nehézség). Mit jelent a preprocessing-szerződés négy komponense? Adjon mindegyikre egy-egy mondatos magyarázatot, és egy példát, ahol a komponens elhanyagolása hibához vezet.
F2 – levezetési (2. nehézség). Legyen az előtanított modell első rétege a fenti 1. ellenpélda szerint, , , , normalizálás . A felhasználó bemenete . Számítsa ki -t és -et, és igazolja a különbséget.
F3 – implementációs (2. nehézség). Írjon
Python-kódot (lab/preprocess_normalize.py), amely beolvassa
a GlyphLab data/images.npy-t, ellenőrzi a dtype-ot és a
tartományt, majd alkalmazza a
normalizálást, és elmenti data/images_norm.npy néven. A kód
tartalmazzon input-ellenőrzést és a kimenet min/max értékének
kiírását.
F4 – hibakeresési (3. nehézség). A következő kód egy külső súlyú modell betöltését végzi, de hibás. Azonosítsa a hibát, és magyarázza el, miért okoz domain shiftet.
import torch
from torchvision import models
model = models.resnet18(weights=None)
model.load_state_dict(torch.load("weights.pth", weights_only=True))
# A felhasználó saját adatai NHWC formátumban, [0,255] uint8.
image = torch.randint(0, 256, (1, 224, 224, 3), dtype=torch.uint8)
image = image.permute(0, 3, 1, 2).float()
logits = model(image)F5 – kísérlettervezési (2. nehézség). Tervezzen egy kísérletet, amely a GlyphLab adatokon méri a domain shift hatását, ha a bemeneti intenzitásokat lineárisan átskálázzuk -ből -be. Adja meg a protokollt, a baseline-t, a metrikát és az érvényességi korlátot. (A futást nem kell elvégezni, csak a tervet leírni.)
F1. A négy komponens: (1) geometriai előkészítés – a térbeli méret rögzítése; hiba: ha a háló 224×224-re tanult, és 32×32-t kap, a láncolt recepciós mezők miatt az outputméret eltér. (2) Normalizálás – a csatornánkénti közép és szórás levonása; hiba: a nyers [0,255] bemenet a bias interakciója miatt eltolja a logiteket (1. ellenpélda). (3) Csatornarend – NCHW vs NHWC; hiba: RGB–BGR felcserélés azonos elemszám mellett más színinformációt ad. (4) Értéktartomány – [0,1] vagy [0,255]; hiba: a skálázás elmaradása nagy gradienst és rossz logiteket okoz.
F2. A normalizálás: . esetén . . Ekkor . A különbség . Ez megegyezik a korábbi levezetéssel: . Alakellenőrzés: skalár, mert .
F3. A kód:
# lab/preprocess_normalize.py
import numpy as np
from pathlib import Path
images = np.load(Path("data/images.npy"))
assert images.dtype == np.float32
assert images.min() >= 0.0 and images.max() <= 1.0
mu, sigma = 0.5, 0.25
norm = (images - mu) / sigma
assert norm.dtype == np.float32
print(f"Eredeti tartomány: [{images.min():.3f}, {images.max():.3f}]")
print(f"Normalizált tartomány: [{norm.min():.3f}, {norm.max():.3f}]")
np.save(Path("data/images_norm.npy"), norm)Ellenőrzés: a bemenet tartománya miatt a normalizált értékek közé esnek; a kód ezt kiírja.
F4. A kód hibája: a betöltött
weights.pth egy olyan modellhez tartozik, amely 224×224-es,
[0,1]-re normalizált, RGB csatornájú bemenetre lett tanítva. A
felhasználó (a) NHWC → NCHW konverziót végez, de nem biztos, hogy a
csatornasorrend RGB marad; (b) a [0,255] uint8 értékeket közvetlenül
floatra konvertálja, normalizálás nélkül, így a modell [0,255]-es
bemenetet kap, ami domain shiftet okoz: a tanítóeloszlás
[0,1], a cél
[0,255]. A hiba javítása: a bemenetet image.float() / 255.0
értékre skálázni, majd a szerződött mean/std párt alkalmazni. A
csatornasorrend ellenőrzéséhez meg kell nézni a modell
dokumentációját.
F5. Kísérleti terv: (a) baseline a GlyphLab teszt splitjén a már betanított CNN pontossága. (b) Kezelés: a tesztképek intenzitásait átskálázzuk , így a tartomány -re szűkül. (c) Metrika: per-image pontosság és macro-F1 a három osztályra. (d) Protokoll: ugyanaz a modell, ugyanaz a split, rögzített seed a szorzásnál. (e) Érvényességi korlát: a GlyphLab adat szintetikus, így az eredmény nem általánosítható természetes képekre; a mérés nem bizonyítja, hogy a modell más domainen is hasonlóan romlik.
A leggyakoribb tévedés: „A letölthető súly automatikusan
minden célra engedélyezett modell.” Ez hamis. A súlyok
letöltése nem jogosít fel semmilyen felhasználásra; a licencet a
terjesztő határozza meg. Például a torchvision súlyaihoz tartozó
licencfeltételek a [D13] modellkatalógusban vannak felsorolva, de ezek
nem mindig azonosak a modell kutatási cikkének licencével. A [P06]
ResNet esetében az arXiv preprint nem tartalmaz licencszekciót; a
modellekhez tartozó súlylicenceket külön kell ellenőrizni. Ha valaki
kereskedelmi termékben használja a súlyokat anélkül, hogy elolvasta
volna a licencet, jogi és etikai hibát követ el. A helyes eljárás: a
súlycsomag mellékelt LICENSE fájlját vagy a terjesztő
weboldalán feltüntetett feltételeket kell alapul venni, és rögzíteni az
eredetjegyzékben.
Ellenőrizze: (1) a bemeneti tensor alakja NCHW, dtype float32,
tartomány [0,1]; (2) ha a szerződés normalizálást ír elő, akkor a mean
és std vektorok csatornánkénti sorrendje megegyezik a súlyok tanításakor
használttal; (3) a licencre vonatkozó állításokat csak forrás alapján
tegye, és a hiányzó ellenőrzéseket jelölje meg. Visszahívás a 20.2. Finomhangolás és tanulási ráta alfejezetből:
a state_dict betöltésekor a weights_only=True
opció csökkenti a deszerializációs kockázatot, de nem oldja meg a
preprocessing problémát; a BatchNorm-pufferek eval módban a tanítás
alatt frissített running statisztikákat használják.
A preprocessing-szerződés rögzíti a bemeneti képek geometriai méretét, normalizálását, csatornarendjét és értéktartományát. A rossz normalizálás és az azonos elemszámú, de hibás csatornarend konkrét ellenpéldákkal igazolhatóan megváltoztatja a modell kimenetét. A domain shift a forrás- és céleloszlás eltérését jelenti, és a teljesítmény romlásához vezethet; a helyes előfeldolgozás ezt nem zárja ki, ezért a target teljesítményt külön, a céladaton kell mérni. A súlycsomag enumja azonosítja a súlyváltozatot, a licenc pedig a felhasználás feltételeit; a letölthető súly nem automatikusan engedélyez minden célra. A laborban elkészítettük a GlyphLab adatokra az eredetjegyzéket, és a külső súlyok licencellenőrzését forrásalapú feladatként jelöltük meg.
A következő egység 20.4. V. ellenőrző pont: indokolt CNN-választás az V. ellenőrző pont: ott a teljes CNN-választást indokolni kell, a preprocessing-szerződést, a finomhangolási stratégiát és a licencet együttesen kell értékelni. Források: [D09] PyTorch contributors (2.14). Saving and Loading Models. https://docs.pytorch.org/tutorials/beginner/saving_loading_models.html – state_dict, eval és weights_only; [D13] PyTorch contributors (online). TorchVision models. https://docs.pytorch.org/vision/stable/models.html – modellkatalógus; [P06] He, Zhang, Ren és Sun (2015). Deep Residual Learning for Image Recognition. https://arxiv.org/abs/1512.03385 – reziduális blokk, 3.1–3.2 szakasz olvasva; a licenc nem ellenőrzött.