[PYTHON] Génération de phrases avec GRU (keras)

introduction

La dernière fois, j'ai créé un article intitulé J'ai essayé de créer automatiquement un rapport avec la chaîne Markov. À ce moment-là, j'utilisais la chaîne de Markov, donc je me suis retrouvé avec une phrase qui ignorait le flux de la phrase. Par conséquent, cette fois, nous prévoyons de créer des phrases qui sont conscientes du contexte en utilisant une technologie appelée GRU.

Qu'est-ce que GRU

Je pense que RNN et LSTM sont bien connus en matière de génération de phrases, mais j'ai choisi cela car cela demande moins de temps d'apprentissage que le LSTM. Je ne connais pas la structure détaillée, donc je ne l'écrirai pas, mais je peux pratiquement l'écrire avec presque le même code que LSTM.

la mise en oeuvre

Implémentons-le maintenant.

Commencez par charger la bibliothèque à utiliser.


import re
import MeCab
import numpy as np
from sklearn.model_selection import train_test_split
from gensim.models import word2vec

from keras.layers.core import Activation
from keras.layers.core import Dense, Dropout
from keras.layers.core import Masking
from keras.models import Sequential
from keras.layers.recurrent import GRU
from keras.layers.embeddings import Embedding
from keras.layers.normalization import BatchNormalization
from keras.utils import np_utils
from keras.optimizers import RMSprop

Lecture / analyse morphologique

Les données utilisées cette fois-ci proviennent de Aozora Bunko. Cette fois, j'ai utilisé "Phantom Twenty Faces" de Ranpo Edogawa.

Définissez une fonction qui supprime les données inutiles de ces données et effectue une analyse morphologique.


def convert(text, train):
    if train:
        #Supprimer les éléments inutiles tels que le rubis
        text = re.split(r"\-{5,}", text)[2]
        text = re.split(r"Livre du bas:", text)[0]
        text = re.sub(r"《.*?》", "", text)
        text = re.sub(r"[.*?]", "", text)
        text = re.sub(r"[|]", "", text)
        text = re.sub("(\n){2,}", "\n", text)
        text = re.sub(r"\u3000", "", text)

    #Analyse morphologique
    mecab = MeCab.Tagger("-Owakati")
    return mecab.parse(text).split()

Ici, je veux l'utiliser pour le prétraitement des données de prédiction, j'ai donc préparé un argument de valeur booléenne appelé train et ruby supprimé, etc. uniquement au moment de la formation. Maintenant, exécutons cette fonction.


path = "text_raw/kaijin_nijumenso.txt"
with open(path, "r") as f:
    text = f.read()
text_split = convert(text, True)

