Ugrás a tartalomra
3/303/30. fejezet

Lejtmenet: gradient descent, és a két lépés, amit mindenki kihagy

Számold ki a tanulási ráta pontos felső határát, majd nézd meg, ahogy 3.600 irány brute-force keresése újra felfedezi a gradientet.

Ezen az oldalon

Az előző fejezet egy völggyel zárult.

Nem metaforikussal: egy tényleges görbével, ahol a veszteséget egyetlen paraméter függvényében ábrázoltuk, lefelé hajló, majd újra emelkedő formában. És az alatta lévő veszteséget nem azért választottuk, mert kényelmes volt — a mérések zajáról tett állításból vezettük le, és a négyzetes hiba következményként jött ki a végén, nem konvencióként.

Van tehát egy tájunk aljjal, és okunk azt hinni, hogy az alj a megfelelő hely. Ami nincs, az egy módszer, amellyel eljutunk oda.

Ez a fejezet megépít egyet, és ez az algoritmus tanítja be a kurzus további részében szereplő összes modellt — mindegyiket, kivétel nélkül, egészen a több száz milliárd paraméteresekig bezárólag. Nagyjából húsz sorban elfér. A két nehéz rész nincs benne abban a húsz sorban, és pontosan ez az a két dolog, amit szinte minden magyarázat kihagy:

  • Miért a mínuszjel. A frissítés kivonja a gradientet. Minden tutorial leírja; nagyon kevés mondja el, miért a gradient az az irány, amely felfelé mutat — márpedig csak ez teszi a mínuszjelet bármi mássá, mint hittétellé.
  • Mekkora legyen a lépés. A „túl nagy divergens, túl kicsi lassú” igaz és haszontalan. Van egy pontos szám, kiszámítható a veszteségből, és ez a fejezet kétszer is kiszámítja — egyszer egy játék-parabolára, egyszer pedig a tényleges adatokra.

A felállás, és miért nem lehet egyszerűen keresni

Link a szakaszhoz: A felállás, és miért nem lehet egyszerűen keresni

Újrafogalmazva, hogy ez a fejezet önmagában is megálljon: a 1. fejezet szállítószalagjáról származó nyolc alkatrész, de más kérdéssel. Nem elfogadni vagy elutasítani — az később visszatér —, hanem megjósolni egy alkatrész tömegét a szélességéből.

belt.pyPYTHON
import numpy as np

WIDTH  = np.array([18.0, 19.5, 20.2, 21.0, 24.0, 25.5, 23.0, 26.0])
WEIGHT = np.array([47.0, 52.0, 49.0, 55.0, 61.0, 66.0, 70.0, 58.0])

x = WIDTH  - WIDTH.mean()      # 22.15 mm
y = WEIGHT - WEIGHT.mean()     # 57.25 g

A mérések középre vannak igazítva, pontosan úgy, mint az 1. fejezetben, és olyan okból, amely kamatostul visszatér, mielőtt ez a fejezet véget ér. A modell egy egyenes, y^=ax+b\hat{y} = a x + b, a veszteség pedig az előző fejezetben levezetett átlagos négyzetes hiba:

L(a,b)=1ni=1n(axi+byi)2L(a, b) = \frac{1}{n} \sum_{i=1}^{n} \left(a x_i + b - y_i\right)^2

Két paraméter. Miért ne próbálnánk ki sok értéket? Tegyük is meg — egy rács a=0a = 0 és 55, illetve b=5b = -5 és 55 között, 0.010.01-es lépésekkel:

TEXT
grid 501 x 1001 = 501,501 evaluations in 3.67 s
  best found: a = 2.1000, b = -0.0000, L = 24.592450

Félmillió kiértékelés két szám két tizedesjegyre való belövéséhez — és az a másodperc falióra-idő egy gépen, ezért egy újrafuttatás három és hat között bárhol landolhat; a kiértékelések száma és a minimum az, ami reprodukálható. A gradient descent a fejezet végén nyolc lépésben négy tizedesjegyet kap, harminchatban pedig a teljes float64 választ.

De nem a sebesség az érv, és ez az a pont, amely az egész kurzust eldönti. A rácskeresés költsége kPk^P kiértékelés PP paraméterre, tengelyenként kk értékkel. Tengelyenként ezer értékkel:

modellparaméterekrácskiértékelések
ez az egyenes210610^{6}
az 5. fejezet XOR-hálózata9102710^{27}
egy kis többrétegű hálózat20.0001060,00010^{60{,}000}

A harmadik sor nem nagy szám, hanem értelmetlen — a megfigyelhető univerzumban nagyjából 108010^{80} atom van. A keresés nem lassabb lesz, ahogy a modellek nőnek; megszűnik létezni. Minden, ami ezután jön, emiatt a táblázat miatt létezik.

A derivált egy mérés, amit el tudsz végezni

Link a szakaszhoz: A derivált egy mérés, amit el tudsz végezni

Rögzítsük b=0b = 0 értékét egy pillanatra, hogy egy paraméter és egy görbe maradjon — ez az a kép, amelyet az előző fejezet rád hagyott. Vegyünk rajta egy pontot, a=1a = 1, és kérdezzük meg: ha aa értékét egy kis hh mennyiséggel elmozdítom, mennyit mozdul a veszteség, az elmozdítás egységére vetítve?

L(a+h)L(a)h\frac{L(a + h) - L(a)}{h}

Ez az arány egy emelkedés osztva futással — a görbe két pontján átmenő egyenes meredeksége. Ahogy hh zsugorodik, a két pont összecsúszik, és az egyenes érintővé válik. Ennek meredeksége a derivált L(a)L'(a): az a ráta, amellyel a veszteség változik aa egységnyi változására. Nem valaminek a közelítése, és nem végtelenül kicsi mennyiség. Közönséges arányok határértéke.

