[PYTHON] Implémentation de DQN avec TensorFlow (je voulais ...)

Après avoir lu les articles suivants, j'ai été impressionné par le fait que DQN (Deep Q-Network) semble être intéressant. L'Alpha-Go récemment évoqué est aussi une extension de DQN ... Vraiment? (Je ne comprends pas) Histoire de DQN + Deep Q-Network écrite dans Chainer Apprentissage DQN (Deep Q Network) avec pendule inversé Jouer avec l'apprentissage automatique avec Chainer: pouvez-vous améliorer l'apprentissage des jeux d'addition avec Chainer?

C'est pourquoi j'ai essayé de l'implémenter avec TensorFlow ... (-_-;)? ?? ?? Je ne suis pas sûr. Non, le problème est que j'essaie de le faire sans comprendre la théorie et les formules. Je pense qu'il y a trop peu d'exemples de TensorFlow. Pour le moment, j'ai essayé de l'imiter, alors je vous serais reconnaissant de bien vouloir commenter s'il y a des malentendus ou des corrections. «Cette zone est correcte» et «Cette zone est correcte» sont également très utiles.

Autres sites référencés: Deep-Q learning Pong with Tensorflow and PyGame J'ai probablement fait référence au code source dans la moitié supérieure de cette page.

Détails d'implémentation

Considérez le jeu suivant.

environnement

TensorFlow 0.7 Ubuntu 14.04 Instance GCE vCPU x8

la mise en oeuvre

Je mettrai le code source en bas, mais je vais expliquer la partie.

Création de graphes

def inference(x_ph):

    with tf.name_scope('hidden1'):
        weights = tf.Variable(tf.truncated_normal([NUM_IMPUT, NUM_HIDDEN1], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN1], dtype=tf.float32), name='biases')
        hidden1 = tf.matmul(x_ph, weights) + biases

    with tf.name_scope('hidden2'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN1, NUM_HIDDEN2], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN2], dtype=tf.float32), name='biases')
        hidden2 = tf.matmul(hidden1, weights) + biases

    with tf.name_scope('output'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN2, NUM_OUTPUT], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_OUTPUT], dtype=tf.float32), name='biases')
        y = tf.matmul(hidden2, weights) + biases

    return y

Il y a deux couches cachées et le nombre d'unités est de 100 et 100, respectivement. Le numéro de ce côté est approprié. (J'essaye en jouant avec) Entrez un seul chiffre indiquant la position actuelle. Il y a deux sorties, les récompenses attendues pour +1 et +2 (je pense). J'ai vu de nombreuses initialisations de variables qui étaient initialisées à zéro, mais cela ne fonctionnait pas, donc une initialisation aléatoire. (Y a-t-il un problème?) La fonction d'activation ne fonctionne pas bien si j'utilise relu, et si je la connecte sans la fonction d'activation, elle fonctionne un peu avec Matomo, donc il n'en reste aucune. (Y a-t-il un problème?)

Calcul des pertes

def loss(y, y_ph):
    return tf.reduce_mean(tf.nn.l2_loss((y - y_ph)))

Le calcul des pertes semble être carré et divisé par deux, alors implémentez-le avec l'API équivalente.

La partie pour s'entraîner réellement

def getNextPositionReward(choice_position):

    if choice_position % 8 == 0:
        next_position_reward = -1.
    elif choice_position % 2 == 0:
        next_position_reward = 1.
    else:
        next_position_reward = 0.

    return next_position_reward

Une fonction qui renvoie une pénalité si la place suivante est un multiple de 8 et une récompense si elle est un multiple de 2.

def getNextPosition(position, action_reward1, action_reward2):

    if random.random() < RANDOM_FACTOR:
        if random.randint(0, 1) == 0:
            next_position = position + 1
        else:
            next_position = position + 2
    else:
        if action_reward1 > action_reward2:
            next_position = position + 1
        else:
            next_position = position + 2

    return next_position

La partie qui compare les deux récompenses et considère s'il faut avancer +1 ou +2. Au moment de l'entraînement, j'essaie de mettre un certain élément aléatoire et de procéder.

    for i in range(REPEAT_TIMES):
        position = 0.
        position_history = []
        reward_history = []

        while(True):
            if position >= GOAL:
                break

            choice1_position = position + 1.
            choice2_position = position + 2.

            next_position1_reward = getNextPositionReward(choice1_position)
            next_position2_reward = getNextPositionReward(choice2_position)

            reward1 = sess.run(y, feed_dict={x_ph: [[choice1_position]]})[0]
            reward2 = sess.run(y, feed_dict={x_ph: [[choice2_position]]})[0]

            action_reward1 = next_position1_reward + GAMMA * np.max(reward1)
            action_reward2 = next_position2_reward + GAMMA * np.max(reward2)

            position_history.append([position])
            reward_history.append([action_reward1, action_reward2])

            position = getNextPosition(position, action_reward1, action_reward2)

        sess.run(train_step, feed_dict={x_ph: position_history, y_ph: reward_history})

