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.
** - 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.
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.
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.
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! !!
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é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
_________________________________________________________________
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])
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()
Recommended Posts