[PYTHON] Zundokokiyoshi avec TensorFlow

(Ajout) Ce n'est pas TensorFlow, mais j'ai trouvé qu'il a été résolu plus magnifiquement par Chainer. Apprenez le Zundokokiyoshi en utilisant LSTM


J'ai l'impression d'avoir raté le boom, mais depuis que j'ai récemment touché TensorFlow, j'ai utilisé TensorFlow pour utiliser __convolutional neural network (CNN, ConvNet: Convolutional neural network) __. J'ai essayé de résoudre Zundokokiyoshi en l'utilisant. Vous n'avez même plus besoin de dépenser votre intelligence humaine pour résoudre Zundokokiyoshi.

Le code complet est ici.

Problème de réglage

Tout d'abord, nous devons réfléchir à ce que le réseau de neurones peut résoudre pour Zundokokiyoshi.

Par exemple, vous pouvez découper 5 éléments d'un Zundcolist (une liste dans laquelle "Zun" et "Doko" sont stockés au hasard) et les laisser déterminer s'ils sont "Zun, Dung, Dung, Dung, Doco". Il est trop facile de créer un problème et ce n'est pas intéressant. Vous n'avez pas besoin de créer un réseau de neurones, il n'y a que des modèles $ 2 ^ 5 = 32 $, il vous suffit donc de vous souvenir de tous les modèles plutôt que de l'apprentissage automatique.

Cela dit, je ne pouvais pas penser à un bon moyen de transmettre un Zund Collist infini comme entrée à un réseau de neurones. C'est pourquoi je vais passer un Zund Collist avec 100 éléments et retourner un index où le premier "Zun" de "Zun, Dung, Dung, Dung, Doco" apparaît pour la première fois. Par exemple, la bonne réponse est de renvoyer «2» pour un Zund Collist qui dit «Dung, Doco, Dung, Dung, Dung, Dung, Doco, ...». Puisque le nombre d'éléments est de 100, il peut y avoir des solutions de "0" à "95". De plus, si "Dung, Dung, Dung, Dung, Doko" n'apparaît pas, supposons que "96" soit renvoyé. Ceci est considéré comme un problème d'identification de 97 classes qui identifie les classes de «0» à «96». Dans ce cas, il existe un motif de 2 $ ^ 100 $, il n'est donc pas possible d'entraîner tous les motifs. Il est nécessaire d'apprendre la logique de jugement par apprentissage automatique.

Pour faciliter la gestion dans un réseau neuronal, l'entrée Zundcolist représente "Zun" sous la forme "-1.0", "Doco" est représenté par "1.0" et la sortie est Tutoriel TensorFlow. Il est représenté par un vecteur one-hot comme dans les versions / 0.6.0 / tutorials / mnist / beginners /). En d'autres termes, pour le Zundcolist "Zun, Doco, Dung, Dung, Dung, Dung, Doco, ...", [-1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0 ,. ..] ʻest entraîné comme entrée et [0.0, 0.0, 1.0, 0.0, ...] ʻest entraîné comme sortie.

Données d'entraînement

Étant donné que le Zund Collist connaît la relation entre l'entrée et la sortie, les données d'apprentissage peuvent être générées indéfiniment. Je suis heureux que la partie qui collecte les données de formation, qui est l'un des points les plus difficiles de l'apprentissage automatique, ait été effacée!

Tout d'abord, créons une fonction make_zundoko_list qui génère aléatoirement un Zundcolist et une fonctionresolve_zundoko_list qui le résout.

from random import choice

zun = -1.0
doko = 1.0
zun_length = 4
zundoko_length = zun_length + 1

def make_zundoko_list(length):
    return [choice([zun, doko]) for _ in range(length)]

def solve_zundoko_list(zundoko_list, index=0, zun_count=0):
    if len(zundoko_list) == 0:
        return index - zun_length
    elif zun_count >= zun_length and zundoko_list[0] == doko:
        return index - zun_length
    else:
        return solve_zundoko_list(zundoko_list[1:], index + 1, zun_count + 1 if zundoko_list[0] == zun else 0)

