10.1 Számítási gráf és lokális derivált

10.1.1 Cél, előismeret és induló becslés

A cél: a visszaterjesztést nem „varázslatként”, hanem egy irányított aciklikus számítási gráfon (DAG) végzett gépi eljárásként leírni, és pontosan bizonyítani, miért összeadódnak egy elágazó csúcshoz több útról érkező gradiens-hozzájárulások. Ez az összegzés a későbbi konvolúciós rétegek és reziduális hálók gradiensének is alapja.

Előismeret: a láncszabály és VJP 4.4. I. ellenőrző pont: matematika és kód megfelelése alfejezetből, az aktivációk lokális deriváltja 9.4. Aktivációk és gradiensáramlás alfejezetből; az optimalizáló frissítés fogalma 6.4. Momentum és adaptív optimizálók alfejezetből, a batch-átlagos veszteség skálája 6.1. Objektív, reguláris tag és gradienslépés alfejezetből. Visszautalunk a neuronra 9.1. Neuron és perceptron: ott egyetlen affin score és egy aktiváció alkotta a modellt; itt ezt kötőelemekre bontjuk.

Induló becslés. Legyen u=(1,−1)⊤u=(1,-1)^\top, x1=(1,2)⊤x_1=(1,2)^\top, x2=(3,1)⊤x_2=(3,1)^\top, és legyen a=u⊤x1a=u^\top x_1, b=u⊤x2b=u^\top x_2, L=12a2+12b2L=\tfrac12 a^2+\tfrac12 b^2. Ha a visszaterjesztéskor csak az aa-ágat vennénk figyelembe, mekkora lenne a hiba ∇uL\nabla_u L-ben? A teljes megoldás a 37.5 szakaszban: a helyes gradiens (5,0)⊤(5,0)^\top, a hiányos (−1,−2)⊤(-1,-2)^\top, így a hiba (6,2)⊤(6,2)^\top, tehát nem kicsi, hanem maga a második ág hozzájárulása.

10.1.2 Számítási gráf, topologikus sorrend, mentett köztes érték

Definíció (számítási gráf). A modell kiértékelésének számítási gráfja egy G=(V,E)G=(V,E) irányított gráf, ahol

A csúcsok szerepe szerint megkülönböztetünk input csúcsokat (paraméterek és bemeneti adatok), köztes csúcsokat és veszteség csúcsot, ahol L∈ℝL\in\mathbb R skalár. A kör kizárása szükséges: kör esetén a forward-kiértékelés nem tudna megállni, mert a v0v_0 kiértékeléséhez önmaga értékére lenne szükség.

Definíció (topologikus sorrend). A G=(V,E)G=(V,E) DAG egy topologikus sorrendje a csúcsok olyan v1,…,vTv_1,\dots,v_T felsorolása, amelyben minden (vi,vj)∈E(v_i,v_j)\in E élre i<ji<j. Minden véges DAG-nak van topologikus sorrendje; a forward-kiértékelés egyszerűen ezt a sorrendet követi, a visszaterjesztés pedig a megfordított vT,…,v1v_T,\dots,v_1 sorrendet.

Definíció (mentett köztes érték). Egy csúcs mentett köztes értékei (saved intermediates) azok a tenzorok, amelyeket a csúcs forward-számításakor elmentünk, mert a lokális gradiens kiszámításához a backward lépésben szükségesek. Például ϕ(z)\phi(z) lokális deriváltjához a bemeneti zz kell, a szigmoidnál σ′(z)=σ(z)(1−σ(z))\sigma'(z)=\sigma(z)(1-\sigma(z)) miatt elegendő az output mentése is. Implementációs döntés, hogy mit mentünk; matematikailag a lokális derivált függvénye a csúcs bemenetének.

10.1.3 Lokális VJP és a visszafelé haladás szabálya

