Rezolvarea ecuației matematice de bază folosind RNN [cu exemplu de codare]
Publicat: 2020-12-07Dacă viața îți dă RNN, fă-ți un calculator
O rețea neuronală recurentă este una dintre rețelele neuronale artificiale clasice, în care conexiunile dintre noduri formează un grafic direcționat secvențial. RNN-urile sunt renumite pentru aplicații precum recunoașterea vorbirii, recunoașterea scrisului de mână etc. datorită memoriei lor interne de stare pentru procesarea secvențelor cu lungime variabilă.
RNN-urile sunt clasificate în continuare în două tipuri. Primul este un impuls finit a cărui rețea neuronală este sub forma unui graf aciclic direcționat în care un nod poate fi conectat cu unul sau mai multe noduri care sunt înainte fără niciun ciclu vizibil în rețea. Un altul este un impuls infinit a cărui rețea neuronală este sub forma unui grafic ciclic direcționat care nu poate fi desfășurat într-o rețea neuronală feed-forward.
Cuprins
Ce vom face?
Să construim un model care prezice rezultatul unei expresii aritmetice. De exemplu, dacă dau o intrare „11+88”, atunci modelul ar trebui să prezică următorul cuvânt din secvență ca „99”. Intrarea și ieșirea sunt o secvență de caractere, deoarece un RNN se ocupă cu date secvențiale.
Acum, proiectarea arhitecturii modelului pare o sarcină simplă în comparație cu colectarea setului de date. Generarea de date sau colectarea setului de date este o sarcină dificilă, deoarece modelele de IA cu foame de date necesită o cantitate suficientă de date pentru o acuratețe acceptabilă.
Deci, acest model poate fi implementat în 6 pași de bază:

- Generarea datelor
- Construirea unui model
- Vectorizarea și de-vectorizarea datelor
- Realizarea unui set de date
- Antrenarea modelului
- Testarea modelului
Înainte de a ne aprofunda în implementarea modelului, să importăm doar toate bibliotecile necesare.
| import numpy ca np import tensorflow ca tf din tensorflow.keras.models import Sequential din tensorflow.keras.layers import Dense, Dropout, SimpleRNN, RepeatVector, TimeDistributed din tensorflow.keras.callbacks import EarlyStopping, LambdaCallback din termcolor import colored |
1. Generarea datelor
Să definim un șir de caractere care să conțină toate caracterele de care avem nevoie pentru a scrie o ecuație aritmetică de bază. Deci, șirul este format din toate caracterele de la 0-9 și toți operatori aritmetici precum /, *, +, -, .(zecimal).
Nu putem alimenta direct datele numerice în modelul nostru, trebuie să transmitem datele sub formă de tensori. Convertirea șirului din date într-un vector codificat one-hot ne va oferi o performanță optimizată a modelului. Un vector one-hot codificat este o matrice cu lungimea aceeași cu lungimea șirului nostru de caractere, fiecare vector one-hot are unul doar la indicele de caractere prezent în fiecare șir.
De exemplu, să presupunem că șirul nostru de caractere este „0123456789”, iar dacă dorim să codificăm un șir precum „12”, atunci vectorul one-hot ar fi [ [0,1,0,0,0,0,0,0 ,0,0], [0,0,1,0,0,0,0,0,0,0] ]. Pentru a face asta, trebuie să creăm două dicționare cu un index ca chei și caractere ca valori și celălalt ca invers.
| char_string = ' 0123456789/*+-. ' num_chars = len (char_string) character_to_index = dict ((c, i) pentru i, c în enumerate (char_string)) index_to_character = dict ((i, c) pentru i, c în enumerate (char_string)) |
Acum să scriem o funcție care returnează o ecuație aritmetică aleatorie împreună cu rezultatul acelei ecuații.
| diviziune def (n, d): returnează n / d dacă d != 0 altfel 0 def datagen (): random1 = np.random.randint(scăzut = 0 , mare = 100 ) random2 = np.random.randint (scăzut = 0 , mare = 100 ) op = np.random.randint(low = 0 , high = 4 ) dacă op == 1 : arith = str (aleatoriu1) + ' + ' + str (aleatoriu2) res = str (aleatoriu1 + aleatoriu2) elif op == 1 : arith = str (aleatoriu1) + ' – ' + str (aleatoriu2) res = str (aleatoriu1 – aleatoriu2) elif op == 2 : arith = str (aleatoriu1) + ' * ' + str (aleatoriu2) res = str (aleatoriu1 * aleatoriu2) altceva : arith = str (aleatoriu1) + ' / ' + str (aleatoriu2) res = str ( rotund (diviziune(aleatoriu1, aleatoriu2), 2 )) returnare arith, res |
Citește și: Idei interesante de proiecte pentru rețele neuronale
2. Construirea unui model
Modelul va avea un encoder și un decodor. Codificatorul este un model RNN simplu cu forma de intrare ca (None,num_chars) și 128 de unități ascunse, motivul pentru care alegem unități ascunse ca 32,64,128 etc. este din cauza performanței mai bune a CPU sau GPU cu unități ascunse ca puteri de 2.
Codificatorul nostru va fi o rețea complet conectată, iar ieșirea acestora va fi reintrodusă în rețea, așa funcționează un RNN. Un strat RNN folosește activarea „tanh” în mod implicit, nu ne vom schimba, deoarece se potrivește cel mai bine codificatorului. Ieșirea acestui strat va fi un singur vector și pentru a obține un singur vector din întreaga ieșire vom folosi stratul RepeatVector() cu numărul necesar de ori ca parametru.
Acum vectorul de ieșire va avea esența intrării dată, iar acest vector va fi introdus în decodor.
Decodorul este compus dintr-un strat RNN simplu și acesta va genera secvența de ieșire, deoarece avem nevoie de stratul RNN pentru a returna secvența prezisă, vom semnala „return_sequences” ca True. Prin atribuirea „return_sequences” ca True, stratul RNN va returna secvența prezisă pentru fiecare pas de timp (de la multe la multe RNN).
Ieșirea acestui strat RNN este introdusă într-un strat Dens cu un număr de unități ascunse „num_chars” și vom folosi activarea softmax, deoarece avem nevoie de probabilitatea fiecărui caracter. Înainte de a implementa un strat Dense, trebuie să prescurăm acest strat într-un strat TimeDistributed, deoarece trebuie să implementăm stratul Dens pentru ieșirea fiecărui pas de timp.
| unități_ascunse = 128 max_time_steps = 5 #codificăm rezultatul să fie de 5 caractere model def (): model = Sequential() model.add(SimpleRNN(hidden_units, input_shape = ( None , num_chars))) model.add(RepeatVector(max_time_steps)) model.add(SimpleRNN(hidden_units, return_sequences = True )) model.add(TimeDistributed(Dense(num_chars, activation = ' softmax ' ))) model de retur model = model() model.summary() model.compile(loss = ' categorical_crossentropy ' , optimizator = ' adam ' , metrics = [ ' precizie ' ]) |

