EDIT (1/3/16): corresponding github issueCome utilizzare Tensorflow Optimizer senza ricalcolare le attivazioni nel programma di apprendimento di rinforzo che restituisce il controllo dopo ogni iterazione?
Sto utilizzando tensorflow (interfaccia Python) per implementare un agente q-apprendimento con funzione di approssimazione addestrata con gradiente stocastico-discesa. Ad ogni iterazione dell'esperimento viene chiamata una funzione di passo nell'agente che aggiorna i parametri dell'approssimatore in base alla nuova ricompensa e attivazione, quindi sceglie una nuova azione da eseguire.
Qui è il problema (con l'apprendimento di rinforzo gergo):
- L'agente calcola le sue previsioni valore dello stato-azione per scegliere un'azione.
- Quindi restituisce il controllo di un altro programma che simula un passaggio nell'ambiente.
- Ora la funzione di passo dell'agente viene chiamata per l'iterazione successiva. Voglio usare la classe Optimizer di Tensorflow per calcolare le sfumature per me. Tuttavia, ciò richiede sia le previsioni del valore di azione dello stato che ho calcolato l'ultimo passaggio, sia il loro grafico. Quindi:
- Se eseguo l'ottimizzatore sull'intero grafico, deve ricalcolare le previsioni del valore di azione dello stato.
- Tuttavia, se si memorizza la previsione (per l'azione scelta) come variabile, quindi la si invia all'ottimizzatore come segnaposto, non ha più il grafico necessario per calcolare i gradienti.
- Non riesco a eseguire tutto nella stessa istruzione sess.run(), perché devo rinunciare al controllo e restituire l'azione scelta per ottenere l'osservazione e la ricompensa successive (da utilizzare nell'obiettivo per funzione di perdita).
Quindi, c'è un modo che io possa (senza rinforzo apprendimento gergo):
- Compute parte del mio grafico, tornando valore1.
- Valore restituito1 al programma chiamante per calcolare il valore2
- Nella successiva iterazione, utilizzare il valore 2 come parte della funzione di perdita per la discesa del gradiente SENZA ricalibrare la parte del grafico che calcola il valore1.
Naturalmente, ho considerato le soluzioni ovvie:
Basta hardcode le pendenze: Questo sarebbe facile per i davvero semplici approssimatori sto usando ora, ma sarebbe davvero scomodo se Stavo sperimentando diversi filtri e funzioni di attivazione in una grande rete convoluzionale. Mi piacerebbe davvero usare la classe Optimizer se possibile.
Chiama la simulazione ambientale dall'interno dell'agente: This system esegue questa operazione, ma renderà il mio più complicato e rimuoverà gran parte della modularità e della struttura. Quindi, non voglio farlo.
Ho letto più volte l'API e il whitepaper, ma non riesco a trovare una soluzione. Stavo cercando di trovare un modo per alimentare il bersaglio in un grafico per calcolare i gradienti, ma non ho potuto trovare un modo per costruire quel grafico automaticamente.
Se risulta che non è ancora possibile in TensorFlow, pensi che sarebbe molto complicato implementarlo come un nuovo operatore? (Non ho usato C++ in un paio d'anni, quindi la sorgente TensorFlow sembra un po 'intimidatoria.) O sarebbe meglio passare a qualcosa come Torch, che ha la differenziazione imperativa di Autograd, invece della differenziazione simbolica?
Grazie per aver trovato il tempo di darmi una mano su questo. Stavo cercando di renderlo il più conciso possibile.
EDIT: Dopo aver fatto qualche ulteriore ricerca mi sono imbattuto in this previously asked question. È un po 'diverso dal mio (stanno cercando di evitare di aggiornare una rete LSTM due volte ogni iterazione in Torch), e non ha ancora risposte.
Ecco po 'di codice se questo aiuta:
'''
-Q-Learning agent for a grid-world environment.
-Receives input as raw rbg pixel representation of screen.
-Uses an artificial neural network function approximator with one hidden layer
2015 Jonathon Byrd
'''
import random
import sys
#import copy
from rlglue.agent.Agent import Agent
from rlglue.agent import AgentLoader as AgentLoader
from rlglue.types import Action
from rlglue.types import Observation
import tensorflow as tf
import numpy as np
world_size = (3,3)
total_spaces = world_size[0] * world_size[1]
class simple_agent(Agent):
#Contants
discount_factor = tf.constant(0.5, name="discount_factor")
learning_rate = tf.constant(0.01, name="learning_rate")
exploration_rate = tf.Variable(0.2, name="exploration_rate") # used to be a constant :P
hidden_layer_size = 12
#Network Parameters - weights and biases
W = [tf.Variable(tf.truncated_normal([total_spaces * 3, hidden_layer_size], stddev=0.1), name="layer_1_weights"),
tf.Variable(tf.truncated_normal([hidden_layer_size,4], stddev=0.1), name="layer_2_weights")]
b = [tf.Variable(tf.zeros([hidden_layer_size]), name="layer_1_biases"), tf.Variable(tf.zeros([4]), name="layer_2_biases")]
#Input placeholders - observation and reward
screen = tf.placeholder(tf.float32, shape=[1, total_spaces * 3], name="observation") #input pixel rgb values
reward = tf.placeholder(tf.float32, shape=[], name="reward")
#last step data
last_obs = np.array([1, 2, 3], ndmin=4)
last_act = -1
#Last step placeholders
last_screen = tf.placeholder(tf.float32, shape=[1, total_spaces * 3], name="previous_observation")
last_move = tf.placeholder(tf.int32, shape = [], name="previous_action")
next_prediction = tf.placeholder(tf.float32, shape = [], name="next_prediction")
step_count = 0
def __init__(self):
#Initialize computational graphs
self.q_preds = self.Q(self.screen)
self.last_q_preds = self.Q(self.last_screen)
self.action = self.choose_action(self.q_preds)
self.next_pred = self.max_q(self.q_preds)
self.last_pred = self.act_to_pred(self.last_move, self.last_q_preds) # inefficient recomputation
self.loss = self.error(self.last_pred, self.reward, self.next_prediction)
self.train = self.learn(self.loss)
#Summaries and Statistics
tf.scalar_summary(['loss'], self.loss)
tf.scalar_summary('reward', self.reward)
#w_hist = tf.histogram_summary("weights", self.W[0])
self.summary_op = tf.merge_all_summaries()
self.sess = tf.Session()
self.summary_writer = tf.train.SummaryWriter('tensorlogs', graph_def=self.sess.graph_def)
def agent_init(self,taskSpec):
print("agent_init called")
self.sess.run(tf.initialize_all_variables())
def agent_start(self,observation):
#print("agent_start called, observation = {0}".format(observation.intArray))
o = np.divide(np.reshape(np.asarray(observation.intArray), (1,total_spaces * 3)), 255)
return self.control(o)
def agent_step(self,reward, observation):
#print("agent_step called, observation = {0}".format(observation.intArray))
print("step, reward: {0}".format(reward))
o = np.divide(np.reshape(np.asarray(observation.intArray), (1,total_spaces * 3)), 255)
next_prediction = self.sess.run([self.next_pred], feed_dict={self.screen:o})[0]
if self.step_count % 10 == 0:
summary_str = self.sess.run([self.summary_op, self.train],
feed_dict={self.reward:reward, self.last_screen:self.last_obs,
self.last_move:self.last_act, self.next_prediction:next_prediction})[0]
self.summary_writer.add_summary(summary_str, global_step=self.step_count)
else:
self.sess.run([self.train],
feed_dict={self.screen:o, self.reward:reward, self.last_screen:self.last_obs,
self.last_move:self.last_act, self.next_prediction:next_prediction})
return self.control(o)
def control(self, observation):
results = self.sess.run([self.action], feed_dict={self.screen:observation})
action = results[0]
self.last_act = action
self.last_obs = observation
if (action==0): # convert action integer to direction character
action = 'u'
elif (action==1):
action = 'l'
elif (action==2):
action = 'r'
elif (action==3):
action = 'd'
returnAction=Action()
returnAction.charArray=[action]
#print("return action returned {0}".format(action))
self.step_count += 1
return returnAction
def Q(self, obs): #calculates state-action value prediction with feed-forward neural net
with tf.name_scope('network_inference') as scope:
h1 = tf.nn.relu(tf.matmul(obs, self.W[0]) + self.b[0])
q_preds = tf.matmul(h1, self.W[1]) + self.b[1] #linear activation
return tf.reshape(q_preds, shape=[4])
def choose_action(self, q_preds): #chooses action epsilon-greedily
with tf.name_scope('action_choice') as scope:
exploration_roll = tf.random_uniform([])
#greedy_action = tf.argmax(q_preds, 0) # gets the action with the highest predicted Q-value
#random_action = tf.cast(tf.floor(tf.random_uniform([], maxval=4.0)), tf.int64)
#exploration rate updates
#if self.step_count % 10000 == 0:
#self.exploration_rate.assign(tf.div(self.exploration_rate, 2))
return tf.select(tf.greater_equal(exploration_roll, self.exploration_rate),
tf.argmax(q_preds, 0), #greedy_action
tf.cast(tf.floor(tf.random_uniform([], maxval=4.0)), tf.int64)) #random_action
'''
Why does this return NoneType?:
flag = tf.select(tf.greater_equal(exploration_roll, self.exploration_rate), 'g', 'r')
if flag == 'g': #greedy
return tf.argmax(q_preds, 0) # gets the action with the highest predicted Q-value
elif flag == 'r': #random
return tf.cast(tf.floor(tf.random_uniform([], maxval=4.0)), tf.int64)
'''
def error(self, last_pred, r, next_pred):
with tf.name_scope('loss_function') as scope:
y = tf.add(r, tf.mul(self.discount_factor, next_pred)) #target
return tf.square(tf.sub(y, last_pred)) #squared difference error
def learn(self, loss): #Update parameters using stochastic gradient descent
#TODO: Either figure out how to avoid computing the q-prediction twice or just hardcode the gradients.
with tf.name_scope('train') as scope:
return tf.train.GradientDescentOptimizer(self.learning_rate).minimize(loss, var_list=[self.W[0], self.W[1], self.b[0], self.b[1]])
def max_q(self, q_preds):
with tf.name_scope('greedy_estimate') as scope:
return tf.reduce_max(q_preds) #best predicted action from current state
def act_to_pred(self, a, preds): #get the value prediction for action a
with tf.name_scope('get_prediction') as scope:
return tf.slice(preds, tf.reshape(a, shape=[1]), [1])
def agent_end(self,reward):
pass
def agent_cleanup(self):
self.sess.close()
pass
def agent_message(self,inMessage):
if inMessage=="what is your name?":
return "my name is simple_agent";
else:
return "I don't know how to respond to your message";
if __name__=="__main__":
AgentLoader.loadAgent(simple_agent())
Fatto un [problema github] (https://github.com/tensorflow/tensorflow/issues/672). –