Érdemes lefuttatni, mert a számok olyasmit mondanak, amit a definíció nem:

slope.pyPYTHON
def loss1(a):
    return np.mean((a * x - y) ** 2)

for h in [1.0, 1e-2, 1e-4, 1e-6, 1e-8, 1e-10, 1e-12, 1e-14]:
    q = (loss1(1.0 + h) - loss1(1.0)) / h
    print(f"h = {h:<8.0e}   slope estimate = {q:.10f}   error = {abs(q + 16.385):.3e}")
TEXT
h = 1e+00      slope estimate = -8.9400000000    error = 7.445e+00
h = 1e-02      slope estimate = -16.3105500000   error = 7.445e-02
h = 1e-04      slope estimate = -16.3842555001   error = 7.445e-04
h = 1e-06      slope estimate = -16.3849925556   error = 7.444e-06
h = 1e-08      slope estimate = -16.3850003787   error = 3.787e-07
h = 1e-10      slope estimate = -16.3850444324   error = 4.443e-05
h = 1e-12      slope estimate = -16.3851154866   error = 1.155e-04
h = 1e-14      slope estimate = -17.0530256582   error = 6.680e-01

Két dolog történik itt, és mindkettő teherhordó.

A hiba nem homályosan arányos hh értékével — pontosan 7.445h7.445\,h. Oszd el hh értékét százzal, a hiba is százzal osztódik, minden alkalommal négy értékes jegyre. Ez a konstans nem dísz: a veszteség második deriváltjának fele, és annak az ötletnek az első megjelenése, amely két szakasszal később jön — hogy egy görbe egy pont közelében úgy néz ki, mint egy egyenes plusz egy h2h^2-val arányos korrekció.

Aztán a minta megtörik. h=108h = 10^{-8} alatt a becslés rosszabb lesz, és 101410^{-14} értéknél már a második jegyben téved. Matematikailag semmi nem történt; az előző fejezet lebegőpontos doboza történt. L(a+h)L(a+h) és L(a)L(a) az első tíz számjegyükben egyeznek, kivonásuk elpusztítja ezeket a jegyeket, és a roncs nagyon kicsi számmal való osztása felerősíti, ami marad. Van egy legjobb hh — itt körülbelül 10810^{-8}, nagyjából a gépi epsilon négyzetgyöke —, és ennél kisebbre menni nem óvatosabb, hanem kevésbé az. Ezt jegyezd meg; a fejezet végén egy függvény ettől függ.

A pontos meredekség, kalkulusból és nem mérésből, 16.385-16.385. Így abbahagyhatjuk a mérést, és elkezdhetünk levezetni.

Itt van az ötlet, amelyre a kurzus további része épül, egyszer, világosan kimondva.

Két függvény komponálása azt jelenti, hogy az egyiket a másikba etetjük: (fg)(x)=f(g(x))(f \circ g)(x) = f(g(x)). Semmi több.

Egy mély hálózat nem olyan, mint egy kompozíció. Az az. Egy réteg egy függvény; rétegek egymásra rakása azok komponálása; a „mélység” a láncban lévő függvények száma. Amikor az 5. fejezet hálózatot épít, f4f3f2f1f_4 \circ f_3 \circ f_2 \circ f_1-t épít, és semmi mást. Ez azt jelenti, hogy a kalkulus számunkra legfontosabb szabálya az, amely egy kompozíciót differenciál:

ddxf(g(x))=f(g(x))g(x)\frac{d}{dx} f(g(x)) = f'(g(x)) \cdot g'(x)

A ráták szorzódnak. Ha gg háromszor olyan gyorsan változik, mint xx, és ff kétszer olyan gyorsan változik, mint gg, akkor ff hatszor olyan gyorsan változik, mint xx. Ez a teljes tartalom, és ezért szorzódik egy tíz rétegen visszafelé haladó jel tíz számmal — ezért szán a 6. fejezet egy szakaszt arra, mi történik, ha ezek a számok mind kicsit kisebbek egynél.

Használjuk a veszteségünkre. Írjuk fel a reziduálist ri=axi+byir_i = a x_i + b - y_i, hogy L=1nri2L = \frac{1}{n}\sum r_i^2. Minden rir_i függ aa-től a belső axia x_i függvényen keresztül, amelynek deriváltja xix_i. Láncszabály, tagonként:

La=1ni2rixi,Lb=1ni2ri1\frac{\partial L}{\partial a} = \frac{1}{n}\sum_i 2 r_i \cdot x_i, \qquad \frac{\partial L}{\partial b} = \frac{1}{n}\sum_i 2 r_i \cdot 1

Ezek a kacskaringós \partial szimbólumok parciális deriváltat jelölnek: egy változó szerint differenciálsz, minden mást konstansként kezelve. Semmi új nem történik — ugyanaz a határérték, mint korábban, csak egy tengely mentén véve. Gyűjtsd a parciális deriváltakat egy vektorba, és megkapod a gradientet:

L=(La, Lb)\nabla L = \left( \frac{\partial L}{\partial a},\ \frac{\partial L}{\partial b} \right)

A (a,b)=(1,4)(a, b) = (1, 4) pontban ez a vektor (16.385, 8.0)(-16.385,\ 8.0). Két szám. A kérdés az, mit jelentenek, és ez az első lépés, amit mindenki kihagy.

A gradient a tengelyek menti meredekségek vektora. Ennyit bizonyítottunk. Nem nyilvánvaló — nem is kellene annak lennie —, hogy ezek vektorba rendezése bármilyen konkrét irányba mutató dolgot eredményez.

Definiáljuk tehát azt, amit valójában akarunk. Válassz egy egységvektort u\mathbf{u}, egy irányt. Az iránymenti derivált az a ráta, amellyel a veszteség változik, miközben arra sétálsz:

