RNN-Implementierung in Python

Einführung

Ich habe RNN in Python implementiert. Ich habe ["Deep Learning"](http://www.amazon.co.jp/ Deep Learning-Maschinelles Lernen Professional Series-Okaya-Takayuki / dp / 4061529021) als Lehrbuch verwendet.

Struktur dieses Artikels

RNN

RNN ist ein rekursives neuronales Netzwerk, das Seriendaten verarbeitet. Beispiele für Seriendaten sind Sprache, Sprache und bewegte Bilder. Das Merkmal solcher Seriendaten ist, dass die Länge der Serie für jede Probe unterschiedlich ist und die Reihenfolge der Elemente in der Serie von Bedeutung ist. RNN ermöglicht es, die Eigenschaften von Seriendaten gut zu handhaben.

Vorwärtsausbreitungsberechnung

Definieren Sie zunächst die Zeichen. Die Indizes jeder Einheit der Eingangsschicht, Zwischenschicht und Ausgangsschicht werden durch $ i, j bzw. k $ dargestellt. Die Eingabe zum Zeitpunkt $ t $, die Eingabe / Ausgabe der Zwischenschicht, die Eingabe / Ausgabe der Ausgabeebene und der Lehrer werden wie folgt ausgedrückt.

Weiterhin werden die Gewichte zwischen der Eingabe-Zwischenschicht, die Gewichte des Rückkopplungspfads zwischen den Zwischen-Zwischenschichten und die Gewichte zwischen den Zwischen-Ausgangsschichten wie folgt ausgedrückt.

Die Struktur des Netzwerks einschließlich der obigen Definition ist in der folgenden Abbildung dargestellt.

rnn.png

Jetzt werde ich die Berechnung der Vorwärtsausbreitung erklären. Eingabe / Ausgabe $ u_j ^ t $ und $ z_j ^ t $ der Einheit $ j $ in der mittleren Ebene sind die Eingabe $ \ boldsymbol x ^ t $ und der Wert der mittleren Ebene zum vorherigen Zeitpunkt $ \ boldsymbol z ^ {t Es kann wie folgt mit -1} $ ausgedrückt werden. $ f $ ist die Aktivierungsfunktion.

\begin{align}
& u_j^t = \sum_i w_{ji}^{(in)}x_i^t + \sum_{j'} w_{jj'}z_{j'}^{t-1} \tag{1} \\
& z_j^t = f(u_j^t) \tag{2}
\end{align}

Wenn jedoch $ t = 1 $ ist, gibt es bisher keine Eingabe, also $ \ boldsymbol z ^ 0 = \ boldsymbol 0 $. Wenn die Gleichungen (1) und (2) zusammengesetzt und in einer Matrix ausgedrückt werden, ist die Ausgabe $ \ boldsymbol z ^ t $ der Zwischenschicht wie folgt.

\boldsymbol z^t = \boldsymbol f(\boldsymbol W^{(in)}\boldsymbol x^t + \boldsymbol W \boldsymbol z^{t-1}) \tag{3}

Die Eingabe / Ausgabe $ v_k ^ t $ und $ y_k ^ t $ der Einheit $ k $ der Ausgabeschicht können wie folgt ausgedrückt werden, indem die Ausgabe $ \ boldsymbol z ^ t $ der Zwischenschicht verwendet wird.

\begin{align}
& v_k^t = \sum_j w_{kj}^{(out)}z_j^t \tag{4} \\
& y_k^t = f^{(out)}(v_k^t) \tag{5}
\end{align}

Wenn die Gleichungen (4) und (5) zusammengesetzt und in einer Matrix ausgedrückt werden, ist die Ausgabe $ \ boldsymbol y ^ t $ wie folgt.

\boldsymbol y^t = \boldsymbol f^{(out)}(\boldsymbol W^{(out)}\boldsymbol z^t) \tag{6}

Backpropagation-Berechnung

Der Gradient wird aus dem Fehler in jeder Einheit jeder Schicht durch das Fehlerrückausbreitungsverfahren berechnet. Dieses Mal werde ich die ** BPTT-Methode (Back Propagation durch die Zeit) ** erklären. Bei der BPTT-Methode wird RNN in der Zeitrichtung erweitert, wie in der folgenden Abbildung gezeigt, und die Fehlerrückausbreitung wird berechnet.

bptt.png

** Intermediate-Slope zwischen den Ausgabeebenen **

\begin{align}
\frac{\partial E}{\partial w_{kj}^{(out)}} &= \sum_{t=1}^T \frac{\partial E}{\partial v_k^t} \frac{\partial v_k^t}{\partial w_{kj}^{(out)}} \\
&= \sum_{t=1}^T \frac{\partial E}{\partial y_k^t} \frac{\partial y_k^t}{\partial v_k^t} \frac{\partial v_k^t}{\partial w_{kj}^{(out)}} \\
&= \sum_{t=1}^T \frac{\partial E}{\partial y_k^t} f^{(out)'}(v_k^t)z_j^t \\
&= \sum_{t=1}^T \delta_k^{(out), t} z_j^t \tag{7}
\end{align}

** Zwischensteigung im Rückweg der Zwischenschicht **

\begin{align}
\frac{\partial E}{\partial w_{jj'}} &= \sum_{t=1}^T \frac{\partial E}{\partial u_j^t} \frac{\partial u_j^t}{\partial w_{jj'}} \\
&= \sum_{t=1}^T \biggl(\sum_{k'} \frac{\partial E}{\partial v_{k'}^t} \frac{\partial v_{k'}^t}{\partial z_j^t} \frac{\partial z_j^t}{\partial u_j^t} + \sum_{j''} \frac{\partial E}{\partial u_{j''}^{t+1}} \frac{\partial u_{j''}^{t+1}}{\partial z_j^t} \frac{\partial z_j^t}{\partial u_j^t} \biggr) \frac{\partial u_j^t}{\partial w_{jj'}} \\
&= \sum_{t=1}^T \biggl(\sum_{k'} \frac{\partial E}{\partial v_{k'}^t} \frac{\partial v_{k'}^t}{\partial z_j^t} + \sum_{j''} \frac{\partial E}{\partial u_{j''}^{t+1}} \frac{\partial u_{j''}^{t+1}}{\partial z_j^t} \biggr) \frac{\partial z_j^t}{\partial u_j^t} \frac{\partial u_j^t}{\partial w_{jj'}} \\
&= \sum_{t=1}^T \biggl(\sum_{k'} \delta_{k'}^{(out), t} w_{k'j} + \sum_{j''} \delta_{j''}^{t+1} w_{j''j}  \biggr) f'(u_j^t) z_j^{t-1} \\
&= \sum_{t=1}^T \delta_j^t z_j^{t-1} \tag{8}
\end{align}

** Input-Slope zwischen Zwischenschichten **

\begin{align}
\frac{\partial E}{\partial w_{ji}^{(in)}} &= \sum_{t=1}^T \frac{\partial E}{\partial u_j^t} \frac{\partial u_j^t}{\partial w_{ji}^{(in)}} \\
&= \sum_{t=1}^T \delta_j^t x_i^t \tag{9}
\end{align}

Intermediate-In dem Gradienten im Rückweg der Zwischenschicht gibt es beim nächsten Mal einen Term des Fehlers $ \ boldsymbol \ delta ^ {t + 1} $ der Zwischenschicht. Wenn $ t = T $, dann ist $ \ boldsymbol \ delta ^ {T + 1} = \ boldsymbol 0 $. Propagieren Sie den Fehler $ \ delta $ in der Reihenfolge $ t = T, T-1, \ cdots, 2, 1 $ und nehmen Sie jeweils die Summe der Gradienten. Das Gewicht wird anhand der Summe dieses Gradienten aktualisiert.

Gewichtsaktualisierung

Aus den Gleichungen (7), (8) und (9) kann der Gradient zwischen jeder Schicht erhalten werden. Aktualisieren Sie mithilfe dieses Verlaufs das Gewicht anhand der folgenden Formel.

w_{new} = w_{old} - \varepsilon \frac{\partial E}{\partial w_{old}} \tag{10}

Implementierung in Python

Sinuswellenvorhersage implementiert. Der Code ist unter [hier] angegeben (https://github.com/shota-takayama/rnn). $ x ^ t = \ sin \ bigl (\ theta + (t -1) \ cdot \ Delta \ theta \ bigr) $ Geben Sie beim nächsten Mal $ x ^ t $ und $ y ^ t = \ ein Sagen Sie $ y ^ t $ voraus, was sin \ bigl (\ theta + t \ cdot \ Delta \ theta \ bigr) $ ist. Bei der Ausgabe von $ y ^ t $ für eine bestimmte Eingabe $ x ^ t $ kann die Vorhersagerichtung nicht nur durch die Eingabe $ x ^ t $ bestimmt werden. Wenn Sie jedoch $ x ^ t $ und $ z ^ {t-1} $ eingeben, können Sie die Informationen der vorherigen Zeit verwenden, um die Vorhersagerichtung zu bestimmen.

Ergebnis

Die Trainingsdaten sind eine $ 1 $ -Stichprobe der Seriendaten von $ \ boldsymbol x = (x ^ 1, x ^ 2, \ cdots, x ^ T) $. $ \ theta $ wird durch eine Zufallszahl aus dem Bereich von $ [0, \ pi] $ bestimmt.

\begin{align}
& \{\theta \,|\, 0 \leq \theta \leq \pi\}, \Delta \theta = \frac{\pi}{6} \\
& x^1 = \sin \theta \\
& x^2 = \sin \bigl(\theta + \Delta \theta\bigr) \\
& \cdots \\
& x^t = \sin \bigl(\theta + (t - 1)\cdot \Delta \theta\bigr) \tag{11} \\
& \cdots \\
& x^T = \sin \bigl(\theta + (T - 1)\cdot \Delta \theta\bigr) \\
\end{align}

Die Lernparameter sind wie folgt. Trainingsdaten: $ 7000 $ Probe Lernrate: $ \ varepsilon = 0,05 $ Regularisierungskoeffizient: $ \ lambda = 0,001 $ Epoche: 30 $

Verlust

Der Verlust während des Lernens ist wie folgt.

loss.png

Vorhersage von Seriendaten

Überprüfen Sie anschließend, ob die Vorhersage korrekt war, als die Zeitreihendaten eingegeben wurden. Die Eingabe wird durch $ x $ dargestellt, die Ausgabe wird durch $ y $ dargestellt und die ideale Ausgabe wird durch $ d $ dargestellt.

\begin{align}
& x^1 = \sin\Bigl(\frac{1}{6}\pi\Bigr) \to y^1 = 0.43831960 \ \ (d^1 = 0.86602540) \tag{12} \\
& x^1 = \sin\Bigl(\frac{5}{6}\pi\Bigr) \to y^1 = 0.43831960 \ \ (d^1 = 0.0) \tag{13}
\end{align}

Die Werte von $ y $ stimmen überein, da die Werte von $ x $ gleich sind. Außerdem ist die Vorhersage $ y $ weit von der idealen Ausgabe $ d $ entfernt, da keine Sequenzinformationen vorhanden sind. Daher werde ich auch die Daten der vorherigen Zeit eingeben.

\begin{align}
& \boldsymbol x = (x^1, x^2) = \biggl(\sin\Bigl(\frac{0}{6}\pi\Bigr), \sin\Bigl(\frac{1}{6}\pi\Bigr)\biggr) \to y^2 = 0.84290507 \ \ (d^2 = 0.86602540) \tag{14} \\
& \boldsymbol x = (x^1, x^2) = \biggl(\sin\Bigl(\frac{4}{6}\pi\Bigr), \sin\Bigl(\frac{5}{6}\pi\Bigr)\biggr) \to y^2 = -0.02663726 \ \ (d^2 = 0.0) \tag{15}
\end{align}

Bei Eingabe als Zeitreihendaten werden korrekte Vorhersageergebnisse erhalten. Dies ist möglich, weil RNN eine rekursive Struktur hat, die Zeitreiheninformationen enthält.

Vorhersage der Sündenwelle

Schließlich sagen wir die Sündenwelle voraus. Ein einfacher Algorithmus ist unten gezeigt.

  1. Geben Sie die Kurzseriendaten $ \ boldsymbol x = (x ^ 1, x ^ 2, \ cdots, x ^ {T '}) $ ein und erhalten Sie die Ausgabe $ y ^ {T'} $.
  2. Geben Sie $ y ^ {T '} $ als $ x ^ {T' + 1} $ ein und erhalten Sie die Ausgabe $ y ^ {T '+ 1} $.
  3. Wiederholen Sie Schritt 2, um die Ergebnisse nacheinander zu erhalten.

Die folgende Abbildung ist das Ergebnis. Seriendaten mit kurzen blauen und grünen Punkten sind die durch Vorhersage erhaltenen Ergebnisse. Wenn Sie sich die Grafik ansehen, können Sie sehen, dass die Sinuswelle korrekt vorhergesagt werden kann.

sin.png

abschließend

Ich konnte RNN implementieren. Als nächstes möchte ich LSTM studieren.

Recommended Posts

RNN-Implementierung in Python
ValueObject-Implementierung in Python
SVM-Implementierung in Python
Implementierung eines neuronalen Netzwerks in Python
Implementierung der schnellen Sortierung in Python
Sortieralgorithmus und Implementierung in Python
Implementierung der HMM-Parameterschätzung in Python
Implementierung einer gemischten Normalverteilung in Python
Implementierung eines Lebensspiels in Python
Implementierung der ursprünglichen Sortierung in Python
Quadtree in Python --2
Python in der Optimierung
CURL in Python
Metaprogrammierung mit Python
Python 3.3 mit Anaconda
SendKeys in Python
Metaanalyse in Python
Unittest in Python
Epoche in Python
Zwietracht in Python
Deutsch in Python
DCI in Python
Quicksort in Python
nCr in Python
N-Gramm in Python
Programmieren mit Python
Plink in Python
Konstante in Python
FizzBuzz in Python
SQLite in Python
Schritt AIC in Python
LINE-Bot [0] in Python
CSV in Python
Reverse Assembler mit Python
Reflexion in Python
Konstante in Python
nCr in Python.
Format in Python
Scons in Python 3
Puyopuyo in Python
Python in Virtualenv
PPAP in Python
Quad-Tree in Python
Reflexion in Python
Chemie mit Python
Hashbar in Python
DirectLiNGAM in Python
LiNGAM in Python
In Python reduzieren
In Python flach drücken
Warteschlangen- und Python-Implementierungsmodul "deque"
Sortierte Liste in Python
Täglicher AtCoder # 36 mit Python
Clustertext in Python
AtCoder # 2 jeden Tag mit Python
Täglicher AtCoder # 32 in Python
Täglicher AtCoder # 6 in Python
Täglicher AtCoder # 18 in Python