Lorsqu'il est lu comme ceci, text = Phantom Twenty Faces \ n Edogawa Ranpo \ n \ n ----------- C'est lu comme. Et il est divisé comme text_split = ['hashi', 'is', 'ki', 'that', 'koro', ',' ,,,.

Créer un jeu de données

Commencez par convertir les mots analysés morphologiquement en nombres. Ce n'est qu'un nombre, alors procédez comme suit: Ici, 0 est utilisé pour le masquage (les données excédentaires sont traitées comme 0), il est donc nécessaire de «+ 1».


#Créer un dictionnaire de mots et de nombres
vocab_r = dict((key + 1, word) for (key, word) in enumerate(set(text_split)))
vocab = dict((word, key) for (key, word) in vocab_r.items())

text_num = list(map(lambda x:vocab[x], text_split))

Ensuite, créez un ensemble de données pour l'entraînement. Comme cela sera décrit plus loin, puisque les données d'entrée vectorisent les mots dans la couche Embedding, définissez la dimension sur (n_sample, n_seq) = (nombre de données d'entrée, combien de mots à apprendre). De plus, puisque l'étiquette de réponse correcte sera convertie en one-hot plus tard, cela devrait également être dans la dimension de (n_sample) = (nombre de données d'entrée).


n_seq = 10 #Combien de mots à apprendre
num_char = len(set(text_split)) + 1 #Type de mot (y compris le masquage)
n_sample = len(text_num) - n_seq #Nombre de données d'entrée

#Créer des données
input_data = np.zeros((n_sample, n_seq))
correct_data = np.zeros((n_sample))

for i in range(n_sample):
    input_data[i] = text_num[i:i + n_seq]
    correct_data[i] = text_num[i + n_seq]

x_train, x_test, y_train, y_test = train_test_split(input_data, correct_data, test_size=0.1, shuffle=True)

Expression distribuée des mots

Pour les données d'entrée, les mots sont vectorisés dans la couche Embedding, mais si vous le faites simplement, la taille des données deviendra énorme, nous utiliserons donc une représentation distribuée. Il s'agit de vectoriser les mots en tenant compte de la relation entre les mots, et en l'utilisant, il est possible d'exprimer des mots dans un petit nombre de dimensions.


model_w2v = word2vec.Word2Vec([text_split], size=100, min_count=1, window=5, iter=10)
embedding_matrix = np.zeros((num_char, 100))
for w, vec in zip(model_w2v.wv.index2word, model_w2v.wv.vectors):
    embedding_matrix[vocab[w]] = vec

Utilisation de model_w2v.wv.index2word, model_w2v.wv.vectors

'Baguettes':[ 0.04145062, -0.01713059, -0.0444374 ,,,],
'Mais':[ 0.554178  , -0.19353375, -0.56997895,,,]

Il peut être vectorisé comme. Combinez cela avec le dictionnaire de mots et de nombres que vous avez créé précédemment

[[ 0.        ,  0.        ,  0.        , ...,  0.        ],
[ 0.00860965, -0.00045624, -0.00883528, ..., -0.00861127],
...
[ 0.00662873, -0.00499085, -0.01188819, ..., -0.01252057]]

J'ai pu créer un vecteur de poids comme celui-ci.

Créer un modèle

Étudions avec GRU. Le modèle lui-même peut apprendre les paramètres tels quels en changeant simplement le LSTM en GRU.


#Créer un modèle
model = Sequential()
model.add(Embedding(num_char, 100, weights=[embedding_matrix], trainable=False, input_length=n_seq))
model.add(BatchNormalization(axis=-1))
model.add(Masking(mask_value=0, input_shape=(n_seq, 100)))
model.add(GRU(128, input_shape=(n_seq, 100), kernel_initializer='random_uniform'))
model.add(Dropout(0.2))
model.add(Dense(num_char))
model.add(Activation('softmax'))

model.compile(loss='categorical_crossentropy', optimizer=RMSprop(lr=0.01), metrics=['categorical_accuracy'])
model.fit(x_train, np_utils.to_categorical(y_train, num_char), batch_size=128, validation_split=0.05, epochs=100,
          shuffle=True)

Je ne connais pas les paramètres, j'ai donc fait référence à cet article.

Jetons un coup d'œil aux données de test.


y_pred = model.predict(x_test)
print(list(map(lambda x:vocab_r[x], np.argmax(y_pred, axis=1))))

La sortie ressemble à ceci:

Hahaha ……. ", Félicitez constamment"À"
J'ai levé les yeux. En effet, la longue main"Les gars"
Vous êtes un aventurier naturel et vous êtes au collège"、"

Il a une atmosphère légèrement subtile.

Prédire par chaîne de caractères d'entrée

Essayons quels types de phrases sont réellement créés en supposant la chaîne de caractères saisie.

Premièrement, le mot est analysé et divisé morphologiquement. Je vais l'essayer avec les nouvelles qui se sont avérées être dans la tendance sur Twitter.


input_text = "Accumulation de substances responsables de la démence due à la maladie parodontale Université Kyushu et autres annoncées"
input_text_split = convert(input_text, False)

Convertissez des mots en nombres. À ce stade, les mots qui ne figurent pas dans les données d'apprentissage ne sont pas enregistrés dans le dictionnaire et une erreur se produit, si bien que le traitement des exceptions qui renvoie 0 est effectué.


def word2vec_input(x):
    """
Convertir des nombres en mots
Renvoie 0 pour les caractères ne figurant pas dans le dictionnaire
    """
    try:
        return vocab[x]
    except:
        return 0


vocab_r[0] = "<nodata>"

#Convertir des mots en nombres
input_text_num = list(map(lambda x:word2vec_input(x), input_text_split))

Lorsque vous faites des prédictions, assurez-vous que les données d'entrée sont (nombre de données d'entrée, combien de mots à apprendre) = (1, n_seq).


#Remplissez avec 0 si le nombre de mots est court
if len(input_text_num) < n_seq:
    input_text_num = [0]*(n_seq - len(input_text_num)) + input_text_num

#Fonction de prédiction
def prediction(input_text_num):
    input_test = np.zeros((1, n_seq))
    input_test[0] = input_text_num[-n_seq:]
    y_pred = model.predict(input_test)
    return np.append(input_text_num, np.where(y_pred == np.sort(y_pred)[:, -1].reshape(-1, 1))[1])  # np.argmax(y_pred))
    #J'ai écrit ceci parce que je jouais avec l'écriture de phrases avec la deuxième probabilité la plus élevée, mais argmax suffit

#Exécuter des prédictions
for i in range(1000):
    input_text_num = prediction(input_text_num)

Après l'apprentissage, les nombres sont reconvertis en mots pour créer des phrases.


test_pred = list(map(lambda x:vocab_r[x], input_text_num[len(input_text_split):])) #Découpez le nombre de mots à apprendre
pred_text = input_text + "".join(test_pred) #Utilisez l'entrée telle quelle
print(pred_text)

La chaîne créée ressemble à ceci.

Accumulation de substances responsables de la démence due à la maladie parodontale L'Université Kyushu et d'autres ont annoncé. "Vous, vous, comment, vous, quel genre de chose, j'ai regardé à l'intérieur." Oui, vous, comment, comme vous, regardez ce genre de chose, "voyez. En plus, aux subordonnés du ministre aux vingt visages, l'un d'eux "battait, c'est tout." Hahaha ... "Akechi a dit:" Oui, quoi, "soir ... "..." "Oh, qu'en est-il de Kobayashi? J'ai regardé en toi et j'ai vu le nigiri." Oh, comment es-tu venu? La gentillesse était sur le visage comme un voleur. "... De nos jours, c'est tout." L'art disait: "Alors, l'étagère." "Et le voleur a saisi son teint, et M. Sotaro a dit

Mon japonais est devenu fou ...

Après cela, enregistrez le modèle selon vos besoins.


#Enregistrer le modèle
model.save('test.h5')
model.save_weights('param.hdf5')

#Lis
from tensorflow.python.keras.models import load_model
model = load_model('model/test.h5')
model.load_weights('model/param.hdf5')

finalement

Comme vous pouvez le voir, la précision est devenue très faible. Si vous avez des idées d'amélioration, faites-le moi savoir.

Les références

Recommended Posts

Génération de phrases avec GRU (keras)
Créez un tweet idole avec Keras LSTM (génération de phrases)
J'ai essayé la génération de phrases avec GPT-2
Reconnaissance d'image avec keras
Tutoriel CIFAR-10 avec Keras
07. Génération de déclaration par modèle
LSTM multivarié avec Keras
Génération automatique de quiz avec COTOHA
J'ai écrit le code pour la génération de phrases japonaises avec DeZero
Génération artificielle de données avec numpy
Installation de Keras (utilisée par Anaconda)
Analyse de régression multiple avec Keras
Classification des documents avec une phrase
Notes AutoEncodder avec Keras
Implémentation de word2vec avec Theano + Keras
Réglage des paramètres Keras avec Keras Tuner
Créez facilement des CNN avec Keras
Génération de légende d'image avec Chainer
Implémentation d'un GAN efficace avec keras
Reconnaissance d'image avec Keras + OpenCV
[Jouons avec Python] Viser la génération automatique de phrases ~ Achèvement de la génération automatique de phrases ~
MNIST (DCNN) avec Keras (backend TensorFlow)
Génération de requêtes plus rapide avec SQLAlchemy ORM
Prédire le Titanic de Kaggle avec Keras (Kaggle ⑦)
[TensorFlow] [Keras] Construction d'un réseau neuronal avec Keras
Implémenter Keras LSTM feed forward avec numpy
Comparez DCGAN et pix2pix avec Keras
Implémentation Score-CAM avec keras. Comparaison avec Grad-CAM
Prédiction de l'onde de péché avec keras
Création de vecteurs de phrases avec BERT (Keras BERT)
Débutant RNN (LSTM) | Essayer avec Keras
Générer un mot de passe pour le manuel avec python
Génération de jetons de contre-mesure CSRF avec Python
Écrire Reversi AI avec Keras + DQN
[PyTorch] Génération de phrases japonaises à l'aide de Transformer
Génération de fonctionnalités avec pandas group par
Génération d'images dégradées avec Python [1] | np.linspace
4/22 prédiction de l'onde de péché avec keras
[Jouons avec Python] Viser la génération automatique de phrases ~ Effectuer une analyse morphologique ~