Ceci est une continuation du chatbot utilisant le Microsoft Cognitive Toolkit (CNTK).
Dans la partie 2, nous formerons des chatbots par CNTK en utilisant les données de conversation préparées dans la partie 1. On suppose que CNTK et NVIDIA GPU CUDA sont installés.
Natural Language: ChatBot Part1-Twitter API Corpus a préparé un ensemble de données de conversation pour les tweets et les réponses de l'API Twitter.
Dans la partie 2, nous allons créer et former un chatbot en utilisant le modèle de conversion en série [1].
Seq2Seq with Attention Pour la structure globale, je me suis référé à GNMT [2]. En tant que composant du réseau neuronal récursif, l'encodeur et le décodeur sont composés de 5 couches de LSTM [3], et le mécanisme d'attention [4] est introduit.
L'encodeur et le décodeur appliquent la normalisation de couche [5] à la sortie de LSTM.
L'encodeur utilise le RNN bidirectionnel [6] pour concaténer les sorties avant et arrière.
De plus, dans Encoder, après avoir appliqué la normalisation de couche à l'avant et à l'arrière respectivement, puis concaténant, dans Decoder, après l'application de la normalisation de couche, Dropout [[7]](# reference) est inséré pour améliorer les performances de généralisation. Faire.
De plus, l'encodeur et le décodeur utilisent la connexion résiduelle [8] pour améliorer la disparition du gradient qui accompagne l'approfondissement du LSTM. Cependant, la sortie de la couche Embedding n'est pas connectée résiduelle.
La valeur initiale de chaque paramètre a été fixée à une distribution uniforme [2] de [-0,04, 0,04].
Puisqu'il s'agit d'un problème de classification qui prédit le mot suivant, nous avons défini la fonction de perte comme Erreur d'entropie croisée et avons adopté Adam [9] comme algorithme d'optimisation. L'hyperparamètre d'Adam $ \ beta_1 $ est défini sur 0.9 et $ \ beta_2 $ est défini sur la valeur par défaut de CNTK.
Pour le taux d'apprentissage, utilisez le taux d'apprentissage cyclique (CLR) [10], le taux d'apprentissage maximal est de 0,01, le taux d'apprentissage de base est de 1e-4, la taille du pas est de 4 fois le nombre d'époques et la stratégie est exp_range. Installer.
La formation du modèle a effectué 100 Epoch par mini-formation par lots.
・ Processeur Intel (R) Core (TM) i7-5820K 3,30 GHz ・ GPU NVIDIA Quadro RTX 5000 16 Go
・ Windows 10 Professionnel 1909 ・ CUDA 10.0 ・ CuDNN 7.6 ・ Python 3.6.6 ・ Cntk-gpu 2.7 ・ Cntkx 0.1.33 ・ Pandas 0.25.0
Le programme de formation est disponible sur GitHub.
stsa_training.py
Je compléterai le contenu principal de cette implémentation.
Attention Mechanism Dans le modèle de conversion en série, les informations de série d'entrée sont codées dans un vecteur de longueur fixe par le codeur comme indiqué dans la figure ci-dessous, et l'état caché au dernier moment est défini comme l'état caché initial du décodeur. Cependant, plus la séquence d'entrée est longue, plus il est difficile de compresser les informations.
De plus, les informations à chaque instant doivent être incluses dans l'état caché à chaque instant ($ h ^ E_1, h ^ E_2, ..., h ^ E_ {S-1} $ dans la figure ci-dessous), mais avec le Seq2Seq naïf Le décodeur ne peut recevoir que $ h ^ E_S $ à la dernière fois.
Le mécanisme d'attention a été proposé comme remède à ces problèmes et a amélioré les performances du modèle de conversion en série.
Ici, la série d'entrée est $ x_s = (x_1, x_2, ..., x_S) $, la série de sortie est $ y_t = (y_1, y_2, ..., y_T) $, et la fonction de transition de RNN est $ \ Psi ^. Si E $, $ \ Psi ^ D $, l'état caché $ h ^ E_s, h ^ D_t $ à chaque instant du codeur et du décodeur peut être exprimé comme suit.
h^E_s = \Psi^E(x_s, h^E_{s-1}) \\
h^D_t = \Psi^D(y_t, h^D_{t-1})
Ensuite, définissez la fonction $ \ Omega $ pour trouver le poids entre $ h ^ E_s et h ^ D_t $. Cette fois, il est défini comme suit en utilisant les paramètres $ W_ {encoder}, W_ {decoder}, W_ {tanh} $. C'est ce qu'on appelle la mise en garde additive [4], et d'autres mises en garde internes au produit [11] ont été proposées.
\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)
Utilisez ensuite la fonction Softmax pour normaliser la somme à 1 pour calculer l'importance de chaque fois pour la série d'entrée.
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)}
Ensuite, ce coefficient de pondération $ a_s $ est utilisé pour trouver la somme pondérée $ \ overhead {h} $ de la série d'entrée.
\overline{h} = \sum^S_{s=1} a_s h^E_s
Enfin, concaténez cette moyenne pondérée avec la première couche de Decoder.
h^D_t = \Psi^D \left( \left[ \overline{h}, y_t \right], h^D_{t-1} \right)
En faisant cela, les informations d'état cachées à chaque instant peuvent être efficacement utilisées, et les informations compressées basées sur le temps qui doit être souligné dans la série d'entrée peuvent être transmises au décodeur.
Bidirectional RNN RNN bidirectionnel est le sens avant de la série d'entrée $ x_t = (x_1, x_2, ..., x_T) $ et le sens inverse de la série d'entrée $ x_ {T-t + 1} = (x_T, x_ {T-1}, En utilisant ..., x_1) $ ensemble, vous pouvez considérer les informations de la série d'entrée entière. Cependant, les RNN bidirectionnels doivent avoir toute la séquence d'entrée jusqu'à l'instant $ T $.
La mise en œuvre elle-même est simple, avec deux RNN, un RNN aller et un RNN inverse, qui calculent respectivement les sens aller et retour. Où $ \ overrightarrow {h \ strut} _t et \ overleftarrow {h} _t $ sont les couches cachées avant et arrière au temps $ t $, et $ b et W $ sont le biais et le poids par rapport à l'heure actuelle. $ H $ représente le poids du calque masqué à l'instant précédent.
\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}
Il existe plusieurs candidats pour connecter la sortie du RNN bidirectionnel, mais cette fois, les sorties des LSTM aller et retour sont concaténées.
Dans CNTK, vous pouvez l'implémenter en définissant simplement la fonction de récurrence go_backwards sur True.
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 La connexion résiduelle a été largement utilisée depuis que ResNet [8] a montré qu'il était possible de former des réseaux avec plus de 1 000 couches. ResNet propose une connexion résiduelle qui s'étend sur deux ou plusieurs couches avec un réseau neuronal convolutif, mais la théorie de la connexion résiduelle est simple.
Ici, si l'entrée est $ h $ comme fonction $ f $ de la couche $ l $, la sortie du réseau de la couche $ l $ peut être exprimée comme suit.
f^{(l)}(h)
L'opération d'ajout de la sortie de la couche précédente, c'est-à-dire de l'entrée $ h $, est une connexion résiduelle.
f^{(l)}(h) + h
Alors la différenciation pour $ h $ dans cette équation est
\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}
Par conséquent, même si la propagation d'erreur à partir de la couche inférieure est une petite valeur, elle sera proche de 1, il sera donc possible de supprimer la disparition du gradient.
Training loss and perplexity
La figure ci-dessous est une visualisation de la fonction de perte et des journaux de taux de faux positifs pendant l'entraînement. Le graphique de gauche montre la fonction de perte, le graphique de droite montre la Perplexité, l'axe horizontal montre le nombre d'époques et l'axe vertical montre la valeur et la Perplexité de la fonction de perte, respectivement.
La valeur de la fonction de perte et la Perplexité sont toujours importantes, il semble donc y avoir quelque chose à améliorer.
Affiche une conversation avec un chatbot qualifié. La phrase commençant par> est l'entrée, et la phrase commençant par >> est la réponse du chatbot à l'entrée.
>Bonjour
>>Bonjour!
>C'est bravo pour le bon travail
>>Il y a un tsu!
>Suis-moi s'il te plait
>>Suivi!
>Quel est votre nom?
>> w
>Quel est ton passe-temps?
>>Est un passe-temps!
>Il fait beau aujourd'hui, n'est-ce pas
>>Il fait beau!
>Merci pour hier
>>Je suis celui qui devrait te remercier!
>quit
Il semble qu'ils aient une réponse simple, mais ils ont cultivé de l'herbe pour leur nom et n'ont pas appris le concept de passe-temps.
Attention améliore non seulement les performances du Seq2Seq naïf, mais vous permet également de visualiser la relation entre les chaînes de mots d'entrée et prédites à l'aide des cartes Attention. La figure ci-dessous montre un exemple de carte Attention, l'axe horizontal représente la séquence de mots d'entrée, l'axe vertical représente la séquence de mots prédite et la carte de couleurs est affichée comme chaude.
Dans cet exemple, le mot d'entrée «beau temps» semble être plus important que les autres mots.
CNTK 204: Sequence to Sequence Networks with Text Data
Natural Language : ChatBot Part1 - Twitter API Corpus
Recommended Posts