Legyen a veszteség LL, és legyen vv valamely csúcs, amelynek gradiense már ismert: minden csúcsra a ∇vL\nabla_v L tenzort keressük, amelynek alakja megegyezik vv alakjával (a JELOLESEK oszlop-konvenciója szerint).

Definíció (lokális VJP). Legyen a v=f(u)v=f(u) művelet, ahol u∈ℝdu\in\mathbb R^d, v∈ℝpv\in\mathbb R^p, ff differenciálható. A művelet lokális VJP-leképezése a gu=Jf(u)⊤gv g_u = J_f(u)^\top g_v hozzárendelés, ahol Jf(u)∈ℝp×dJ_f(u)\in\mathbb R^{p\times d} a Jacobi-mátrix (sor: output-index, oszlop: input-index), és gv=∇vL∈ℝpg_v=\nabla_v L\in\mathbb R^p. A gug_u eredmény ℝd\mathbb R^d-beli, tehát alakja megegyezik uu alakjával. A VJP-t az egész Jacobi-mátrix anyagiasítása nélkül számoljuk: minden elemi művelethez zárt, kis költségű VJP-képlet tartozik.

Például az f(u)=u⊤xf(u)=u^\top x skalár művelet lokális VJP-je Jf=x⊤J_f=x^\top, tehát gu=xgvg_u=x\,g_v, ahol gv∈ℝg_v\in\mathbb R skalár gradienst szorozzuk az input vektorral.

A visszafelé haladás a topologikus sorrend megfordítottján halad. Amikor a vv csúcsot feldolgozzuk, a rá érkező összes él lokális VJP-jét kiszámítjuk, és az eredményt a megfelelő uu csúcs gradiens-mezőjébe hozzáadjuk. Az összeadás a 37.4 lemmából következik, és a PyTorch autograd is ezt a „grad mező +=” mechanizmust valósítja meg; a jelen könyv a [D05] hivatkozást csak kiinduló státusszal közli, a saját kódban az accumulation explicit lista alapján történik.

Elágazás (branching): amikor egy uu csúcsból legalább két él indul ki, azaz uu-t több leszármazott művelet használja. A gradiens-felhalmozás (gradient accumulation) ilyenkor kötelező: minden leszármazott hozzájárulását az uu-hoz rendelt gradiens-mezőben összegezzük.

10.1.4 A gradiens-összegzés lemmája két ággal

Lemma (két ág gradiense összeadódik). Legyen u∈ℝdu\in\mathbb R^d, f1:ℝd→ℝp1f_1:\mathbb R^d\to\mathbb R^{p_1} és f2:ℝd→ℝp2f_2:\mathbb R^d\to\mathbb R^{p_2} differenciálható, valamint h:ℝp1+p2→ℝh:\mathbb R^{p_1+p_2}\to\mathbb R differenciálható. Definiáljuk a=f1(u),b=f2(u),L(u)=h(a,b). a=f_1(u),\qquad b=f_2(u),\qquad L(u)=h(a,b). Ha az adott uu pontban mindegyik függvény differenciálható, akkor ∇uL=Jf1(u)⊤∇ah(a,b)+Jf2(u)⊤∇bh(a,b). \boxed{\;\nabla_u L=J_{f_1}(u)^\top\nabla_a h(a,b)+J_{f_2}(u)^\top\nabla_b h(a,b).\;} A két tagot összeadjuk, nem átlagoljuk, és nem választjuk ki közülük a nagyobbat.