Partie formation (extrait). Il y a deux options, comparez les récompenses et choisissez celle avec la récompense la plus élevée. La récompense est la somme des valeurs maximales de «la récompense (certainement) obtenue à la position suivante» et de «la valeur prédite de la récompense (probablement) obtenue après cela». Également, établissez une liste des deux récompenses et de votre position actuelle pour l'apprentissage supervisé. Ceci est répété environ 1000 fois. ⇒ Je suis inquiet à ce sujet. Je pense que je fais une grosse erreur.

résultat

Jetons un coup d'œil à la trajectoire de la façon dont il s'est réellement déplacé après l'entraînement.

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98]

Il renvoie complètement juste un nombre pair. Je marche parfaitement sur des multiples de 8! J'ai l'impression que je vais obtenir des récompenses positives, mais je n'ai pas l'impression d'éviter les récompenses négatives. Quand j'ai essayé diverses choses telles que l'augmentation de la valeur négative de la récompense, il semble que la valeur ci-dessus soit différente, il semble donc que la valeur ne soit pas une valeur fixe, mais elle n'a pas bougé idéalement ... ・ ・. À propos, la perte a convergé.

Code source (tout)

import tensorflow as tf
import numpy as np
import random

# definition
NUM_IMPUT = 1
NUM_HIDDEN1 = 100
NUM_HIDDEN2 = 100
NUM_OUTPUT = 2
LEARNING_RATE = 0.1
REPEAT_TIMES = 100
GOAL = 100
LOG_DIR = "tf_log"
GAMMA = 0.8
stddev = 0.01
RANDOM_FACTOR = 0.1

def inference(x_ph):

    with tf.name_scope('hidden1'):
        weights = tf.Variable(tf.truncated_normal([NUM_IMPUT, NUM_HIDDEN1], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN1], dtype=tf.float32), name='biases')
        hidden1 = tf.matmul(x_ph, weights) + biases

    with tf.name_scope('hidden2'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN1, NUM_HIDDEN2], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN2], dtype=tf.float32), name='biases')
        hidden2 = tf.matmul(hidden1, weights) + biases

    with tf.name_scope('output'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN2, NUM_OUTPUT], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_OUTPUT], dtype=tf.float32), name='biases')
        y = tf.matmul(hidden2, weights) + biases

    return y

def loss(y, y_ph):
    return tf.reduce_mean(tf.nn.l2_loss((y - y_ph)))

def optimize(loss):
    optimizer = tf.train.AdamOptimizer(LEARNING_RATE)
    train_step = optimizer.minimize(loss)
    return train_step

def getNextPositionReward(choice_position):

    if choice_position % 8 == 0:
        next_position_reward = -1.
    elif choice_position % 2 == 0:
        next_position_reward = 1.
    else:
        next_position_reward = 0.

    return next_position_reward

def getNextPosition(position, action_reward1, action_reward2):

    if random.random() < RANDOM_FACTOR:
        if random.randint(0, 1) == 0:
            next_position = position + 1
        else:
            next_position = position + 2
    else:
        if action_reward1 > action_reward2:
            next_position = position + 1
        else:
            next_position = position + 2

    return next_position

if __name__ == "__main__":

    x_ph = tf.placeholder(tf.float32, [None, NUM_IMPUT])
    y_ph = tf.placeholder(tf.float32, [None, NUM_OUTPUT])

    y = inference(x_ph)
    loss = loss(y, y_ph)
    tf.scalar_summary("Loss", loss)
    train_step = optimize(loss)

    sess = tf.Session()
    summary_op = tf.merge_all_summaries()
    init = tf.initialize_all_variables()
    sess.run(init)
    summary_writer = tf.train.SummaryWriter(LOG_DIR, graph_def=sess.graph_def)

    for i in range(REPEAT_TIMES):
        position = 0.
        position_history = []
        reward_history = []

        while(True):
            if position >= GOAL:
                break

            choice1_position = position + 1.
            choice2_position = position + 2.

            next_position1_reward = getNextPositionReward(choice1_position)
            next_position2_reward = getNextPositionReward(choice2_position)

            reward1 = sess.run(y, feed_dict={x_ph: [[choice1_position]]})[0]
            reward2 = sess.run(y, feed_dict={x_ph: [[choice2_position]]})[0]

            action_reward1 = next_position1_reward + GAMMA * np.max(reward1)
            action_reward2 = next_position2_reward + GAMMA * np.max(reward2)

            position_history.append([position])
            reward_history.append([action_reward1, action_reward2])

            position = getNextPosition(position, action_reward1, action_reward2)

        sess.run(train_step, feed_dict={x_ph: position_history, y_ph: reward_history})
        summary_str = sess.run(summary_op, feed_dict={x_ph: position_history, y_ph: reward_history})
        summary_writer.add_summary(summary_str, i)
        if i % 10 == 0:
            print "Count: " + str(i)

    # TEST
    position = 0
    position_history = []
    while(True):
        if position >= GOAL:
                break

        position_history.append(position)

        rewards = sess.run(y, feed_dict={x_ph: [[position]]})[0]
        choice = np.argmax(rewards)
        if choice == 0:
            position += 1
        else:
            position += 2

    print position_history

