[PYTHON] J'ai essayé de créer un générateur de dialogue de personnage automatique par chaîne Markov N étage

introduction

J'étudie généralement les textes financiers dans le cadre du traitement du langage naturel. Étant donné que le contenu traité dans la recherche est le contenu d'une recherche conjointe et ne peut pas être publié à l'extérieur, et que le contenu qui peut être publié est résumé en présentant lors d'une conférence ou en soumettant un article, il n'était pas nécessaire de le réécrire comme un article, donc un nouvel article J'ai décidé de commencer à faire ce que je pouvais. Dans cet article, l'animation "[Kemono Friends](https://ja.wikipedia.org/wiki/%E3%81%91%E3%82%82%E3%81%AE%E3%83%95%E3" % 83% AC% E3% 83% B3% E3% 82% BA_ (% E3% 82% A2% E3% 83% 8B% E3% 83% A1))) Comment générer automatiquement des lignes serval dans la chaîne de Markov J'aimerais présenter. image.png (Illustrateur stable car je ne connais pas les droits d'auteur)

Quant au flux de l'article

  1. Acquisition de données
  2. À propos de la chaîne Markov au Nième étage
  3. Mise en œuvre
  4. Examen
  5. Résumé Il devient.

Acquisition de données textuelles de Kemono Friends

Pour les données de dialogue, j'utiliserai celui sur GitHub de akahuku. J'ai fait. Je suis vraiment reconnaissant pour ce type de données. Etant donné que ces données textuelles reçoivent une étiquette indiquant quel caractère parle, il était possible d'extraire uniquement les lignes servales. A l'origine, je recherchais ces données lorsque je cherchais des données utilisables pour la classification car je voulais étudier la mise en œuvre de la classification des phrases par pytorch au lieu de générer automatiquement des lignes (l'article sur la classification des lignes en est un autre). Je l'écrirai à l'occasion). D'ailleurs, la raison de l'utilisation de la génération automatique de lignes serval est simplement parce que les lignes étaient les plus nombreuses (812 lignes longues et lignes courtes combinées). En fait, je voulais le faire avec Tsuchinoko et Dr., mais malheureusement le nombre de données était extrêmement insuffisant. En fait, je pense que je devrais écrire un traitement de données fin, mais je vais l'omettre car l'article sera inutilement long, mais je n'ai effectué aucun traitement spécial autre que l'alignement de tous les caractères en pleine largeur. Les données suivantes ont été extraites des données collectées.

Vous trouverez ça chez le médecin.
Dr Il est nécessaire lors de l'exécution sur terre. Utilise ta tête.
Des bus similaires ont été observés sur plusieurs îles. Cherchez-le d'abord.
Docteur, je ne peux pas m'en empêcher. Il y a quelque chose comme un bus dans le parc d'attractions.
Dr C'est bon pour vous les gars, c'est bien.
:
Serval Après tout, j'ai pensé que je devrais le suivre un peu plus.
Serval Soyons amis!
Serval Wow! patron! ??
Serval a parlé! ??

À propos de la chaîne Markov Nth Floor

Concernant la chaîne de Markov et l'implémentation, l'article de @ k-jimon [Python] Sentence generation with Nth floor Markov chain a été très utile. C'était. Pour être honnête, je ne ressens pas le besoin d'écrire à partir de zéro dans cet article. Une explication intuitive et facile à comprendre sur la génération de phrases par chaîne de Markov est ["Génération de phrases par chaîne de Markov"](https://omedstu.jimdofree.com/2018/05/06/%E3%83%9E%E3%83 % AB% E3% 82% B3% E3% 83% 95% E9% 80% A3% E9% 8E% 96% E3% 81% AB% E3% 82% 88% E3% 82% 8B% E6% 96% 87 Il est écrit en% E6% 9B% B8% E7% 94% 9F% E6% 88% 90 /). Pour le moment, je vais l'introduire brièvement dans cet article afin que l'article lié puisse disparaître.

Chaîne de Markov

Pour le moment [Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%AB%E3%82%B3%E3%83%95%E9%80%A3%E9% À partir de 8E% 96).

La chaîne de Markov (chaîne de Markov) est un type de processus stochastique dans lequel les états possibles sont discrets (finis ou dénombrables) (processus de Markov à états discrets). En particulier, il se réfère souvent à des temps discrets (le temps est représenté par des indices) (il existe également un processus de Markov en temps continu, qui est continu dans le temps). Dans la chaîne de Markov, le comportement futur n'est déterminé que par la valeur actuelle et n'a pas de rapport avec le comportement passé (propriété de Markov). Concernant le changement d'état (transition ou transition) qui se produit à chaque instant, la chaîne de Markov est une série dans laquelle la probabilité de transition ne dépend pas de l'état passé mais uniquement de l'état actuel. Il est appliqué à divers domaines comme un processus stochastique particulièrement important.

Pour faire simple, il est écrit que la probabilité de devenir l'état suivant est déterminée en tenant compte de l'état actuel, et les résultats passés n'affectent pas la probabilité. En termes de temps, s'il fait beau aujourd'hui, il est probable qu'il fera beau demain, et s'il pleut aujourd'hui, il fera nuageux ou pluvieux demain. Selon l'hypothèse de nature de Markov, si le temps d'aujourd'hui est ensoleillé, c'est la chaîne de Markov qui n'a aucun effet, que le temps d'hier soit ensoleillé ou pluvieux.

Dans la génération de phrases, considérez les trois phrases suivantes comme un exemple. "Serval aime chasser" "Je suis doué pour penser aux sacs" "Dr. n'est pas bon en cuisine" Puisque nous ne traiterons pas cela en détail cette fois, nous omettons une explication détaillée, mais comme la phrase peut être divisée en unités de mots, la figure suivante peut être créée. image.png Il s'agit d'un diagramme montrant la transition d'état, et vous pouvez créer une phrase en effectuant une transition de gauche à droite. Par exemple, en effectuant la transition comme suit "** Le sac ** n'est ** pas bon à la chasse **" Vous pouvez créer des phrases telles que. image.png De cette manière, en accumulant l'apparence des mots qui apparaissent dans les données d'apprentissage, il devient possible de générer diverses phrases.

Chaîne de Markov au Nième étage

La chaîne de Markov d'ordre N prédit l'état suivant en ajoutant les N états de l'état avant N-1 à l'état actuel. Lorsque N = 1, cela devient identique à une chaîne de Markov normale. Dans l'exemple précédent de la météo, si possible, vous pouvez comprendre intuitivement que la prévision de demain sera meilleure si la météo de la veille est également prise en compte. S'il continue à être ensoleillé et ensoleillé, il y a de fortes chances qu'il fasse beau demain, et s'il fait pluvieux et ensoleillé, la probabilité qu'il fasse beau demain sera inférieure à celle de ensoleillé et ensoleillé. La génération de phrases ressemblera davantage au texte généré si vous prenez en compte ce qui est apparu il y a quelque temps. Par exemple, en plus de la phrase précédente, "Le curry est délicieux le deuxième jour" S'il y a une phrase comme celle-ci et N = 1, "Le curry est bon à la chasse" Sera généré. Cependant, plus N est grand, plus il est difficile de générer de nouvelles phrases. J'aimerais avoir beaucoup plus de données ...

la mise en oeuvre

C'est la mise en œuvre tant attendue. Cependant, dans cette chaîne de Markov d'ordre N, le modèle n'est pas créé en unités de mots mais en unités de caractères. Comme ces données sont des données de dialogue, c'est une langue parlée, il existe de nombreux hiragana et katakana en raison des caractéristiques de l'œuvre, et il existe de nombreuses expressions uniques (Japari Park etc.), il est donc difficile d'analyser la morphologie avec MeCab etc. Étant donné que le nombre de données est petit, nous avons généré des phrases en unités de caractères. Par exemple "Dr. n'est pas bon en cuisine" Est "Haku", "Shi", "Ha", "Fee", "Ri", "Ga", "Bitter", "Hand" Créez un modèle de transition d'état séparément comme suit. En contrepartie, nous verrons également comment cela change en fonction de la taille de N. (~~ Ce n'est pas qu'il était difficile d'introduire ou d'écrire MeCab ~~)

environnement

・ Python3.7

Connaissances préalables

Pour la création de modèles ["Maintenant", "Jour"] → ["est", "aussi", ",", "est", "est", "est", "est", ",", "est"] Il est nécessaire de créer une structure de données comme celle-ci. Ceci est un exemple lorsque N = 2, et lorsque les caractères "maintenant" et "jour" apparaissent, il est nécessaire d'accumuler quel caractère viendra ensuite (lors de la génération de phrases). , Parce que les «caractères» sont choisis au hasard parmi ceux-ci, les plus dupliqués sont plus susceptibles d'être sélectionnés). Il existe également un moyen de créer une structure de données pour réduire le nombre de données, mais cette fois, nous allons simplement créer une structure de données comme celle-ci.

Puisque ces données ont une liste (["est", ...]) correspondant à la clé (["maintenant", "jour"] ci-dessus)), utilisez le dict et la liste de python. Je vais. Utilisez également deque pour créer la clé. Il peut être utilisé dans le module collections, qui est une bibliothèque standard de python, et il est également écrit en [Python] Sentence generation with Nth-order Markov chain, mais cette implémentation C'est très pratique. Pour expliquer brièvement ce qui est différent de la liste, si vous spécifiez d'abord la longueur, lorsque vous l'ajoutez avec append, si la longueur spécifiée est dépassée, la valeur du début peut être repoussée. Je peux le faire. En d'autres termes, si ["now", "day"] est inclus dans deque et "ha" est ajouté à la fin avec append, ["day", "" devient "](vraiment pratique). Vous pouvez l'implémenter comme ça.

python


from collections import deque
n_size = 2
queue = deque([], n_size)

Cependant, comme deque ne peut pas être utilisé tel quel pour la clé, il est converti en type tuple.

python


key = tuple(queue)

Cela devrait être tout ce dont vous avez besoin pour les connaissances préalables.

Lire les données

Les données extraites sont Ligne de nom Puisqu'il est sauvegardé dans "kemono_friends.txt" avec un délimiteur vide, il est lu ligne par ligne, les sauts de ligne sont supprimés et il est divisé par un blanc. Et celui avec le nom "Serval" est ajouté à text_list.

data_load.py


text_list = []
with open("./data/kemono_friends.txt") as data:
    for line in data:
        char, text = line.rstrip('\n').split(" ")
        if char == "Serval":
            text_list.append(text)

La modélisation

Créez un modèle. «BOS» est une balise qui indique le début d'une phrase et est une abréviation pour Début de phrase, et «EOS» est une balise qui indique la fin d'une phrase et est une abréviation pour Fin de phrase. n_size est N de la chaîne de Markov d'ordre N.

mk_model.py


from collections import deque
import pickle
n_size = 4
def mk_model(text_list):
    model = {}
    for text in text_list:
        queue = deque([], n_size)
        queue.append("[BOS]")
        for i in range(0, len(text)):
            key = tuple(queue)
            if key not in model:
                model[key] = []
            model[key].append(text[i])
            queue.append(text[i])
        key = tuple(queue)
        if key not in model:
            model[key] = []
        model[key].append("[EOS]")
    return model

"""
Données ici_load.Copier py
"""

Génération automatique de dialogues

Le programme qui génère automatiquement des phrases à l'aide du modèle créé ajoute le code suivant au programme précédent.

mk_serihu.py


import random
def mk_serihu():
    value_list = []
    queue = deque([], n_size)
    queue.append("[BOS]")
    key = tuple(queue)
    while(True):
        key = tuple(queue)
        value = random.choice(model[key])
        if value == "[EOS]":
            break
        value_list.append(value)
        queue.append(value)
    return value_list
#Pour le moment, 10 lignes sont automatiquement générées
for i in range(0, 10):
    serihu = ''.join(mk_serihu())
    print(serihu)

En tant que programme, "BOS" devient la clé en premier, et les caractères sont générés aléatoirement à partir du modèle. Après cela, la clé change progressivement, les caractères sont générés les uns après les autres, et lorsque "EOS" apparaît, la génération se termine. La sortie ressemble à ceci.

Mais continuez-vous autant?
C'est ma première fois. Tu l'as fait.
Ah. Il fait froid.
Bye Bye.
Ouaip. Hé, ours brun. J'y vais.
Eh bien, dites-vous idole et commencez à danser et à chanter?
Attendre attendre.
En aucune façon.
Je vous ai donné le nom plus tôt. Pour quoi.
Je me demande quoi.

Ça fait du bien! À propos, il est difficile de générer un modèle à chaque fois que le nombre de données est important, il est donc pratique de l'enregistrer sous forme de fichier binaire avec pickle et de l'appeler immédiatement. Le programme qui l'enregistre en tant que model.binaryfile et l'appelle est le suivant. (Si vous souhaitez ignorer le traitement des données et exécuter la génération automatique pour le moment, si vous obtenez des DM de Twitter, etc., passez model.binaryfile)

mk_serihu.py


from collections import deque
import random
import pickle
n_size = 4
f = open("data/model.binaryfile",'rb')
model = pickle.load(f)

def mk_serihu():
    value_list = []
    queue = deque([], n_size)
    queue.append("[BOS]")
    key = tuple(queue)
    while(True):
        key = tuple(queue)
        value = random.choice(model[key])
        if value == "[EOS]":
            break
        value_list.append(value)
        queue.append(value)
    return value_list
#Pour le moment, 10 lignes sont automatiquement générées
for i in range(0, 10):
    serihu = ''.join(mk_serihu())
    print(serihu)

Considération

Lorsque j'ai changé la valeur de N de différentes manières, j'ai pu créer une ligne comme celle-là avec N = 4. Si N est augmenté, les données seront les mêmes que les données d'entraînement, et si N est petit, la phrase ne sera pas valide et ce sera difficile (transpiration). Choisissez un bon gars qui ne figure pas dans les données d'entraînement lorsque N = 4.

Eh bien, pourquoi ne pas l'essayer?
Dis-moi ce qu'est le patron!
Y a-t-il quelque chose là-dedans?
Ouais. Kaban-chan est adroit.
Vous plaisantez, Kaban-chan.
Regarde, allons-y!
Kaban-chan était comme ça, non?
Qu'est-ce que c'est? Je me demande comment l'avoir.
Vous nous oubliez aussi.

Vous pouvez générer des lignes qui ne sont pas dans les données d'entraînement d'environ 63%! Vient ensuite celui qui n'est pas dans les données d'apprentissage lorsque N = 3.

Qu'est-ce qui ne va pas? Et Kaban-chan?
d'accord. Que devrais-je faire?
C'était des amis ...
C'est foiré. J'ai hâte d'y être.
Ah! Pas bien! Pouvez-vous le prendre?
Je pense que tout le monde est inquiet.
Eh bien, cette voix a été mangée par quelqu'un.

80% des lignes ne sont pas dans les données d'entraînement, mais elles sont toujours instables. Vient ensuite celui qui n'est pas dans les données d'entraînement lorsque N = 2.

D'accord, est-il normal de courir sans se laisser tromper?
quelque part. C'est un sac ... Je me demande si quelqu'un est blanc. Hé, lave?
Ou devrais-je simplement l'appeler?
Je vais bien. Est-ce sous la forme d'amis?

96% des lignes ne sont pas dans les données d'entraînement ... Le dernier est N = 5

Je me suis endormi en chemin hier.
Il y a beaucoup de sable.
Yeah Yeah. Que voulez-vous dire? ici?

35% des lignes ne sont pas dans les données d'entraînement. Il y a un sentiment de stabilité, mais je veux que vous fassiez plus de lignes qui n'existent pas à l'origine, donc N = 4 est juste. Puisque les lignes comme "Kaban-chan" sont longues, si une chaîne de caractères d'un mot aussi long vient, il sera plus facile de faire des lignes sans signification, donc après tout, la chaîne de Markov seule est difficile (sueur)

Résumé

Pour le moment, c'est un modèle qui peut être facilement créé, mais il est difficile de générer des phrases. Il y a encore beaucoup de choses qui peuvent être faites facilement, comme enregistrer des chaînes de caractères de caractères et de lieux avec une extraction d'expressions uniques, et les remplacer par des mots similaires par word2vec. De plus, il existe de nombreuses générations de phrases récentes qui utilisent l'apprentissage en profondeur, alors j'aimerais l'essayer. Personnellement, j'aimerais créer un modèle capable de générer une grande quantité de données d'entraînement à l'aide d'un générateur de dialogue automatique, et lorsqu'un dialogue approprié est entré, il peut être converti en un dialogue et une sortie de type caractère spécifié. Après tout, je voudrais construire un modèle qui permette un dialogue plus court qu'un dialogue unilatéral. Kemono Friends avait de bonnes données, mais en réalité elles seront utilisées dans @RemChabot En utilisant les données textuelles du roman acquises par l'API, il sera possible d'interagir avec Rem je veux Les données du roman n'ont pas d'étiquette pour le dialogue, donc ça s'arrête au point de faire les données (suer) ~~ Je veux que quelqu'un crée des données. ~~ Quoi qu'il en soit, le traitement du langage naturel est difficile à créer des données d'apprentissage, donc si vous souhaitez coopérer, veuillez nous contacter.

Je n'ai pas l'habitude d'écrire des articles, et je pense qu'il y avait beaucoup de points difficiles à lire, mais merci d'avoir lu jusqu'au bout. Si vous pensez que "cela a été utile" ou "je veux en savoir plus", je vous serais reconnaissant de bien vouloir l'aimer. (Parce que ça devient motivé).

Liste des sites de référence

J'ai essayé de transcrire les lignes de l'anime télévisé Kemono Friends Wikipedia [Python] Générer des phrases avec une chaîne de Markov au Nième étage ["Génération de phrases par chaîne de Markov"](https://omedstu.jimdofree.com/2018/05/06/%E3%83%9E%E3%83%AB%E3%82%B3%E3%83%95 % E9% 80% A3% E9% 8E% 96% E3% 81% AB% E3% 82% 88% E3% 82% 8B% E6% 96% 87% E6% 9B% B8% E7% 94% 9F% E6 % 88% 90 /)

Recommended Posts

J'ai essayé de créer un générateur de dialogue de personnage automatique par chaîne Markov N étage
J'ai essayé d'obtenir une image en grattant
J'ai essayé de créer une application OCR avec PySimpleGUI
J'ai essayé de faire un BOT de détection de lèvre d'air et de réponse automatique pour le travail à distance
J'ai essayé de créer automatiquement un rapport avec la chaîne de Markov
[Chaîne de Markov] J'ai essayé de charger des émotions négatives dans Python.
[Chaîne de Markov] J'ai essayé de lire les citations en Python.
J'ai essayé de faire une activité qui définit collectivement les informations de position
J'ai essayé de rendre possible l'envoi automatique d'un e-mail en double-cliquant simplement sur l'icône [Python]
J'ai essayé de faire 5 modèles de base d'analyse en 3 ans
[Python] Japonais simple ⇒ J'ai essayé de créer un outil de traduction en anglais
J'ai essayé de créer une fonction de similitude d'image avec Python + OpenCV
J'ai essayé de rendre possible l'envoi automatique d'un e-mail en double-cliquant simplement sur l'icône [GAS / Python]
J'ai créé un capteur d'ouverture / fermeture (lien Twitter) avec TWE-Lite-2525A
[Chaîne de Markov] J'ai essayé de lire des citations et des émotions négatives en Python.
Je veux faire un programme d'automatisation!
J'ai créé une API Web
J'ai fait de mon mieux pour créer une fonction d'optimisation, mais cela n'a pas fonctionné.
J'ai essayé de programmer la bulle de tri par langue
J'ai essayé de faire de l'IA pour Smash Bra
J'ai essayé de détecter un objet avec M2Det!
J'ai essayé de générer une chaîne de caractères aléatoire
J'ai essayé de classer les boules de dragon par adaline
J'ai créé un jeu ○ ✕ avec TensorFlow
Suite ・ J'ai essayé de créer Slackbot après avoir étudié Python3
J'ai essayé d'implémenter le perceptron artificiel avec python
J'ai essayé d'obtenir une AMI en utilisant AWS Lambda
J'ai essayé de devenir un Ann Man en utilisant OpenCV
J'ai essayé de trouver la classe alternative avec tensorflow
J'ai essayé d'implémenter le calcul automatique de la preuve de séquence
[Python] J'ai essayé de faire une application qui calcule le salaire en fonction des heures de travail avec tkinter
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 faire d'Othello AI que j'ai appris 7,2 millions de mains par apprentissage profond avec Chainer