[PYTHON] J'ai essayé de faire une étrange citation pour Jojo avec LSTM

introduction

Il existe de nombreuses applications fascinantes de l'apprentissage en profondeur ces dernières années, dont la génération automatique de phrases. C'est passionnant de générer des phrases comme celle écrite par l'auteur à partir du style du livre, ou d'apprendre les paroles et de créer de nouvelles chansons. Donc, je voulais faire quelques phrases, mais comme il y a beaucoup de livres et de chansons, je me demandais s'il y avait quelque chose, "Laissez-moi apprendre la vision du monde de Jojo et Jojo World. Ne serait-il pas intéressant de pouvoir le construire? " Eh bien, je savais que la raison pour laquelle je n'ai pas fait grand chose en levant les yeux était parce qu'il n'y avait pas assez de données d'entraînement et que cela n'a pas fonctionné, mais je l'ai essayé dans un essai, donc je vais le partager.

Qu'est-ce que Jojo

** - Vous souvenez-vous du nombre de pains que vous avez déjà mangés? ** ** ** - Mais déclin **

Même ceux qui disent "Je ne connais pas Jojo" ont peut-être entendu les lignes ci-dessus une fois. Jojo est un manga pour garçon "Jojo's Bizarre Adventure" sérialisé par le professeur Hirohiko Araki depuis 1986, et est une histoire avec une vision du monde unique avec le thème de "l'hymne humain" (wiki. //ja.wikipedia.org/wiki/%E3%82%B8%E3%83%A7%E3%82%B8%E3%83%A7%E3%81%AE%E5%A5%87%E5% À partir de A6% 99% E3% 81% AA% E5% 86% 92% E9% 99% BA)). En raison de sa méthode d'expression unique, j'estime qu'il s'agit d'un dessin animé dans lequel les lignes et les effets sonores (Zukuuun, Memeta, etc.) sont les plus cités sur le net.

LSTM L'algorithme utilisé cette fois est LSTM (Long Short Term Memory). LSTM est une sorte de RNN (réseau neuronal récurrent) qui est un réseau neuronal qui peut gérer des informations de séries temporelles. En introduisant trois portes appelées porte d'entrée, porte de sortie et porte d'oubli, des données qui ne pouvaient pas être effectuées dans le passé Vous serez en mesure de mémoriser pendant une longue période et vous pourrez gérer des informations de séries chronologiques longues telles que des phrases. Par exemple, pour apprendre la phrase «Vous souvenez-vous du nombre de pains que vous avez mangés?», Extrayez le caractère N et apprenez le caractère suivant. Si N = 10, "Vous avez mangé jusqu'à présent" sera l'échantillon d'apprentissage, et le prochain "Pa" sera l'étiquette. Ensuite, par exemple, décalez cette phrase de 3 caractères pour créer de nouvelles données, et apprenez comme "est le pain que j'ai mangé" → "feuille". Comme vous pouvez le voir dans cet exemple, une énorme quantité de phrases est nécessaire en tant que données d'entraînement pour la génération de phrases. Si j'utilisais cette méthode avec le montant d'une collection de citations, la phrase serait cassée en japonais, donc je l'ai appris mot par mot plutôt que par lettre. En d'autres termes, "vous avez mangé jusqu'à présent" → "pain". Pour plus d'informations sur LSTM, veuillez consulter cet article. LSTM est fourni dans des frameworks tels que Keras, vous pouvez donc le créer facilement sans l'implémenter vous-même.

la mise en oeuvre

Mettons-le en œuvre. Ce code est principalement basé sur lstm_text_generation.py publié par l'équipe Keras. L'environnement d'exécution est Google Colanoratory.

Import de bibliothèque

Tout d'abord, importez les bibliothèques requises.

Import de bibliothèque


import os
import re
import bs4
import requests
from __future__ import print_function
from keras.callbacks import LambdaCallback
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.optimizers import Adam
from keras.utils.data_utils import get_file
import numpy as np
import random
import sys
import io
import matplotlib.pyplot as plt
!apt install aptitude
!aptitude install mecab libmecab-dev mecab-ipadic-utf8 git make curl xz-utils file -y
!pip install mecab-python3==0.7
import MeCab

Cette fois, nous obtiendrons les données du site Web et analyserons la morphologie, nous avons donc installé les éléments nécessaires en plus de la bibliothèque d'apprentissage automatique habituelle. Les quatre dernières lignes sont l'outil d'analyse morphologique d'OSS appelé Mecab, qui décompose les phrases en mots.

Obtenez des citations de Jojo

Ensuite, obtenez le devis en grattant. Cette fois, je l'ai obtenu sur ce site Web.

Obtenez des devis


'''Obtenez des citations de Jojo'''
with open('jojo.txt', 'a') as f:
  url = 'http://kajipon.sakura.ne.jp/art/jojo9.htm'
  res = requests.get(url)
  res.raise_for_status()

  '''Analysez le HTML acquis et n'acquérez que la ligne de dialogue'''
  soup = bs4.BeautifulSoup(res.content, 'html.parser')
  soup = soup.find_all( text=re.compile("「.+?」+(.+?)+Non.") )
  
  for s in soup:
    txt = s.__str__()
    '''Retirer les pièces supplémentaires'''
    txt = re.sub('Non..+?rouleau', '', txt)
    txt = re.sub('(.+?)', '', txt)
    txt = re.sub('※.+', '', txt)
    txt = txt.replace('「', '')
    txt = txt.replace('」', '')
    print(txt)
    f.write(txt)

Le résultat de l'exécution ressemble à ceci (seulement les 20 premières lignes).

Nah! Qu'est-ce que tu fais! Yuru-san!

Comme prévu, Dio! Faites ce que nous ne pouvons pas faire! C'est engourdi là-bas! J'aspire à ça!

Dioooooooo! Vous êtes! Jusqu'à ce que tu pleures! Je n'arrêterai pas de te frapper!

Dio! Si votre stupide baiser visait cela, il aurait été plus efficace que prévu!

Le motif du combat est différent de vous les gars!

Ne vous en débarrassez pas! Rich Ama-chan!

Je vais quitter les humains! Jojo! !!

Non! L'esprit de ce père est ... son fils Jonathan Joe Star en a hérité! Ce sera sa forte volonté, sa fierté et son avenir! !!

Bon sang! Je vais entrer dans cette salle et célébrer de toutes mes forces! !!

Le speed wagon part cool

Oh cher! Quoi! Moi avec un bras cassé! Je te soutiens toujours

Est-ce le destin ... Il se peut que la rencontre des gens soit déterminée par le destin ...

Uhohohohohoho!

Retirez les articulations et étendez vos bras! La douleur intense est adoucie par l'énergie ondulatoire!

Papau! Pow Pow! Coupeur d'ondulations! !!

Vous souvenez-vous du nombre de pains que vous avez déjà mangés?

"Ondulations"? Qu'est-ce que la "méthode de respiration"? Si vous soufflez hoo hoo ... Cela me convient de souffler même en fanfare pour moi!

Surprenant! Ce sont les cheveux!

Pensez à l'inverse. Je pense que c'est normal de le donner

Secoue le cœur! Chaleur au point de brûler! !! Oh oh, je vais couper le rythme du sang! Sprint ondulé en montagne! !!

Création de données de formation

Lisez le jojo.txt créé ci-dessus et créez des données d'entraînement. De plus, contrairement aux phrases et aux paroles, les citations sont indépendantes en principe, il n'y a donc pas de série chronologique. Par conséquent, créez des données d'entraînement ligne par ligne afin que la fin du devis précédent → la racine du devis suivant ne soit pas connectée. Voyons d'abord combien il y a de citations.

Lire ligne par ligne


'''Lecture de fichiers'''
path = './jojo.txt'

'''Obtenir des lignes ligne par ligne'''
nline = 0
with io.open(path, encoding='utf-8') as f:
  lines = f.readlines()
  for line in lines:
    nline += 1
print('Nombre de lignes:', nline)  

résultat


Nombre de lignes: 283

Il y avait 283 citations en tout. Ensuite, nous décomposons toutes les citations en parties et remplissons les éléments dans le conteneur de tous les mots qui apparaissent (corpus), le conteneur de toutes les phrases qui seront les données d'apprentissage (phrases) et le conteneur de l'étiquette des phrases (next_chars). .. La longueur des données d'apprentissage est de 3 mots et l'intervalle de décalage est de 1 mot pour créer les données suivantes. "Vous êtes maintenant" → "jusqu'à" "Jusqu'à présent" → "Manger" ・ ・ ・

python


'''Définissez la taille de la phrase et l'intervalle pour apprendre'''
corpus = []
sentences = []
next_chars = []
maxlen = 3
step = 1

mecab= MeCab.Tagger('-Ochasen')
mecab.parse('')
for line in lines:
  '''Obtenez des paroles de partie pour chaque ligne'''
  corpusl = []
  nodel = mecab.parseToNode(line)
  while nodel:
    corpusl.append(nodel.surface)
    corpus.append(nodel.surface)
    nodel = nodel.next

  '''Générer des phrases d'apprentissage et des étiquettes pour les enseignants'''
  for i in range(0, len(corpusl) - maxlen, step):
    sentences.append(corpusl[i: i + maxlen])
    next_chars.append(corpusl[i + maxlen])
print('Nombre de phrases', len(sentences))
print('Nombre de mots: ', len(corpus))  
'''Générer un corpus avec les mots en double supprimés'''
chars = set(corpus)
print('Taille du corpus: ', len(chars))

résultat


Nombre de phrases 8136
Nombre de mots:  8984
Taille du corpus:  1883

Pour savoir comment utiliser Mecab, j'ai renvoyé à cet article. corpusl est un corpus temporaire qui stocke les mots dans cette ligne. Le nombre total de mots sortis cette fois est de 1883, et les phrases générées sont faites à partir de ces mots. Comme l'ordinateur ne peut pas gérer les mots tels quels, créez des dictionnaires correspondant respectivement aux mots → index et index → mot. Enfin, créez les données d'apprentissage x et l'étiquette d'enseignant y en tant que vecteur one-hot.

python


'''Créer des dictionnaires correspondant à des mots → des nombres et des nombres → des mots'''
char_indices = dict((c, i) for i, c in enumerate(chars))
indices_char = dict((i, c) for i, c in enumerate(chars)) 

'''Vectorisation'''
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

Création de modèle LSTM

Créez un modèle LSTM. Le nombre d'unités de couches cachées est de 128, la fonction de coût est l'entropie croisée catégorielle et la méthode d'optimisation est Adam.

LSTM


'''Création de modèle LSTM'''
model = Sequential()
model.add(LSTM(128, input_shape = (maxlen, len(chars))))
model.add(Dense(len(chars), activation='softmax'))

optimizer = Adam()
model.compile(loss='categorical_crossentropy', optimizer=optimizer)
model.summary()

résultat


Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
lstm_1 (LSTM)                (None, 128)               1030144   
_________________________________________________________________
dense_1 (Dense)              (None, 1883)              242907    
=================================================================
Total params: 1,273,051
Trainable params: 1,273,051
Non-trainable params: 0
_________________________________________________________________

Apprentissage

Maintenant que nous sommes prêts, nous allons étudier.

Apprentissage


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)

