计算机

深度 Q 网络

深度 Q 网络(Deep Q Network,DQN)是一种基于 Q-Learning 和深度学习的算法,是第一个深度强化学习(Deep Reinforcement Learning, DRL)的算法,于 2015 年提出。

动机

表格型强化学习存在的问题:

  • 维度灾难
  • 泛化性差。对于未探索过的状态—动作对,表格中的数值完全没有更新过,导致 agent 的表现很差。

原理

使用深度神经网络代替原本 Q-Learning 中的 Q 表,即称为深度 Q 网络。

下面介绍的这种方法直接将 Q-Learning 与深度学习结合,为了与其他优化的方法区分,称为 Classic DQN。

损失函数

用 DNN 代替表格后,关键在于如何更新神经网络。

由于 Q 表的更新公式是:

Q(s, a) \leftarrow Q(s, a) + \alpha\left[r + \gamma \max_{a' \in \mathcal{A}} Q(s', a') - Q(s, a)\right].

当算法接近收敛时,Q 表将几乎不再更新,代表 TD 误差 r_t + \gamma \max_{a' \in \mathcal{A}} Q(s', a') - Q(s, a) 一项接近于 0。

因此,可以想到将 Q 网络的损失直接定义为 TD 误差:

\sum_{i = 1}^N \left[ r_i + \gamma \max_{a' \in \mathcal{A}} Q(s'_i, a') - Q(s_i, a_i) \right]

上式可以视为 r_i + \gamma \max_{a' \in \mathcal{A}} Q(s'_i, a') 与 Q(s_i, a_i) 之间的均方误差。

Naive DQN

直接用上述损失函数,配合反向传播算法,代替 Q-Learning 中表格的参数更新步骤,得到的算法称为 Naive DQN。这种算法的训练过程非常不稳定,具体将在下文解释。

经验回放

Naive DQN 的训练样本不满足独立同分布。在一个 episode 中,上一步和下一步的相关性很强,导致训练不稳定。经验回放(experience replay)是一种解决样本不独立同分布的方法。

每次通过环境交互采样得到四元组 (s, a, r, s') 后,存入缓存 \mathcal{B},然后在训练时随机从缓存 \mathcal{B} 随机采样。

经验回放池的一种通常实现是:固定容量,当数据超过容量时,删除最旧的数据,再加入新数据。实现上,通常除了四元组 s, a, r, s' 还记录是否是终止状态(done)。以下是实现的代码:

class ReplayBuffer:
    def __init__(self, capacity):
        self.capacity = capacity
        self.buffer = deque(maxlen=capacity) # <- 使用 deque 实现快速删除

    def add(self, state, action, reward, next_state, done):
        if len(self.buffer) >= self.capacity:
            self.buffer.popleft()
        self.buffer.append((state, action, reward, next_state, done))

    def sample(self, batch_size):
        indices = np.random.choice(len(self.buffer), batch_size)
        batch = [self.buffer[i] for i in indices]
        return zip(*batch)

    def __len__(self):
        return len(self.buffer)
警告

经验回放池中,给定 s, a 后,r, s' 实际上都由环境模型决定,因此其中所有的数据都是“真实”数据,都可用于训练,并不需要在目标网络的参数更新后重新采样。

但是 s, a 的取值则与采样策略(如 \epsilon-greedy)有关,需要尽可能让网络接触“有价值”的数据。

目标网络

严格来说,Q 网络的损失函数并不是梯度下降方法。对于损失函数:

L =\sum_{i = 1}^N \left[ Q_{\theta} (s_i, a_i) - \left( r_i + \gamma \max_{a' \in \mathcal{A}} Q_{\theta} (s'_i, a') \right) \right],

当 Q 网络的参数 \theta 更新时,其拟合的目标 \max_{a' \in \mathcal{A}} Q(s'_i, a') 也在变动,导致训练很不稳定。

因此准备两套网络:实时更新的网络和目标网络,目标网络的结构与实时网络完全相同,只是使用了较旧的、固定的参数 \theta^-,因此记为 Q_{\theta^-}。目标网络用于计算损失函数的目标值,损失函数公式变为:

L =\sum_{i = 1}^N \left[ Q_{\theta} (s_i, a_i) - \left( r_i + \gamma \max_{a' \in \mathcal{A}} Q_{\theta^{-}} (s'_i, a') \right) \right]

目标网络的存在使得训练更加稳定。

DQN 的改进

Double DQN

在 Classic DQN 中,Q 值容易被过高估计(overestimation)。

使用两个 Q 网络,一个估计动作的价值,一个更新参数。具体地说,计算 Q 值和损失函数时,我们首先由当前的网络选出最优动作:

a^* = \arg \max_{a' \in \mathcal{A}} Q_{\theta} (s'_i, a');

然后再计算损失函数:

L =\sum_{i = 1}^N \left[ Q_{\theta} (s_i, a_i) - \left( r_i + \gamma Q_{\theta^{-}} (s'_i, a^*) \right) \right].

实际上这又产生了 Naive DQN 的训练不稳定问题,但实践证明,Double DQN 通常比标准DQN更稳定,性能也更好,因为它能得到更准确的价值估计。

Dueling DQN

优先经验回放

对具有较高 TD 误差的四元组 (s_i, a_i, r_i, s_i') 给予较高的优先级。

优缺点

DQN 通常仅用于具有离散动作的环境。

BEYOND THE ARTICLE

读完了,有什么想法?

阅读已保存的问答示例,并循着引用回到原文。

查看公开问答示例
— 本文完 — 返回文章列表