DuL=limh0L(θ+hu)L(θ)hD_{\mathbf{u}} L = \lim_{h \to 0} \frac{L(\boldsymbol{\theta} + h\mathbf{u}) - L(\boldsymbol{\theta})}{h}

A láncszabály ezt kiszámíthatóvá teszi. u\mathbf{u} mentén sétálva aa u1u_1 rátával, bb pedig u2u_2 rátával változik, a hozzájárulások pedig összeadódnak:

DuL=Lau1+Lbu2=LuD_{\mathbf{u}} L = \frac{\partial L}{\partial a} u_1 + \frac{\partial L}{\partial b} u_2 = \nabla L \cdot \mathbf{u}

A változás rátája bármely irányban a gradient és az adott irány skalárszorzata. És most a csattanó, ami egy sor geometria. A skalárszorzatot a vektorok közötti ϕ\phi szöggel felírva,

Lu=Lucosϕ=Lcosϕ\nabla L \cdot \mathbf{u} = \lVert \nabla L \rVert \, \lVert \mathbf{u} \rVert \cos\phi = \lVert \nabla L \rVert \cos\phi

mivel u\mathbf{u} hossza 1. Az egyetlen dolog, amit irányítasz, cosϕ\cos\phi, amely ϕ=0\phi = 0-nál a legnagyobb, és fél fordulatnál, ϕ=180\phi = 180 foknál a legkisebb. Tehát:

  • A legmeredekebb emelkedés maga L\nabla L mentén van, és a meredekség ott pontosan L\lVert \nabla L \rVert.
  • A legmeredekebb ereszkedés L-\nabla L mentén van, és a meredekség ott L-\lVert \nabla L \rVert.
  • A gradientre merőlegesen a veszteség egyáltalán nem változik. Ezért metszi egy szintvonalas térkép vonalait a gradient derékszögben.

Ez a mínuszjel. Nem konvenció, nem valaki által választott előjelcsere: a leggyorsabb csökkenés iránya a negatív gradient, mert cosϕ\cos\phi fél fordulatnál minimális, és semmi másért.

Mivel ez minden irányra vonatkozó állítás, teszteljük minden irány ellen. Mintavételezzünk 3.600-at, tizedfokonként egyet, és mérjük meg mindet egy kis elmozdítással:

directions.pyPYTHON
theta = np.array([1.0, 4.0])
g = grad(theta)
print("gradient      ", g)
print("its length    ", np.linalg.norm(g))
print("its angle     ", np.degrees(np.arctan2(g[1], g[0])) % 360, "degrees")

best = max(
    ((loss(theta + 1e-6 * u) - loss(theta - 1e-6 * u)) / 2e-6, np.degrees(ang))
    for ang, u in (
        (a, np.array([np.cos(a), np.sin(a)])) for a in np.arange(3600) * 2 * np.pi / 3600
    )
)
print("steepest slope", best[0], "at", best[1], "degrees")
TEXT
gradient       [-16.385   8.   ]
its length     18.23371122399386
its angle      153.97598928042032 degrees
steepest slope 18.233709624837502 at 154.0 degrees

Egy keresés, amely semmit sem tud a gradientekről, 3.600 irányon át a legmeredekebb emelkedést 154,0 foknál találja — a gradient saját irányában, a keresés 0,1 fokos felbontásán belül. És a meredekség, amelyet ott talál, 18,2337, hat értékes jegyre a gradient hossza. A tétel nem történet arról, mit jelentenek a gradientek; mérhető tény, és ez a mérés.

Miért segít tényleg egy kis lépés lefelé

Link a szakaszhoz: Miért segít tényleg egy kis lépés lefelé

Most a második kihagyott lépés. Tudjuk, merre van lefelé. Ebből nem következik, hogy arra sétálva csökken a veszteség, mert a „lefelé” végtelenül kicsi elmozdításról szóló állítás, a lépés pedig nem végtelenül kicsi.

A híd a linearizálás. Egy sima függvény egy pont közelében az érintője plusz egy korrekció:

L(θ+δ)=L(θ)+Lδ+O(δ2)L(\boldsymbol{\theta} + \boldsymbol{\delta}) = L(\boldsymbol{\theta}) + \nabla L \cdot \boldsymbol{\delta} + O(\lVert\boldsymbol{\delta}\rVert^2)

Ez az elsőrendű Taylor-kifejtés. Az elhagyott O(δ2)O(\lVert\boldsymbol{\delta}\rVert^2) a görbület — ugyanaz a tag, amely a meredekségtáblázat becslését pontosan 7.445h7.445\,h-val tévesztette el. Tegyük be a lépést, amelyet meg akarunk tenni, δ=ηL\boldsymbol{\delta} = -\eta \nabla L:

L(θηL)L(θ)ηL2L(\boldsymbol{\theta} - \eta \nabla L) \approx L(\boldsymbol{\theta}) - \eta \lVert \nabla L \rVert^2

A veszteség ηL2\eta \lVert \nabla L \rVert^2-val csökken. Ennek minden része nemnegatív, tehát az ígéret valós — elég kicsi η\eta esetén, mert az elhanyagolt tag η2\eta^2 szerint nő, és végül felfalja. Ez a teljes elmélet. Íme az ígéret betartva, majd megszegve:

TEXT
eta = 0.2       promised    66.49364500   delivered   -16.01619240   ratio -0.240868
eta = 0.1       promised    33.24682250   delivered    12.61936315   ratio  0.379566
eta = 0.01      promised     3.32468225   delivered     3.11840766   ratio  0.937957
eta = 0.001     promised     0.33246822   delivered     0.33040548   ratio  0.993796
eta = 0.0001    promised     0.03324682   delivered     0.03322620   ratio  0.999380
eta = 1e-05     promised     0.00332468   delivered     0.00332448   ratio  0.999938

