26.4 Formarea rețelei neuronale

Conceperea rețelei neuronale poate fi cel mai bine explicată printr-un exemplu. Figura 26-8 prezintă problema pe care o vom ataca, identificând literele individuale într-o imagine de text. Această sarcină de recunoaștere a modelului a primit multă atenție. Este destul de ușor ca multe abordări să atingă un succes parțial, dar destul de dificil că nu există soluții perfecte. Multe produse comerciale de succes s-au bazat pe această problemă, cum ar fi: citirea adreselor pe litere pentru rutarea poștală, intrarea documentelor în procesoarele de text etc.

Primul pas în dezvoltarea unei rețele neuronale este crearea unei baze de date cu exemple. Pentru problema de recunoaștere a textului, aceasta se realizează prin imprimarea a 26 majuscule: A, B, C, D ... Y, Z, de 50 de ori pe o coală de hârtie. Apoi, aceste 1300 de litere sunt convertite într-o imagine digitală utilizând unul dintre numeroasele dispozitive de scanare disponibile pentru computerele personale. Această imagine digitală mare este apoi împărțită în imagini mici de 10×10 pixeli, fiecare conținând o singură literă. Aceste informații sunt stocate ca o bază de date de 1,3 megabyte: 1300 de imagini; 100 pixeli pe imagine; 8 biți pe pixel. Vom folosi primele 260 de imagini din această bază de date pentru a instrui rețeaua neuronală (adică, a determina ponderile), iar restul pentru a testa performanțele sale. Baza de date trebuie să conțină și o modalitate de identificare a literei conținute în fiecare imagine. De exemplu, ar putea fi adăugat un octet suplimentar la fiecare imagine de 10×10, care conține codul ASCII al literei. Într-o altă schemă, poziția fiecărei imagini de 10 × 10 din baza de date ar putea indica ce literă este. De exemplu, imaginile de la 0 la 49 ar putea fi toate "A", imaginile 50-99 ar putea fi toate "B" etc.

Figura 26-8 Imagine exemplu a unui text.

Identificarea literelor în imaginile textului este un exemplu clasic de căutare a problemelor. În acest exemplu, fiecare literă este conținută într-o imagine de 10x10 pixeli, cu 256 nivele de gri pe pixel. Baza de date utilizată pentru a pregăti și testa rețeaua neuronală exemplu constă din 50 de seturi de 26 litere mari, pentru un total de 1300 de imagini. Imaginile arătate aici sunt o parte a acestei baze de date.

Pentru această demonstrație, rețeaua neuronală va fi proiectată pentru o sarcină arbitrară: a determina care dintre cele imagini 10×10 conține o vocală, adică A, E, I, O sau U. Aceasta poate să nu aibă o aplicație practică, dar ilustrează capacitatea rețelei neuronale de a învăța probleme de recunoaștere foarte abstractă a modelului. Prin includerea a zece exemple din fiecare literă în setul de instruire, rețeaua va (sperăm) învăța caracteristicile cheie care disting ținta de imaginile non-țintă.

Rețeaua neuronală utilizată în acest exemplu este arhitectura tradițională, cu trei straturi, complet interconectată, cum se arată în Fig. 26-5 și 26-6. Există 101 noduri în stratul de intrare (100 valori pixeli plus un nod de polarizare), 10 noduri în stratul ascuns și 1 nod în stratul de ieșire. Atunci când se aplică o imagine de 100 de pixeli la intrarea rețelei, dorim ca valoarea de ieșire să fie apropiată de unu dacă există o vocală și aproape de zero dacă nu există o vocală. Nu vă faceți griji că semnalul de intrare a fost achiziționat ca un șir bi-dimensional (10×10), în timp ce intrarea în rețeaua neuronală este un șir uni-dimensional. Aceasta este înțelegerea dvs. cu privire la modul în care valorile pixelilor sunt interconectate; rețeaua neuronală va găsi relații proprii.