'''Une fonction qui affiche les lignes générées pour chaque époque'''
def on_epoch_end(epoch, _):
  print()
  print('----- %d epoch:' % epoch)

  start_index = random.randint(0, len(corpus) - maxlen -1)
  for diversity in [8.0, 16.0, 32.0, 64.0, 128.0, 256, 512, 1024]:
    print('----- diversity:', diversity)

    generated = ''
    sentence = corpus[start_index: start_index + maxlen]
    generated += ''.join(sentence)
    print('-----la graine"' + ''.join(sentence) + '"Généré par:')
    sys.stdout.write(generated)

    for i in range(10):
      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]

      sentences.append(next_char)

      sys.stdout.write(next_char)
      sys.stdout.flush()
    print()

sample est une fonction qui échantillonne la distribution de probabilité et il semble que plus la température est élevée, plus la prédiction des mots est faible. (https://www.freecodecamp.org/news/applied-introduction-to-lstms-for-text-generation-380158b29fb3/) À l'origine, des valeurs faibles telles que 0,2 à 1,2 sont utilisées, mais dans ces données, seuls les mêmes mots sont sortis probablement parce que le nombre est trop petit (probablement les mots «sûrs» qui se produisent fréquemment sont sortis intensément. ), J'essaie donc d'utiliser différents mots avec une grande valeur. Sélectionnez au hasard 3 mots pour chaque époque, prédisez les 10 mots suivants et affichez la phrase.

Passez la fonction ci-dessus pour s'adapter.

python


print_callback = LambdaCallback(on_epoch_end = on_epoch_end)
history = model.fit(x, y, batch_size=128, epochs=60, callbacks=[print_callback])

Résultat d'apprentissage

Le résultat de l'exécution est le suivant. (Extrait)

Résultat d'exécution après 5 époques


~~~
Epoch 5/60
8136/8136 [==============================] - 1s 98us/step - loss: 5.5118

-----Dialogue généré après 4 époques:
----- diversity: 8.0
-----la graine"Gah!"Généré par:
Gah! C'est rafraîchissant, tout le monde s'épuise
----- diversity: 16.0
-----la graine"Gah!"Généré par:
Gah! J'ai l'impression que je vais t'appeler
----- diversity: 32.0
-----la graine"Gah!"Généré par:
Gah! Il est possible de chercher un singe, mais il brille
----- diversity: 64.0
-----la graine"Gah!"Généré par:
Gah! Juste avant que tu ne le saches, un groupe de prog ennuyeux me pardonne
----- diversity: 128.0
-----la graine"Gah!"Généré par:
Gah! Difficile de venir, je suis désolé de l'enterrer. Eh
----- diversity: 256
-----la graine"Gah!"Généré par:
Gah! Suma Miro Fuji Sankai Venezia Jornot World Disaster
----- diversity: 512
-----la graine"Gah!"Généré par:
Gah! Respectez le premier courage misérable que W Isagi appelle souvent comme ça
----- diversity: 1024
-----la graine"Gah!"Généré par:
Gah! Combattre le slapstick de requin F, le pari d'amour correct, peut-être
~~~

C'est un mot de type Jojo, mais c'est incohérent et quelque chose comme ça ...

Résultat d'exécution après 33 époques


~~~
Epoch 33/60
8136/8136 [==============================] - 1s 98us/step - loss: 2.3640

-----Dialogue généré après 32 époques:
----- diversity: 8.0
-----la graine"Grand-père Joseph"Généré par:
L'histoire de Joseph de mon grand-père, je ne suis pas amoureux pour la première fois d'une star
----- diversity: 16.0
-----la graine"Grand-père Joseph"Généré par:
Le cerveau de mon grand-père Joseph a une vie de dieu mignon dans le pays.
----- diversity: 32.0
-----la graine"Grand-père Joseph"Généré par:
Grand-père Joseph, guerrier aaaaaaa--.. de!
----- diversity: 64.0
-----la graine"Grand-père Joseph"Généré par:
Vous avez été abattu par votre grand-père Joseph. Rakai Handsome Ooohehehehe
----- diversity: 128.0
-----la graine"Grand-père Joseph"Généré par:
Mon grand-père Joseph se souvient de la vie formée par Kuranenza
----- diversity: 256
-----la graine"Grand-père Joseph"Généré par:
Grand-père Joseph Pig Joseph étant protégé ici Jojooooooo Desert Suka
----- diversity: 512
-----la graine"Grand-père Joseph"Généré par:
Grand-père Joseph Faites-le avec un vrai visage Sui Eee Eee Eee Un secret de pharmacie qui vous gêne
----- diversity: 1024
-----la graine"Grand-père Joseph"Généré par:
Mon grand-père Joseph Teme gagne et secoue le désert
~~~

Je n'ai pas l'impression d'être devenu un peu japonais. Même ainsi, il y a des mots terrifiants tels que "Grand-père Joseph Brains Country".

Résultat d'exécution 60epoch


~~~
Epoch 60/60
8136/8136 [==============================] - 1s 104us/step - loss: 0.7271

-----Dialogue généré après 59 époque:
----- diversity: 8.0
-----la graine"Problème jusque juste avant"Généré par:
Jusqu'à juste avant le problème o Quantité effrayante que Cherry a reçue Tir sur une blessure non pertinente
----- diversity: 16.0
-----la graine"Problème jusque juste avant"Généré par:
Jusqu'à juste avant le problème Jojo, renforcez toujours la relation de beauté mystérieuse du roi centimètre Asahi
----- diversity: 32.0
-----la graine"Problème jusque juste avant"Généré par:
Jusqu'à juste avant le problème Les tripes des passagers sont convaincues Grandes roues Vieille fille utile pour se tenir à vos côtés
----- diversity: 64.0
-----la graine"Problème jusque juste avant"Généré par:
Cela semble être un problème jusqu'à juste avant, et c'est ignorant et cruel
----- diversity: 128.0
-----la graine"Problème jusque juste avant"Généré par:
Jusqu'à juste avant le problème, je m'en fiche jusqu'à ce que j'enlève mes sentiments
----- diversity: 256
-----la graine"Problème jusque juste avant"Généré par:
Jusqu'à juste avant le problème Mother Cola 216 Quelle est la personne Gedged Honneur de pedigree de Papou aligné
----- diversity: 512
-----la graine"Problème jusque juste avant"Généré par:
Prenez une décision de problème d'aiguille juste avant Star Valkyrie Recherchez-la
----- diversity: 1024
-----la graine"Problème jusque juste avant"Généré par:
Jusqu'à ce que juste avant le problème, l'enfant du bonheur comprend le vieil homme et reçoit un ordre

C'est une chaîne de caractères qui semble sortir dans votre cerveau lorsque vous avez du mal à vous endormir à cause d'un rhume. J'ai couru 60epoch, mais je ne pouvais pas tout à fait faire une phrase qui n'était pas étrange en japonais. Je pense que c'est approprié compte tenu du nombre de mots et du nombre de données. Mais y a-t-il quelque chose comme "Papau Pedigree" ou "Star Valkyrie"? C'était très intéressant pour les fans de Jojo de voir des mots qui m'ont fait réfléchir. Je pense qu'il y a beaucoup de points à améliorer, mais je pense que ce sera difficile à améliorer, alors je vais m'arrêter ici cette fois. C'était raisonnable pour un procès. Après tout, la génération de phrases est intéressante. J'ai mis le code dans GitHub, donc si vous êtes intéressé, veuillez jouer avec. Enfin, tracez la fonction de coût.

Graphique de la fonction de coût


'''visualisation des pertes'''
plt.figure(figsize=(10,7))
loss = history.history['loss']
plt.plot(loss, color='b', linewidth=3)
plt.tick_params(labelsize=18)
plt.ylabel('loss', fontsize=20)
plt.xlabel('epoch', fontsize=20)
plt.legend(['training'], loc='best', fontsize=20)
plt.show()

image.png

Recommended Posts

J'ai essayé de faire une étrange citation pour Jojo avec LSTM
J'ai créé une API Web
[5e] J'ai essayé de créer un certain outil de type Authenticator avec python
[2nd] J'ai essayé de créer un certain outil de type Authenticator avec python
[3ème] J'ai essayé de créer un certain outil de type Authenticator avec python
J'ai essayé de faire un processus d'exécution périodique avec Selenium et Python
J'ai essayé de créer une application todo en utilisant une bouteille avec python
[4th] J'ai essayé de créer un certain outil de type Authenticator avec python
[1er] J'ai essayé de créer un certain outil de type Authenticator avec python
J'ai essayé de créer un mécanisme de contrôle exclusif avec Go
J'ai essayé de faire de l'IA pour Smash Bra
J'ai créé un jeu ○ ✕ avec TensorFlow
J'ai essayé de faire un diagnostic de visage AI pour les golfeuses professionnelles ①
J'ai essayé de faire un diagnostic de visage AI pour les golfeuses professionnelles ②
J'ai essayé de créer un LINE BOT "Sakurai-san" avec API Gateway + Lambda
J'ai essayé de faire un signal avec Raspeye 4 (édition Python)
J'ai essayé de créer un service de raccourcissement d'url sans serveur avec AWS CDK
J'ai essayé de faire un "putain de gros convertisseur de littérature"
J'ai essayé de faire un processus périodique avec CentOS7, Selenium, Python et Chrome
J'ai fait une application d'envoi de courrier simple avec tkinter de Python
Quand j'ai essayé de créer un VPC avec AWS CDK mais que je n'ai pas pu le faire
[Analyse des brevets] J'ai essayé de créer une carte des brevets avec Python sans dépenser d'argent
J'ai créé une API de recherche de château avec Elasticsearch + Sudachi + Go + echo
J'ai essayé de créer un bouton pour Slack avec Raspeye + Tact Switch
J'ai essayé de créer une application OCR avec PySimpleGUI
J'ai essayé de créer une API de reconnaissance d'image simple avec Fast API et Tensorflow
J'ai essayé de faire une simulation de séparation de source sonore en temps réel avec l'apprentissage automatique Python
J'ai essayé de créer un environnement d'apprentissage amélioré pour Othello avec Open AI gym
J'ai essayé de faire de l'art créatif avec l'IA! J'ai programmé une nouveauté! (Article: Réseau Adversaire Créatif)
J'ai essayé d'implémenter une ligne moyenne mobile de volume avec Quantx
J'ai essayé de créer automatiquement un rapport avec la chaîne de Markov
Je veux créer un éditeur de blog avec l'administrateur de django
Expérimentez pour créer un PDF indépendant pour Kindle avec Python
Je veux faire une macro de clic avec pyautogui (désir)
[Chaîne de Markov] J'ai essayé de lire les citations en Python.
J'ai essayé de résoudre le problème d'optimisation des combinaisons avec Qiskit
J'ai essayé de commencer avec Hy ・ Définir une classe
J'ai essayé de trier une colonne FizzBuzz aléatoire avec un tri à bulles.
J'ai essayé de créer un bot pour annoncer un événement Wiire
J'ai fait un chronomètre en utilisant tkinter avec python
J'ai essayé de créer une interface graphique à trois yeux côte à côte avec Python et Tkinter
J'ai essayé d'écrire dans un modèle de langage profondément appris
J'ai créé un éditeur de texte simple en utilisant PyQt
[1 hour challenge] J'ai essayé de créer un site de bonne aventure qui soit trop adapté à Python
J'ai essayé de créer un générateur qui génère une classe conteneur C # à partir de CSV avec Python
J'ai essayé de créer une caméra de surveillance à détection de mouvement avec OpenCV en utilisant une caméra WEB avec Raspberry Pi
J'ai essayé de créer un système qui ne récupère que les tweets supprimés
Rubyist a essayé de créer une API simple avec Python + bouteille + MySQL
Un mémorandum lors de l'acquisition automatique avec du sélénium
J'ai essayé de créer une expression régulière de "montant" en utilisant Python
[Python] J'ai essayé d'implémenter un tri stable, alors notez
J'ai essayé de créer une expression régulière de "temps" en utilisant Python
[Python] Un mémo que j'ai essayé de démarrer avec asyncio
J'ai essayé de créer une liste de nombres premiers avec python
J'ai essayé de créer une expression régulière de "date" en utilisant Python
[Pandas] J'ai essayé d'analyser les données de ventes avec Python [Pour les débutants]
[Introduction] Je veux créer un robot Mastodon avec Python! 【Débutants】