Bizonyítás. Definiáljuk az F:ℝd→ℝp1+p2F:\mathbb R^d\to\mathbb R^{p_1+p_2} leképezést az F(u)=(f1(u)f2(u)) F(u)=\begin{pmatrix}f_1(u)\\ f_2(u)\end{pmatrix} oszlopvektorral. Ekkor L(u)=(h∘F)(u)L(u)=(h\circ F)(u). A Jacobi-mátrix blokkmátrix alakú: JF(u)=(Jf1(u)Jf2(u))∈ℝ(p1+p2)×d. J_F(u)=\begin{pmatrix}J_{f_1}(u)\\ J_{f_2}(u)\end{pmatrix}\in\mathbb R^{(p_1+p_2)\times d}. A többváltozós láncszabály (amelyet 4.3. Jacobi-mátrix, láncszabály és VJP alfejezetben az elemi függvényekre felépítettünk) szerint Jh∘F(u)=Jh(a,b)JF(u)∈ℝ1×d. J_{h\circ F}(u)=J_h(a,b)\,J_F(u)\in\mathbb R^{1\times d}. Mivel LL skalár kimenetű, ∇uL=Jh∘F(u)⊤\nabla_u L=J_{h\circ F}(u)^\top. Behelyettesítve a blokkmátrixot és használva, hogy Jh(a,b)J_h(a,b) partíciója (∇ah,∇bh)(\nabla_a h,\nabla_b h) a p1p_1 és p2p_2 koordinátablokkok szerint: ∇uL=(Jf1(u)⊤Jf2(u)⊤)(∇ah∇bh)=Jf1(u)⊤∇ah+Jf2(u)⊤∇bh. \nabla_u L =\begin{pmatrix}J_{f_1}(u)^\top & J_{f_2}(u)^\top\end{pmatrix} \begin{pmatrix}\nabla_a h\\ \nabla_b h\end{pmatrix} =J_{f_1}(u)^\top\nabla_a h+J_{f_2}(u)^\top\nabla_b h. Ezzel a lemma állítását megkaptuk. ▫\square

A lemma tetszőleges véges sok kk ágra indukcióval terjeszthető ki; a k=2k=2 eset a könyv további fejezeteihez is elegendő alap. Az összegzés nem „heurisztika”, hanem a láncszabály folyománya, feltéve a sima differenciálhatóságot a vizsgált pontban. A ReLU nullpontját ezért a 9.4. Aktivációk és gradiensáramlás alfejezetben megadott konvencióval, külön kezeljük a numerikus ellenőrzés során.

10.1.5 Kézi példa: egy paraméter, két ág

Tekintsük az alábbi gráfot:

       ┌── a = uᵀx₁ ──┐
u ─────┤              ├── L = ½(a²+b²)
       └── b = uᵀx₂ ──┘

Legyen u=(1−1),x1=(12),x2=(31). u=\begin{pmatrix}1\\ -1\end{pmatrix},\qquad x_1=\begin{pmatrix}1\\ 2\end{pmatrix},\qquad x_2=\begin{pmatrix}3\\ 1\end{pmatrix}. A forward: a=u⊤x1=1⋅1+(−1)⋅2=−1,b=u⊤x2=3−1=2,L=12(1+4)=52. a=u^\top x_1=1\cdot1+(-1)\cdot2=-1,\qquad b=u^\top x_2=3-1=2,\qquad L=\tfrac12(1+4)=\tfrac52. Lokális VJP-k az egyes ágakon:

A lemma szerint ∇uL=(−1,−2)⊤+(6,2)⊤=(5,0)⊤. \nabla_u L=(-1,-2)^\top+(6,2)^\top=(5,0)^\top. Ellenőrzés elemi parciális deriválással: ∂L∂u1=a∂a∂u1+b∂b∂u1=−1⋅1+2⋅3=5,∂L∂u2=−1⋅2+2⋅1=0. \frac{\partial L}{\partial u_1}=a\frac{\partial a}{\partial u_1}+b\frac{\partial b}{\partial u_1}=-1\cdot 1+2\cdot 3=5,\qquad \frac{\partial L}{\partial u_2}=-1\cdot 2+2\cdot 1=0. Az induló becslésben kérdezett „csak az első ág”-gradiens (−1,−2)⊤(-1,-2)^\top, tehát a hiba valóban a második ág teljes hozzájárulása, (6,2)⊤(6,2)^\top.

10.1.6 NumPy-labor: elágazó gráf és elhagyott gradiens

