[PYTHON] Créez un tweet idole avec Keras LSTM (génération de phrases)

Contenu de l'article

J'étais intéressé par la génération automatique de phrases à l'aide de l'IA, alors j'ai essayé de générer des phrases à l'aide de Keras. Ce que j'ai fait, c'est obtenir les tweets du groupe d'idols, les laisser apprendre et faire des phrases.

référence

J'ai fait référence à cet article.

Essayez de générer des phrases rapidement avec Keras LSTM

Le code est fondamentalement le même, mais je laisserai une note des parties qui étaient un peu difficiles à comprendre à partir de cet article seul.

Essayez de faire un tweet

Acquisition de données d'entraînement

Le premier est l'acquisition de données d'entraînement.

import json
import config
from requests_oauthlib import OAuth1Session
from time import sleep
import re
import emoji
from mongo_dao import MongoDAO

# Non utilisé cette fois
# Supprimer les pictogrammes
def remove_emoji(src_str):
    return ''.join(c for c in src_str if c not in emoji.UNICODE_EMOJI)

# Paramètre de clé API (défini dans un autre fichier config.py)
CK = config.CONSUMER_KEY
CS = config.CONSUMER_SECRET
AT = config.ACCESS_TOKEN
ATS = config.ACCESS_TOKEN_SECRET

# Processus d'authentification
twitter = OAuth1Session(CK, CS, AT, ATS)  

# Point final d'acquisition de la chronologie
url = "https://api.twitter.com/1.1/statuses/user_timeline.json"  

# Compte d'acquisition
necopla_menber = ['@yukino__NECOPLA', '@yurinaNECOPLA', '@riku_NECOPLA', '@miiNECOPLA', '@kaori_NECOPLA', '@sakuraNECOPLA', '@miriNECOPLA', '@renaNECOPLA']

# Définition des paramètres
params = {'q': '-filter:retweets',
 'max_id': 0, #ID pour commencer à obtenir
          'count': 200}

 arg1:DB Name
 arg2:Collection Name
mongo = MongoDAO("db", "necopla_tweets")
mongo.delete_many({})

regex_twitter_account = '@[0-9a-zA-Z_]+'

for menber in necopla_menber:
    print(menber)
 del params ['max_id'] # Effacer l'ID pour démarrer l'acquisition
 # Obtenez les 200 derniers tweets / Obtenez des tweets plus anciens que l'ID défini dans les paramètres ['max_id'] à partir de la deuxième fois
    for j in range(100):
        params['screen_name'] = menber
        res = twitter.get(url, params=params)
        if res.status_code == 200:
 #API compte restant
            limit = res.headers['x-rate-limit-remaining']
            print("API remain: " + limit)
            if limit == 1:
                sleep(60*15)
            
            n = 0
            tweets = json.loads(res.text)
 # Quittez la boucle si vous ne pouvez pas obtenir de tweets du compte que vous traitez
            if len(tweets) == 0:
                break
 # Processus par tweet
            for tweet in tweets:
 # Enregistrez toutes les données du tweet
                if not "RT @" in tweet['text'][0:4]:
                    mongo.insert_one({'tweet':re.sub(regex_twitter_account, '',tweet['text'].split('http')[0]).strip()})
            
                if len(tweets) >= 1:
                    params['max_id'] = tweets[-1]['id']-1

Pour les données d'entraînement de cet article, nous avons obtenu des tweets du groupe "// Necopla //". Les éléments suivants ont été supprimés des tweets acquis. ・ Lien d'image ・ Compte au moment de la réponse

Les données à entraîner de cette manière sont placées dans mongoDB.

 {"_id": ObjectId ("5e511a2ffac622266fb5801d"), "tweet": "Je suis allé au karaoké pour pratiquer des chansons en solo, mais je me suis cassé la gorge normalement"}
 {"_id": ObjectId ("5e511a2ffac622266fb5801e"), "tweet": "Je peux encore y aller"}

