[PYTHON] Construire un modèle seq2seq à l'aide de l'inférence API fonctionnelle de Keras

Quel genre d'article?

Pour ceux qui veulent essayer ceci ou cela pour la modélisation du deep learning mais ne savent pas comment l'implémenter Utiliser l'API fonctionnelle de Keras comme un framework relativement flexible et raisonnablement abstrait Essayez d'implémenter seq2seq, ce qui est difficile avec séquentiel, aussi simplement que possible

table des matières

  1. Présentation
  2. Prétraitement
  3. Construction et apprentissage de modèles
  4. Raisonnement (Imakoko)
  5. Amélioration du modèle (pas encore réalisée)

Motivation pour cet article

J'ai pu tout apprendre, mais le flux de données au moment de l'apprentissage et le flux de données au moment de l'inférence sont légèrement différents. Comment puis-je faire des inférences en utilisant les paramètres obtenus par l'apprentissage? Je vais répondre à la question.

Ce que vous devez déduire

Commençons par charger le modèle qui a été entraîné et enregistré une fois. Puisque le flux de données est différent lors de l'inférence, il est nécessaire de définir un modèle avec un graphe de calcul différent de celui de l'apprentissage.

Aussi, afin de réaliser le processus de prédiction du mot suivant à partir du mot précédent Utilisez le modèle défini comme une fonction dans une boucle pour déduire séquentiellement.

Implémentation d'inférence

Chargement du modèle

Les modèles enregistrés dans des fichiers h5, etc. peuvent être chargés comme suit.

model = keras.models.load_model(filepath)

De plus, pickle semble être obsolète.

Définition du graphe de calcul

Nous allons construire le modèle montré dans la figure suivante LSTM-Page-1.png

encodeur

Le même encodeur qu'au moment de l'apprentissage peut être utilisé tel quel.

#define encoder
encoder_model = Model(inputs=model.input[0], #encoder_input
                      outputs=model.get_layer('lstm_1').output[1:]) #enconder lstm hidden state

S'il peut être utilisé tel quel, il est possible d'extraire la sortie au milieu de Model de cette manière.

Décodeur

Le décodeur a un code un peu plus long. Il y a trois choses à faire avec le décodeur: Incorporation (pour forcer l'enseignant), LSTM et Dense dans le mot précédent. L'incorporation, LSTM et Dense ont chacun des pondérations pendant l'entraînement, utilisez donc ces valeurs. De plus, la mémoire de la couche cachée qui doit être entrée dans LSTM n'est pas toujours la même que la sortie de l'encodeur, mais la mémoire après avoir déduit le mot précédent, elle doit donc être réécrite à partir du moment de l'apprentissage. L'exemple de mise en œuvre est le suivant

from keras.layers import Input, LSTM, Dense, Embedding
#define decoder
embedding_dim = 256
units = 1024
vocab_tar_size = model.get_layer('dense_1').weights[1].shape.as_list()[0]

decoder_word_input = Input(shape=(1,),name='decoder_input')
decoder_input_embedding = Embedding(input_dim=vocab_tar_size, 
                                    output_dim=embedding_dim,
                                    weights=model.get_layer('embedding_2').get_weights())(decoder_word_input)


decoder_state_input_h = Input(shape=(units,), name='decoder_input_h')
decoder_state_input_c = Input(shape=(units,), name='decoder_input_c')
decoder_states_inputs = [decoder_state_input_h, decoder_state_input_c]

decoder_lstm = LSTM(units, 
                    return_sequences=False, 
                    return_state=True,
                    weights=model.get_layer('lstm_2').get_weights())
decoder_output, state_h, state_c = decoder_lstm(decoder_input_embedding,
                                                initial_state=decoder_states_inputs)

decoder_states = [state_h, state_c]

decoder_dense = Dense(vocab_tar_size, 
                      activation='softmax',
                      weights=model.get_layer('dense_1').get_weights())
decoder_output = decoder_dense(decoder_output)

decoder_model = Model(inputs=[decoder_word_input] + decoder_states_inputs,
                      outputs=[decoder_output] + decoder_states)

Qu'est-ce qui est différent d'apprendre

Vérifiez le modèle généré

SVG(model_to_dot(decoder_model).create(prog='dot', format='svg'))

image.png

Définition de la fonction à traduire

Convertir l'ID de mot d'entrée en ID de mot de sortie

En fait, entrez la colonne d'ID de mot pour obtenir l'ID de mot traduit. Faire

  1. Encodage dans la mémoire de couche cachée par encodeur
  2. Prédiction du premier mot à l'aide de la mémoire obtenue du codeur et du jeton de démarrage
  3. Prédiction du mot suivant en utilisant la mémoire du mot précédent et de la couche cachée précédente
  4. Sortie du résultat de la prédiction

est. L'exemple de mise en œuvre est le suivant. (Je l'ai écrit pour qu'il puisse être traité par lots, mais ce n'est pas indispensable)