Olvasd lentről. Ahogy η\eta zsugorodik, a tényleges csökkenés konvergál az ígérthez — 0,99938-as, majd 0,99994-es arány —, vagyis Taylor tétele helyes. Olvasd fentről, és η=0.2\eta = 0.2-nél a tényleges „csökkenés” negatív tizenhat. A lépés lefelé ment, a veszteség pedig nőtt.

A frissítési szabály tehát

θθηL(θ)\boldsymbol{\theta} \leftarrow \boldsymbol{\theta} - \eta \nabla L(\boldsymbol{\theta})

és jár hozzá egy feltétel, amelyet senki nem mond ki: η\eta legyen elég kicsi. Elég kicsi pontosan mihez képest — ez a következő szakasz.

A learning rate-nek van felső határa, és kiszámítható

Link a szakaszhoz: A learning rate-nek van felső határa, és kiszámítható

Kezdjük a lehető legegyszerűbb völggyel, f(x)=x2f(x) = x^2, ahol f(x)=2xf'(x) = 2x. A gradient descent egy lépése

xxη2x=x(12η)x \leftarrow x - \eta \cdot 2x = x\,(1 - 2\eta)

A pozíció minden lépésben (12η)(1 - 2\eta)-tel szorzódik. Ez geometriai sorozat, a geometriai sorozatoknak pedig pontosan egy szabályuk van: akkor zsugorodnak, ha a szorzó abszolút értékben kisebb 1-nél, különben nőnek. Tehát 12η<1\lvert 1 - 2\eta \rvert < 1, ami 0<η<10 < \eta < 1.

A határ pontosan η=1\eta = 1-nál van. Nem „körülbelül 1”, nem „az 1 általában túl nagy”. η=1\eta = 1-nél a szorzó 1-1, és a pont örökké xx és x-x között pattog, se nem közeledik, se nem szökik el. Alatta konvergál; felette divergens. Az intervallum újra kettéhasad η=0.5\eta = 0.5-nál, ahol a szorzó előjelet vált: alatta a közeledés monoton, felette a pont túllő, és felváltva kerül a másik oldalra, pontosan 0.50.5-nél pedig a szorzó 0, és egyetlen lépés a minimumra ér.

Négy rezsim, négy sor algebrából. Menj, és lépd át a határokat magad:

14 lépés, végpont: x = -0.0836.

Adatok megtekintése táblázatként
Lépésxf(x)
0⁨-1.9000⁩⁨3.6100⁩
1⁨-1.5200⁩⁨2.3104⁩
2⁨-1.2160⁩⁨1.4787⁩
3⁨-0.9728⁩⁨0.9463⁩
4⁨-0.7782⁩⁨0.6057⁩
5⁨-0.6226⁩⁨0.3876⁩
6⁨-0.4981⁩⁨0.2481⁩
7⁨-0.3985⁩⁨0.1588⁩
8⁨-0.3188⁩⁨0.1016⁩
9⁨-0.2550⁩⁨0.0650⁩
10⁨-0.2040⁩⁨0.0416⁩
11⁨-0.1632⁩⁨0.0266⁩
12⁨-0.1306⁩⁨0.0170⁩
13⁨-0.1045⁩⁨0.0109⁩
14⁨-0.0836⁩⁨0.0070⁩
Gradienscsökkenés, interaktívan

Tizennégy lépés 0,1-es rátával, x=1.9x = -1.9-ból, 0.0836-0.0836-nál végezve. Emeld a rátát 0,5-re, és már az első lépés az aljra ér. Emeld 0,9-re, és ugyanannál a 0.0836-0.0836-nál végez, mint a 0,1 — ugyanaz a távolság, ellenkező stílus, mert 12η\lvert 1 - 2\eta \rvert mindkettőnél 0,8 —, csak úgy jut oda, hogy cikcakkban átvág a völgyön, nem pedig lesétál az egyik oldalán.

És most az érdekes:

14 lépés, végpont: x = -1.9000.

Adatok megtekintése táblázatként
Lépésxf(x)
0⁨-1.9000⁩⁨3.6100⁩
1⁨1.9000⁩⁨3.6100⁩
2⁨-1.9000⁩⁨3.6100⁩
3⁨1.9000⁩⁨3.6100⁩
4⁨-1.9000⁩⁨3.6100⁩
5⁨1.9000⁩⁨3.6100⁩
6⁨-1.9000⁩⁨3.6100⁩
7⁨1.9000⁩⁨3.6100⁩
8⁨-1.9000⁩⁨3.6100⁩
9⁨1.9000⁩⁨3.6100⁩
10⁨-1.9000⁩⁨3.6100⁩
11⁨1.9000⁩⁨3.6100⁩
12⁨-1.9000⁩⁨3.6100⁩
13⁨1.9000⁩⁨3.6100⁩
14⁨-1.9000⁩⁨3.6100⁩
Gradienscsökkenés, interaktívan

Pontosan a határon. Tizennégy lépés 1-es rátával, és 1.9-1.9-nál fejezi be: pontosan ott, ahol elkezdte, semmi mást nem csinálva, csak pattogva. Egy hajszállal feljebb, és a pattogás tartás helyett nőni kezd; 1,2-nél négy lépés alatt lemegy a grafikonról. A túl nagy ráta nem lassan konvergál. Nem konvergál.

Most az általános szabály, amely ugyanebből az érvből esik ki. A 12η1 - 2\eta szorzó valójában 1ηf1 - \eta f'' volt, és egy minimum közelében egy többparaméteres veszteségnek irányonként van egy ilyen száma — a második deriváltak mátrixának sajátértékei. Minden iránynak egyszerre kell stabilnak lennie, ezért a plafont a legnagyobb állítja be:

η<2λmax\eta < \frac{2}{\lambda_{\max}}

f(x)=x2f(x) = x^2 esetén f=2f'' = 2, a plafon 1, amit az imént levezettünk. A szalagunknál a második deriváltak mátrixa 2nAA\frac{2}{n} A^{\top} A, ahol AA a bemenetek kétoszlopos mátrixa, sajátértékei pedig 2 és 14,89, ezért a plafon 2/14.89=0.134322 / 14.89 = 0.13432. Ez öt értékes jegyű előrejelzés. Teszteljük:

TEXT
lr=0.1343    -> L =      24.5924
lr=0.13431   -> L =      24.5924
lr=0.13432   -> L =       4707.8       BLEW UP
lr=0.13433   -> L =  4.00452e+16       BLEW UP
lr=0.1344    -> L = 1.18229e+107       BLEW UP

Öt tizedesjegynyi egyezés egy sor lineáris algebra és egy for ciklus százezer iterációja között.

És itt tér vissza az 1. fejezet. Fent minden a középre igazított méréseket használta. Futtasd ugyanezt a kódot nyers millimétereken és grammokon, és a sajátértékek 2 és 14,89 helyett 0,0298 és 998,1 lesznek. A plafon 0,134-ről 0,002004-re omlik össze — ugyanilyen pontosan, lr=0.002003-nél konvergálva és lr=0.002004-nél felrobbanva.

A plafonnál is rosszabb a sajátértékek közötti arány. A kondíciószám azt méri, mennyire nem kerek a völgy: egy hosszú, vékony árok olyan rátát kényszerít ki, amely elég kicsi a meredek falakhoz, majd az árok alján is ugyanilyen csigatempóban halad. A miénk középre igazítva 7,44-ről nyersen 33.452-re megy. A legjobb rátával, amelyet az egyes verziók elviselnek:

jellemzőkkondíciószámlegjobb rátalépések az optimum 1%-án belülre
középre igazítva7,440,118410
nyers milliméterek és grammok33.4520,002003779.513

Ugyanazok az adatok, ugyanaz a kód, ugyanaz a válasz a végén — és nyolcezerszer annyi munka, mert senki nem vont ki átlagot. Az 1. fejezetben ugyanez a mulasztás hatezerszeres szorzóba került a perceptron epochjaiban, és ott a diagnózis geometriai volt: az adatok messze lebegtek az origótól. Itt ugyanez a geometria optimalizálási jelmezben, és ezért a bemenet-normalizálás nem higiéniai tanács, hanem aritmetika.1

A fentiekhez nem kellett könyvtár. Itt a teljes optimalizáló.

descent.pyPYTHON
def loss(theta):
    a, b = theta
    return np.mean((a * x + b - y) ** 2)


def grad(theta):
    a, b = theta
    residual = a * x + b - y
    return np.array([np.mean(2 * residual * x), np.mean(2 * residual)])


def descend(theta, lr, steps):
    theta = np.array(theta, dtype=float)
    for _ in range(steps):
        theta = theta - lr * grad(theta)   
    return theta


theta = descend([0.0, 0.0], lr=0.05, steps=60)
print(theta, loss(theta))
TEXT
[ 2.10040296e+00 -2.76445533e-15] 24.592448791134984

A zárt alakú legkisebb négyzetes válasz erre a nyolc pontra a=2.100403a = 2.100403, b=0b = 0, 24.59244924.592449 veszteséggel. A ciklus nyolc értékes jegyre megtalálta anélkül, hogy tudta volna, létezik zárt alak — ami fontos, mert az 5. fejezettől kezdve nem lesz ilyen.

A pálya, mert a lényeg az, hogy nézzük:

TEXT
   0 a=0.000000 b=0.000000 L=57.437500
   1 a=1.563750 b=0.000000 L=26.736582
   2 a=1.963288 b=-0.000000 L=24.732418
   5 a=2.098116 b=-0.000000 L=24.592488
  10 a=2.100400 b=-0.000000 L=24.592449
  60 a=2.100403 b=-0.000000 L=24.592449

A távolság nagy részét az első két lépés fedezi le, mert a gradient akkor a legnagyobb, amikor a legtávolabb vagy az aljtól, és zsugorodik, ahogy közeledsz. A gradient descent automatikusan lelassul egy minimum közelében. Ez egy feature, és a 6. fejezetben egyben probléma is.

Az eddigi érvben van egy lyuk. A lépés akkor áll meg, amikor L=0\nabla L = \mathbf{0}, és ezt eddig „a minimumnak” neveztük. A nulla gradientű pont kritikus pont, és a minimum csak az egyik módja annak, hogy valami kritikus pont legyen:

  • lokális minimum: minden irányban felfelé van, de nem feltétlenül ez a legalacsonyabb ilyen pont bárhol;
  • lokális maximum: minden irányban lefelé van;
  • nyeregpont: egyes irányokban felfelé, másokban lefelé van. A f(x,y)=x2y2f(x,y) = x^2 - y^2 felületnél f=(2x,2y)\nabla f = (2x, -2y), ami az origóban nulla; ott a függvény a xx-tengely mentén minimum, a yy-tengely mentén pedig maximum ugyanabban az időben.

A gradient descent nem tudja megkülönböztetni ezeket, mert mindig csak a gradientet nézi, és a gradient mindháromnál nulla.

Az egyenesünknek egyetlen kritikus pontja van, és az a válasz — egy lineáris modell négyzetes hibájú vesztesége konvex, egyetlen tál, és a descent rajta nem hibázhatja el a globális minimumot. Ez a tulajdonság nem éli túl a kurzussal való találkozást. Egy neurális hálózat vesztesége nem konvex, és az 5. fejezettől kezdve „a minimum” nem létező dolog: sok van belőle, különböző mélységűek, és hogy melyiket kapod, attól függ, honnan indultál. Ez egy mondat, és egy mondat is marad, mert az elmélet nagy, a gyakorlati következmény pedig kicsi.