A labor célja annak bemutatása, hogy a helyes backward egyezik a középső differenciával, a szándékosan elhagyott ág pedig mérhető hibát okoz. A kód futtatandó a lab/n037_graph.py fájlból a lab munkakönyvtárban; a kimeneti blokk a képletből számított érték, nem végrehajtott mérés jegyzőkönyve.

import numpy as np

rng = np.random.default_rng(20261020)      # seed a reprodukálhatósághoz
u  = np.array([1.0, -1.0], dtype=np.float64)
x1 = np.array([1.0,  2.0], dtype=np.float64)
x2 = np.array([3.0,  1.0], dtype=np.float64)

def forward(u, x1, x2):
    """A 37.5 gráf forward-ja; visszaadja L-et és a mentett értékeket."""
    a = u @ x1
    b = u @ x2
    L = 0.5 * (a * a + b * b)
    return L, (a, b, x1, x2)

def backward_both(cache):
    """Helyes backward: mindkét ág hozzájárulását összeadjuk."""
    a, b, x1, x2 = cache
    return a * x1 + b * x2                     # dL/du

def backward_missing_second(cache):
    """Hibás kód: a második ág hozzájárulását elhagyjuk."""
    a, b, x1, x2 = cache
    return a * x1                              # hiányzik: b*x2

def central_diff(f, u, i, eps=1e-6):
    up = u.copy(); up[i] += eps
    um = u.copy(); um[i] -= eps
    return (f(up)[0] - f(um)[0]) / (2.0 * eps)

L, cache = forward(u, x1, x2)
num   = np.array([central_diff(lambda v: forward(v, x1, x2), u, i)
                  for i in range(2)])
ana   = backward_both(cache)
wrong = backward_missing_second(cache)

def rel_err(a, b):
    denom = max(np.abs(a), np.abs(b), 1e-12)
    return np.abs(a - b) / denom

print("L      =", L)
print("numeric =", num)
print("analytic=", ana)
print("rel_err =", [rel_err(n, a) for n, a in zip(num, ana)])
print("missing =", wrong)
print("err_miss=", wrong - ana)

Várható kimenet a képletből számolva, nem mért futtatás:

L       = 2.5
numeric = [5.0 0.0]  (középső differenciával, eps=1e-6, f64)
analytic= [5. 0.]
rel_err = [~1e-16, ~1e-16]  (a középső differencia O(eps²) hibája mellett)
missing = [-1. -2.]
err_miss= [-6. -2.]

Az err_miss pontosan −bx2=−(6,2)⊤-b x_2=-(6,2)^\top: a hiba nem zaj, hanem a hiányzó lokális VJP determinisztikus értéke. A numerikus és analitikus gradiens közötti egyezést 10−710^{-7} abszolút tűréssel fogadjuk el; a középső differencia 10−610^{-6} lépésköz mellett f64-ben O(10−12)O(10^{-12}) elméleti hibájú, így a tapasztalt 10−1610^{-16} szintű relatív hiba a kerekítésnek megfelelő. A ReLU-szerű töréspont itt nem szerepel, tehát sima függvényen dolgozunk.

10.1.7 Feladatok

F1 (fogalmi, nehézség 1). Definiálja pontosan a topologikus sorrendet, és magyarázza meg, miért nem lehet irányított kör egy érvényes forward-gráfban. Adjon egy három csúcsból álló DAG-példát, amelyben a u -> v -> w él és a u -> w közvetlen él egyszerre szerepel; mondja meg, hány topologikus sorrendje van, és írja fel a lehetséges sorrendeket. Átadandó: definíció, indoklás, a példagráf és a sorrendek listája.