Arhitectura modelului va fi cea prezentată mai sus
Trebuie citit: Tutorial pentru rețeaua neuronală
3. Vectorizarea și de-vectorizarea datelor
Să definim funcții pentru vectorizarea și de-vectorizarea datelor.
Iată funcția pentru vectorizarea expresiei aritmetice și a rezultatului împreună.
| def vectorize (arith, res): x = np.zeros((max_time_steps, num_chars)) y = np.zeros((max_time_steps, num_chars)) x_remaining = max_time_steps – len (arith) ![]() y_remaining = max_time_steps – len (res) pentru i, c în enumerare (arith): x[x_remaining + i, character_to_index[c]] = 1 pentru i în interval (x_remaining): x[i, character_to_index[ ' 0 ' ]] = 1 pentru i, c în enumerare (res): y[y_remaining + i, character_to_index[c]] = 1 pentru i în interval (y_remaining): y[i, character_to_index[ ' 0 ' ]] = 1 returnează x, y |
În mod similar, iată funcția pentru de-vectorizarea șirului. Deoarece rezultatul primit este un vector de probabilități, vom folosi np.argmax() pentru a alege caracterul cu cea mai mare probabilitate. Acum, dicționarul index_to_character este folosit pentru a urmări caracterul de la acel index.
| def devectorize (intrare): res = [index_to_character[np.argmax(vec)] pentru i, vec în enumerate ( input )] returnează ' ' .join(res) |
Acum, constrângerea pe care o avem cu funcția „devectorize” este aceea că va completa caracterele din urmă cu zerouri. De exemplu, dacă vectorul de intrare este ('1-20', '-19'), atunci ieşirea de-vectorizată va fi ('01-20', '00-19'). Trebuie să avem grijă de aceste zerouri suplimentare căptușite. Să scriem o funcție pentru dezlipirea șirului.
| def stripping (intrare): steag = fals ieșire = ' ' pentru c în intrare : dacă nu flag și c == ' 0 ' : continua dacă c == ' + ' sau c == ' – ' sau c == ' * ' sau c == ' / ' sau c == ' . ' : steag = fals altceva : steag = Adevărat ieșire += c ieșire de întoarcere |
4. Realizarea unui set de date
Acum că am terminat cu definirea unei funcții pentru generarea datelor, să folosim acea funcție și să facem un set de date cu multe astfel de perechi (expresie aritmetică, rezultat).
| def create_dataset (num_equations): x_train = np.zeros((num_equations, max_time_steps, num_chars)) y_train = np.zeros((num_equations, max_time_steps, num_chars)) pentru i în interval (num_equations): e, l = datagen() x, y = vectorize(e, l) x_tren[i] = x y_train[i] = y întoarce x_train, y_train |
5. Antrenarea modelului
Să creăm un set de date de 50.000 de eșantioane, ceea ce reprezintă un număr corect pentru a ne instrui modelul de aprofundare a datelor, vom folosi 25% din aceste date pentru validare. De asemenea, să creăm un apel invers pentru întrerupere inteligentă a antrenamentului dacă precizia rămâne neschimbată timp de 8 epoci. Acest lucru poate fi realizat prin setarea parametrului de răbdare la 8.