Az egész következményt egy görbén láthatod. Vedd f(x)=x44x22+x10f(x) = \tfrac{x^4}{4} - \tfrac{x^2}{2} + \tfrac{x}{10}-t, amelynek két különböző mélységű völgye van:

TEXT
   x =  -1.046681   f(x) =  -0.352386   minimum
   x =   0.101031   f(x) =   0.005026   maximum
   x =   0.945649   f(x) =  -0.152639   minimum

40 lépés, végpont: x = 0.9456.

Adatok megtekintése táblázatként
Lépésxf(x)
0⁨0.1100⁩⁨0.0050⁩
1⁨0.1122⁩⁨0.0050⁩
2⁨0.1149⁩⁨0.0049⁩
3⁨0.1182⁩⁨0.0049⁩
4⁨0.1223⁩⁨0.0048⁩
5⁨0.1275⁩⁨0.0047⁩
6⁨0.1338⁩⁨0.0045⁩
7⁨0.1416⁩⁨0.0042⁩
8⁨0.1513⁩⁨0.0038⁩
9⁨0.1633⁩⁨0.0032⁩
10⁨0.1781⁩⁨0.0022⁩
11⁨0.1962⁩⁨0.0007⁩
12⁨0.2183⁩⁨-0.0014⁩
13⁨0.2453⁩⁨-0.0046⁩
14⁨0.2779⁩⁨-0.0093⁩
15⁨0.3170⁩⁨-0.0160⁩
16⁨0.3633⁩⁨-0.0253⁩
17⁨0.4172⁩⁨-0.0377⁩
18⁨0.4783⁩⁨-0.0535⁩
19⁨0.5455⁩⁨-0.0721⁩
20⁨0.6163⁩⁨-0.0922⁩
21⁨0.6869⁩⁨-0.1116⁩
22⁨0.7526⁩⁨-0.1277⁩
23⁨0.8092⁩⁨-0.1393⁩
24⁨0.8540⁩⁨-0.1463⁩
25⁨0.8868⁩⁨-0.1499⁩
26⁨0.9091⁩⁨-0.1516⁩
27⁨0.9236⁩⁨-0.1522⁩
28⁨0.9325⁩⁨-0.1525⁩
29⁨0.9379⁩⁨-0.1526⁩
30⁨0.9411⁩⁨-0.1526⁩
31⁨0.9430⁩⁨-0.1526⁩
32⁨0.9441⁩⁨-0.1526⁩
33⁨0.9448⁩⁨-0.1526⁩
34⁨0.9451⁩⁨-0.1526⁩
35⁨0.9454⁩⁨-0.1526⁩
36⁨0.9455⁩⁨-0.1526⁩
37⁨0.9455⁩⁨-0.1526⁩
38⁨0.9456⁩⁨-0.1526⁩
39⁨0.9456⁩⁨-0.1526⁩
40⁨0.9456⁩⁨-0.1526⁩
Gradienscsökkenés, interaktívan

Negyven lépés x=0.11x = 0.11-ból, 0.94560.9456-nál megállva — a két völgy közül a sekélyebbnél. Most mozdítsd a kezdőpontot egy rovátkával balra, 0.100.10-re. Ugyanaz a ráta, ugyanaz a negyven lépés, és helyette 1.0461-1.0461-nál áll meg, ahol a veszteség 0,199747-tel alacsonyabb. A vízválasztó a 0.1010310.101031-nél lévő púp, és a két válasz közötti teljes különbség annyi, hogy ennek melyik oldalán történt kezdened.

A sekély völgyben landolni veszteségben 56,7%-kal rosszabb, és az algoritmusnak nincs módja ezt tudni, mert egy völgy belsejéből minden irány felfelé van. Erre nincs javítás a gradient descentben, és nem is érkezik. Ami a gyakorlatban van, az a megállapítás, hogy ez sokkal kevésbé számít, mint amit ez a kép sugall — egy valódi hálózat nagyon magas dimenzióiban a legtöbb kritikus pont csapda helyett nyeregpontnak bizonyul,2 az 5. fejezet pedig megméri, milyen gyakran akad el ténylegesen egy kis hálózat.

Olcsóbb lépések: stochastic, minibatch, momentum

Link a szakaszhoz: Olcsóbb lépések: stochastic, minibatch, momentum

A fenti grad-ban egy dolognak zavarnia kellene: minden lépéshez az egész adathalmazon összegez. Nyolc alkatrész semmi. Egymillió már egymillió gradient-számítás ahhoz, hogy a paraméterek egyszer mozduljanak.

A menekülőút az, hogy a gradient egy átlag, és egy átlag mintából becsülhető. Számold ki egy véletlen marékon — egy minibatchen —, és lépj arra. A becslés zajos; egyben torzítatlan is, és több száz olcsó, zajos lépés legyőz egy drága, pontos lépést. Százezer szintetikus alkatrészen, példánkénti gradienteket számolva lépések helyett:

módszerlépések az optimum 0,1%-án belülrepéldánkénti gradientek
full batch7700.000
32-es minibatch1003.200
egyszerre egy példa17.58017.580

Kétszáztizenkilencszer kevesebb aritmetika ugyanoda jutni. És a szélsőség — egyszerre egy példa, Robbins és Monro eredeti stochastic approximációja3nem a győztes: ötször rosszabb, mint a 32-es batch, mert 32 példa szinte semmivel sem kerül többe egynél olyan hardveren, amely mátrixokat szoroz, miközben a zaj a batchméret négyzetgyökével esik. Ez a kompromisszum az oka, hogy minden training scriptben, amit valaha olvasni fogsz, lesz egy batch_size.

