Risoluzione di equazioni matematiche di base utilizzando RNN [con esempio di codifica]

Pubblicato: 2020-12-07

Se la vita ti dà RNN, crea una calcolatrice

Una rete neurale ricorrente è una delle classiche reti neurali artificiali, in cui le connessioni tra i nodi formano un grafo sequenziale diretto. Gli RNN sono famosi per applicazioni come il riconoscimento vocale, il riconoscimento della grafia, ecc. a causa della loro memoria di stato interna per l'elaborazione di sequenze di lunghezza variabile.

Gli RNN sono ulteriormente classificati in due tipi. Il primo è un impulso finito la cui rete neurale ha la forma di un grafo aciclico diretto in cui un nodo può essere connesso con uno o più nodi che sono avanti senza alcun ciclo visibile nella rete. Un altro è un impulso infinito la cui rete neurale ha la forma di un grafo ciclico diretto che non può essere svolto in una rete neurale feed-forward.

Sommario

Cosa faremo?

Costruiamo un modello che predice l'output di un'espressione aritmetica. Ad esempio, se fornisco un input "11+88", il modello dovrebbe prevedere la parola successiva nella sequenza come "99". L'input e l'output sono una sequenza di caratteri poiché un RNN si occupa di dati sequenziali.

Ora la progettazione dell'architettura del modello sembra un compito semplice rispetto alla raccolta di set di dati. La generazione di dati o la raccolta di set di dati è un compito faticoso perché i modelli di intelligenza artificiale per la fame di dati richiedono una discreta quantità di dati per un'accuratezza accettabile.

Quindi questo modello può essere implementato in 6 passaggi fondamentali:

  1. Generazione di dati
  2. Costruire un modello
  3. Vettorizzazione e Devettorizzazione dei dati
  4. Realizzazione di un set di dati
  5. Allenare il modello
  6. Testare il modello

Prima di immergerci nell'implementazione del modello, importiamo semplicemente tutte le librerie richieste.

importa numpy come np

importa flusso tensoriale come tf

da tensorflow.keras.models import Sequential

da tensorflow.keras.layers import Dense, Dropout, SimpleRNN, RepeatVector, TimeDistributed

da tensorflow.keras.callbacks import EarlyStopping, LambdaCallback

da importazione termcolor colorato

1. Generazione di dati

Definiamo una stringa di caratteri contenente tutti i caratteri necessari per scrivere un'equazione aritmetica di base. Quindi, la stringa è composta da tutti i caratteri da 0 a 9 e da tutti gli operatori aritmetici come /, *, +, -, .(decimale).

Non possiamo inserire direttamente i dati numerici nel nostro modello, dobbiamo passare i dati sotto forma di tensori. La conversione della stringa nei dati in un vettore codificato one-hot ci darà prestazioni del modello ottimizzate. Un vettore codificato one-hot è un array con una lunghezza uguale alla lunghezza della nostra stringa di caratteri, ogni vettore one-hot ne ha uno solo al rispettivo indice di carattere presente in ciascuna stringa.

Ad esempio, supponiamo che la nostra stringa di caratteri sia '0123456789', e se vogliamo codificare una stringa come '12', il vettore one-hot sarebbe [ [0,1,0,0,0,0,0,0 ,0,0], [0,0,1,0,0,0,0,0,0,0] ]. Per fare ciò dobbiamo creare due dizionari con un indice come chiavi e caratteri come valori e l'altro come viceversa.

char_string = ' 0123456789/*+-. '

num_chars = len (char_string)

character_to_index = dict ((c, i) for i, c in enumerate (char_string))

index_to_character = dict ((i, c) for i, c in enumerate (char_string))

Ora scriviamo una funzione che restituisce un'equazione aritmetica casuale insieme al risultato di tale equazione.

def divisione (n, d):

restituisce n / d se d != 0 altrimenti 0

def datagen ():

casuale1 = np.random.randint(basso = 0 , alto = 100 )

casuale2 = np.random.randint(basso = 0 , alto = 100 )

op = np.random.randint(basso = 0 , alto = 4 )

se op == 1 :

arith = str (casuale1) + ' + ' + str (casuale2)

res = str (casuale1 + casuale2)

elif op == 1 :

arith = str (casuale1) + ' ' + str (casuale2)

res = str (casuale1 casuale2)

elif op == 2 :

arith = str (casuale1) + ' * ' + str (casuale2)

res = str (casuale1 * casuale2)

altro :

arith = str (casuale1) + ' / ' + str (casuale2)

res = str ( round (division(random1, random2), 2 ))

ritorno arit, ris

Leggi anche: Idee interessanti per progetti di reti neurali

2. Costruire un modello

Il modello avrà un codificatore e un decoder. L'encoder è un semplice modello RNN con forma di input come (Nessuno,num_chars) e 128 unità nascoste, il motivo per cui scegliamo unità nascoste come 32,64,128, ecc è dovuto alle migliori prestazioni della CPU o della GPU con unità nascoste come potenze di 2.