Tabelul 26-2 prezintă programul principal pentru calcularea ponderilor rețelei neuronale, Tabelul 26-3 conținând trei subrutine apelate din programul principal. Elementele șirului: X1 [1] până la X1 [100], țin valorile stratului de intrare. În plus, X1 [101] deține întotdeauna o valoare de 1, furnizând intrarea către nodul de polarizare. Valorile de ieșire de la nodurile ascunse sunt conținute în elementele șirului: X2 [1] până la X2 [10]. Variabila X3 conține valoarea de ieșire a rețelei. Ponderile stratului ascuns sunt cuprinse în șirul WH [ , ] unde primul indice identifică nodul ascuns (1 până la 10), iar al doilea indice este nodul stratului de intrare (1 la 101). Ponderile stratului de ieșire sunt păstrate în WO [1] până la WO [10]. Acest lucru face ca un total de 1020 valori de pondere să definească modul în care va opera rețeaua.

Prima acțiune a programului este de a seta fiecare pondere la o valoare inițială arbitrară, utilizând un generator de numere aleatorii. Așa cum se arată în liniile 190-240, ponderile stratului ascuns sunt atribuite valorilor inițiale între -0,0005 și 0,0005, în timp ce ponderile stratului de ieșire sunt între -0,5 și 0,5. Aceste intervale sunt alese pentru a avea același ordin de mărime cu ponderile finale. Aceasta se bazează pe: (1) intervalul de valori din semnalul de intrare, (2) numărul de intrări însumate la fiecare nod și (3) intervalul valorilor pe care sigmoidul este activ, o intrare de aproximativ -5<x<5 și o ieșire de la 0 la 1. De exemplu, când 101 intrări cu o valoare tipică de 100 sunt înmulțite cu valoarea de pondere tipică de 0,0002, suma produselor este de aproximativ 2, care este în intervalul activ al intrării sigmoidului.

Dacă am evaluat performanța rețelei neuronale folosind aceste ponderi aleatorii, ne-am fi așteptat ca ea să fie aceeași ca și ghicirea aleatoare. Algoritmul de învățare îmbunătățește performanța rețelei prin schimbarea treptată a fiecărei ponderi în direcția corectă. Aceasta se numește o procedură iterativă și este controlată în program prin bucla FOR-NEXT în liniile 270-400. Fiecare iterație face ca ponderile să fie ușor mai eficiente la separarea țintei de exemplele non-țintă. Buclele de iterație sunt de obicei efectuate până când nu se fac alte îmbunătățiri. În rețelele neuronale tipice, acest lucru poate fi oriunde între zece și zece mii de iterații, dar câteva sute sunt comune. Acest exemplu realizează 800 iterații.

Pentru ca această strategie iterativă să funcționeze, trebuie să existe un singur parametru care să descrie cât de bine funcționează sistemul în prezent. Variabila ESUM (pentru suma de erori) servește această funcție în program. Prima acțiune în interiorul buclei de iterație este de a seta ESUM la zero (linia 290) astfel încât să poată fi folosită ca un acumulator. La sfârșitul fiecărei iterații, valoarea ESUM este imprimată pe ecranul video (linia 380), astfel încât operatorul se poate asigura că se înregistrează progrese. Valoarea ESUM va porni foarte mare și va scădea treptat, pe măsură ce rețeaua neuronală este pregătită să recunoască obiectivele. Figura 26-9 prezintă exemple de modul în care ESUM scade odată cu trecerea iterațiilor.

Toate cele 260 de imagini din setul de instruire sunt evaluate în timpul fiecărei iterații, așa cum sunt controlate de bucla FOR-NEXT în liniile 310-360. Subrutina 1000 este utilizată pentru a prelua imagini din baza de date a exemplelor. Deoarece acest lucru nu este de interes deosebit aici, vom descrie doar parametrii transmiși către și de la această subrutină. Subrutina 1000 este introdusă cu parametrul LETTER%, fiind între 1 și 260. La întoarcere, valorile nodului de intrare, X1 [1] la X1 [100], conțin valorile pixelilor pentru imaginea din baza de date corespunzătoare lui LETTER%. Valoarea nodului de polarizare, X1 [101], este returnată întotdeauna cu o valoare constantă de unu. Subrutina 1000 returnează și un alt parametru, CORRECT. Aceasta conține valoarea de ieșire dorită a rețelei pentru această literă particulară. Adică, dacă litera din imagine este o vocală, CORRECT va fi returnată cu o valoare de unu. Dacă litera din imagine nu este o vocală, CORRECT va fi returnată cu o valoare zero.

