为什么我的DDQN在反复击败游戏后会变得更糟?

数据挖掘 Python 深度学习 强化学习 q学习 开放式健身房
2021-10-11 14:28:50

我一直在尝试训练一个 DDQN 来玩 OpenAI Gym 的 CartPole-v1,但发现虽然它开始很好并且开始反复获得满分(500)(在下图中大约 600 集),然后它似乎去了偏离轨道,玩得越多,做得越差。

变得好,然后变得非常糟糕的图表

我对 ML 还很陌生,所以我不确定是什么原因造成的,所以我不确定如何开始调试(我尝试过调整一些超参数,但似乎没有什么能阻止这种趋势)。

如果有帮助,这是我的代理的(可能)相关部分:

def _build_model(self):
    model = Sequential()
    model.add(Dense(24, input_dim=self.state_size, activation="relu"))
    model.add(Dense(24, activation="relu"))
    model.add(Dense(self.action_size, activation="linear"))
    model.compile(optimizer=Adam(lr=self.learning_rate), loss="mse")
    return model

def get_action(self, state):
    # Use random exploration for the current rate.
    if np.random.rand() < self.epsilon:
        return random.randrange(self.action_size)
    
    # Otherwise use the model to predict the rewards and select the max.
    q_values = self.model.predict(state)
    return np.argmax(q_values[0])

def replay(self, batch_size):
    if len(agent.memory) < minibatch_size:
        return
    
    # Decay the exploration rate.
    self.epsilon *= self.epsilon_decay
    self.epsilon = max(self.epsilon_min, self.epsilon)
        
    minibatch = random.sample(self.memory, minibatch_size)
    
    state_batch, q_values_batch = [], []
    for state, action, reward, next_state, done in minibatch:
        # Get predictions for all actions for the current state.
        q_values = self.model.predict(state)
        
        # If we're not done, add on the future predicted reward at the discounted rate.
        if done:
            q_values[0][action] = reward
        else:
            f = self.target_model.predict(next_state)
            future_reward = max(self.target_model.predict(next_state)[0])
            q_values[0][action] = reward + self.gamma * future_reward
        
        state_batch.append(state[0])
        q_values_batch.append(q_values[0])
        
    # Re-fit the model to move it closer to this newly calculated reward.
    self.model.fit(np.array(state_batch), np.array(q_values_batch), batch_size=batch_size, epochs=1, verbose=0)
       
    self.update_weights()
        
def update_weights(self):
    weights = self.model.get_weights()
    target_weights = self.target_model.get_weights()
    
    for i in range(len(target_weights)):
        target_weights[i] = weights[i] * self.tau + target_weights[i] * (1 - self.tau)
        
    self.target_model.set_weights(target_weights)

完整的笔记本在这里

1个回答

这被称为“灾难性遗忘”,在许多 RL 场景中可能是一个严重的问题。

如果你训练了一个神经网络来识别猫和狗并做了以下事情:

  • 在一个完整的数据集上训练它很多 epoch,直到你获得高准确度。

  • 继续训练它,但删除所有的猫图片。

然后在相对较短的时间内,NN 将开始失去准确性。它会忘记猫的样子。它会了解到它的任务是尽可能高地切换狗的预测,因为平均而言,训练人群中的所有东西都是狗。

在您的 DQN 体验重放记忆中会发生非常类似的事情。一旦它擅长一项任务,它可能只会获得成功。最终,只有成功的例子在它的记忆中。NN 忘记了失败是什么样子(状态是什么,以及它应该预测它们的值),并预测所有事物的高值。

当一些不好的事情发生并且 NN 的高预测值完全错误时,错误可能会很高,并且 NN 可能错误地“链接”了它的状态表示,因此它无法区分特征空间的哪些部分是造成这种情况的原因。就它对所有状态值的了解而言,这会产生奇怪的效果。NN 通常会在几集中表现不正确,但随后会重新学习最佳行为。但也有可能它完全破裂并且永远不会恢复。

有很多关于灾难性遗忘的积极研究,我建议您搜索该术语以找出您可以使用的多种缓解方法中的一些。

对于 Cartpole,我发现一个非常简单的 hack 使学习非常稳定。只需保留一定比例的回放内存,这些内存中存放着最初表现不佳的随机探索。为这个长期记忆保留 10% 就足以让 Cartpole 中的学习变得坚如磐​​石,因为 NN 总是有一些不该做什么的例子。不幸的是,这个想法不能很好地扩展到更复杂的环境,但它是一个很好的演示。要更深入地了解类似的解决方案,您可以查看论文“经验回放数据库组合在深度强化学习中的重要性