Aprile 2018
Volume 33 Numero 4
Il presente articolo è stato tradotto automaticamente.
Esecuzione dei test - Informazioni sulle celle LSTM con C#
Dal James McCaffrey
Una cella di memoria (LSTM) long a breve termine è un componente software di piccole dimensioni che può essere utilizzato per creare una rete neurale ricorrente che è possibile eseguire stime relative alle sequenze di dati. Sono state responsabile principale successi in diverse aree di machine learning LSTM reti. In questo articolo, è possibile illustrare come implementare una cella LSTM usando c#. Sebbene sia improbabile che si sarà mai necessario creare una rete neurale ricorrente da zero, comprendere esattamente le celle LSTM funzionano sarà utile se è necessario creare una rete LSTM usando una libreria di codice, ad esempio Microsoft CNTK o Google TensorFlow.
Nella schermata in figura 1 viene illustrato in questo articolo ha inizio. Il programma demo crea una cella LSTM che accetta un input vettore di dimensioni n = 2 e genera un vettore di output esplicita delle dimensioni m = 3 e un vettore di stato di cella di dimensioni m = 3. Una caratteristica chiave delle celle LSTM è che mantengono uno stato.
Figura 1 LSTM cella Input-Output Demo
Dispone di una cella LSTM (4 * n * m) + (4 * m * m) pesi e (4 * m) pregiudizi. I pesi e i pregiudizi sono solo costanti, con i valori come 0,1234, che definiscono il comportamento della cella LSTM. La dimostrazione 60 pesi e 12 pregiudizi impostati su valori arbitrari.
La dimostrazione invia input (1.0, 2.0) per la cella LSTM. L'output calcolata è (0.0629, 0.0878, 0.1143) senza che sia il nuovo stato cella (0.1143, 0.1554, 0.1973). Verrà illustrato ciò che questi valori numerici potrebbero rappresentare a breve, ma per ora il punto è che una cella LSTM accetta l'input, l'output e aggiorna lo stato. I valori dei pesi e pregiudizi non sono stati modificati.
Quindi, i feed demo (3.0, 4.0) alla cella LSTM. Il nuovo output calcolato è (0.1282, 0.2066, 0.2883). Il nuovo stato cella è (0.2278, 0.3523, 0.4789). Sebbene non sia evidente, il nuovo valore dello stato della cella contiene informazioni su tutti gli input precedente e i valori di output. Questa è la parte "long" di memoria long a breve termine.
Questo articolo si presuppone è intermedie o migliori delle competenze di programmazione, ma non si supponga che si conosce assolutamente celle LSTM. La dimostrazione è codificata tramite c#, ma dovrebbe essere possibile eseguire il refactoring del codice in un altro linguaggio, ad esempio Python o Visual Basic, se si desidera. Il codice demo è semplicemente un po' troppo lungo per presentare nella sua interezza, ma il codice completo è disponibile nel download di file allegati.
Informazioni sulle celle LSTM
Esistono tre modi per descrivere celle LSTM: utilizzando un diagramma dell'architettura, come illustrato nel figura 2; utilizzando equazioni matematiche, come illustrato nel figura 3; o il codice presentato in questo articolo. L'impressione iniziale del diagramma architettura nel figura 2 è probabilmente lungo le righe di "Quali avendo?" I concetti principali sono che una cella LSTM accetta x(t) un vettore di input, dove t è l'acronimo di un'ora. L'output esplicita è h(t). L'utilizzo insolito di h (anziché o) per rappresentare l'output è cronologico e deriva dal fatto che i sistemi neurali spesso fosse descritto come h e g funzioni.
La cella LSTM utilizza inoltre h(t-1) e c(t-1) come input. In questo caso, di t-1 significa che il passaggio di tempo precedente. La lettera c rappresenta lo stato di cella, in modo h(t-1) e c(t-1) sono i valori di output precedenti e i valori dello stato precedente. L'interno dell'architettura della cella LSTM ricerca complicata. E, ma non è così complicata come si può immaginare.
Le equazioni matematiche figura 3 definiscono il comportamento della cella LSTM programma demo. Se non si regolarmente opera con definizioni di matematica, la reazione agli figura 3 è probabile che, anche in questo caso "quali avendo?" Equazioni (1), (2) e (3) definire tre gate: un gate Ignora, un controllo input e un gate di output. Ogni controllo è un vettore di valori compreso tra 0,0 e 1,0, che vengono usati per determinare la quantità di informazioni a dimenticare (o, allo stesso modo, ricordare) in ogni ciclo di input / output. Equazione (4) calcola il nuovo stato di cella ed equazione (5) calcola il nuovo output.
Figura 2 LSTM cella architettura
Figura 3 LSTM cella matematiche equazioni
Tali equazioni sono più semplici rispetto a vengono visualizzati. Ad esempio, equazione (1) viene implementata dal codice demo come:
float[][] ft = MatSig(MatSum(MatProd(Wf, xt),
MatProd(Uf, h_prev), bf));
In questo caso, MatSig è una funzione definita dall'applicazione che applica logistica sigmoide a ciascun valore in una matrice. MatSum aggiunge tre matrici. MatProd Moltiplica due matrici. Dopo aver appreso matrice semplice e le operazioni vettore, implementazione di una cella LSTM è piuttosto semplice.
Struttura generale del programma Demo
La struttura del programma demo, con poche modifiche secondarie per risparmiare spazio, verrà presentata in figura 4. La dimostrazione Usa un approccio di metodo statico piuttosto che un approccio OOP per mantenere i concetti principali più chiare possibili.
Struttura del programma Demo figura 4
using System;
namespace LSTM_IO
{
class LSTM_IO_Program
{
static void Main(string[] args)
{
Console.WriteLine("Begin LSTM IO demo");
// Set up inputs
// Set up weights and biases
float[][] ht, ct; // Outputs, new state
float[][][] result;
result = ComputeOutputs(xt, h_prev, c_prev,
Wf, Wi, Wo, Wc, Uf, Ui, Uo, Uc, bf, bi, bo, bc);
ht = result[0]; // Outputs
ct = result[1]; // New state
Console.WriteLine("Output is:");
MatPrint(ht, 4, true);
Console.WriteLine("New cell state is:");
MatPrint(ct, 4, true);
// Set up new inputs
// Call ComputeOutputs again
Console.WriteLine("End LSTM demo");
}
static float[][][] ComputeOutputs(float[][] xt,
float[][] h_prev, float[][] c_prev,
float[][] Wf, float[][] Wi, float[][] Wo, float[][] Wc,
float[][] Uf, float[][] Ui, float[][] Uo, float[][] Uc,
float[][] bf, float[][] bi, float[][] bo, float[][] bc)
{ . . }
// Helper matrix functions defined here
}
}
Per creare la dimostrazione, è possibile avviare Visual Studio e creata una nuova applicazione console c# denominata LSTM_IO. È possibile utilizzare Visual Studio 2015, ma demo senza dipendenze significativo .NET Framework, in modo da qualsiasi versione di Visual Studio funziona correttamente.
Dopo aver caricato il codice del modello, nella finestra Esplora soluzioni è possibile rinominato file Program.cs per LSTM_IO_Program.cs e Visual Studio rinominare automaticamente classe Program per me è consentito. Nella parte superiore della finestra dell'editor, è possibile eliminare tutti i riferimenti non necessari agli spazi dei nomi, lasciando solo a quella per il primo livello dello spazio dei nomi System. Tutto il lavoro viene eseguito dalla funzione ComputeOutputs.
Matrici con c#
Per implementare una cella LSTM, è necessario comprendere a fondo l'utilizzo delle matrici di c#. Nel linguaggio c#, una matrice è una matrice di matrici. In caso di machine learning, è comune utilizzare float a 32 bit digitare piuttosto che a 64 bit a byte doppio.
La dimostrazione definisce un helper per creare una matrice come:
static float[][] MatCreate(int rows, int cols)
{
float[][] result = new float[rows][];
for (int i = 0; i < rows; ++i)
result[i] = new float[cols];
return result;
}
La prima istruzione crea una matrice con il numero specificato di righe, in cui ogni riga è una matrice di tipo float. L'istruzione di ciclo for esegue l'allocazione di ogni riga sotto forma di matrice con il numero di colonne specificato. Si noti che, diversamente dalla maggior parte dei linguaggi di programmazione c# supporta un tipo di matrice true, ma con un approccio di matrice di matrice è molto più comuni.
Nell'apprendimento automatico, il termine colonna vettore o vettore solo in breve, si riferisce a una matrice con una sola colonna. La maggior parte dei computer inclinati codice funziona con i vettori anziché matrici unidimensionali. Demo viene definita una funzione per generare un matrice/vettore da una matrice unidimensionale:
static float[][] MatFromArray(float[] arr, int rows, int cols)
{
float[][] result = MatCreate(rows, cols);
int k = 0;
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
result[i][j] = arr[k++];
return result;
}
La funzione può essere chiamata per creare un 3 x 1 (3 righe, 1 colonna) vettore simile al seguente:
float[][] v = MatFromArray(new float[] {1.0f, 9.0f, 5.0f}, 3,1);
La dimostrazione definisce una funzione MatCopy che è possibile duplicare una matrice. Può essere chiamato MatCopy:
float[][] B = MatCopy(A);
In questo caso, B è una matrice di nuovo, indipendente con gli stessi valori di A. prestare attenzione del codice, ad esempio:
float[][] B = A;
B viene creato come un riferimento all'oggetto, pertanto, qualsiasi modifica apportata a una matrice influisce su altra. È possibile il comportamento desiderato, ma è probabile che non.
Operazioni tra gli elementi della matrice
Un'implementazione di cella LSTM utilizza molte funzioni tra gli elementi alle matrici, in cui ogni valore in una matrice viene utilizzato o modificata. Ad esempio, viene definita funzione MatTanh:
static float[][] MatTanh(float[][] m)
{
int rows = m.Length; int cols = m[0].Length;
float[][] result = MatCreate(rows, cols);
for (int i = 0; i < rows; ++i) // Each row
for (int j = 0; j < cols; ++j) // Each col
result[i][j] = Tanh(m[i][j]);
return result;
}
La funzione consente di attraversare la matrice di input m e viene applicata la tangente iperbolica (tanh) a ogni valore. Funzione di supporto Tanh definita:
static float Tanh(float x)
{
if (x < -10.0) return -1.0f;
else if (x > 10.0) return 1.0f;
return (float)(Math.Tanh(x));
}
La dimostrazione definisce anche una funzione MatSigmoid che corrisponde esattamente a MatTanh ma logistica sigmoide viene applicato a ogni valore. La funzione logistica sigmoidale è strettamente correlata tanh e restituisce un valore compreso tra 0,0 e 1,0 anziché tra -1,0 e + 1.0.
La dimostrazione definisce una funzione MatSum che somma i valori delle due matrici della stessa forma. Se si osservano all'equazione matematica (1) figura 3, si noterà che un LSTM aggiunge tre matrici. La dimostrazione overload MatSum per lavorare con due o tre matrici.
Funzione MatHada Moltiplica i valori corrispondenti in due matrici che dispongono della stessa forma:
static float[][] MatHada(float[][] a, float[][] b)
{
int rows = a.Length; int cols = a[0].Length;
float[][] result = MatCreate(rows, cols);
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
result[i][j] = a[i][j] * b[i][j];
return result;
}
Elemento per elemento moltiplicazione viene talvolta definita la funzione Hadamard. Le equazioni matematiche (4) e (5) nella figura 3, la funzione Hadamard è indicata dal simbolo di punto aperto. Non confondere la funzione Hadamard tra gli elementi con la moltiplicazione, che è una funzione molto diversa.
La moltiplicazione
Che significa che la moltiplicazione prima, l'operazione non è ovvio. Si supponga che è una matrice 3x2:
1.0, 2.0
3.0, 4.0
5.0, 6.0
E si supponga che B è una matrice 2 x 4:
10.0, 11.0, 12.0, 13.0
14.0, 15.0, 16.0, 17.0
Il risultato di C = AB (moltiplicazione tra A e B) rappresenta una matrice di 3 x 4:
38.0 41.0 44.0 47.0
86.0 93.0 100.0 107.0
134.0 145.0 156.0 167.0
La dimostrazione implementa moltiplicazione di matrici come funzione MatProd. Si noti che quando si usa c#, per le matrici di dimensioni molto grandi si può usare l'istruzione Parallel. for Task Parallel Library.
Per riepilogare, l'implementazione di una cella LSTM usando c# richiede diverse funzioni helper che creano e operano sui matrici (matrici di matrici) e vettori (matrici con una sola colonna). Il codice demo definisce funzioni MatCreate, MatFromArray, MatCopy(m), MatSig(m), MatTanh(m), MatHada (a, b), MatSum (a, b), MatSum (a, b, c) e MatProd (a, b). Sebbene non sia essenziale per la creazione di una cella LSTM, è utile disporre di una funzione per visualizzare una matrice di c#. Consente di definire la demo in funzione MatPrint.
Implementazione e la chiamata LSTM. Input / Output
Il codice per la funzione ComputeOutputs verrà presentato in figura 5. La funzione ha 15 parametri, ma 12 di essi sono sostanzialmente uguali.
Figura 5 funzione ComputeOutputs
static float[][][] ComputeOutputs(float[][] xt,
float[][] h_prev, float[][] c_prev,
float[][] Wf, float[][] Wi, float[][] Wo, float[][] Wc,
float[][] Uf, float[][] Ui, float[][] Uo, float[][] Uc,
float[][] bf, float[][] bi, float[][] bo, float[][] bc)
{
float[][] ft = MatSig(MatSum(MatProd(Wf, xt),
MatProd(Uf, h_prev), bf));
float[][] it = MatSig(MatSum(MatProd(Wi, xt),
MatProd(Ui, h_prev), bi));
float[][] ot = MatSig(MatSum(MatProd(Wo, xt),
MatProd(Uo, h_prev), bo));
float[][] ct = MatSum(MatHada(ft, c_prev),
MatHada(it, MatTanh(MatSum(MatProd(Wc, xt),
MatProd(Uc, h_prev), bc))));
float[][] ht = MatHada(ot, MatTanh(ct));
float[][][] result = new float[2][][];
result[0] = MatCopy(ht);
result[1] = MatCopy(ct);
return result;
}
Testing esplorativo vettore costituisce l'input, ad esempio (1.0, 2.0). C_prev e h_prev vettori sono il vettore di output precedente e lo stato della cella precedente. Le matrici W quattro sono i pesi gate associati valori di input, dove f è un controllo Ignora i è un controllo input e o è un gate di output. Le matrici U quattro sono i pesi associati all'output di cella. I quattro di b vettori è pregiudizi.
Nel corpo della funzione, le prime cinque istruzioni sono un mapping uno a uno per le equazioni cinque matematiche nel figura 3. Si noti che ft, insieme a ot gates tutte utilizzare la funzione MatSig. Pertanto, tutti e tre sono vettori con valori compresi tra 0,0 e 1,0. È possibile considerare queste informazioni come i filtri applicati all'input, output o stato, in cui il valore del controllo e la percentuale mantenuta. Ad esempio, se uno dei valori in ft è 0,75, viene mantenuto al 75% del valore corrispondente nella combinato input e output precedente vettore. In alternativa, allo stesso modo, è stato dimenticato del 25% delle informazioni.
Il calcolo del nuovo stato di cella, ct, è facile da implementare, ma concettualmente profonda. In generale, il nuovo stato di cella dipende da una combinazione gestita di testing esplorativo vettore input e lo stato di vettore e di cella output precedente, h_prev e c_prev. Il nuovo output, Hyper-Threading, dipende il nuovo stato di cella e il controllo di output. È notevole.
La funzione restituisce il nuovo output e il nuovo stato di cella in una matrice. Ciò provoca un tipo restituito float [] [], dove risultato [0] è una matrice di matrici di matrici che contiene l'output e risultato [1] contiene il nuovo stato di cella.
La chiamata ComputeOutputs è tratta principalmente di impostare i valori dei parametri. La dimostrazione inizia le operazioni di preparazione con:
float[][] xt = MatFromArray(new float[] {
1.0f, 2.0f }, 2, 1);
float[][] h_prev = MatFromArray(new float[] {
0.0f, 0.0f, 0.0f }, 3, 1);
float[][] c_prev = MatFromArray(new float[] {
0.0f, 0.0f, 0.0f }, 3, 1);
L'output precedente sia lo stato di cella in modo esplicito vengono inizializzati a zero. Successivamente, due insiemi di peso arbitrario vengono creati i valori:
float[][] W = MatFromArray(new float[] {
0.01f, 0.02f,
0.03f, 0.04f,
0.05f, 0.06f }, 3, 2);
float[][] U = MatFromArray(new float[] {
0.07f, 0.08f, 0.09f,
0.10f, 0.11f, 0.12f,
0.13f, 0.14f, 0.15f }, 3, 3);
Si noti che le due matrici abbiano forme diverse. I valori di peso vengono copiati i parametri di input:
float[][] Wf = MatCopy(W); float[][] Wi = MatCopy(W);
float[][] Wo = MatCopy(W); float[][] Wc = MatCopy(W);
float[][] Uf = MatCopy(U); float[][] Ui = MatCopy(U);
float[][] Uo = MatCopy(U); float[][] Uc = MatCopy(U);
Poiché non vengono modificati i pesi, demo potrebbe assegnate per riferimento anziché MatCopy. I pregiudizi vengono impostati mediante lo stesso modello:
float[][] b = MatFromArray(new float[] {
0.16f, 0.17f, 0.18f }, 3, 1);
float[][] bf = MatCopy(b); float[][] bi = MatCopy(b);
float[][] bo = MatCopy(b); float[][] bc = MatCopy(b);
Funzione ComputeOutputs è simile al seguente:
float[][] ht, ct;
float[][][] result;
result = ComputeOutputs(xt, h_prev, c_prev,
Wf, Wi, Wo, Wc, Uf, Ui, Uo, Uc,
bf, bi, bo, bc);
ht = result[0]; // Output
ct = result[1]; // New cell state
Il concetto di una cella LSTM è per inserire una sequenza di vettori di input, in modo che la demo imposta e invia un secondo vettore di input:
h_prev = MatCopy(ht);
c_prev = MatCopy(ct);
xt = MatFromArray(new float[] {
3.0f, 4.0f }, 2, 1);
result = ComputeOutputs(xt, h_prev, c_prev,
Wf, Wi, Wo, Wc, Uf, Ui, Uo, Uc,
bf, bi, bo, bc);
ht = result[0];
ct = result[1];
Si noti che la demo in modo esplicito invia l'output precedente e vettori stato ComputeOutputs. In alternativa è possibile feed solo nuovo input vettore, poiché l'output precedente e lo stato della cella sono comunque archiviate in Hyper-Threading e ct.
I punti di connessione
In tal caso, qual è il punto? Una cella LSTM può essere usata per creare una rete neurale ricorrente LSTM, ovvero una cella LSTM con alcuni plumbing aggiuntive. Queste reti hanno consentito progressi significativi nei sistemi di previsioni in grado di interagire con i dati delle sequenze. Ad esempio, si supponga che è stato chiesto di stimare il successivo parola nella frase, "In 2017, il championship è stata acquisita da _". Con tali informazioni, sarebbe difficile premuta per eseguire una stima. Ma si supponga che il sistema era stato e memorizzate che non è parte di una frase precedente, "il NBA ha mantenuto un gioco championship dall'1947." È ora sarebbe in grado di stimare uno tra i team NBA 30.
Esistono numerose variazioni di architetture LSTM. Inoltre, poiché le celle LSTM vengono complesse, esistono decine di varianti di implementazione per ogni architettura. Ma se si comprende il meccanismo di cella LSTM base, è possibile comprendere facilmente le variazioni.
Il programma demo imposta i pesi LSTM e i pregiudizi valori arbitrari. I pesi e i pregiudizi per una rete LSTM reali verrà determinati dal training della rete. È necessario ottenere un set di dati di training con valori di input noti e i valori di output corretto noto. Quindi si utilizzerà un algoritmo, ad esempio retropropagazione per trovare i valori per i pesi e pregiudizi da ridurre al minimo di errore tra calcolata gli output e output corretto.
Dr. James McCaffreyfunziona per Microsoft Research Redmond, WA Ha lavorato su diversi prodotti Microsoft, tra cui Internet Explorer e Bing. Dr. McCaffrey può essere raggiunto al jamccaff@microsoft.com.
Grazie per i seguenti esperti Microsoft che ha revisionato in questo articolo: Ricky Loynd e Adith Swaminathan
Viene illustrato in questo articolo nel forum di MSDN Magazine