def decode_sequence(input_seq, targ_lang, max_length_targ):
    # Encode the input as state vectors.
    states_value = encoder_model.predict(input_seq)
    vocab_tar_size = np.array(list(targ_lang.index_word.keys())).max()
    inp_batch_size = len(input_seq)
    # Generate empty target sequence of length 1.
    target_seq = np.zeros((inp_batch_size, 1))
    # Populate the first character of target sequence with the start character.
    target_seq[:, 0] = targ_lang.word_index['<start>']
    
    # Sampling loop for a batch of sequences
    decoded_sentence = np.zeros((inp_batch_size, max_length_targ))
    
    for i in range(max_length_targ):
        output_tokens, h, c = decoder_model.predict([target_seq] + states_value)

        # Sample a token
        sampled_token_index = np.argmax(output_tokens,axis=1) #array of size [inp_batch_size, 1]

        decoded_sentence[:,i] = sampled_token_index

        # Update the target sequence (of length 1).
        target_seq = np.zeros((inp_batch_size, 1))
        target_seq[:, 0] = sampled_token_index

        # Update states
        states_value = [h, c]

    return decoded_sentence    

Les instances de la classe «Model» ont une méthode «prédire». Si vous passez l'entrée à la méthode «prédire», le calcul sera effectué selon le graphe de calcul défini et la sortie sera obtenue.

Tout d'abord, nous utilisons ʻencoder_model.predict` pour encoder l'entrée dans la mémoire de couche cachée.

En supposant que target_seq avec une taille de [batch_size, 1] ʻest le mot précédent, utilisez decoder_model.predict` avec la mémoire de la couche cachée pour se souvenir du mot suivant et de la couche cachée à entrer ensuite. Je suis en train

Les mots obtenus prennent ʻargmaxdans l'ordre et prennent Stockez-le dansdecoded_sentence pour que la sortie soit de taille [batch_size, max_length_targ]`.

Exécutez cette boucle autant de fois que la longueur maximale de la chaîne de mots de sortie et affichez decoded_sentence.

Exemple de sortie

array([[  15.,   33.,    5.,   27.,  121.,    9.,  482.,    6.,    8.,
           4.,    3.,    0.,    0.,    0.,    0.,    0.,    0.,    0.]])

Convertir l'ID de mot de sortie en mot

Puisque l'ID de mot et la règle de conversion de mot sont obtenus à l'avance par keras.preprocessing.text.Tokenizer Tout ce que vous avez à faire est d'appliquer la loi de conversion de chaque composant de ndarray. Pour que les fonctions python fonctionnent sur tous les composants de ndarray, vous pouvez utiliser np.vectorize pour écrire sans boucles

L'exemple de mise en œuvre est le suivant

#decoded_mot de sens_Convertir l'index en mot et supprimer les jetons de début / fin
def seq2sentence(seq,lang):
    def index2lang(idx, lang):
        try:
            return lang.index_word[idx]
        except KeyError:
            return ''
    langseq2sentence = np.vectorize(lambda x: index2lang(x,lang),otypes=[str])
    sentences = langseq2sentence(seq)
    sentences = [' '.join(list(sentence)) for sentence in sentences]
    sentences = [sentence.lstrip('<start>').strip(' ').strip('<end>') for sentence in sentences]
    return sentences

Pour le moment, le traitement des exceptions a été inclus. Enfin, supprimez l'espace perdu et les jetons de début / fin pour terminer.

référence

La partie prétraitement est la suivante Traduction automatique neuronale avec attention https://www.tensorflow.org/tutorials/text/nmt_with_attention

La base de code pour la partie apprentissage / inférence est la suivante Sequence to sequence example in Keras (character-level). https://keras.io/examples/lstm_seq2seq/

Les données utilisées pour l'apprentissage sont les suivantes https://github.com/odashi/small_parallel_enja

Le référentiel contenant le code de cet article https://github.com/nagiton/simple_NMT

Recommended Posts

Construire un modèle seq2seq à l'aide de l'inférence API fonctionnelle de Keras
Construire un modèle seq2seq en utilisant la vue d'ensemble de l'API fonctionnelle de Keras
Construire un modèle seq2seq en utilisant la création et l'apprentissage du modèle d'API fonctionnelle de Keras
Implémentation de VGG16 à l'aide de Keras créé sans utiliser de modèle entraîné
Créer une API qui renvoie les données d'un modèle à l'aide de turicreate
Modèle multi-entrées / multi-sorties avec API fonctionnelle
Créer un modèle d'apprentissage à l'aide de MNIST
Créer une API CRUD à l'aide de l'API rapide
Essayez d'implémenter XOR avec l'API fonctionnelle Keras
Créer un environnement virtuel en utilisant homebrew + pyenv-virtualenv
Obtenir un modèle de référence à l'aide de Django Serializer
Ajouter une couche à l'aide du backend Keras
Créez une API REST à l'aide du modèle appris dans Lobe et TensorFlow Serving.
Python: analyse des séries temporelles: création d'un modèle SARIMA
Créons une API REST en utilisant SpringBoot + MongoDB
Création d'une application interactive à l'aide d'un modèle de rubrique
Préparer un pseudo serveur API à l'aide d'actions GitHub