Cependant, si vous utilisez un Zund Collist généré aléatoirement comme données d'entraînement, la sortie sera biaisée, ce qui n'est pas bon. Nous voulons nous entraîner uniformément de «0» à «96», donc créons également une fonction «make_solved_zundoko_list» qui spécifie une solution et génère un Zundcolist.

def make_solved_zundoko_list(length, answer):
    zundoko_list = make_zundoko_list(length)
    while True:
        solved_answer = solve_zundoko_list(zundoko_list)
        if solved_answer >= answer:
            break
        zundoko_list[solved_answer] = doko
    if answer + zundoko_length <= length:
        zundoko_list[answer:answer + zundoko_length] = [zun for _ in range(zun_length)] + [doko]
    return zundoko_list

Comme mentionné ci-dessus, la solution doit être convertie en un vecteur one-hot, donc créons également une fonction dense_to_one_hot pour cela.

def dense_to_one_hot(index, num_classes):
    return [(1.0 if i == index else 0.0) for i in range(num_classes)]

Utilisez-le pour préparer les données d'entraînement et les données de test. Supposons qu'il existe 100 000 données d'entraînement et 1 000 données de test.

Notez que nous utilisons make_solved_zundoko_list pour les données d'entraînement et make_zundoko_list pour les données de test.

list_length = 100
num_classes = list_length - zundoko_length + 1 + 1

zundoko_lists = [make_solved_zundoko_list(list_length, i % num_classes) for i in range(100000)]
zundoko_answers = [dense_to_one_hot(solve_zundoko_list(z), num_classes) for z in zundoko_lists]

test_zundoko_lists = [make_zundoko_list(list_length) for _ in range(1000)]
test_zundoko_answers = [dense_to_one_hot(solve_zundoko_list(z), num_classes) for z in test_zundoko_lists]

Réseau de neurones à convolution

Voici le problème principal. Jusqu'à présent, j'utilise juste Python.

