【问题标题】:Tensorflow reinforcement Learning Model will barely ever make a decision on its own and will not learn.TensorFlow 强化学习模型几乎不会自行做出决定,也不会学习。
【发布时间】:2018-07-30 01:52:48
【问题描述】:

我正在尝试创建一个可以购买、出售或持有股票头寸的强化学习代理。我遇到的问题是,即使经过 2000 多集,代理仍然无法知道何时买入、卖出或持有。这是第 2100 集中的一张图片,详细说明了我的意思,除非它是随机的,否则代理不会采取任何行动。 代理使用重放内存进行学习,我进行了两次和三次检查以确保没有错误。这是代理的代码: 将 numpy 导入为 np 将张量流导入为 tf 随机导入 从集合导入双端队列 从 .agent 导入代理

class Agent(Agent):
def __init__(self, state_size = 7, window_size = 1, action_size = 3, 
batch_size = 32, gamma=.95, epsilon=.95, epsilon_decay=.95, epsilon_min=.01, 
learning_rate=.001, is_eval=False, model_name="", stock_name="", episode=1):
    """
    state_size: Size of the state coming from the environment
    action_size: How many decisions the algo will make in the end
    gamma: Decay rate to discount future reward
    epsilon: Rate of randomly decided action
    epsilon_decay: Rate of decrease in epsilon
    epsilon_min: The lowest epsilon can get (limit to the randomness)
    learning_rate: Progress of neural net in each iteration
    episodes: How many times data will be run through
    """
    self.state_size = state_size
    self.window_size = window_size
    self.action_size = action_size
    self.batch_size = batch_size
    self.gamma = gamma
    self.epsilon = epsilon
    self.epsilon_decay = epsilon_decay
    self.epsilon_min = epsilon_min
    self.learning_rate = learning_rate
    self.is_eval = is_eval
    self.model_name = model_name
    self.stock_name = stock_name
    self.q_values = []

    self.layers = [150, 150, 150]
    tf.reset_default_graph()
    self.sess = tf.Session(config=tf.ConfigProto(allow_soft_placement = True))

    self.memory = deque()
    if self.is_eval:
        model_name = stock_name + "-" + str(episode)
        self._model_init()
        # "models/{}/{}/{}".format(stock_name, model_name, model_name + "-" + str(episode) + ".meta")
        self.saver = tf.train.Saver()
        self.saver.restore(self.sess, tf.train.latest_checkpoint("models/{}/{}".format(stock_name, model_name)))

        # self.graph = tf.get_default_graph()
        # names=[tensor.name for tensor in tf.get_default_graph().as_graph_def().node]
        # self.X_input = self.graph.get_tensor_by_name("Inputs/Inputs:0")
        # self.logits = self.graph.get_tensor_by_name("Output/Add:0")


    else:
        self._model_init()
        self.sess.run(self.init)
        self.saver = tf.train.Saver()
        path = "models/{}/6".format(self.stock_name)
        self.writer = tf.summary.FileWriter(path)
        self.writer.add_graph(self.sess.graph)

def _model_init(self):
    """
    Init tensorflow graph vars
    """
    # (1,10,9)
    with tf.device("/device:GPU:0"):

        with tf.name_scope("Inputs"):
            self.X_input = tf.placeholder(tf.float32, [None, self.state_size], name="Inputs")
            self.Y_input = tf.placeholder(tf.float32, [None, self.action_size], name="Actions")
            self.rewards = tf.placeholder(tf.float32, [None, ], name="Rewards")

        # self.lstm_cells = [tf.contrib.rnn.GRUCell(num_units=layer)
        #             for layer in self.layers]

        #lstm_cell = tf.contrib.rnn.LSTMCell(num_units=n_neurons, use_peepholes=True)
        #gru_cell = tf.contrib.rnn.GRUCell(num_units=n_neurons)

        # self.multi_cell = tf.contrib.rnn.MultiRNNCell(self.lstm_cells)
        # self.outputs, self.states = tf.nn.dynamic_rnn(self.multi_cell, self.X_input, dtype=tf.float32)

        # self.top_layer_h_state = self.states[-1]

        # with tf.name_scope("Output"):
        #     self.out_weights=tf.Variable(tf.truncated_normal([self.layers[-1], self.action_size]))
        #     self.out_bias=tf.Variable(tf.zeros([self.action_size]))
        #     self.logits = tf.add(tf.matmul(self.top_layer_h_state,self.out_weights), self.out_bias)

        fc1 = tf.contrib.layers.fully_connected(self.X_input, 512, activation_fn=tf.nn.relu)
        fc2 = tf.contrib.layers.fully_connected(fc1, 512, activation_fn=tf.nn.relu)
        fc3 = tf.contrib.layers.fully_connected(fc2, 512, activation_fn=tf.nn.relu)
        fc4 = tf.contrib.layers.fully_connected(fc3, 512, activation_fn=tf.nn.relu)
        self.logits = tf.contrib.layers.fully_connected(fc4, self.action_size, activation_fn=None)

        with tf.name_scope("Cross_Entropy"):
            self.loss_op = tf.losses.mean_squared_error(self.Y_input,self.logits)
            self.optimizer = tf.train.RMSPropOptimizer(learning_rate=self.learning_rate)
            self.train_op = self.optimizer.minimize(self.loss_op)
        # self.correct = tf.nn.in_top_k(self.logits, self.Y_input, 1)

        # self.accuracy = tf.reduce_mean(tf.cast(self., tf.float32))
        tf.summary.scalar("Reward", tf.reduce_mean(self.rewards))
        tf.summary.scalar("MSE", self.loss_op)
        # Merge all of the summaries
        self.summ = tf.summary.merge_all()
        self.init = tf.global_variables_initializer()