După ce imaginea de lucru este încărcată în X1 [1] ... X1 [100], subrutina 2000 transmite datele prin rețeaua neuronală curentă pentru a produce valoarea nodului de ieșire X3. Cu alte cuvinte, subrutina 2000 este aceeași cu programul din Tabelul 26-1, cu excepția unui număr diferit de noduri din fiecare strat. De asemenea, această subrutină calculează cât de bine rețeaua curentă identifică litera ca țintă sau non-țintă. În linia 2210, variabila ELET (pentru litera-eroare) este calculată ca diferența dintre valoarea de ieșire reală generată, X3 și valoarea dorită, CORRECT. Acest lucru face ELET o valoare între -1 și 1. Toate cele 260 de valori pentru ELET sunt combinate (linia 340) pentru a forma ESUM, eroarea totală pătrată a rețelei pentru întregul set de instruire.

Linia 2220 prezintă o opțiune care este adesea inclusă la calcularea erorii: atribuirea unei importanțe diferite erorilor pentru ținte și non-ținte. De exemplu, reamintiți exemplul cu cancer prezentat mai devreme în acest capitol, și consecințele unei erori fals-pozitive față de o eroare fals-negativă. În acest exemplu, vom declara în mod arbitrar că eroarea de detectare a unei ținte este de cinci ori mai rea decât eroarea de detectare a unei non-ținte. De fapt, acest lucru îi spune rețelei să facă o treabă mai bună cu țintele, chiar dacă aceasta dăunează performanței non-țintelor.

Subrutina 3000 este inima strategiei rețelei neuronale, algoritmul de modificare a ponderilor pentru fiecare iterație. Vom folosi o analogie pentru a explica matematica de bază. Luați în considerare situația unui parașutist militar care a căzut în spatele liniilor inamice. El s-a parașutat la pământ pe un teritoriu necunoscut, doar pentru a găsi că este atât de întunecat că nu poate vedea mai mult de câțiva metri distanță. Ordinele lui sunt să se îndrepte spre fundul celei mai apropiate vale pentru a începe restul misiunii sale. Problema este, fără a putea vedea mai mult de câțiva metri, cum se îndreaptă spre nivelul văii? Altfel spus, are nevoie de un algoritm pentru a-și ajusta poziția x și y pe suprafața pământului pentru a minimiza altitudinea sa. Acest lucru este similar cu problema ajustării ponderilor rețelei neuronale, astfel încât eroarea rețelei, ESUM, este redusă la minimum.

Vom analiza doi algoritmi pentru a rezolva această problemă: evoluția și cea mai abruptă coborâre. În evoluție, parașutistul face un salt în direcție aleatoare. În cazul în care noua altitudine este mai înaltă decât cea precedentă, el blesteamă și revine la locul său de plecare, unde încearcă din nou. Dacă noua elevație este mai joasă, el simte o măsură de succes și repetă procesul din noua locație. În cele din urmă el va ajunge la fundul văii, deși într-un mod foarte ineficient și hazardat. Această metodă se numește evoluție deoarece este același tip de algoritm folosit de natură în evoluția biologică. Fiecare nouă generație a unei specii are variații aleatorii față de cea anterioară. Dacă aceste diferențe sunt benefice speciei, este mult mai probabil să fie reținute și transferate către următoarea generație. Acesta este rezultatul îmbunătățirii, care permite animalului să primească mai multă mâncare, să scape de dușmanii săi, să producă mai mulți pui etc. Dacă noua trăsătură este dăunătoare, animalul dezavantajat devine prânz pentru un prădător și variația este renunțată. În acest sens, fiecare nouă generație este o iterație a procedurii de optimizare evolutivă.

Când evoluția este folosită ca algoritm de instruire, fiecare pondere din rețeaua neuronală este ușor schimbată prin adăugarea valorii de la un generator de numere aleatorii. Dacă ponderile modificate fac o rețea mai bună (adică o valoare mai mică pentru ESUM), modificările sunt reținute, altfel ele sunt renunțate. În timp ce acest lucru funcționează, este foarte lent în convergență. Acesta este jargonul folosit pentru a descrie că se face o îmbunătățire continuă spre o soluție optimă (fundul văii). În termeni simpli, programul va avea nevoie de zile pentru a ajunge la o soluție, mai degrabă decât minute sau ore.