Puisque Zundoko Kiyoshi veut détecter des motifs adjacents («Zun, Dung, Dung, Dung, Doco») dans la liste, __Convolution Neural Network (CNN) __ convient. Le [Second Tutorial] de TensorFlow (https://www.tensorflow.org/versions/r0.7/tutorials/mnist/pros/index.html) est un exemple de CNN, alors écrivez-le comme référence. Allons-y.

CNN est souvent utilisé pour la reconnaissance d'image. Puisque l'image est bidimensionnelle, la [convolution] bidimensionnelle (http://www.clg.niigata-u.ac.jp/~medimg/practice_medical_imaging/imgproc_scion/4filter/index.htm) est effectuée dans la reconnaissance d'image. Cependant, puisque Zund Collist est une chaîne de données unidimensionnelle, il est nécessaire d'effectuer une convolution unidimensionnelle. Le motif que je veux détecter en ce moment est «Dung, Dung, Dung, Dung, Doco», il semble donc bon de le plier avec un noyau de taille 5.

Cependant, j'ai cherché la [Référence API] de TensorFlow (https://www.tensorflow.org/versions/r0.7/api_docs/index.html) et n'ai trouvé aucune fonction pour la convolution unidimensionnelle [^ 1]. ]. Puisqu'il n'y a aucune aide pour cela, le Zund Collist fera «100» x «1», et le noyau fera «remodeler» en «5» x «1» et le traitera comme une valeur bidimensionnelle. Vous pouvez maintenant utiliser la convolution bidimensionnelle conv2d pour obtenir une pseudo convolution unidimensionnelle.

La partie à plier à partir de la couche d'entrée est la suivante.

x = tf.placeholder(tf.float32, [None, list_length])
x_reshaped = tf.reshape(x, [-1, list_length, 1, 1])
W1 = tf.Variable(tf.truncated_normal([5, 1, 1, 1], stddev=0.1))
b1 = tf.Variable(tf.truncated_normal([1], stddev=0.1))
h1_reshaped = tf.nn.relu(tf.nn.conv2d(x_reshaped, W1, strides=[1, 1, 1, 1], padding='SAME') + b1)
h1 = tf.reshape(h1_reshaped, [-1, list_length])

On s'attend à ce que cette convolution détecte les modèles «excréments, excréments, excréments, excréments, doco». Normalement, CNN effectue une mise en commun après la convolution, mais cette fois, elle ne se regroupe pas car le résultat de la convolution indiquera directement si "bouse, bouse, bouse, bouse, doco" a été détectée. ..

Au fait, même si vous pouvez détecter le motif de "Zun, Dung, Dung, Dung, Doco" en pliant, cela ne suffit pas. Par exemple, si l'entrée «Dung, Doco, Dung, Dung, Dung, Dung, Doco, Dung, Dung, Dung, Dung, Doco, ...» est passée, «7» est détecté en plus de «2». On s'attend à ce que cela finisse. Cependant, il est mécaniquement difficile de détecter uniquement "2" par convolution. Alors ajoutons une autre couche et débarrassons-nous des valeurs comme «7».

Comme il est difficile d'exprimer un tel calcul par convolution, la couche suivante est entièrement connectée. Cependant, le calcul consistant à ne supprimer que «7» en laissant «2» semble compliqué. Une connexion complète (multipliée simplement par une matrice) a-t-elle autant de pouvoir expressif? Si vous ne pouvez pas exprimer le calcul que vous souhaitez réaliser avec cette formule, vous ne pouvez pas l'entraîner.

Avec «2» et «7» détectés («[0, 0, 1, 0, 0, 0, 0, 1, 0, ...]»), quel type de matrice doit être appliqué à «2 Est-il possible d'obtenir le résultat de la détection uniquement ( [0, 0, 1, 0, 0, 0, 0, 0, ...] `)? Par exemple, si vous appliquez la matrice suivante (à partir de la droite), il semble que vous puissiez passer aux valeurs négatives sauf pour le premier "Zun, Zun, Zun, Zun, Doko" détecté. Si vous pouvez séparer les valeurs que vous souhaitez détecter des valeurs que vous ne souhaitez pas, la fonction d'activation fera le reste.

\left(\begin{matrix}
   1.0 &   -1.0 &   -1.0 & \cdots \\
   0.0 &    1.0 &   -1.0 & \cdots \\
   0.0 &    0.0 &    1.0 & \cdots \\
\vdots & \vdots & \vdots & \ddots \\
\end{matrix}\right)

Maintenant, nous savons que la simple multiplication de la matrice est suffisamment puissante pour supprimer des valeurs comme «7». L'expressivité ne signifie pas que l'apprentissage réussira, mais appliquons une matrice de «100» × «97» (y compris le biais et «softmax») à la sortie. Le décrochage est omis car il semble incompatible en raison de la nature du problème (en raison de la configuration du réseau neuronal?).

W2 = tf.Variable(tf.truncated_normal([list_length, num_classes], stddev=0.1))
b2 = tf.Variable(tf.truncated_normal([num_classes], stddev=0.1))
y = tf.nn.softmax(tf.matmul(h1, W2) + b2)

Apprentissage

Après cela, comme dans le didacticiel, optimisez pour minimiser l'entropie croisée et trouvez «W1», «b1», «W2», «b2».

y_ = tf.placeholder(tf.float32, [None, num_classes])

cross_entropy = -tf.reduce_sum(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))

train_step = tf.train.GradientDescentOptimizer(1e-5).minimize(cross_entropy)

answer = tf.argmax(y, 1)

init = tf.initialize_all_variables()

sess = tf.Session()
sess.run(init)

for i in range(1000):
    sess.run(train_step, feed_dict={x: zundoko_lists, y_: zundoko_answers})

J'ai modifié divers détails du didacticiel, tels que l'entraînement avec toutes les données d'entraînement à chaque étape et l'utilisation de GradientDescentOptimizer. La «cross_entropy» a été corrigée en se référant à cette Réponse de StackOverflow.

Affichage des résultats

Enfin, affichez Zundokokiyoshi sur le réseau neuronal entraîné et vous avez terminé.

zundoko_list = make_zundoko_list(list_length)
zundoko_answer = sess.run(answer, feed_dict={x: [zundoko_list]})[0]
zundoko_string_list = ['Bouse' if zundoko == zun else 'Doco' for zundoko in zundoko_list]
zundoko_string_list = zundoko_string_list[:min(zundoko_answer + zundoko_length, len(zundoko_string_list))]
for zundoko_string in zundoko_string_list:
    print(zundoko_string)