F2 (levezetési, nehézség 2). Legyen u=(1,2,3)⊤u=(1,2,3)^\top, p=(1,0,0)⊤p=(1,0,0)^\top, q=(0,1,0)⊤q=(0,1,0)^\top, r=(0,0,1)⊤r=(0,0,1)^\top, és legyen a=u⊤pa=u^\top p, b=u⊤qb=u^\top q, c=u⊤rc=u^\top r, továbbá L(u)=a2+exp(b)+cos(c). L(u)=a^2+\exp(b)+\cos(c). Vezesse le ∇uL\nabla_u L-et a 37.4 lemma három ágra alkalmazásával, és számítsa ki a megadott pontban. Ellenőrizze az alakot: a gradiens ℝ3\mathbb R^3-beli. Átadandó: a háromágas képlet, a részleges deriváltak, a numerikus eredmény.

F3 (implementációs, nehézség 1). Egészítse ki a 37.6 labor kódját egy harmadik ággal: c=2u⊤x3c=2u^\top x_3, L=12(a2+b2+c2)L=\tfrac12(a^2+b^2+c^2), ahol x3=(0,1)⊤x_3=(0,1)^\top. Írja meg a teljes backward-ot, és ellenőrizze mindkét komponensre középső differenciával, f64, eps=1e-6 mellett. Átadandó: futtatható kód, a három analitikus hozzájárulás, a numeric/analytic összehasonlítás, abszolút tolerancia 10−710^{-7}.

F4 (hibakeresési, nehézség 2). Az 37.6 labor backward_missing_second függvénye elhagyja a második ágat. (a) Nevezze meg a hiba okát a láncszabály szintjén. (b) Mondja meg, milyen numerikus jel utal erre a hibára, ha az eredményt középső differenciával vetjük össze. (c) Írja le a javítást és a visszaellenőrzés pontos tűrését. Átadandó: ok, következmény, javított sor, a numerikus egyezés kritériuma.

F5 (kísérleti/transzfer, nehézség 3). Tegyük fel, hogy uu helyett U∈ℝN×dU\in\mathbb R^{N\times d} batch-et használunk, és a veszteség L=1N∑i=1Nh(f1(ui),f2(ui))L=\frac1N\sum_{i=1}^N h(f_1(u_i),f_2(u_i)), ahol uiu_i az UU ii-edik sora. Tervezze meg a backward lépést, és magyarázza meg, hogyan viszonyul a batch-átlag 1/N1/N skálája a gráf elágazási összegzéséhez. Mi lenne a gradiens, ha a veszteséget sum reductionnel definiálnánk? Átadandó: a gradiens képlete, a reduction-választás hatásának indoklása, legalább egy numerikus kontrollterv a helyes skála ellenőrzésére.

10.1.8 Megoldások és indoklás

F1. A topologikus sorrend definíciója a 37.2 szakaszban szerepel. Ciklus esetén a forward-kiértékelés végtelen rekurzióba kerülne, mert egy csúcs értékének kiszámításához saját maga kellene; így a gráf aciklikussága a kiértékelhetőség feltétele. A megadott példa csúcsai {u,v,w}\{u,v,w\}, élei u→vu\to v, v→wv\to w, u→wu\to w. Egyetlen érvényes topologikus sorrend van: (u,v,w)(u,v,w), mert uu-nak vv és ww előtt, vv-nek pedig ww előtt kell állnia, és ez a két feltétel a sorrendet teljesen meghatározza.

F2. Alkalmazzuk a lemmát k=3k=3 ágra: ha L=h(a,b,c)L=h(a,b,c), akkor ∇uL=Jf1⊤∇ah+Jf2⊤∇bh+Jf3⊤∇ch. \nabla_u L=J_{f_1}^\top\nabla_a h+J_{f_2}^\top\nabla_b h+J_{f_3}^\top\nabla_c h . Itt Jf1=p⊤J_{f_1}=p^\top, Jf2=q⊤J_{f_2}=q^\top, Jf3=r⊤J_{f_3}=r^\top. A hh parciálisai: ∇ah=2a,∇bh=eb,∇ch=−sin(c). \nabla_a h=2a,\qquad \nabla_b h=e^b,\qquad \nabla_c h=-\sin(c). A megadott uu pontban a=1a=1, b=2b=2, c=3c=3, így ∇uL=2⋅1⋅p+e2⋅q−sin(3)⋅r=(2,e2,−sin3)⊤. \nabla_u L=2\cdot 1\cdot p+e^2\cdot q-\sin(3)\cdot r =(2,\ e^2,\ -\sin 3)^\top . Numerikusan e2≈7.389056e^2\approx 7.389056, −sin3≈−0.141120-\sin 3\approx -0.141120, tehát ∇uL≈(2,7.389056,−0.141120)⊤∈ℝ3. \nabla_u L\approx(2,\ 7.389056,\ -0.141120)^\top\in\mathbb R^3.