La source de l'opération mongoDB est ici

Apprenez les tweets

C'est presque la même que la source dont j'ai parlé.

from __future__ import print_function
from keras.callbacks import LambdaCallback
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.layers import LSTM
from keras.optimizers import RMSprop
from keras.utils.data_utils import get_file
 import matplotlib.pyplot comme plt # add
import numpy as np
import random
import sys
import io
from mongo_dao import MongoDAO

mongo = MongoDAO("db", "necopla_tweets")
results = mongo.find()

text = ''
for result in results:
    text += result['tweet']

chars = sorted(list(set(text)))
print('total chars:', len(chars))
char_indices = dict((c, i) for i, c in enumerate(chars))
indices_char = dict((i, c) for i, c in enumerate(chars))

 cut the text in semi-redundant sequences of maxlen characters
maxlen = 3
step = 1
sentences = []
next_chars = []
for i in range(0, len(text) - maxlen, step):
    sentences.append(text[i: i + maxlen])
    next_chars.append(text[i + maxlen])
print('nb sequences:', len(sentences))

print('Vectorization...')
x = np.zeros((len(sentences), maxlen, len(chars)), dtype=np.bool)
y = np.zeros((len(sentences), len(chars)), dtype=np.bool)
for i, sentence in enumerate(sentences):
    for t, char in enumerate(sentence):
        x[i, t, char_indices[char]] = 1
    y[i, char_indices[next_chars[i]]] = 1
 
 
 build the model: a single LSTM
print('Build model...')
model = Sequential()
model.add(LSTM(128, input_shape=(maxlen, len(chars))))
model.add(Dense(len(chars)))
model.add(Activation('softmax'))
 
optimizer = RMSprop(lr=0.01)
model.compile(loss='categorical_crossentropy', optimizer=optimizer)
 
 
def sample(preds, temperature=1.0):
    # helper function to sample an index from a probability array
    preds = np.asarray(preds).astype('float64')
    preds = np.log(preds) / temperature
    exp_preds = np.exp(preds)
    preds = exp_preds / np.sum(exp_preds)
    probas = np.random.multinomial(1, preds, 1)
    return np.argmax(probas)
 
# Exécuter à la fin de l'époque
def on_epoch_end(epoch, logs):
    # Function invoked at end of each epoch. Prints generated text.
    print()
    print('----- Generating text after Epoch: %d' % epoch)
     
    # start_index = random.randint(0, len(text) - maxlen - 1)
 # start_index = 0 # Génération de phrases à partir de "Le vieil homme était vieux" à chaque fois
 pour la diversité dans [0,2]: # diversité = 0,2 uniquement
        print('----- diversity:', diversity)
 
        generated = ''
        # sentence = text[start_index: start_index + maxlen]
 phrase = 'Demain'
        generated += sentence
        print('----- Generating with seed: "' + sentence + '"')
        sys.stdout.write(generated)
 
        for i in range(120):
            x_pred = np.zeros((1, maxlen, len(chars)))
            for t, char in enumerate(sentence):
                x_pred[0, t, char_indices[char]] = 1.
 
            preds = model.predict(x_pred, verbose=0)[0]
            next_index = sample(preds, diversity)
            next_char = indices_char[next_index]
 
            generated += next_char
            sentence = sentence[1:] + next_char
 
            sys.stdout.write(next_char)
            sys.stdout.flush()
        print()

# Exécuter à la fin de l'apprentissage
def on_train_end(logs):
    print('----- saving model...')
    model.save_weights("necopla_model" + 'w.hdf5')
    model.save("necopla_model.hdf5")

print_callback = LambdaCallback(on_epoch_end=on_epoch_end,
                                on_train_end=on_train_end)
 
history = model.fit(x, y,
                    batch_size=128,
                    epochs=5,
                    callbacks=[print_callback])
 
 Plot Training loss & Validation Loss