Din fericire, cel mai abrupt algoritm de coborâre este mult mai rapid. Acesta este modul în care parașutistul ar răspunde în mod firesc: să evalueze în ce direcție este coborârea și să se miște în acea direcție. Gândiți-vă la situație în acest fel. Parașutistul poate să se miște cu un pas spre nord și să înregistreze schimbarea în altitudine. După revenirea la poziția sa inițială, el poate face un pas spre est, și înregistrează schimbarea înălțimii. Folosind aceste două valori, el poate determina care direcție este în jos. Să presupunem că parașutistul cade 10 cm atunci când se mișcă cu un pas în direcția nord și cade cu 20 cm când se mișcă cu un pas în direcția est. Pentru a călători direct în jos, trebuie să se deplaseze de-a lungul fiecărei axe într-o cantitate proporțională cu panta de-a lungul acelei axe. În acest caz, s-ar putea muta la nord cu 10 pași și la est cu 20 de pași. Aceasta îl deplasează pe cea mai abruptă parte a pantei pe o distanță de √102 + 202 pași. Alternativ, el ar putea să se deplaseze într-o linie dreaptă în noua locație, 22,4 pași de-a lungul diagonalei. Punctul cheie este: cea mai abruptă coborâre este realizată prin deplasarea de-a lungul fiecărei axe cu o distanță proporțională cu panta de-a lungul acelei axe.

Figura 26-9 Convergența rețelei neuronale.

Acest grafic prezintă cum descrește eroarea rețelei neuronale (valoarea lui ESUM) cu continuarea iterațiilor. Sunt arătate trei încercări separate, fiecare pornind cu ponderi inițiale diferite.

Subrutina 3000 implementează același algoritm de cea mai abruptă coborâre pentru ponderile rețelei. Înainte de a intra în subrutina 3000, una dintre imaginile exemplu a fost aplicată stratului de intrare, iar informația propagată la ieșire. Aceasta înseamnă că valorile pentru: X1[ ], X2[ ] și X3 sunt toate specificate, precum și valorile de pondere curente: WH[ , ] și WO[ ]. În plus, știm eroarea pe care o produce rețeaua pentru această imagine particulară ELET. Ponderile stratului ascuns sunt actualizate în liniile 3050-3120, în timp ce ponderile stratului de ieșire sunt modificate în liniile 3150-3190. Aceasta se face prin calcularea pantei pentru fiecare pondere și apoi prin schimbarea fiecărei ponderi cu o valoare proporțională cu această pantă. În cazul parașutistului, panta de-a lungul unei axe se găsește prin deplasarea unei mici distanțe de-a lungul axei (de ex., Δx), măsurând schimbarea în altitudine (să zicem, ΔE) și apoi împărțind cele două (ΔE/Δx). Panta unei ponderi a rețelei neuronale poate fi găsită în același mod: adăugați un mic increment la valoarea ponderii (Δw), găsiți modificarea rezultată a semnalului de ieșire (ΔX3) și împărțiți cele două (ΔX3/Δw). Mai târziu, în acest capitol vom analiza un exemplu care calculează panta în acest fel. Totuși, în prezentul exemplu vom folosi o metodă mai eficientă.

Anterior am spus că neliniaritatea (sigmoidul) trebuie să fie diferențiabilă. Aici vom folosi această proprietate. Dacă cunoaștem panta în fiecare punct al nelinearității, putem scrie direct o ecuație pentru panta fiecărei ponderi (ΔX3/Δw) fără a trebui să o perturbăm. Considerați o pondere specifică, de ex. WO [1], care corespunde primei intrări a nodului de ieșire. Priviți la structura din Fig. 26-5 și 26-6 și întrebați: cum va fi afectată ieșirea (X3) dacă această pondere specifică (w) este ușor modificată, dar toate celelalte lucruri sunt păstrate la fel? Răspunsul este:

Ecuația 26-3 Panta ponderilor stratului de ieșire.

Această ecuație este scrisă pentru ponderea WO[1].