| x_train, y_train = create_dataset( 50000 ) simple_logger = LambdaCallback( on_epoch_end = lambda e, l: print ( ' {:.2f} ' .format(l[ ' val_accuracy ' ]), end = ' _ ' ) ) early_stopping = EarlyStopping(monitor = ' val_loss ' , rabdare = 8 ) model.fit(x_train, y_train, epochs = 100 , validation_split = 0.25 , verbose = 0 , apeluri inverse = [simple_logger, early_stopping]) |
6. Testarea modelului
Acum să testăm modelul nostru creând un set de date de dimensiunea 30.
| x_test, y_test = create_dataset(num_equations = 20 ) preds = model.predict(x_test) full_seq_acc = 0 pentru i, pred în enumerate (preds): pred_str = stripping(devectorize(pred)) y_test_str = stripping(devectorize(y_test[i])) x_test_str = stripping(devectorize(x_test[i])) col = ' verde ' dacă pred_str == y_test_str else ' roşu ' full_seq_acc += 1 / len (preds) * int (pred_str == y_test_str) outstring = ' Intrare: {}, Ieșire: {}, Predicție: {} ' .format(x_test_str, y_test_str, pred_str) imprimare (colorat(outstring, col)) print ( ' \n Precizie completă a secvenței: {:.3f} % ' .format( 100 * full_seq_acc)) |
Ieșirea va fi după cum urmează

Putem vedea că acuratețea este puțin slabă aici, oricum o putem optimiza prin modificarea câțiva hiperparametri, cum ar fi numărul de unități ascunse, diviziunea de validare, numărul de epoci etc.
Concluzie
Am înțeles fluxul de lucru de bază al unui RNN, am înțeles că RNN-urile sunt cele mai potrivite pentru date secvențiale, am generat un set de date de ecuații aritmetice aleatoare, am dezvoltat un model secvenţial pentru prezicerea rezultatului unei expresii aritmetice de bază, am antrenat acel model cu setul de date care am creat și, în cele din urmă, am testat acel model cu un mic set de date pe care modelul nu l-a mai văzut până acum.
Dacă sunteți interesat să aflați mai multe despre RNN, învățarea automată, consultați Diploma PG de la IIIT-B și upGrad în învățare automată și AI, care este concepută pentru profesioniști care lucrează și oferă peste 450 de ore de formare riguroasă, peste 30 de studii de caz și sarcini, Statut de absolvenți IIIT-B, peste 5 proiecte practice practice și asistență pentru locuri de muncă cu firme de top.
Care sunt diferitele tipuri de rețele neuronale în învățarea automată?
În învățarea automată, rețelele neuronale artificiale sunt practic modele de calcul care au fost proiectate să semene cu creierul uman. Există diferite tipuri de rețele neuronale artificiale pe care învățarea automată le folosește pe baza calculelor matematice care trebuie realizate. Aceste rețele neuronale sunt un subset de diferite tehnici de învățare automată care învață din date în moduri diferite. Unele dintre cele mai utilizate tipuri de rețele neuronale sunt – rețea neuronală recurentă – memorie pe termen lung, rețea neuronală feedforward – neuron artificial, rețea neuronală cu funcție de bază radială, rețea neuronală auto-organizată Kohonen, rețea neuronală convoluțională și rețea neuronală modulară, printre alții.
Care sunt avantajele unei rețele neuronale recurente?
Rețelele neuronale recurente sunt printre cele mai frecvent utilizate rețele neuronale artificiale în învățarea profundă și învățarea automată. În acest tip de model de rețea neuronală, rezultatul obținut din pasul anterior este alimentat ca intrare în pasul următor. O rețea neuronală recurentă vine cu mai multe avantaje, cum ar fi – poate reține fiecare bit de informație de-a lungul timpului, inclusiv intrările sale anterioare, ceea ce o face ideală pentru predicția seriilor temporale. Acest tip este cel mai bun exemplu de memorie lung-scurtă. De asemenea, rețelele neuronale recurente oferă o vecinătate constructivă a pixelilor folosind straturi convoluționale.
Cum sunt utilizate rețelele neuronale în aplicațiile din lumea reală?
Rețelele neuronale artificiale sunt o parte integrantă a învățării profunde, care din nou este o ramură super-specializată a învățării automate și a inteligenței artificiale. Rețelele neuronale sunt utilizate în diferite industrii pentru a atinge diferite obiective critice. Unele dintre cele mai interesante aplicații din lumea reală ale rețelelor neuronale artificiale includ prognoza bursieră, recunoașterea facială, pilotarea automată de înaltă performanță și diagnosticarea defecțiunilor în industria aerospațială, analiza atacurilor armate și localizarea obiectelor în sectorul apărării, procesarea imaginilor, descoperirea medicamentelor și detectarea bolilor în sectorul sănătății, verificarea semnăturii, analiza scrisului de mână, prognoza meteo și prognoza tendințelor rețelelor sociale, printre altele.