loss = history.history["loss"]
epochs = range(1, len(loss) + 1)
plt.plot(epochs, loss, "bo", label = "Training loss" )
plt.title("Training loss")
plt.legend()
plt.savefig("loss.png ")
plt.close()

Les changements sont les suivants. -Ajout d'un processus pour sauvegarder les données d'entraînement à la fin de l'entraînement (on_train_end) ・ Changement de la longueur des caractères (maxlen) de 8 à 3

Le premier point était que j'ai vu une douleur que les données d'entraînement qui avaient été déplacées pendant une journée entière n'étaient pas enregistrées, j'ai donc ajouté un processus de sauvegarde. Le deuxième point était l'apprentissage avec 8 caractères, et quand j'ai prédit une phrase commençant par un mot de 3 caractères tel que "Demain" à partir des données d'apprentissage, cela ne fonctionnait pas bien. Depuis que j'ai fait des tweets, j'ai appris à commencer par des mots courts.

Le processus d'apprentissage ressemble à ceci.

Epoch 1/5
663305/663305 [==============================] - 401s 605us/step - loss: 3.5554

----- Generating text after Epoch: 0
----- diversity: 0.2
 ----- Génération avec semences: "Demain"
 demain! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !!
 J'ai hâte de travailler avec vous! !! !!

 "Nekopura // Nekopura
# Nekopura
# Nekopura // Nekopura // Nekopura // Nekopura // Nekopura
# Nekopura
# Nekopura // Je préfère Nekopura
Epoch 2/5
663305/663305 [==============================] - 459s 693us/step - loss: 3.2893

----- Generating text after Epoch: 1
----- diversity: 0.2
 ----- Génération avec semences: "Demain"
 Ici demain! !!

# C'est une performance live de Nekopura!

# Il y a une performance live de Nekopura! !!

# Merci pour Nekopura! !! !!

# Merci pour toutes les informations sur Nekopura! !!

# Je serais heureux s'il y avait un chat en plastique ...

# chat
Epoch 3/5
663305/663305 [==============================] - 492s 742us/step - loss: 3.2109

----- Generating text after Epoch: 2
----- diversity: 0.2
 ----- Génération avec semences: "Demain"
 Ici demain! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Epoch 4/5
663305/663305 [==============================] - 501s 755us/step - loss: 3.1692

----- Generating text after Epoch: 3
----- diversity: 0.2
 ----- Génération avec semences: "Demain"
 Ici demain! !!






# Nekopura
# Nekopura
# Je suis content que vous soyez venu chez les Nekopura! !!



# Nekopura
# Nekopura
# À propos de Nekopura Plus Plus Plus Plus Plus Plus Plus Plus Plus Plus Plus Plus Plus
Epoch 5/5
663305/663305 [==============================] - 490s 739us/step - loss: 3.1407

----- Generating text after Epoch: 4
----- diversity: 0.2
 ----- Génération avec semences: "Demain"
 Venez me voir demain! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !! !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Apprentissage supplémentaire

Formation continue à l'aide des données d'entraînement enregistrées Chargez simplement les données d'entraînement enregistrées après la création du modèle.

Le code est ici

print('Build model...')
model = Sequential()
model.add(LSTM(128, input_shape=(maxlen, len(chars))))
model.add(Dense(len(chars)))
model.add(Activation('softmax'))
 
optimizer = RMSprop(lr=0.01)
model.compile(loss='categorical_crossentropy', optimizer=optimizer)
model.load_weights("necopla_modelw.hdf5")

Créer un tweet en utilisant les données apprises

Quand j'ai fait ce processus, j'ai réfléchi à la signification de chaque code. (lent··.) Le processus de "on_epoch_end" est appelé à la fin de l'époque d'apprentissage, mais ici, au moment de la fin de l'époque, les phrases sont créées en utilisant les données d'apprentissage à ce moment-là. Par conséquent, lors de la création d'un tweet, vous pouvez essentiellement imiter ce processus.