unde SLOPEO este prima derivată a sigmoidului stratului de ieșire, evaluat unde operăm pe curba sa. Cu alte cuvinte, SLOPEO descrie cât de mult se modifică ieșirea sigmoidului ca răspuns la o modificare a intrării în sigmoid. Din Ec. 26-2, SLOPEO poate fi calculat din valoarea curentă de ieșire a sigmoidului, X3. Acest calcul este prezentat în linia 3160. În linia 3170, panta pentru această pondere se calculează prin Ec. 26-3 și stocată în variabila DX3DW (adică, ΔX3/Δw).

Folosind o analiză similară, panta pentru o pondere pe stratul ascuns, cum ar fi WH [1,1], poate fi găsită prin:

Ecuația 26-4 Panta ponderii stratului ascuns.

Această ecuație este scrisă pentru ponderea WH[1,1].

SLOPEH1 este prima derivată a sigmoidului stratului ascuns, evaluată unde operăm pe curba sa. Celelalte valori, X1[1] și WO[1], sunt simple constante pe care le vede schimbarea în pondere pe măsură ce își face drumul către ieșire. În liniile 3070 și 3080, pantele sigmoidelor sunt calculate utilizând Ec. 26-2. Panta ponderii stratului ascuns, DX3DW, se calculează în linia 3090 prin Ec. 26-4.

Acum, când știm panta fiecărei ponderi, putem să vedem cum se schimbă fiecare pondere pentru următoarea iterație. Noua valoare pentru fiecare pondere este găsită luând în considerare ponderea actuală și adăugând o valoare proporțională cu panta:

Ecuația 26-5 Actualizarea ponderilor. Fiecare pondere este ajustată prin adăugarea unei valori proporționale cu panta ponderii.

Acest calcul se realizează în linia 3100 pentru stratul ascuns și în linia 3180 pentru stratul de ieșire. Constanta de proporționalitate constă în doi factori: ELET, eroarea rețelei pentru această intrare specifică și MU, o constantă stabilită la începutul programului. Pentru a înțelege necesitatea pentru ELET în acest calcul, imaginați-vă că o imagine plasată pe intrare produce o mică eroare în semnalul de ieșire. Apoi, imaginați-vă că o altă imagine aplicată la intrare produce o eroare de ieșire mare. Atunci când ajustăm ponderile, dorim să îndemnăm rețeaua mai mult pentru a doua imagine decât prima. Dacă ceva lucrează prost, vrem să îl schimbăm; dacă lucrează bine, vrem să o lăsăm în pace. Aceasta se realizează prin schimbarea fiecărei ponderi proporțional cu eroarea curentă, ELET.

Pentru a înțelege modul în care UM afectează sistemul, amintiți-vă exemplul parașutistului. Odată ce determină direcția de coborâre, trebuie să decidă cât de departe să procedeze înainte de a reevalua panta terenului. Făcând o distanță scurtă de un metru, de exemplu, el va putea să urmărească cu precizie conturul terenului și să se miște întotdeauna într-o direcție optimă. Problema este că el își petrece cea mai mare parte a timpului evaluând panta, mai degrabă decât coborând pe deal. În comparație, el putea alege distanța să fie mare, să zicem 1000 de metri. În timp ce acest lucru ar permite parașutistului să se miște rapid de-a lungul terenului, ar putea depăși traseul de coborâre. O distanță prea mare îl face să sară peste tot câmpul, fără a face progresul dorit.

În rețeaua neuronală, MU controlează cât de mult se schimbă ponderile pe fiecare iterație. Valoarea de utilizat depinde de problema particulară, fiind de la 10-6 la 0,1. Din analogia parașutistului, se poate aștepta ca o prea mică valoare să determine rețeaua să conveargă prea lent. În comparație, o valoare prea mare va determina convergența să fie neregulată și va prezenta oscilații haotice în jurul soluției finale. Din păcate, modul în care rețelele neuronale reacționează la diferite valori ale UM poate fi dificil de înțeles sau de prezis. Acest lucru face critic faptul că eroarea de rețea (de exemplu, ESUM) este monitorizată în timpul instruirii, cum ar fi imprimarea pe ecranul video la sfârșitul fiecărei iterații. Dacă sistemul nu converge corect, opriți programul și încercați o altă valoare pentru MU.

Secțiunea următoare: Evaluarea rezultatelor