A CNN-ekben a megosztott konvolúciós kernel a térbeli pozíciókra alkalmazza ugyanazt a lokális műveletet. A szekvenciamodellekben a hasonló induktív torzítás az időbeli tengelyre vonatkozik: egy szövegrészlet, hangjel vagy idősor egymást követő tokenjei között feltételezzük, hogy a feldolgozás szabálya időben nem változik. Ebben az alfejezetben az egyszerű rekurrens cella állapotegyenletét, paramétermegosztását, a változó hosszúságú bemenetek paddingjét és a kauzális információs határt vizsgáljuk.
Előismeret: a cross-correlation és az alakok 13.2. Konvolúció és cross-correlation alfejezetből, a hibaszeletek és az értékelési körülmények 23.4. Hibaszeletek és alkalmazási határ alfejezetből, a zárt/nyílt világú inputkezelés 25.4. Nyílt halmaz és ismeretlen input alfejezetből, az alkalmazási szerződés 28.4. VII. ellenőrző pont: CNN alkalmazási szerződés alfejezetből, a látens állapot és a likelihood 31.1. VAE és variációs alsó korlát alfejezetből, valamint az embedding mint reprezentáció 28.1. Embedding, távolság és normalizálás alfejezetből. A 20.1. Feature extractor és új fej alfejezetben látott befagyasztott paraméterek gondolatát itt annyiban használjuk, hogy a rekurrens cella megosztott súlyai egyetlen paramétercsoportot alkotnak.
Induló kérdés: egy batch három különböző hosszúságú szekvenciát tartalmaz. Hogyan ábrázoljuk ezt egyetlen, fix alakú tensorral úgy, hogy a mesterségesen hozzátett üres helyek ne adjanak hamis tanítójelet, és egy adott időpont kimenete ne lássa a jövőbeli tokeneket? Becslés: kell egy explicit hosszlista, egy padding maszk és szükség esetén egy kauzális maszk; a három közül egyik sem pótolja a másikat.
Definíció (véges szekvencia). Egy hosszúságú szekvencia
ahol a diszkrét időindex, pedig a -edik token vektoros reprezentációja. Szöveges adatban a token lehet szó, részcímke vagy karakter beágyazása; hangban spektrális keret; a korábbi GlyphLab-képekhez hasonlóan a bemeneti objektumot a feladat szerint választott ábrázolás adja.
A gyakorlati minták hossza általában nem azonos. Legyen a batch elemszáma , az egyes minták valódi hossza , és
A batchelt reprezentáció
ahol az -edik mintánál a pozíciók feltöltött, pad elemek. A pad értéke leggyakrabban a vektor, de önmagában a nulla érték nem azonosítja a pad pozíciót, mivel valódi token is lehet nulla. Ezért a hosszlistát külön nyilvántartjuk.
Definíció (padding maszk). A padding maszk
A veszteségszámításban a pad pozíciókhoz tartozó tagokat ki kell zárni. Ha a modell minden időlépésre ad egy kimenetet és a veszteség elemenkénti, akkor a maszkolt átlag például
Itt a nevező az érvényes, nem pad pozíciók száma; ez fontos, mert a változó hosszúság miatt a mintánkénti átlagok egyszerű átlaga nem feltétlenül azonos a tokenenkénti átlaggal. A nevező , és ez különbözik a padelt tokenek számától. Az átlagolási konvenciót a 7.3. Bináris, multilabel és regressziós cél veszteségfüggvényeknél is következetesen rögzítjük.
Definíció (kauzális maszk). Az autoregresszív vagy időben okszerű feldolgozásban az -edik időlépés kimenete csak a inputoktól függhet. A kauzális maszk
A maszk tehát a páronkénti függésmátrix felső háromszögét tiltja a főátló fölött. A padding maszk az üres pozíciókra vonatkozik, a kauzális maszk az időrendre; a kettő nem helyettesíti egymást. Egy pad pozíció lehet múltbeli időindex is, ezért általában szükség van mindkettőre.
Intuíció a CNN-hez képest. A 2D konvolúcióban a kernel minden térbeli ablakra ugyanazt a paramétert használja: ez a térbeli eltolási equivarianciához kapcsolódik 16.1. Eltolási equivariance és invariance. A szekvenciamodellben az időbeli súlymegosztás azt fejezi ki, hogy „ugyanaz a szabály dolgozza fel a mondat elejét és végét”. A fontos különbség a recepciós mező jellege: a konvolúció véges ablakot lát, a rekurrens cella állapota viszont az egész múlt összefoglalója lehet.
Definíció (egyszerű rekurrens cella, oszlopvektoros alak). Legyen a rejtett dimenzió, a kezdeti állapot (leggyakrabban ). A cella paraméterei
Egy elemenként alkalmazott aktivációval az állapotfrissítés
A pre-aktivációt külön névvel jelöljük, mert a gradiensszámításban szerepel.
A batchelt, mintát tartalmazó alakban a PyTorch-szerű konvencióval
A bias itt is soronként broadcastolódik, ahogy az affin rétegnél megszoktuk 3.2. Mátrixszorzás és affín réteg.
A definíció lényege, hogy a paraméterek minden időlépésben ugyanazok a változók. A rekurrencia tehát egy
függvény ismételt alkalmazása, nem pedig darab független réteg.
Lemma (időbeli paramétermegosztás gradiense). Tegyük fel, hogy elemenkénti, komponensenként differenciálható, és legyen skalár veszteség, amely a rejtett állapotokon keresztül függ a cellától. Jelölje
az aktiváció Jacobi-mátrixát a -edik lépésben. Ekkor a teljes veszteség gradiense a megosztott paraméterekre
ahol a veszteség alakú (ha csak a végső állapottól függ, akkor minden -re), és a vektorok a következők. A közvetlen tag , vagyis deriváltja szerint úgy, hogy a későbbi állapotokon át ható függést nem számoljuk. A teljes visszaterjesztett vektor (a jövő lépéseken át érkező hatással együtt) az utolsó lépéstől visszafelé:
és az előaktivációk gradiense . A fenti képletekben tehát .
Bizonyítás (rövid, a láncszabályból). Rögzített -re a kifejezésben a lineárisan szerepel. A mátrix–vektor szorzat deriváltja a bemeneti vektorral vett külső szorzat, ezért a -n keresztül vett parciális hozzájárulás . Mivel maga is függ a korábbi lépések -jától, de ugyanaz a változó szerepel azokban a lépésekben is, a láncszabály szerint a teljes gradiens az egyes indexekre vonatkozó parciális hozzájárulások összege. Az összegzés indexhatára ; az és esetén analóg módon járunk el. A rekurziója a 4.3. Jacobi-mátrix, láncszabály és VJP alfejezetben bevezetett VJP láncszabály következménye: két úton hat -re, közvetlenül -n át () és a következő előaktiváción át, amelynek VJP-je ; a két hozzájárulás összeadódik. A függőségi gráf irányított, ezért az idő mentén visszafelé haladunk. Az alakellenőrzés: , , a külső szorzat alakú; esetén adódik. ∎
Kétlépéses kézi kontroll (nemnulla visszacsatolással). Legyen , , , , , , , , és , tehát , . A forward: , ; , . A Jacobi-tényezők : , . A rekurzió: , ; , . Így
Ha valaki a -ben csak a közvetlen tagot venné (a jövőből érkező nélkül), -re -öt kapna. A PyTorch autograd float64-ben ugyanezt a két értéket adja hat tizedesjegyre ( és ).
A lemma a backpropagation through time elnevezés mögötti pontos számítási szabályt adja. A megosztott paraméter fontos következménye, hogy a modell paraméterszáma nem függ a szekvencia hosszától, szemben egy olyan naiv rétegsorozattal, amely minden időlépésre külön affin réteget tanulna.
LSTM-áttekintés. Az egyszerű rekurrens cella gyakorlati problémája, hogy a hosszú időlépéseken át visszaterjedő gradiens szorzataiban a mátrixok ismétlődnek, ami a gradiens eltűnését vagy felrobbanását okozhatja. Az LSTM ezt úgy kezeli, hogy külön sejtállapotot tart fenn, és input-, felejtő- meg kimeneti kapukkal szabályozza, mennyi információ íródjon be, maradjon meg vagy kerüljön a rejtett kimenetbe. Az alábbiakban csak a fogalmi szerkezetet használjuk; a pontos kapuformulákat a későbbi szekvenciafejezetben, ellenőrzött forrás mellett vezetjük be.
Legyen , ,
és elemenként. A bemenetek:
A rekurzív számolás négy tizedesjegyre kerekítve:
Két tulajdonság látható: az hatása a -ban már csak nagyságrendű, tehát a rekurrens állapot exponenciálisan halványíthatja a régi bemeneteket; másrészt a lépésben a modell csak és ismeretében számolt, a bemenetet nem látta. Az alábbi minikód ellenőrzi ugyanezt:
import torch
torch.manual_seed(0)
W_h = 0.5 * torch.eye(2, dtype=torch.float32)
W_x = torch.eye(2, dtype=torch.float32)
b = torch.zeros(2, dtype=torch.float32)
x = torch.tensor([[0.5, 0.0], [0.0, 0.5], [0.0, 0.0]],
dtype=torch.float32)
h = torch.zeros(2, dtype=torch.float32)
print(f"{'t':>2} {'h_t':>20}")
print(f"{0:>2} {h.tolist()}")
for t, x_t in enumerate(x, start=1):
h = torch.tanh(h @ W_h.T + x_t @ W_x.T + b)
print(f"{t:>2} {[round(float(v), 4) for v in h]}")A kód a batchelt formát ugyanazzal a transzponált affin konvencióval
használja; a fenti számokkal a kerekített egyezés várható, de a
tanh implementációja miatt az utolsó tizedesjegyekben
eltérés lehet, ezért 1e-3 abszolút tolerancia az ésszerű
ellenőrzési határ.
A labor célja, hogy egyetlen minibatchben lássuk a padding maszk és a kauzális maszk különböző szerepét. A kód nem követeli meg a teljes tanítást, csak a két maszk konstrukcióját és egy ellenőrző mérést.
import torch
torch.manual_seed(0)
# Három változó hosszúságú minta, T=4, d_in=3.
# Az első 4, a második 3, a harmadik 1 érvényes token.
lengths = torch.tensor([4, 3, 1])
X = torch.randn(3, 4, 3, dtype=torch.float32)
# Padding maszk: P[i,t]=1, ha t >= lengths[i].
T = X.size(1)
pad_mask = torch.arange(T)[None, :] >= lengths[:, None]
# Kauzális maszk: M[i,j]=1, ha j > i (a jövő tiltása).
causal_mask = torch.triu(torch.ones(T, T, dtype=torch.bool), diagonal=1)
# Ellenőrzés: pad maszk érvényes elemszáma egyenlő a hosszlista összegével.
assert int((~pad_mask).sum()) == int(lengths.sum())
# Causal maszk: főátló és alsó háromszög engedélyezett.
allowed = ~causal_mask
assert torch.equal(allowed, torch.tril(torch.ones(T, T, dtype=torch.bool)))
print("pad_mask =")
print(pad_mask.int())
print("causal_mask (tiltott = 1) =")
print(causal_mask.int())A várt kimenet (jelölt szemléltetés, nem mért futás):
pad_mask =
tensor([[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 1, 1, 1]], dtype=torch.int32)
causal_mask (tiltott = 1) =
tensor([[0, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 0, 1],
[0, 0, 0, 0]])
Az ellenőrzési pont: az első mintának nincs pad eleme, a harmadiknak a időindexű elemei mind pad pozíciók. A kauzális maszk első sora a pozíciót tiltja, mert az első időlépés kimenete csak az első inputtól függhet. Ha egy modell minden időlépésben ugyanazt az inputot kapná, a padding maszk önmagában nem tiltaná a jövőt; a kauzális maszkra akkor is szükség van, ha az összes pozíció érvényes, tehát a kettő nem ugyanazt a hibát védi ki.
Futtatási utasítás: a fenti kódot a
lab/n125/pad_causal_demo.py fájlba téve a
python lab/n125/pad_causal_demo.pyparancs futtatja. A torch.manual_seed(0) miatt a
véletlen bemenet reprodukálható CPU-n, de más PyTorch-verzió esetén a
generált számok nem garantáltan bitazonosak; a két assert
ekkor is ellenőrzi a maszkok szerkezetét.
F1 (fogalmi, nehézség 1). Adjon olyan konkrét , példát, amelyben a padding maszk és a kauzális maszk különböző pozíciókat tilt, és magyarázza meg, miért nem elegendő önmagában a padding maszk egy autoregresszív modell tanításához.
F2 (levezetési, nehézség 2). Tekintsünk egy lineáris rekurrens cellát , , , és skalár paraméterrel , ahol . Vezesse le a zárt alakját függvényében, és adja meg pontosan, mely értékekre korlátos a limesz tetszőleges, egyenletesen korlátos bemeneti sorozatra. Ellenőrizze az eredményt a lemma gradienseinek speciális esetére.
F3 (implementációs, nehézség 2). Írjon olyan
Python-függvényt, amely egy változó hosszúságú batch X és
lengths tenorból kiszámítja a pad_mask-et,
majd egy adott loss_per_step azonos alakú tensoron a
maszkolt átlagot. A függvény térjen vissza az átlaggal és az érvényes
elemszámmal is. Teszteset: X alakja (3,4,3),
lengths = [4,3,1], loss_per_step legyen csupa
egy; várt érvényes elemszám
,
várt átlag
.
F4 (hibakeresési, nehézség 2). Egy fejlesztő a következőt írja: a paddingnek a veszteségben való kihagyásához a pad pozícióknál nullázza a rejtett állapotot a rekurrens lépés után, de a maszkot nem használja a veszteségátlagban. Lokalizálja a két hibát, indokolja a tanulási következményt, és adjon minimális javítást a fenti labor kódjához.
F5 (kísérlettervezési/transzfer, nehézség 3). Egy osztályozó modell bemenetként változó hosszúságú, legfeljebb hosszú szekvenciákat kap. Tervezzen kísérletet annak eldöntésére, hogy a -re való padding vagy a -re való csonkolás ad-e jobb validációs pontosságot adott számítási keret mellett. Adja meg a protokollt: adatforrás, megfigyelési egység, split, baseline, változó tényező, metrika, validációs választás és a következtetés érvényességi határát. A feladat nyitott, egy lehetséges terv ismertetése elfogadható.
F1. Legyen , , így . A padding maszk csak a második minta harmadik pozícióját tiltja: . A kauzális maszk ezzel szemben a (query-idő, key-idő) párokra : a kimenet időpontban nem láthatja a jövőbeli bemenetet, akkor sem, ha mindkét minta minden pozíciója érvényes. A padding maszk csak az üres pozíciókat kezeli; ha a modell például attentiont számol, akkor egy érvényes token jövőbeli tokenre is figyelhetne, ami tanításban magas pontosságot, de az autoregresszív használatban összeomlást ad. A két maszk együtt használandó: az engedélyezett pozícióhalmaz .
F2. A lineáris rekurzió . Teljes indukcióval:
Ez a konvolúciós forma is: egy geometriailag csillapodó, időben megosztott szűrő. Az alakellenőrzés: , minden tag ugyanakkora dimenziójú. Ha minden -re, akkor
A sorozat korlátos minden -re pontosan akkor, ha , ekkor a felső korlát . Ha , választható konstans bemenet, amelyre divergál; ha , az esetben , ami már konstans bemenet mellett is lineárisan nő, esetén pedig váltakozó módon nem konvergál. A lemma szerint a lineáris esetben , így , ami a kimondott képlet speciális esete.
F3. Minimális, futtatható megoldás:
import torch
def masked_mean_loss(loss_per_step, lengths):
"""
loss_per_step: float32 tensor, shape (N, T)
lengths: int64 tensor, shape (N,), minden elem 1..T
Visszaadja a nem pad elemek átlagát és az érvényes elemszámot.
"""
N, T = loss_per_step.shape
pos = torch.arange(T)[None, :]
valid = pos < lengths[:, None]
denom = int(valid.sum())
if denom == 0:
raise ValueError("üres batch: nincs érvényes pozíció")
return float(loss_per_step[valid].sum() / denom), denom
# Teszt
loss = torch.ones(3, 4, dtype=torch.float32)
lengths = torch.tensor([4, 3, 1], dtype=torch.int64)
mean, count = masked_mean_loss(loss, lengths)
print(mean, count) # 1.0, 8
assert mean == 1.0 and count == 8Szélsőeset: ha egy minta hossza
,
a függvény azt a pozícióját kihagyja; ha minden hossz
,
az üres batch hibát dob, mert az átlag nem definiált. Az
assert float egyenlőséget használ, ami itt a
csupa egyes mátrixon pontos; más adatoknál toleranciát kell adni.
F4. Az első hiba: a rejtett állapot nullázása
utólag nem szünteti meg, hogy a rekurrens lépésben a
pad token már beírta a hatását a megelőző lépésekből; ráadásul ha a
nullázás a következő lépés bemeneteként szolgál, az állapotdinamika
torzul. A második hiba: a veszteségátlagban a pad pozíciók továbbra is
szerepelnek, ezért a nevező
lesz az érvényes elemszám helyett, és a modell a pad tokenekre is
illeszteni próbál. Következmény: a veszteség hamis jelzést ad, a
gradiens felfelé torzul a hosszú minták irányába, a rövid mintákra
rosszabbul általánosít. Javítás: a rekurrens lépés bemeneti pozíciójában
a pad tokeneket ne etessük be, vagy ha az RNN implementáció minden
lépést számol, akkor a veszteségben alkalmazzuk a
pad_mask-et; a fenti labor
masked_mean_loss-hez hasonlóan. Visszaellenőrzés: érvényes
elemszámnak
-nak
kell lennie a tesztesetben, nem
-nek.
F5. Egy lehetséges terv: készítünk egy procedurális, 64-nél nem hosszabb szekvenciákat generáló adatforrást; minden adatpont egy független szekvencia, a generálási folyamat rögzített seeddel. A split train/val/test például 600/100/100, a testet csak a végén használjuk. A baseline legyen egy osztályonkénti prior-osztályozó, hogy a magas osztályarány ne adjon hamis képet. A változó tényező a bemenet-előkészítés: (A) pad -re; (B) csonkol -re. Ugyanazt a modellvázat (például egy rekurrens cella vagy kauzális konvolúció utolsó állapotára illesztett lineáris fej) mindkét beállítással tanítjuk, azonos loss, optimizer, seed és epochszám mellett. A kiválasztás metrikája a validációs accuracy; a seedek több ismétlésével (például 10) a különbségre adunk szórást is. Az érvényességi korlát: az eredmény csak a saját szekvencia-eloszlásra és hossztartományra vonatkozik; a -re csonkolásnál a hosszú minták elveszett farokinformációja miatt a pontosságromlás az adott tartalomtól függ, ezért a következtetést nem szabad általános csonkolási szabályként kimondani. A számítási költség mérésekor a futási időt is rögzíteni kell, mert a rövidebb bemenet nemcsak pontosabb vagy pontatlanabb, hanem gyorsabb is lehet.
A leggyakoribb tévedés, hogy a tanításkor elérhető teljes szekvenciát automatikusan az inferenciahelyzettel azonosnak tekintjük. Ez nemcsak a padding mask hiányakor, hanem akkor is hibás, ha a modell a -edik kimenethez a utáni tokeneket is bemenetként kapja. Ellenpélda: legyen egy fordítói vagy következő token predikciós modell, amely tanításkor a inputot is felhasználja a kimenet előállításához. A tanítási veszteség kicsi lehet, mert a cél token gyakran megegyezik a következő bemeneti tokennel. Az éles használatban azonban még nem áll rendelkezésre a döntésnél, így a modellt olyan bemenetre kényszerítjük, amelyet soha nem látott. A megoldás a kauzális maszk: a -edik kimenetnek kizárólag bemeneteken szabad múlnia; a padding maszk önmagában ezt nem garantálja. A helyes kísérleti napló ezért külön rögzíti a tanítási és az autoregresszív kiértékelési módot 12.1. Tanítás, validáció és kiértékelési mód.
Önellenőrző kérdések: (1) Meg tudom-e mondani a és az maszk pontos alakját? (2) A lemma összegzésében miért -től -ig összegzünk, és miért nem ugyanaz, mint egyetlen hosszú affin lánc gradiense? (3) Mi a zero padding szerepe a CNN-ben 14.1. Stride, padding, dilation és outputméret, és miért nem azonos a szekvenciális padding maszkkal?
Visszahívás: a 31.1. VAE és variációs alsó korlát alfejezetben bevezetett látens kódolóval szemben a rekurrens determinisztikus időbeli állapot, nem valószínűségi posterior. A 28.1. Embedding, távolság és normalizálás alfejezetben az embedding egyetlen input statikus reprezentációja volt; itt a rejtett állapot az inputok sorozatától függő, kontextusfüggő reprezentáció. A 20.1. Feature extractor és új fej alfejezetben a befagyasztott backbone paramétereihez hasonlóan a rekurrens cellában is egy paramétercsoportként kezeljük a megosztott hármast.
A szekvenciamodell a változó hosszúságú token-sorozatokat közös időtengelyen ábrázolja. A padding maszk az érvénytelen pozíciókat, a kauzális maszk a jövőbeli információs csatornát zárja le; a kettő nem helyettesíthető. Az egyszerű rekurrens cella ugyanazt a paramétert használja minden időlépésben; a lemmában megmutattuk, hogy a gradiensük az időlépésenkénti külső szorzatok összege. Az LSTM kapukkal vezérli a hosszú távú állapotot; a temporális konvolúció ezzel szemben véges recepciós mezőjű, nem rekurrens művelet. A kézi és a kódos példa a maszkok szerkezetét és az időbeli súlymegosztás hatását ellenőrzi.
A 32.2. Scaled dot-product attention egységben a rekurrenciát elhagyjuk, és a scaled dot-product attention operátort vezetjük be. A most definiált kauzális és padding maszk ott közvetlenül a figyelmi súlymátrixra kerül; az időbeli súlymegosztás helyébe a pozíciófüggetlen, de pozíciókódolást igénylő attention lép.