Vraiment

Nous attendons avec impatience vos conseils et votre inutilité.

2016/04/27 PostScript

dsanno nous a donné quelques conseils dans les commentaires. Merci beaucoup. Je vais essayer ça.

Partie 1

Avec ce paramètre de problème, il n'y a pas de couche cachée, Je pense que vous pouvez apprendre avec une seule couche de embedding_lookup avec 100 valeurs d'entrée (un vecteur unique représentant votre emplacement actuel) et 2 valeurs de sortie.

Je vois je vois··· Je ne comprends toujours pas embedding_lookup, alors je vais le laisser de côté et faire de l'entrée un vecteur unique et l'essayer sans couche cachée.

def inference(x_ph):

    with tf.name_scope('output'):
        weights = tf.Variable(tf.truncated_normal([NUM_IMPUT, NUM_OUTPUT], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_OUTPUT], dtype=tf.float32), name='biases')
        y = tf.matmul(x_ph, weights) + biases

Voici une fonction pour créer un vecteur one-hot.

def onehot(idx):
    idx = int(idx)
    array = np.zeros(GOAL)
    array[idx] = 1.
    return array

résultat

[0, 2, 4, 6, 7, 9, 10, 12, 14, 15, 17, 18, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 38, 39, 41, 42, 44, 46, 47, 49, 50, 52, 53, 54, 55, 57, 58, 60, 62, 63, 65, 66, 68, 70, 71, 73, 74, 76, 78, 79, 81, 82, 84, 86, 88, 90, 92, 94, 95, 97, 98, 99]

C'est un peu comme ça. Ce n'est pas parfait, mais j'ai l'impression d'essayer d'éviter les multiples de 8 tout en marchant sur des multiples de 2 autant que possible.

Partie 2

Avec ReLu, il n'y a pas de limite supérieure à la sortie et cela semble incompatible, alors faites de tanh ou relu6 avec une limite supérieure une fonction d'activation

J'ai essayé avec 100 100 unités de couche cachée tout en gardant une entrée. Ce n'est pas très différent de l'absence de fonction d'activation.

résultat

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98]

Partie 3

Si vous pouvez supposer que la solution est périodique, utilisez tf.sin pour la fonction d'activation (utilisez comme sin pour la première étape et relu pour la deuxième étape). J'ai essayé avec 100 100 unités de couche cachée tout en gardant une entrée.

def inference(x_ph):

    with tf.name_scope('hidden1'):
        weights = tf.Variable(tf.zeros([NUM_IMPUT, NUM_HIDDEN1], dtype=tf.float32), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN1], dtype=tf.float32), name='biases')
        hidden1 = tf.sin(tf.matmul(x_ph, weights) + biases)

    with tf.name_scope('hidden2'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN1, NUM_HIDDEN2], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_HIDDEN2], dtype=tf.float32), name='biases')
        hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)

    with tf.name_scope('output'):
        weights = tf.Variable(tf.truncated_normal([NUM_HIDDEN2, NUM_OUTPUT], stddev=stddev), name='weights')
        biases = tf.Variable(tf.zeros([NUM_OUTPUT], dtype=tf.float32), name='biases')
        y = tf.matmul(hidden2, weights) + biases

    return y

résultat

[0, 2, 4, 6, 8, 9, 10, 12, 14, 15, 17, 18, 20, 22, 23, 25, 26, 28, 29, 30, 31, 33, 34, 36, 38, 39, 41, 43, 44, 46, 47, 49, 50, 51, 53, 55, 57, 58, 60, 62, 63, 64, 66, 68, 69, 71, 73, 74, 76, 78, 79, 81, 82, 83, 84, 85, 87, 89, 90, 92, 94, 95, 97, 98]

Je marche sur les 8 premiers, mais je sens que je fais de mon mieux ici aussi.