Momentum a másik olcsó javítás, és pontosan az árokra céloz. Rosszul kondicionált völgyben a lépések cikcakkban átszelik a keskeny irányt, miközben a hosszú irány mentén araszolnak. A momentum a múltbeli gradientek futóátlagát tartja, így az oszcilláló komponensek kioltják egymást, a következetes pedig felhalmozódik:4

vβv+L(θ),θθηv\mathbf{v} \leftarrow \beta \mathbf{v} + \nabla L(\boldsymbol{\theta}), \qquad \boldsymbol{\theta} \leftarrow \boldsymbol{\theta} - \eta \mathbf{v}

Két extra sor. A nyers, nem középre igazított szalagon — kondíciószám 33.452, a legrosszabb esetünk — a sima descent által elviselhető legjobb rátán:

TEXT
momentum beta=0.0   ->    79,513 steps to 1%
momentum beta=0.9   ->     1,609 steps to 1%
momentum beta=0.99  ->       461 steps to 1%

172-es szorzó két sornyi kódért. A 6. fejezet ezt Adammé alakítja; a mechanizmus már itt van.

Az ellenőrzés, amelyre az 5. fejezetben szükséged lesz

Link a szakaszhoz: Az ellenőrzés, amelyre az 5. fejezetben szükséged lesz

Ebben a fejezetben minden gradientet kézzel vezettünk le, ezért lehet, hogy rosszak. A javítás a fejezet eleji meredekségtáblázat: mérd meg a deriváltat numerikusan, és hasonlítsd össze. Használd a central differenciát, L(θ+h)L(θh)2h\frac{L(\theta+h) - L(\theta-h)}{2h}, amely kioltja a vezető hibatagot, és ugyanarra a hh-ra sokkal pontosabb.

gradcheck.pyPYTHON
def numeric_grad(f, theta, h=1e-5):
    theta = np.asarray(theta, dtype=float)
    out = np.zeros_like(theta)
    for i in range(theta.size):
        bump = np.zeros_like(theta)
        bump[i] = h
        out[i] = (f(theta + bump) - f(theta - bump)) / (2 * h)     
    return out


def gradcheck(f, df, theta, h=1e-5):
    analytic = np.asarray(df(theta), dtype=float)
    numeric = numeric_grad(f, theta, h)
    return np.max(np.abs(analytic - numeric) / np.maximum(1e-8, np.abs(analytic) + np.abs(numeric)))

Az összehasonlítás relatív formája számít: egy 10410^{-4} abszolút különbség katasztrófa egy 10310^{-3} méretű gradienten, és lényegtelen egy 10610^{6} méretűn.

TEXT
relative error: 1.8929136036763527e-11
with 2 dropped: 0.33333333331650744

Az első sor a fent kézzel levezetett gradient. A második ugyanaz a függvény úgy, hogy az egyik komponensből kimaradt a 2-es faktor — egyetlen karakteres elírás —, és az ellenőrzés azonnal elkapja. Körülbelül 10710^{-7} alatt egyezés; 10410^{-4} felett bug. Tartsd meg ezt a függvényt: az 5. fejezet ezzel debugol egy automatikus differenciáló motort, és ez az egyetlen ok, amiért egy rossz gradient egyáltalán megtalálható.

Ebben a fejezetben minden egy soha ki nem mondott feltételezésen nyugodott: hogy le tudod írni L/θ\partial L / \partial \theta-t.

Egy kétparaméteres egyenesnél ez egy sornyi algebra volt. Szinte azonnal megszűnik annak lenni. Kérd meg egy szimbolikus algebrai rendszert, hogy adja meg egy hálózat veszteségének deriváltját egy egyetlen első rétegbeli súly szerint, egy egyetlen példára, és számold meg a válaszban az aritmetikai műveleteket:

hálózatműveletek egy parciális deriváltban
négy rejtett egység, egy réteg40
négy rejtett egység, két réteg301
négy rejtett egység, három réteg1.717

A harmadik sor egy 57 paraméteres hálózat — olyan kicsi, hogy a 6. fejezetben lábjegyzet lenne —, és a gradient kézi kiírása egyetlen training példára körülbelül 97.869 műveletet jelent. Nincs olyan jelölés, amely ezt megmenti. Ami megmenti, az a megfigyelés, hogy a kompozícióra alkalmazott láncszabálynak hatalmas szerkezete van, ugyanazok a köztes mennyiségek újra és újra megjelennek, és megfelelő sorrendben számolva az összes derivált megkapható nagyjából egy forward pass áráért. Ez az 5. fejezet.

De előbb van egy kisebb probléma, és közvetlenül előttünk vár.

Most már van egy gépünk, amely bármely differenciálható veszteségen lefelé gurul. Irányítsuk a szalag eredeti kérdésére — elfogadni vagy elutasítani, ahol a cél 1 vagy 0 —, tegyünk sigmoidot a kimenetre, hogy valószínűséget jósoljon, és minimalizáljuk a négyzetes hibát. Futni fog. De épp akkor alig mozdul majd, amikor a leginkább téved, és a gradient megmondja, miért:

kimenet zzpredikcióigazsággradient négyzetes hibávalgradient cross-entropyvel
000.500012.5×1012.5 \times 10^{-1}5.0×1015.0 \times 10^{-1}
2-20.119211.850×1011.850 \times 10^{-1}8.808×1018.808 \times 10^{-1}
6-60.002514.921×1034.921 \times 10^{-3}9.975×1019.975 \times 10^{-1}
10-104.54×1054.54 \times 10^{-5}19.079×1059.079 \times 10^{-5}1.0001.000