F3. A kiegészített kód:

x3 = np.array([0.0, 1.0], dtype=np.float64)

def forward3(u, x1, x2, x3):
    a = u @ x1
    b = u @ x2
    c = 2.0 * (u @ x3)
    L = 0.5 * (a*a + b*b + c*c)
    return L, (a, b, c, x1, x2, x3)

def backward3(cache):
    a, b, c, x1, x2, x3 = cache
    return a*x1 + b*x2 + (2.0*c)*x3   # c ág lokális VJP-je 2*I miatt 2c*x3

Az u=(1,−1)⊤u=(1,-1)^\top pontban: a=−1a=-1, b=2b=2, c=2⋅(−1)=−2c=2\cdot(-1)=-2. A három hozzájárulás: (−1)(1,2)⊤=(−1,−2),2(3,1)⊤=(6,2),(2⋅(−2))(0,1)⊤=(0,−4). (-1)(1,2)^\top=( -1,-2),\qquad 2(3,1)^\top=(6,2),\qquad (2\cdot(-2))(0,1)^\top=(0,-4). Összegük (−1+6+0,−2+2−4)=(5,−4)⊤(-1+6+0,\ -2+2-4)=(5,-4)^\top. A középső differencia ugyanezt adja 10−710^{-7} abszolút tűrésen belül; a kód a bb-ágat nem érintő komponensben is ellenőrzi a harmadik ág hatását.

F4. (a) A hiba oka: a teljes deriváltban a bb-ágból származó ∇bhJf2(u)\nabla_b h\, J_{f_2}(u) tag hiányzik; a kód csak Jf1⊤∇ahJ_{f_1}^\top\nabla_a h-t számol. (b) A numerikus jel: a középső differenciától való eltérés pontosan bx2=(6,2)⊤b x_2=(6,2)^\top, nem pedig kerekítési zaj; a két mennyiség közötti különbség nem csökken az eps finomításával. (c) A javítás a return a*x1 + b*x2 sor; a visszaellenőrzés kritériuma: mindkét komponensre |numerici−analytici|≤10−7 |\text{numeric}_i-\text{analytic}_i|\le 10^{-7} f64 és eps=1e-6 mellett, a 37.6 szakasz rel_err stabil nevezős relatív hibájával kiegészítve.

F5. A soronkénti elágazás változatlan: minden uiu_i sorra a gradiens-hozzájárulás a két ág összege. A batch-átlag miatt ∂L∂ui=1N(Jf1(ui)⊤∇ahi+Jf2(ui)⊤∇bhi), \frac{\partial L}{\partial u_i} =\frac1N\Big(J_{f_1}(u_i)^\top\nabla_a h_i+J_{f_2}(u_i)^\top\nabla_b h_i\Big), és a teljes paramétergradiens a sorok összege, vagyis a N×dN\times d alakú ∇UL\nabla_U L mátrix ii-edik sora a fenti vektor. A 1/N1/N a loss-reductionból fakadó globális skála, az elágazási összeg pedig a gráf szerkezetéből fakadó hozzájárulás-összeg; a kettő szorzatként jelenik meg. Ha sum reduction lenne, a 1/N1/N skála eltűnne, és a gradiens NN-szeresére nőne; ez a batch-méret változtatásakor eltérő optimáló lépésköz-igényt eredményezne. Numerikus kontrollterv: egy N=2N=2 batch esetén a teljes ∇UL\nabla_U L-et középső differenciával, soronkénti perturbációval ellenőrizni; a hiba minden elemre 10−710^{-7} abszolút tűrés alatt kell maradjon.