if zundoko_answer + zundoko_length == len(zundoko_string_list):
    print('Ki yo shi!')
Bouse
Doco
Bouse
Doco
Doco
Bouse
Doco
Doco
Doco
Bouse
Bouse
Doco
Bouse
Doco
Doco
Doco
Doco
Bouse
Bouse
Bouse
Bouse
Doco
Ki yo shi!

Oh! !! Il était affiché correctement!

Cependant, après avoir essayé plusieurs fois avec des paramètres légèrement différents, le taux de réponse correct dans les données de test n'était que de 98% au maximum. Avant de le faire, je pensais que je pourrais atteindre 100% avec une logique aussi simple, mais c'est assez difficile. Dans la configuration actuelle, je pense qu'il est difficile si toutes les combinaisons (l'indice de la solution et l'index suivant qui est ignoré) ne sont pas incluses dans les données d'entraînement, donc je peux exprimer des fonctionnalités plus abstraites telles que l'ajout de couches. Alors ça a peut-être été bon.


[^ 1]: Je viens de faire une recherche rapide sur conv, alors peut-être que j'ai raté quelque chose.

Recommended Posts

Zundokokiyoshi avec TensorFlow
Casser des blocs avec Tensorflow
Apprenez Zundokokiyoshi en utilisant LSTM
Lecture de données avec TensorFlow
Prévisions de courses de bateaux avec TensorFlow
Essayez la régression avec TensorFlow
Traduire Premiers pas avec TensorFlow
Essayez l'apprentissage en profondeur avec TensorFlow
Utiliser TensorFlow avec Intellij IDEA
Fonction sinueuse approximative avec TensorFlow
Zundokokiyoshi avec python / rubis / Lua
Prévision du cours de l'action avec tensorflow
Essayez TensorFlow MNIST avec RNN
Assurer la reproductibilité avec tf.keras dans Tensorflow 2.3
TensorFlow 2.2 ne peut pas être installé avec Python 3.8!
MNIST (DCNN) avec Keras (backend TensorFlow)
Personnaliser le modèle / la couche / la métrique avec TensorFlow
Affichage des inférences et des résultats avec Tensorflow + matplotlib
Précautions lors de l'installation de tensorflow avec anaconda
[TensorFlow 2] Apprendre RNN avec perte CTC
Essayez l'apprentissage en profondeur avec TensorFlow Partie 2
Utilisez Tensorflow 2.1.0 avec Anaconda sur Windows 10!
Essayez les données en parallèle avec TensorFlow distribué
Zura prédisant la température d'aujourd'hui avec TensorFlow
Intellisense ne fonctionne pas avec tensorflow2.0 + VScode
Obtenez un rembourrage de réflexion Pytorch avec Tensorflow
Apprenez les données distribuées avec TensorFlow Y = 2X
J'ai essayé de visualiser AutoEncoder avec TensorFlow
Mettre TensorFlow dans une instance P2 avec pip3
Créer un environnement Tensorflow avec Raspberry Pi [2020]
Comparez le TensorFlow brut avec tf.contrib.learn et Keras
Implémenter DQN (version complète) avec Tensorflow
L'histoire du calcul numérique des équations différentielles avec TensorFlow 2.0
Prévision de stock avec TensorFlow (LSTM) ~ Prévision de stock Partie 1 ~
Glossaire Tensorflow
tensorflow mnist_deep.py
Tutoriel du didacticiel TensorFlow
Essayez TensorFlow RNN avec un modèle de base
Prédiction d'images vidéo à l'aide de la convolution LSTM avec TensorFlow
Mélangez des centaines de milliers d'images uniformément avec tensorflow.
J'ai essayé la décomposition matricielle non négative (NMF) avec TensorFlow
Une fuite de mémoire s'est produite après l'apprentissage du DQN avec tensorflow == 2.0.0
Chargez le fichier de modèle TensorFlow .pb avec readNetFromTensorflow ().
Calculer l'angle entre les vecteurs à n dimensions avec TensorFlow