def remember(self, state, action, reward, next_state, done):
    self.memory.append((state, action, reward, next_state, done))

def act(self, state):
    if np.random.rand() <= self.epsilon and not self.is_eval:
        prediction = random.randrange(self.action_size)
        if prediction == 1 or prediction == 2:
            print("Random")
        return prediction

    act_values = self.sess.run(self.logits, feed_dict={self.X_input: state.reshape((1, self.state_size))})
    if np.argmax(act_values[0]) == 1 or np.argmax(act_values[0]) == 2:
        pass
    return np.argmax(act_values[0])

def replay(self, time, episode):
    print("Replaying")
    mini_batch = []
    l = len(self.memory)
    for i in range(l - self.batch_size + 1, l):
        mini_batch.append(self.memory[i])

    mean_reward = []
    x = np.zeros((self.batch_size, self.state_size))
    y = np.zeros((self.batch_size, self.action_size))
    for i, (state, action, reward, next_state, done) in enumerate(mini_batch):
        target = reward
        if not done:
            self.target = reward + self.gamma * np.amax(self.sess.run(self.logits, feed_dict = {self.X_input: next_state.reshape((1, self.state_size))})[0])
        current_q = (self.sess.run(self.logits, feed_dict={self.X_input: state.reshape((1, self.state_size))}))

        current_q[0][action] = self.target
        x[i] = state
        y[i] = current_q.reshape((self.action_size))
        mean_reward.append(self.target)

    #target_f = np.array(target_f).reshape(self.batch_size - 1, self.action_size)
    #target_state = np.array(target_state).reshape(self.batch_size - 1, self.window_size, self.state_size)
    _, c, s = self.sess.run([self.train_op, self.loss_op, self.summ], feed_dict={self.X_input: x, self.Y_input: y, self.rewards: mean_reward}) # Add self.summ into the sess.run for tensorboard
    self.writer.add_summary(s, global_step=(episode+1)/(time+1))

    if self.epsilon > self.epsilon_min:
        self.epsilon *= self.epsilon_decay 

一旦重放内存大于批量大小,它就会运行重放功能。代码可能看起来有点乱,因为我已经搞砸了好几天,现在试图弄清楚这一点。这是来自 tensorboard 的 MSE 的屏幕截图。 正如您在第 200 集看到的那样,MSE 消失为 0 或几乎为 0。我被难住了!我不知道发生了什么。请帮我解决这个问题。代码发布在here 以查看整个内容,包括火车和评估文件。我一直在研究的主要代理是代理文件夹中的 LSTM.py。谢谢!

【问题讨论】:

  • 我很确定你的 epsilon_decay 设置得太低了。仅经过几次迭代后,您的值将几乎为零(例如,尝试 0.95^40,大约为 0.12)。因此,仅在 40 个 epoch 之后,您就几乎不再进行任何随机预测。尝试将其设置为更高的值,并查看报告值是否确实发生了更显着的变化。
  • 听起来不错,我试试看会发生什么。
  • 我不确定这段代码是什么意思:如果 prediction == 1 or prediction == 2: print("Random") return prediction
  • 这只是为了让我可以看到预测是随机的还是由网络做出的。 @dennlinger 我提高了 epsilon 衰减,现在已经运行了 1 天,它似乎运行良好。网络已经开始自己做出决定,也开始做出好的决定。谢谢!
  • 我会添加一个答案,可能会提供更多关于衰变的细节,这样我们就可以在这篇文章中得到一个可以接受的答案。

标签: python tensorflow deep-learning reinforcement-learning q-learning


【解决方案1】:

正如问题的 cmets 中所讨论的,这似乎是高学习率衰减的问题。

基本上,对于每一集,您将学习率乘以某个因子 j,这意味着在 n 集/时期之后您的学习率将等于
lr = initial_lr * j^n。在我们的示例中,衰减设置为 0.95,这意味着仅经过几次迭代,学习率就已经显着下降。随后,更新将仅执行微小的更正,不再“学习”非常重要的更改。

这就引出了一个问题:为什么衰变是有意义的?一般来说,我们希望达到局部最优(可能非常窄)。为此,我们尝试“相对接近”这样一个最小值,然后只做更小的增量来引导我们达到这个最优值。如果我们只是继续原来的学习率,可能是我们每次都只是简单地跨过最优解,而永远达不到我们的目标。 从视觉上看,这个问题可以用这张图来概括:

除了衰减之外的另一种方法是在算法不再达到任何重要更新时简单地将学习率降低一定量。这避免了纯粹因为有很多情节而降低学习率的问题。

具体而言,就您而言,较高的衰减值(即较慢的衰减)似乎已经有很大帮助。

【讨论】:

    【解决方案2】:

    强化学习中的 Q 值不代表“奖励”,而是“回报”,即当前奖励和折扣未来奖励的总和。当您的模型进入所有零动作的“死胡同”时,根据您的设置,奖励将为零。然后一段时间后,你的回放会充满“零动作奖励零”的记忆,所以无论你如何更新你的模型,它都无法走出这个死胡同。

    正如@dennlinger 所说,您可以增加您的 epsilon 以让您的模型有一些新鲜的记忆需要更新,您也可以使用优先体验重播来训练“有用”的体验。

    不过,我建议你先看的是环境本身。您的模型输出为零,因为没有更好的选择,这是真的吗?正如你所说的你在交易股票,你确定有足够的信息可以引导你获得大于零的回报的策略吗?我认为在对此进行任何调整之前,您需要先考虑一下。例如,如果股票以纯随机 50/50 的机会上下波动,那么您将永远找不到使平均回​​报大于零的策略。

    强化学习代理可能已经找到了最好的,尽管它不是你想要的。

    【讨论】:

      最近更新 更多