10.1.9 Tipikus tévedés, ellenpélda, önellenőrzés

Tipikus tévedés. A visszaterjesztést sokan azonosítják az optimalizáló paraméterfrissítésével. A kettő különböző: a backprop kiszámítja a gradienst, az optimalizáló pedig felhasználja azt a 6.4. Momentum és adaptív optimizálók alfejezetben definiált frissítésre. A backprop önmagában nem változtatja a paramétereket.

Ellenpélda. Legyen w=3w=3 skalár, és L=12w2L=\tfrac12 w^2. A backward a ∇wL=w=3\nabla_w L=w=3 gradienst adja. A backward() hívás után ww továbbra is 33; csak az optimalizáló lépése, például w←w−η∇wL=3−0.1⋅3=2.7w\leftarrow w-\eta\nabla_w L=3-0.1\cdot 3=2.7, módosítja. Ha valaki a backward hívás után azonnal w=2.7w=2.7-et várna, összekeverné a gradiensszámítást a paraméterfrissítéssel. Ugyanez a hiba előfordulhat batch-átlag esetén: a gradiensben a 1/N1/N skála a loss definíciójából következik, nem az optimalizáló beállításából.

Önellenőrzés.

  1. A gráfomban nincs irányított kör? A topologikus sorrendben minden él korábbi csúcsból későbbibe mutat?
  2. A gradiens minden csúcsra ugyanolyan alakú, mint maga a csúcs?
  3. Az elágazó csúcsnál összeadást használtam, nem pedig átlagolást vagy az egyik ág elhagyását?
  4. A batch-veszteség mean reductionje esetén a 1/N1/N megjelenik a gradiensben, míg sum esetén nem?
  5. A numerikus gradiensellenőrzés f64, középső differencia, megadott eps és tűrés mellett történt; töréspontos függvényt csak sima pontban ellenőriztem?

Visszahívás. A 4.4. I. ellenőrző pont: matematika és kód megfelelése alfejezetben az affin réteg lokális VJP-jeit bizonyítottuk; ott a g↦W⊤gg\mapsto W^\top g lépés ugyanennek a „lokális VJP” gépezetnek egy esete. A 6.1. Objektív, reguláris tag és gradienslépés alfejezetben látott batch-átlag az itteni 1/N1/N skálát adja, a 9.1. Neuron és perceptron perceptronjának score-ja pedig egyetlen gráf-él, amelyet a következő egységben kötünk össze.

10.1.10 Rövid összefoglaló

A számítási gráf egy DAG, amelynek csúcsai tenzorok, élei a felhasználási relációk. A forward a topologikus sorrendben halad, és menti a backwardhoz szükséges köztes értékeket. A visszaterjesztés a megfordított sorrendben minden élre lokális VJP-t számol, gu=Jf⊤gvg_u=J_f^\top g_v alakban. A központi lemma azt mondja ki és bizonyítja a többváltozós láncszabályból, hogy elágazó csúcsnál a leszármazott ágak gradiensei összeadódnak. Kézzel és NumPy-ban megmutattuk, hogy egy ág elhagyása nem kicsi numerikus zajt, hanem a hiányzó tag pontos értékét okozza. A backprop gradiensszámítás, nem paraméterfrissítés.

10.1.11 Következő alkalmazás és források

A következő 10.2. Affín réteg és aktiváció backward egységben az affin réteg és az elemenkénti aktiváció konkrét backward-képleteit vezetjük le ezzel a gépezettel, és az ennek során felépített VJP-készletből tanuló MLP-t építünk.