Dies ist eine Fortsetzung des Chatbots mit dem Microsoft Cognitive Toolkit (CNTK).
In Teil 2 werden wir Chatbots von CNTK anhand der in Teil 1 vorbereiteten Konversationsdaten trainieren. Es wird davon ausgegangen, dass CNTK und NVIDIA GPU CUDA installiert sind.
Natürliche Sprache: ChatBot Part1-Twitter API Corpus hat einen Konversationsdatensatz für Tweets und Antworten von der Twitter-API vorbereitet.
In Teil 2 erstellen und trainieren wir einen Chatbot mit dem Serienkonvertierungsmodell [1].
Seq2Seq with Attention Für die Gesamtstruktur habe ich mich auf GNMT [2] bezogen. Als Komponente des rekursiven neuronalen Netzwerks bestehen sowohl Encoder als auch Decoder aus 5 Schichten LSTM [3], und der Aufmerksamkeitsmechanismus [4] wird eingeführt.
Sowohl Encoder als auch Decoder wenden die Layernormalisierung [5] auf den Ausgang von LSTM an.
Der Encoder verwendet Bidirectional RNN [6], um Vorwärts- und Rückwärtsausgänge zu verketten.
Außerdem wird in Encoder nach dem Anwenden der Ebenennormalisierung auf Vorwärts bzw. Rückwärts und dem anschließenden Verketten im Decoder nach dem Anwenden der Ebenennormalisierung Dropout [[7]](# Referenz) eingefügt, um die Generalisierungsleistung zu verbessern. Machen.
Darüber hinaus verwenden sowohl Encoder als auch Decoder Residual Connection [8], um das mit der Vertiefung von LSTM einhergehende Verschwinden des Gradienten zu verbessern. Die Ausgabe von der Einbettungsschicht ist jedoch nicht restverbunden.
Der Anfangswert jedes Parameters wurde auf eine gleichmäßige Verteilung [2] von [-0,04, 0,04] eingestellt.
Da es sich um ein Klassifizierungsproblem handelt, das das nächste Wort vorhersagt, haben wir die Verlustfunktion als Cross Entropy Error festgelegt und Adam [9] als Optimierungsalgorithmus übernommen. Adams Hyperparameter $ \ beta_1 $ werden auf 0,9 und $ \ beta_2 $ auf die CNTK-Standardwerte gesetzt.
Verwenden Sie für die Lernrate die zyklische Lernrate (CLR) [10], die maximale Lernrate beträgt 0,01, die Basislernrate beträgt 1e-4, die Schrittgröße beträgt das 4-fache der Anzahl der Epochen und die Strategie lautet exp_range. Installieren.
Das Modelltraining führte 100 Epochen durch Mini-Batch-Training durch.
・ CPU Intel (R) Core (TM) i7-5820K 3,30 GHz ・ GPU NVIDIA Quadro RTX 5000 16 GB
・ Windows 10 Pro 1909 ・ CUDA 10.0 ・ CuDNN 7.6 ・ Python 3.6.6 ・ Cntk-gpu 2.7 ・ Cntkx 0.1.33 ・ Pandas 0.25.0
Das Schulungsprogramm ist auf [GitHub] verfügbar (https://github.com/sho-watari/NaturalLanguage/tree/master/STSA).
stsa_training.py
Ich werde den Hauptinhalt dieser Implementierung ergänzen.
Attention Mechanism In dem Serienkonvertierungsmodell werden die eingegebenen Serieninformationen von Encoder in einen Vektor fester Länge codiert, wie in der folgenden Abbildung gezeigt, und der verborgene Zustand zum letzten Mal wird als der anfängliche verborgene Zustand des Decoders festgelegt. Je länger die Eingabesequenz ist, desto schwieriger ist es jedoch, die Informationen zu komprimieren.
Außerdem sollten die Informationen zu jedem Zeitpunkt im verborgenen Zustand enthalten sein ($ h ^ E_1, h ^ E_2, ..., h ^ E_ {S-1} $ in der folgenden Abbildung), jedoch mit dem naiven Seq2Seq Der Decoder kann nur $ h ^ E_S $ zum letzten Mal empfangen.
Der Aufmerksamkeitsmechanismus wurde als Lösung für diese Probleme vorgeschlagen und verbesserte die Leistung des Serienkonvertierungsmodells.
Hier ist die Eingabeserie $ x_s = (x_1, x_2, ..., x_S) $, die Ausgabeserie ist $ y_t = (y_1, y_2, ..., y_T) $ und die Übergangsfunktion von RNN ist $ \ Psi ^. Wenn E $, $ \ Psi ^ D $, kann der verborgene Zustand $ h ^ E_s, h ^ D_t $ zu jedem Zeitpunkt von Encoder und Decoder wie folgt ausgedrückt werden.
h^E_s = \Psi^E(x_s, h^E_{s-1}) \\
h^D_t = \Psi^D(y_t, h^D_{t-1})
Definieren Sie als nächstes die Funktion $ \ Omega $, um das Gewicht zwischen $ h ^ E_s und h ^ D_t $ zu ermitteln. Dieses Mal wird es unter Verwendung der Parameter $ W_ {Encoder}, W_ {Decoder}, W_ {tanh} $ wie folgt definiert. Dies wird als additive Vorsicht [4] bezeichnet, und andere interne Produktwarnungen [11] wurden vorgeschlagen.
\Omega(h^E_s, h^D_t) = W_{tanh} \cdot tanh \left( W_{decoder} \cdot h^D_t + W_{encoder} \cdot h^E_s \right)
Verwenden Sie dann die Softmax-Funktion, um die Summe auf 1 zu normalisieren und die Wichtigkeit jedes Mal für die Eingabeserie zu berechnen.
a_s = \frac{\exp \left( \Omega(h^E_s, h^D_{t-1}) \right)}{\sum \exp \left( \Omega(h^E_s, h^D_{t-1}) \right)}
Dieser Gewichtungskoeffizient $ a_s $ wird dann verwendet, um die gewichtete Summe $ \ overhead {h} $ der Eingabeserie zu ermitteln.
\overline{h} = \sum^S_{s=1} a_s h^E_s
Verketten Sie schließlich diesen gewichteten Durchschnitt mit der ersten Schicht des Decoders.
h^D_t = \Psi^D \left( \left[ \overline{h}, y_t \right], h^D_{t-1} \right)
Auf diese Weise können die verborgenen Zustandsinformationen zu jedem Zeitpunkt effektiv genutzt werden, und die komprimierten Informationen basierend auf der Zeit, die in der Eingabeserie hervorgehoben werden sollte, können an den Decoder übergeben werden.
Bidirectional RNN Bidirektionales RNN ist die Vorwärtsrichtung der Eingabeserie $ x_t = (x_1, x_2, ..., x_T) $ und die Rückwärtsrichtung der Eingabeserie $ x_ {T-t + 1} = (x_T, x_ {T-1}, Wenn Sie ..., x_1) $ zusammen verwenden, können Sie die Informationen der gesamten Eingabeserie berücksichtigen. Bidirektionale RNNs müssen jedoch die gesamte Eingabesequenz bis zum Zeitpunkt $ T $ haben.
Die Implementierung selbst ist einfach, mit zwei RNNs, einem Vorwärts-RNN und einem Rückwärts-RNN, die die Vorwärts- bzw. Rückwärtsrichtung berechnen. Wobei $ \ overrightarrow {h \ strut} _t und \ overleftarrow {h} _t $ die vorwärts und rückwärts verborgenen Schichten zum Zeitpunkt $ t $ sind und $ b und W $ die Vorspannung und das Gewicht in Bezug auf die aktuelle Zeit sind. $ H $ repräsentiert das Gewicht für die verborgene Ebene zum vorherigen Zeitpunkt.
\overrightarrow{h\strut}_t = \overrightarrow{b\strut} + x_t \overrightarrow{W\strut} + \overrightarrow{h\strut}_{t-1} \overrightarrow{H\strut} \\
\overleftarrow{h}_t = \overleftarrow{b} + x_{T-t+1} \overleftarrow{W} + \overleftarrow{h}_{t-1} \overleftarrow{H}
Es gibt mehrere Kandidaten zum Verbinden der Ausgabe des bidirektionalen RNN, aber diesmal werden die Ausgaben der Vorwärts- und Rückwärts-LSTMs verkettet.
In CNTK können Sie es implementieren, indem Sie einfach die Wiederholungsfunktion go_backwards auf True setzen.
sequence_to_sequence_attention
h_enc_forward = Recurrence(lstm_forward[i])(h_enc)
h_enc_backward = Recurrence(lstm_backward[i], go_backwards=True))(h_enc)
Residual Connection Residual Connection ist weit verbreitet, seit ResNet [8] gezeigt hat, dass es möglich ist, Netzwerke mit mehr als 1.000 Schichten zu trainieren. ResNet schlägt eine Restverbindung vor, die zwei oder mehr Schichten mit einem Faltungsnetzwerk überspannt, aber die Theorie der Restverbindung ist einfach.
Wenn hier die Eingabe $ h $ als Funktion $ f $ der Schicht $ l $ ist, kann die Ausgabe des Netzwerks der Schicht $ l $ wie folgt ausgedrückt werden.
f^{(l)}(h)
Die Operation des Hinzufügens der Ausgabe der vorherigen Ebene, dh der Eingabe $ h $, zu dieser ist eine Restverbindung.
f^{(l)}(h) + h
Dann ist die Differenzierung für $ h $ in dieser Gleichung
\begin{align}
\frac{\partial (f^{(l)}(h) + h)}{\partial h} &= \frac{\partial f^{(l)}(h)}{\partial h} + \frac{\partial h}{\partial h} \\
&= w^{(l)} + 1
\end{align}
Selbst wenn die Fehlerausbreitung von der unteren Schicht ein kleiner Wert ist, liegt sie nahe bei 1, so dass das Verschwinden des Gradienten unterdrückt werden kann.
Training loss and perplexity
Die folgende Abbildung zeigt die Verlustfunktion und die Protokolle mit falsch positiven Raten während des Trainings. Das Diagramm links zeigt die Verlustfunktion, das Diagramm rechts zeigt die Ratlosigkeit, die horizontale Achse zeigt die Anzahl der Epochen und die vertikale Achse zeigt den Wert bzw. die Ratlosigkeit der Verlustfunktion.
Sowohl der Wert der Verlustfunktion als auch die Ratlosigkeit sind immer noch groß, daher scheint es etwas zu geben, das verbessert werden muss.
Zeigt ein Gespräch mit einem geschulten Chatbot. Der mit> beginnende Satz ist die Eingabe, und der mit >> beginnende Satz ist die Antwort des Chatbots auf die Eingabe.
>Hallo
>>Hallo!
>Ist Prost auf gute Arbeit
>>Es gibt ein Tsu!
>Bitte folgen Sie mir
>>Gefolgt!
>Wie heißen Sie?
>> w
>Was ist dein Hobby?
>>Ist ein Hobby!
>Das Wetter ist heute gut, nicht wahr?
>>Es ist schönes Wetter!
>Danke für gestern
>>Ich bin derjenige, der dir danken sollte!
>quit
Es scheint, dass sie eine einfache Antwort haben, aber sie haben Gras für ihre Namen angebaut und das Konzept der Hobbys nicht gelernt.
Attention verbessert nicht nur die Leistung des naiven Seq2Seq, sondern ermöglicht es Ihnen auch, die Beziehung zwischen Eingabe und vorhergesagten Wortfolgen mithilfe von Attention Maps zu visualisieren. Die folgende Abbildung zeigt ein Beispiel für eine Aufmerksamkeitskarte, die horizontale Achse repräsentiert die eingegebene Wortsequenz, die vertikale Achse repräsentiert die vorhergesagte Wortsequenz und die Farbkarte wird als heiß angezeigt.
In diesem Beispiel scheint das Eingabewort "gutes Wetter" wichtiger zu sein als die anderen Wörter.
CNTK 204: Sequence to Sequence Networks with Text Data
Natural Language : ChatBot Part1 - Twitter API Corpus
Recommended Posts