Machine Learning

4 Comments

Orice decizie care face o persoană normală în - Andrew Ng

Recent experimentam cu Inteligența Artificială, mai exact cu Machine Learning, mai exact cu Deep Learning… pentru geeks… mă jucam cu LSTM.

Mi-a venit un gând să încerc să corectez cu ajutorul LSTM diacriticele în limba română.

Am cumpărat cel mai puternic GPU găsit prin țară, un NVIDIA Geforce GTX 1080 TI. Fără GPU în Deep Learning nu faci nimic. Cumperi cât te ține buzunarul, altfel pierzi timpul. Am construit un model AI, am colectat texte în limba română de pe Internet. I-am dat GPU-ului să ”rugume” acest text și rezultatul l-am pus pe server online.

Țin să menționez că modelul AI nu are idee de limba română, cuvinte în limba română sau reguli de care să se conducă. Simplu, îi dai cât mai mult text și îl lași singur să se descurce. Serverul a muncit din greu câteva zile până am primit precizia uimitoare de 99.97%.

Boom! AI-ul a învățat să pună diacriticele în dependență de context. Încercați: "Langa casa mea nu creste iarba. Langa casa creste un copac." ;-)

Vedeți ce mi-a reușit pe https://diacritice.ai sau să vă instalați extensiunea Chrome.

Pentru curioși urmează detalii.

Machine Learning deschide noi perspective în rezolvarea problemelor care până acum nu se puteau rezolva pe cale algoritmică. Diacriticele sunt un exemplu.

Nu e ușor să construiești un algoritm care să corecteze diacriticele pentru că unele din ele reies din context. Exemplu: “Lângă casa mea crește un copac. Lângă casă nu este nimeni”. În același cuvânt casa și casă se pune sau nu diacritic în dependență de context.

Pentru a rezolva astfel de probleme îți trebuie multă informație. Eu am colectat tocmai 7.3 GB de texte în limba română scrise cu diacritice.

Apoi îți trebuie putere de calcul. În cazul meu, am cumpărat NVIDIA Geforce GTX 1080 TI, una din cele mai puternice cartele grafice găsite în Moldova. Antrenarea rețelei neuronale se face pe cartele grafice cu cele 3584 de CUDA procesoare care lucrează în paralel. Anume această tranziție de la procesor la cartele grafice a dat un imbold mare dezvoltării acestui domeniu.

Ne mai trebuie și un framework pentru a crea rețeaua neuronală. Eu am ales Keras pentru simplitate și Tensorflow pentru execuție.

Ideea este următoarea. Să căutăm în text literele a, i, s, t și apoi analizăm 30 de litere în dreapta și 30 din stânga și le transmitem la intrare în rețeaua neuronală, iar la ieșire îi spunem că trebuie să avem a, i, s, t, ă, â, î, ș, ț. De ce 30 din stânga și din dreapta? Am încercat și câte 15 caractere și câte 20, însă cu 30 am ajuns la un rezultat bun. Posibil că există și alte lungimi mai bune, rămâne pe viitor să mai încerc.

Deep learning se reduce până la urmă la înmulțiri de matrici (aka tensori). X*W + b = Y. Unde X este matricea de intrare (textul nostru codat într-o anumită formă), Y este rezultatul în baza căruia se învață, în cazul nostru e un vector cu 3 elemente căruia îi indicăm dacă este simbolul diacritic sau nu.

Cum transformăm textul în matrice? Îi atribuim fiecărei litere din alfabetul român o poziție în spațiul creat de noi. Pentru simplitate tot textul este convertat la minuscule.

alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r',
's','t','u','v','w','x','y','z',' ','.',',','!','?','-']

Facem o matrice 32x61 adica lungimea afabetului (32 caractere) și fereastra care noi o analizăm (61 caractere).

Să luam de exemplu textul:
langa casa creste un copac
Prima literă din șir 'l' este în afabet pe locul 11, deci primul rând în matrice va avea totul cu 0 și doar pe locul 11 va fi scris 1.
[0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
A doua literă din șir 'a', al doilea rând va fi pe locul 0 scris 1 și restul va fi 0....
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
și așa încă 59 de rânduri.

Așa căpătăm matricea X care trebuie servită la intrare. Vectorul Y de la ieșire e din 3 elemente și poate fi [1, 0, 0] sau [0, 1, 0] sau [0, 0, 1]. Mai jos urmează explicația de ce Y anume așa este reprezentat.

Matricea W și vectorul b se inițializează cu niște valori arbitrare. Apoi în procesul de antrenare Deep Learning încearcă să schimbe valorile la W și b cât mai exact pentru ca la înmulțirea a cât mai multor X*W+b  să ne dea cât mai exact rezultatul indicat de noi în Y.

O problemă observată de mine aici e că dacă folosești LSTM doar într-o singură direcție, la texte scurte sau la începutul textului, apar dificultăți cu detectarea corectă. Așa că am trecut la LSTM bidirecțional. Modelele bidirecționale se mai folosesc și la recunoașterea vorbirii, traduceri, recunoașterea scrisului de mână. Adică indic rețelei neuronale cele 61 caractere de la dreapta la stânga și apoi de la stânga la dreapta.

Schematic arată așa:

Bidirectional LSTM

Codul exprimat în frameworkul Keras arată așa:

Modelul LSTM pentru corectarea diacriticilor în limba română.

Modelul LSTM pentru corectarea diacriticilor în limba română.

Pentru a face iterații cât mai multe testăm pe un text mai mic, am luat toate transcrierile de la privesc.eu (aproximativ 62 MB) și după un weekend am ajuns la performanța de 98.98% la training set, 98.97 la validation set și 97.71 la test set (1MB de texte din arhiva revistei contrafort.md)

Primul lucru încercat a fost ca la ieșire rețeaua să aleagă din cele  9 caractere, a, i, s, t, ă, â, î, ș, ț. Însă teoretic ar fi mai bine să ne dea răspunsul 0 sau 1. Adică dacă trebuie să fie diacritic pus pe locul 31 ori nu. Și deoarece noi știm că dacă pe locul 31 este i atunci și rezultatul 1, atunci pune î. Problema e că unii scriu cu â din a și la a avem 3 opțiuni a, ă, â. Pentru a minimiza spațiul de răspunsuri am ales vector cu 3 categorii [1, 0, 0] - nu este diacritic, [0, 1, 0] - este diacritic [0, 0, 1] - este â.

Dacă ați observat nicăieri nu indic sistemului că, de fapt,  caracterul diacritic care noi îl căutăm e anume pe poziția 31. Însă după câteva milioane de iterații el își dă seama singur :D .

După training cu Keras și Tensorflow urmărim rezultatul cu Tensorboard. Dacă nu avem overfit sau underfit e super, am găsit modelul corect. Am exportat modelul pentru a fi servit cu Tensorflow Serving. Am arendat pe Digitalocean un server de 5$/lună, am instalat Tensorflow Serving. Pentru a nu mă complica cu web serverul, am utilizat Flask.

Job done.

Vă invit să vă expuneți cu idei, sugestii, laude sau critici pe site-ul diacritice.ai.

PS: Ce urmează?
Versiunea curentă 1.1 e antrenată pe un volum de text de 1.4 GB. O epocă (iterație peste tot textul) durează aproximativ 15 ore. Urmează să încep să fac training pe cele 7.3 GB, însă va dura câteva săptămâni până voi face câteva epoci. Calitatea de 99.97% care o are sistemul acum e destul de acceptabilă. Nu mă opresc aici, sper să ajung la 99.99%