Egy modell, amely magabiztosan, katasztrofálisan téved — 0,0000454-et jósol, amikor a válasz 1 —, 9×1059 \times 10^{-5} négyzetes hibás gradientet produkál. Fogalma sincs, hogy bajban van. A másik oszlop, egy még le nem vezetett veszteségből, 1,0-t jelent: maximális sürgősséget, pontosan ott, ahol megérdemelt.

Ez veti fel a kérdést, amellyel a következő fejezet kezd. Az előző fejezet azt mondta, hogy a veszteség a zajról tett feltételezés, a négyzetes hiba pedig Gauss-zajt feltételez. Milyen zajmodellje van egy igen-vagy-nem válasznak — és milyen veszteség jön ki, ha ugyanazt a levezetést lefuttatod rajta?


A módszer mindezeknél régebbi: Cauchy 1847-ben az Académie des Sciences-nek írt jegyzetében írta le, egyenletrendszerek megoldásának módjaként úgy, hogy a négyzetes reziduálisok összegén sétálunk lefelé. E fejezet mellé szintén érdemes olvasni Sebastian Ruder An overview of gradient descent optimization algorithms című írását (arXiv:1609.04747), amely tizennégy olvasható oldalon visz végig a momentumtól Adamig; Nocedal és Wright Numerical Optimization című könyvének 3. fejezetét (2. kiadás, Springer, 2006), amelynek 3.3. tétele egy kvadratikuson a steepest descent konvergenciarátáját a kondíciószám függvényében adja meg — ez az elmélet amögött, hogy a kondicionáltság miért dönti el a lépésszámot, bár line searcht tárgyal, nem a fent mért fix lépésű 2/λmax2/\lambda_{\max} plafont —, vagy Deisenroth, Faisal és Ong Mathematics for Machine Learning című könyvének §5.8 és §7.1 szakaszát ugyanehhez kevesebb apparátussal; Prince Understanding Deep Learning című könyvének §6.1 szakaszát és Goodfellow, Bengio és Courville Deep Learning című könyvének §4.3 szakaszát; a Dive into Deep Learning §12.1–12.3 szakaszait, ahol a minibatch elemzés több méréssel szerepel, mint amennyinek itt hely jut; valamint Géron Hands-On Machine Learning című könyvének 4. fejezetét (3. kiadás), amely a learning rate leggyakorlatiasabb tárgyalása mint hangolandó, nem pedig levezetendő dolog. Az MIT 6.390 jegyzetei a gradient descentet a klasszifikáció elé teszik, ahogy ez a kurzus is, és ugyanabból az okból.

  1. LeCun, Y., Bottou, L., Orr, G. B. és Müller, K.-R. Efficient BackProp, in Neural Networks: Tricks of the Trade (Springer, 1998), 9–50. o. A 4.3. szakasz adja az ajánlást, az 5.1. szakasz pedig a fenti részletdobozban használt érvet: a bemenetek középre igazítása és skálázása megváltoztatja a második deriváltak mátrixának sajátértékeit, és ezért a lépések számát is, nem pusztán a numerikus kényelmet.

  2. Dauphin, Y. N., Pascanu, R., Gulcehre, C., Cho, K., Ganguli, S. és Bengio, Y. Identifying and attacking the saddle point problem in high-dimensional non-convex optimization, arXiv:1406.2572 (2014). Az érv szerint nagy dimenzióban a kritikus pontok túlnyomórészt nyeregpontok, nem lokális minimumok, mivel egy minimumhoz egyszerre több ezer irány mindegyikének felfelé kell görbülnie.

  3. Robbins, H. és Monro, S. A Stochastic Approximation Method. Annals of Mathematical Statistics 22(3), 400–407. o. (1951). A cikk, amely megállapította, hogy egy gradient zajos becslése is elég, ha a lépésméret a megfelelő módon zsugorodik.

  4. Polyak, B. T. Some methods of speeding up the convergence of iteration methods. USSR Computational Mathematics and Mathematical Physics 4(5), 1–17. o. (1964). A heavy-ball módszer, amely a fenti momentum frissítés, huszonkét évvel azelőtt, hogy a backpropagation elérte volna ezt a területet.


Készítette

David Vicente Campos

A NeuraLIA Labs alapítója és a MyRealFood társalapítója

Mérnökinformatikus vagyok, a Leóni Egyetemen végeztem. Társalapítottam a MyRealFoodot, ahol CTO-ként felépítettem azt az alkalmazást, amelyet emberek milliói használtak arra, hogy egészségesebben táplálkozzanak, és megalapítottam a NeuraLIA Labst, ahol AI-termékeket fejlesztek. Itt arról írok, amit menet közben meg kellett értenem, úgy, ahogy szerettem volna, hogy valaki elmagyarázza nekem.

Továbbiak a szerzőről

Közzétette a NeuraLIA Labs.

Kapj új bejegyzéseket a postaládádba

AI-hírek, útmutatók és termékfrissítések — rövid email, amikor valami igazán hasznosat publikálunk.

Kurzusindex

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev11 perc olvasás

A Jev AI-modell döntésekre készült, nem prózára

A TypeSafe AI Jev modellje azért kap figyelmet, mert a szoftveres intelligenciát valószínűségi problémaként kezeli: válaszd ki a megfelelő ágat, rendelj hozzá bizalmi szintet, és ne fizess egy LLM-nek szövegírásért, amikor a kódnak döntésre van szüksége.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering11 perc olvasás

Kontextustervezés hosszú távú AI-ügynökökhöz

A hosszú ideig futó ügynökök nem csak azért vallanak kudarcot, mert kicsi az ablak. Akkor hibáznak, amikor a fájlok, eszközkimenetek és elavult előzmények kiszorítják azt a feladatot, amelyet az ügynöknek be kellett volna fejeznie.

Készen állsz, hogy a LIA válasszon helyetted?

Építs az összes AI-modellel egy helyen – kezdd el ma, ingyen.