Corrigé un peu et ajusté le nombre d'unités de calques cachés à 500.100.

résultat

[0, 2, 4, 6, 7, 9, 10, 12, 14, 15, 17, 18, 20, 22, 23, 25, 26, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 46, 47, 49, 50, 52, 54, 55, 57, 58, 60, 62, 63, 65, 66, 68, 70, 71, 73, 74, 76, 78, 79, 81, 82, 84, 86, 87, 89, 90, 92, 94, 95, 97, 98]

Est-ce parfait? Je n'ai même pas du tout pensé à utiliser sin (). Merci encore, dsanno.

Impressions

Quand j'ai entendu parler de l'intelligence artificielle, j'ai eu l'illusion que si je le faisais pour le moment, je penserais à tout moi-même, mais j'ai réalisé que les caractéristiques des données d'entrée et le créateur devaient y réfléchir correctement. ..

Recommended Posts

Implémentation de DQN avec TensorFlow (je voulais ...)
Je voulais résoudre ABC159 avec Python
Je veux utiliser self avec Backpropagation (tf.custom_gradient) (tensorflow)
Je voulais supprimer plusieurs objets en s3 avec boto3
Chaîne de hachage que je voulais éviter (2)
Je voulais faire évoluer cGAN vers ACGAN
Comment exécuter du code TensorFlow 1.0 en 2.0
Chaîne de hachage que je voulais éviter (1)
Je voulais faire quelque chose comme la pipe d'Elixir en Python
J'ai essayé d'implémenter Autoencoder avec TensorFlow
J'ai essayé d'implémenter la permutation en Python
Je veux imprimer dans la notation d'inclusion
J'ai essayé de visualiser AutoEncoder avec TensorFlow
J'ai essayé d'implémenter PLSA dans Python 2
Je voulais résoudre ABC160 avec Python
J'ai essayé de classer le texte en utilisant TensorFlow
J'ai essayé d'implémenter la régression logistique de Cousera en Python
J'ai essayé d'implémenter ADALINE en Python
Je veux intégrer Matplotlib dans PySimpleGUI
Je voulais résoudre ABC172 avec Python
Je voulais utiliser le notebook jupyter avec docker dans l'environnement pip (opticspy)
J'ai implémenté le modèle VGG16 avec Keras et essayé d'identifier CIFAR10
J'ai essayé d'implémenter le filtre anti-spam bayésien de Robinson avec python
Je veux corriger Datetime.now dans le test de Django
Je voulais résoudre NOMURA Contest 2020 avec Python
J'ai implémenté DCGAN et essayé de générer des pommes
Scraping de pages i-Town: je voulais prendre la place de Wise-kun
Python: j'ai pu récurer en lambda
Je veux créer une fenêtre avec Python
J'ai essayé d'intégrer Keras dans TFv1.1
Je voulais jouer avec la courbe de Bézier
Comment exécuter CNN en notation système 1 avec Tensorflow 2
J'ai écrit "Introduction à la vérification des effets" en Python
Je souhaite stocker les informations de la base de données dans la liste
Je veux fusionner des dictionnaires imbriqués en Python
J'ai implémenté CycleGAN (1)
J'ai essayé d'implémenter TOPIC MODEL en Python
J'ai essayé d'implémenter la fonction gamma inverse en python
[Je veux classer les images à l'aide de Tensorflow] (2) Classifions les images
J'ai implémenté ResNet!
J'ai essayé d'implémenter le tri sélectif en python
Je veux afficher la progression en Python!
J'ai créé un jeu ○ ✕ avec TensorFlow
Je voulais juste comprendre le module Pickle de Python
J'ai essayé d'implémenter la recherche de priorité de largeur avec python (file d'attente, dessin personnalisé)
Je veux écrire en Python! (1) Vérification du format de code
J'ai essayé de représenter graphiquement les packages installés en Python
Je souhaite intégrer une variable dans une chaîne Python
Je veux facilement implémenter le délai d'expiration en python
Je veux que DQN Puniki frappe un home run
Je voulais aussi vérifier les indices de type avec numpy
Je veux faire la transition avec un bouton sur le ballon
Je veux écrire en Python! (2) Écrivons un test
Procédure d'installation de TensorFlow dans un environnement de coquille de poisson (Anaconda 4.0.0)
Même avec JavaScript, je veux voir Python `range ()`!
J'ai fait un script pour mettre un extrait dans README.md
J'ai essayé d'implémenter un pseudo pachislot en Python
Je voulais utiliser la bibliothèque Python de MATLAB
Je veux échantillonner au hasard un fichier avec Python
J'ai essayé d'implémenter le poker de Drakue en Python