EDIT (03.01.16): corresponding github issueJak korzystać z Optymalizatora Tensorflow bez ponownej obliczania aktywacji w programie uczenia zbrojenia, który zwraca kontrolę po każdej iteracji?
Używam Tensorflow (interfejs Python) wdrożenie Q-learning agenta z funkcji zbliżenia wyszkolonych za pomocą gradientu stochastycznego zejście. Przy każdej iteracji eksperymentu wywoływana jest funkcja krokowa w agencie, która aktualizuje parametry aproksymatora na podstawie nowej nagrody i aktywacji, a następnie wybiera nową akcję do wykonania.
Tutaj jest problem (z żargonu uczenia zbrojenie):
- Środek oblicza swoje prognozy wartość stanu działania, aby wybrać akcję.
- Następnie daje kontrolę nad innym programem symulującym krok w środowisku.
- Teraz funkcja kroku agenta jest wywoływana dla następnej iteracji. Chcę użyć klasy Optimizer firmy Tensorflow do obliczenia gradientów dla mnie. Wymaga to jednak zarówno prognoz wartości stanu działania, które obliczałem w ostatnim kroku, jak i ich wykresu. A więc:
- Po uruchomieniu optymalizatora na całym wykresie, należy ponownie przeliczyć prognozy wartości stanu.
- Ale jeśli przechowuję predykcję (dla wybranej akcji) jako zmienną, a następnie wprowadzam ją do optymalizatora jako symbolu zastępczego, nie ma on już wykresu niezbędnego do obliczenia gradientów.
- Nie mogę uruchomić tego wszystkiego w tym samym słowie sess.run(), ponieważ muszę zrezygnować z kontroli i zwrócić wybraną akcję, aby uzyskać następną obserwację i nagrodę (do wykorzystania w celu dla funkcja straty).
Więc, czy jest jakiś sposób, że mogę (bez zbrojenia uczenia żargonie):
- Compute część mojego wykresu, powracającego Value1.
- Zwróć wartość1 programowi wywołującemu, aby obliczyć wartość2
- W następnej iteracji użyj wartości 2 jako części funkcji utraty dla spadku gradientu BEZ przeliczania części wykresu, która oblicza wartość1.
Oczywiście, mam uznać oczywistych rozwiązań:
Wystarczy zakodować na gradienty: To byłoby łatwe dla bardzo prostych approximators używam teraz, ale byłoby bardzo niewygodne jeśli Eksperymentowałem z różnymi filtrami i funkcjami aktywacyjnymi w dużej splotowej sieci. Bardzo chciałbym użyć klasy Optimizer, jeśli to możliwe.
Zadzwoń do symulacji środowiska z poziomu agenta: This system robi to, ale to sprawiłoby, że moja praca byłaby bardziej skomplikowana, a także usunięto by modułowość i strukturę. Więc nie chcę tego robić.
Przeczytałem kilka razy API i dokumentację, ale nie mogę wymyślić rozwiązania. Próbowałem wymyślić jakiś sposób, aby nakierować cel na wykres, aby obliczyć gradienty, ale nie mógł wymyślić sposobu na automatyczne zbudowanie tego wykresu.
Jeśli okaże się, że w TensorFlow nie jest to jeszcze możliwe, czy uważa Pan/Pani, że wdrożenie tego jako nowego operatora byłoby bardzo skomplikowane? (Nie używałem C++ za parę lat, więc źródło TensorFlow wygląda trochę onieśmielająco.) A może lepiej byłoby przejść na coś takiego jak Latarka, które ma imperatywne zróżnicowanie Autogradu zamiast symbolicznego różnicowania?
Dzięki za poświęcenie czasu, aby mi pomóc w tej sprawie. Próbowałem uczynić to tak zwięzłym, jak tylko mogłem.
EDYCJA: Po wykonaniu dalszych poszukiwań natrafiłem na this previously asked question. Jest trochę inny niż mój (próbują uniknąć aktualizacji sieci LSTM dwa razy w każdej iteracji w Pochodni) i nie ma jeszcze żadnych odpowiedzi.
Oto niektóre kodu, jeśli pomaga:
'''
-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())
Made [github problem] (https://github.com/tensorflow/tensorflow/issues/672). –