Il nostro codificatore sarà una rete completamente connessa e l'output di questi verrà reimmesso nella rete, ecco come funziona un RNN. Un livello RNN utilizza l'attivazione "tanh" per impostazione predefinita, non cambieremo perché si adatta meglio all'encoder. L'output di questo livello sarà un singolo vettore e per ottenere un singolo vettore dell'intero output utilizzeremo il livello RepeatVector() con il numero di volte richiesto come parametro.

Ora il vettore di output avrà l'essenza dell'input fornito e questo vettore verrà inserito nel decodificatore.

Il decodificatore è composto da un semplice livello RNN e questo genererà la sequenza di output poiché abbiamo bisogno del livello RNN per restituire la sequenza prevista che contrassegneremo 'return_sequences' come True. Assegnando 'return_sequences' come True, il livello RNN restituirà la sequenza prevista per ogni passaggio temporale (da molti a molti RNN).

L'output di questo livello RNN viene inserito in uno strato Denso con il numero 'num_chars' di unità nascoste e useremo l'attivazione softmax poiché abbiamo bisogno della probabilità di ogni carattere. Prima di distribuire un livello Dense, è necessario ridurre questo livello in un livello TimeDistributed perché è necessario distribuire il livello Dense per l'output di ogni passaggio temporale.

unità_nascoste = 128

max_time_steps = 5 #stiamo codificando l'output in modo che sia di 5 caratteri

def modello ():

modello = sequenziale()

model.add(SimpleRNN(unità_nascoste, forma_input = ( Nessuno , num_chars)))

model.add(RepeatVector(max_time_steps))

model.add(SimpleRNN(unità_nascoste, sequenze_di_ritorno = True ))

model.add(TimeDistributed(Dense(num_chars, activation = ' softmax ' )))

modello di ritorno

modello = modello()

modello.riepilogo()

model.compile(loss = ' categorical_crossentropy ' , Optimizer = ' adam ' , metrics = [ ' precision ' ])

L'architettura del modello sarà quella mostrata sopra

Da leggere: Tutorial sulle reti neurali

3. Vettorizzazione e Devettorizzazione dei Dati

Definiamo le funzioni per vettorizzare e devettorizzare i dati.

Ecco la funzione per vettorizzare insieme l'espressione aritmetica e il risultato.

def vettorizzare (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)

per i, c in enumerare (arit):

x[x_rimanente + i, da_carattere a_indice[c]] = 1

per i nell'intervallo (x_remaining) :

x[i, carattere_a_indice[ ' 0 ' ]] = 1

per i, c in enumerare (res):

y[y_remaining + i, character_to_index[c]] = 1

per i nell'intervallo (y_remaining) :

y[i, carattere_a_indice[ ' 0 ' ]] = 1

restituire x, y

Allo stesso modo ecco la funzione per de-vettorizzare la stringa. Poiché l'output che riceviamo è un vettore di probabilità, utilizzeremo np.argmax() per selezionare il carattere con la probabilità più alta. Ora il dizionario index_to_character viene utilizzato per risalire al carattere in quell'indice.

def devictorize (input):

res = [index_to_character[np.argmax(vec)] for i, vec in enumerate ( input )]

return ' ' .join(res)

Ora il vincolo che abbiamo con la funzione 'devectorize' è che riempirà i caratteri finali con zeri. Ad esempio, se il vettore di input è ('1-20', '-19'), l'output devettorizzato sarà ('01-20', '00-19'). Dobbiamo prenderci cura di questi zeri extra imbottiti. Scriviamo una funzione per lo stripping della stringa.

def stripping (ingresso):

bandiera = falso

uscita = ' '

per c in ingresso :

se non flag e c == ' 0 ' :

Continua

se c == ' + ' oppure c == ' ' oppure c == ' * ' oppure c == ' / ' oppure c == ' . ' :

bandiera = falso

altro :

bandiera = Vero

uscita += c

uscita di ritorno

4. Creazione di un set di dati

Ora che abbiamo finito di definire una funzione per generare i dati, usiamo quella funzione e creiamo un set di dati con molte di queste coppie (espressione aritmetica, risultato).

def create_dataset (num_equazioni):

x_train = np.zeros((num_equazioni, max_time_steps, num_chars))

y_train = np.zeros((num_equazioni, max_time_steps, num_chars))

per i nell'intervallo (num_equazioni) :

e, l = datagen()

x, y = vettorizza(e, l)

x_treno[i] = x

y_treno[i] = y

restituisci x_treno, y_treno

5. Formazione del Modello