Le code est ici

def evaluate_tweet():
 pour la diversité dans [0,2]: # diversité = 0,2 uniquement
        print('----- diversity:', diversity)
 
        generated = ''
 phrase = 'Demain'
        generated += sentence
        print('----- Generating with seed: "' + sentence + '"')

        sameCharCount = 0
        for i in range(120):
            x_pred = np.zeros((1, maxlen, len(chars)))

            for t, char in enumerate(sentence):
                x_pred[0, t, char_indices[char]] = 1.

            preds = model.predict(x_pred, verbose=0)[0]
            next_index = sample(preds, diversity)
            next_char = indices_char[next_index]

            if next_char == generated[-1]:
                sameCharCount += 1
                if sameCharCount >= 3: 
                    continue
            elif sameCharCount != 0:
                sameCharCount = 0
            generated += next_char
            sentence = sentence[1:] + next_char

    return generated

for i in range(10):
    tweet = evaluate_tweet()
 print ('----------------' + str (i + 1) + 'ième fois ----------------')
    print(tweet)

Lors de la création d'une phrase de tweet, si le même personnage continue pendant 3 caractères ou plus, les personnages ne seront pas connectés. Les tweets sont créés avec des phrases commençant par les mots "Demain est".

Le résultat de sortie ressemble à ceci.

 ---------------- Première fois ----------------
 Ici demain! !! !!
 ---------------- Deuxième fois ----------------
 Ici demain! !! !!
 ---------------- Troisième fois ----------------
 Je me demande si nous pouvons nous rencontrer demain! !! !!
 ---------------- 4ème ----------------
 Ici demain! !! !!
 ---------------- 5ème fois ----------------
 Ici demain! !! !!
 ---------------- 6ème fois ----------------
 Ici demain! !! !!
 ---------------- 7ème fois ----------------
 Ici demain! !! !!
 ---------------- 8ème fois ----------------
 Ici demain! !! !!
 ---------------- 9ème fois ----------------
 Ici demain! !! !!
 ---------------- 10ème fois ----------------
 Ici demain! !! !!

D'une manière ou d'une autre, j'ai pu créer quelque chose comme ça.

Impressions

J'ai déjà fait la même chose avec Chainer, mais c'est définitivement plus facile et plus facile à faire avec Keras. Le résultat de sortie sera une courte phrase car le nombre d'apprentissage est petit, je vais donc essayer de voir le résultat tout en effectuant un apprentissage supplémentaire.

Je pense que la méthode d'apprentissage sera différente s'il s'agit d'une méthode d'apprentissage par le partage, alors je vais essayer cela aussi.

Recommended Posts

Créez un tweet idole avec Keras LSTM (génération de phrases)
Génération de phrases avec GRU (keras)
LSTM multivarié avec Keras
Créer un environnement avec virtualenv
Créer une API avec Django
Implémenter Keras LSTM feed forward avec numpy
Débutant RNN (LSTM) | Essayer avec Keras
Créez une tranche d'âge avec les pandas
J'ai essayé la génération de phrases avec GPT-2
Créer une application en classifiant avec Pygame
Créez wordcloud à partir de votre tweet avec python3
Créer une visionneuse de traitement d'image avec PySimpleGUI
Créez rapidement un fichier Excel avec Python #python
Créer un écran de mise à jour avec Django Updateview
[Python] Créez rapidement une API avec Flask
Générer une instance Excel compatible avec les compléments avec xlwings
Créez une application de mots anglais avec python
Créez un fichier msi évolutif avec cx_Freeze
Créez une application qui devine les étudiants avec Python
Créer un programme académique avec optimisation des combinaisons
Créez une application de composition d'images avec Flask + Pillow
Créer une image avec des caractères avec python (japonais)
Créez rapidement un serveur API avec Python + Falcon