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.
Considérez le jeu suivant.
TensorFlow 0.7 Ubuntu 14.04 Instance GCE vCPU x8
Je mettrai le code source en bas, mais je vais expliquer la partie.
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?)
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.
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.
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é.
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
Nous attendons avec impatience vos conseils et votre inutilité.
dsanno nous a donné quelques conseils dans les commentaires. Merci beaucoup. Je vais essayer ça.
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
[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.
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.
[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]
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
[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.
[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.
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. ..