Creiamo un set di dati di 50.000 campioni che è un numero equo per addestrare il nostro modello di fame di dati, utilizzeremo il 25% di questi dati per la convalida. Inoltre, creiamo una richiamata per l'interruzione intelligente dell'allenamento se la precisione rimane invariata per 8 epoche. Questo può essere ottenuto impostando il parametro pazienza su 8.

x_train, y_train = create_dataset( 50000 )

logger_semplice = LambdaCallback(

on_epoch_end = lambda e, l: print ( ' {:.2f} ' .format (l[ ' val_accuracy ' ]), end = ' _ ' )

)

early_stopping = EarlyStopping(monitor = ' val_loss ' , pazienza = 8 )

model.fit(x_train, y_train, epochs = 100 , validation_split = 0.25 , verbose = 0 ,

callbacks = [simple_logger, early_stopping])

6. Testare il Modello

Ora testiamo il nostro modello creando un set di dati della dimensione 30.

x_test, y_test = create_dataset(num_equations = 20 )

preds = model.predict(x_test)

full_seq_acc = 0

per i, pred in 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 ' if pred_str == y_test_str else ' rosso '

full_seq_acc += 1 / len (preds) * int (pred_str == y_test_str)

outstring = ' Input: {}, Output: {}, Prediction: {} ' .format(x_test_str, y_test_str, pred_str)

stampa (colorato(outstring, col))

print ( ' \n Precisione sequenza completa: {:.3f} % ' .format( 100 * full_seq_acc))

L'output sarà il seguente

Possiamo vedere che la precisione è un po' scarsa qui, comunque possiamo ottimizzarla modificando alcuni iperparametri come il numero di unità nascoste, la divisione di convalida, il numero di epoche, ecc.

Conclusione

Abbiamo compreso il flusso di lavoro di base di un RNN, capito che gli RNN sono più adatti per dati sequenziali, generato un set di dati di equazioni aritmetiche casuali, sviluppato un modello sequenziale per prevedere l'output di un'espressione aritmetica di base, addestrato quel modello con il set di dati che abbiamo creato e infine testato quel modello con un piccolo set di dati che il modello non aveva mai visto prima.

Se sei interessato a saperne di più su RNN, machine learning, dai un'occhiata al Diploma PG di IIIT-B e upGrad in Machine Learning e AI, progettato per i professionisti che lavorano e offre oltre 450 ore di formazione rigorosa, oltre 30 casi di studio e incarichi, Status di Alumni IIIT-B, oltre 5 progetti pratici pratici e assistenza sul lavoro con le migliori aziende.

Quali sono i diversi tipi di reti neurali nell'apprendimento automatico?

Nell'apprendimento automatico, le reti neurali artificiali sono fondamentalmente modelli computazionali progettati per assomigliare al cervello umano. Esistono diversi tipi di reti neurali artificiali che l'apprendimento automatico impiega in base al calcolo matematico che deve essere raggiunto. Queste reti neurali sono un sottoinsieme di diverse tecniche di apprendimento automatico che apprendono dai dati in modi diversi. Alcuni dei tipi più utilizzati di reti neurali sono – rete neurale ricorrente – memoria a lungo termine, rete neurale feedforward – neurone artificiale, rete neurale con funzione di base radiale, rete neurale auto-organizzante di Kohonen, rete neurale convoluzionale e rete neurale modulare, tra gli altri.

Quali sono i vantaggi di una rete neurale ricorrente?

Le reti neurali ricorrenti sono tra le reti neurali artificiali più comunemente utilizzate nell'apprendimento profondo e nell'apprendimento automatico. In questo tipo di modello di rete neurale, il risultato ottenuto dal passaggio precedente viene alimentato come input per il passaggio successivo. Una rete neurale ricorrente presenta diversi vantaggi come: può conservare ogni bit di informazione nel tempo, inclusi i suoi input precedenti, il che la rende ideale per la previsione di serie temporali. Questo tipo è la migliore istanza di memoria lunga e corta. Inoltre, le reti neurali ricorrenti forniscono una vicinanza di pixel costruttiva utilizzando strati convoluzionali.

Come vengono impiegate le reti neurali nelle applicazioni del mondo reale?

Le reti neurali artificiali sono parte integrante del deep learning, che ancora una volta è un ramo super specializzato dell'apprendimento automatico e dell'intelligenza artificiale. Le reti neurali vengono utilizzate in diversi settori per raggiungere vari obiettivi critici. Alcune delle applicazioni reali più interessanti delle reti neurali artificiali includono la previsione del mercato azionario, il riconoscimento facciale, il pilota automatico ad alte prestazioni e la diagnosi dei guasti nell'industria aerospaziale, l'analisi degli attacchi armati e la localizzazione degli oggetti nel settore della difesa, l'elaborazione delle immagini, scoperta di farmaci e rilevamento di malattie nel settore sanitario, verifica della firma, analisi della grafia, previsioni meteorologiche e previsione delle tendenze dei social media, tra gli altri.