Documente Academic
Documente Profesional
Documente Cultură
mai tehnică.
Obiectivele lecției:
1. Vei afla cum poți să evaluezi cu un nivel înalt de fidelitate algoritmii de
învățare automată
2. O să afli cum poți determina când un algoritm de învățare automată, și în
special aprofundată încetează să învețe și începe să memoreze datele
3. O să obții o înțelegere generală a tehnicii de propagare inversă ce permite
învățarea rețelelor neuronale
Evaluarea algoritmilor
Așa dar, hai să discutăm mai întâi despre evaluarea algoritmilor. E de la sine
înțeles că pentru a evalua corect un algoritm trebuie ca datele utilizate în acest
proces să nu fie aceleași date care au fost utilizate la învățare. O practică des
utilizată este de a împărți datele existente într-un set de învățare/antrenare și unul
de testare. În linii mari, același principiu este utilizat și la evaluarea oamenilor. Ai de
făcut teme pe acasă și vezi exemple de exerciții la școală, dar în cadrul testărilor ai
de rezolvat exerciții similare cu cele pe care le-ai mai văzut, dar nu exact aceleași.
Majoritatea cercetătorilor dar și dezvoltatorilor în domeniul învățării automate fac o
împărțire 70% pentru setul de date de antrenament și 30% pentru cel de testare. În
dependență de volumul de date pus la dispoziție, aceste cifre pot fi diferite. Dacă ai
la dispoziție milioane de valori de intrare, poți utiliza până la 90% pentru setul de
antrenament. O problemă des întâlnită este lipsa, sau reprezentarea slabă a unor
clase mai rare în setul de antrenare. Din acest motiv rezultatele evaluării pot să fie
derutante. Această problemă poate fi rezolvată cu un volum mai mare de date. Dar
ce să faci dacă ai puține date, spre exemplu până la câteva mii de exemple?
Răspunsul ar fi același, de a testa pe un volum mai mare de date. Nu, nu te
iau peste picior, vorbesc serios. Pentru a testa pe un volum mai mare de date,
având puține date, avem nevoie de un truc numit “validarea încrucișată” sau
cross-validation. Ce înseamnă asta? Să ne imaginăm că ai ales o partiție de 80%
pentru setul de antrenament și 20% pentru testare/validare. Rulezi o operație de
învățare și una de evaluare, pui de o parte rezultatele obținute. Iar acum trucul.
Selectezi o altă partiție, la fel de 20%, care nu conține nici un element din partiția de
testare precedentă și cu restul 80% din date (re)înveți același algoritm de la 0.
Mai repeți de 3 ori. E voila, ca prin magie, ai reușit să testezi algoritmul tău, într-un
mod fidel, pe întreg volumul de date disponibil. Drăguț, nu?
Algoritmii de învățare automată deseori pot fi observați când aceștia trec din
regimul de învățare/generalizare în regimul de memorare. Analizând graficile erorilor
pe setul de date de evaluare și de antrenare putem detecta acest moment și spre
exemplu opri procesul de învățare. Sursa:
https://rmartinshort.jimdofree.com/2019/02/17/overfitting-bias-variance-and-
leaning-curves/
Deci cum învăță totuși o rețea neuronală? Din greșeli. Mai exact, avem
nevoie de o funcție ce ar cuantifica cât de mult a greșit algoritmul în predicția lui.
Cea mai simplă variantă pentru o astfel de funcție ar fi spre exemplu scăderea.
Imaginează-ți, avem o rețea neuronală care încearcă să prezică dacă într-o
imagine avem o pisică sau un câine. O să codăm clasa “câine” drept cifra 1 și clasa
“pisică” drept cifra 0. De ce? Pentru că mulți algoritmi de învățare automată, rețelele
neuronale inclusiv, pot lucra doar cu valori numerice. Așa dar, trecând prin tot setul
nostru de date obținem o secvență de predicții gen 0.9, 0.1, 0.15, 0.2, 0.87, 0.99,
0.98, 0.19, 0.84, … Observi că niciuna din valori nu este fix 0 sau 1, aceasta se
întâmplă din 2 motive, rețelele neuronale de obicei nu sunt niciodată 100 la 100
sigure în predicțiile care le fac, iar în al doilea rând, predicțiile neprocesate sunt de
fapt niște probabilități. Deci clasa prezisă ar fi aceste probabilități rotunjite. Pe de
altă parte, avem clasele adevărate: 1, 0, 0, 1, 1, 1, 1, 0, 0, … Cum vezi, avem câteva
predicții greșite, dar avem și ceva erori. Dacă am fi să utilizăm scăderea direct, am
obține următoarea secvență de erori:
(1-0.9) = 0.1,
(0-0.1) = -0.1,
-0.15, 0.8, 0.13, 0.01, 0.02, -0.19, -0.84, … Avem nevoie să sumarizăm
aceste măsurări, spre exemplu calculând eroarea medie.
[0.1 + (-0.1) + (-0.15) + 0.8 + 0.13 + 0.01 + 0.02 + (-0.19) + (-0.84) + …] / N
unde N este numărul total de valori în setul de date de învățare. O problemă cu
sumarea directă a erorilor este faptul că avem erori pozitive și negative, care se
atenuează unele pe celelalte. Nu dorim asta. La fel ar fi drăguț dacă am penaliza
prezicerile greșite mai mult decât nesiguranța în răspunsul care ni-l dă algoritmul.
Pentru aceasta am putea să calculăm media erorilor la pătrat. Apropo, media
erorilor la pătrat este foarte des utilizată în asemenea scenarii.
Acum că avem posibilitatea să exprimăm printr-un număr cât de bună sau
rea este o rețea neuronală, dorim să optimizăm această rețea, adică să o facem
mai bună. Pentru aceasta o să avem nevoie de un domeniu foarte interesant și
practic al matematicii care se numește optimizare. Domeniul optimizării este
preocupat cu identificarea punctelor extreme ale funcțiilor. De ce ar fi important
aceasta? Ei bine, spre exemplu putem exprima printr-o funcție cantitatea de energie
electrică pe care o poate genera o stație electrică în dependență de parametrii
generatorului electric. Sau configurația motorului unei rachete cosmice pentru a
atinge viteza maximă cu cât mai puțin combustibil. Sau valoarea tuturor parametrilor
unei rețele neuronale pentru ca aceasta să aibă o performanță cât mai înaltă.
Rețelele neuronale pot fi percepute drept niște funcții foarte complexe, cu
sute de mii, sau chiar sute de milioane de parametri. Cu alte cuvinte, o rețea
neuronală în final este fratele mai mare care are doctorat, este campion mondial la
nu știu ce sport și câștigă milioane a unei funcții de genul mx+n unde m și n sunt
niște parametri pe care tu trebuie să-i identifici astfel încât funcția dată să modeleze
datele tale cât mai bine.
Pentru a optimiza rețelele neuronale este utilizat pe larg un algoritm numit
Gradient Descent, sau algoritmul coborârii gradientului stohastic, și variații ale
acestuia. Sună strașnic, dar nu-ți fă griji, conceptul e simplu. Așa dar, în primul rând
ce este un gradient. Gradientul este un vector ce conține derivata unei funcții cu mai
multe variabile cu respect față de toate variabilele. Spre exemplu, având funcția
f(x, y) = 2x + y, gradientul acestei funcții o să fie (2 + y, 2x+1). Pentru a
înțelege de ce gradientul este important, este important să înțelegi o proprietate
extrem de importantă a derivatei unei funcții în general. Derivata reprezintă cât de
mult se schimbă o funcție. Așa dar, gradientul, fiind format din mai multe derivate,
una per direcție de schimbare, o să ne indice direcția unde schimbarea este cea mai
drastică într-o funcție.
O clipă, am discutat despre funcții care estimează cât de rea sau bună este o rețea
neuronală, și despre faptul că rețelele neuronale sunt de fapt niște funcții mari și
complicate și dorim să le optimizăm pentru a avea, sperăm noi, un predictor robust
când va fi utilizat cu date reale. Dar am menționat că și faptul că avem nevoie de
gradienți, adică derivate, pentru a învăța. Deci cum se leagă totul împreună?
Fii atent, acuș o să fie rău. Ești gata? Ei bine, calculăm gradientul, deci derivatele,
pentru funcția ce ne estimează erorile. De exemplu funcția erorilor pătrate medii. Nu
pare complicat, dacă știi regulile de bază a derivării, nu? DAR, există un dar mare,
acea funcție implicit conține rețeaua noastră neuronală, cu alte cuvinte o funcție cu
sute de mii sau chiar milioane de parametri. Adică învățarea în cazul dat înseamna
estimarea valorilor de actualizare pentru toți parametrii noștri. aaaaaaaaa!!!!! Mai
mult de atât, rețeaua neuronală fiind o funcție foarte complexă, implică și niște
derivate complexe. Deci e rău de tot. În nici un caz nu vom realiza estimările date,
nici pentru o problemă mică de tot, dar intuiția acestui proces o vom acoperi.
N
1
∑ ( y i−nn(x i , ω t ))❑2
ω t+ 1=ωt + γ ∇
N i
Unde ωeste mulțimea tuturor parametrilor unei rețele neuronale, iar nn este rețeaua
❑
neruonală. Simbolul ∑ ❑ (sigma) semnifică sumarea. Cu alte cuvinte
❑
N
Cum am mai spus, o rețea neuronală este de fapt o funcție imensă, compusă
din numeroase operații de înmulțire și adunare a matricilor, plus aplicarea unor
funcții non-liniare. Asta sugerează că pentru a deriva o astfel de funcție imensă o să
fie nevoie de regula derivării a unei funcții compuse, dar cu mici adaptări pentru a
obține o eficiență computațională sporită. În general derivata unei funcții compuse
de genul f(g(x)) o să fie egală cu f’(g(x))g’(x) . Sau sub altă formă:
dz dz d ω 1 d ωn
= ⋅ ⋅...⋅
dx d ω 1 d ω 2 dx
Unde ω sunt parametrii intermediari, spre exemplu conexiunile într-o rețea
neuronală.
Concluzie
Acum defininitiv putem spune că posezi o intuiție bună referitor la cum
funcționează algoritmii de învățare aprofundată și chiar cunoști anumite trucuri cum
să înveți asemenea algoritmi pentru a avea o performanță bună în situații și pe date
reale. Mai departe în cadrul cursului o să faci cunoștință și cu alți algoritmi mai
simpli, dar care deseori pot rezolva numeroase probleme reale și sunt cu mult mai
rapizi și interpretabili față de rețelele neuronale. De asemenea vei învăță încă multe
alte trucuri necesare în a excela la rezolvarea problemelor utilizând inteligența
artificială.
Exerciții
Test