2613 words
13 minutes
强化学习 Chapter 5 - 基于价值的深度强化学习
首次发布: 2025-04-19
... 次访问

5.1 价值函数近似#

5.1.1 问题背景#

对于状态空间与动作空间均规模较小且离散的有限型问题,我们可以创建一个查询表,在表中维护价值函数,从而用于求解问题。这类问题也被称作表格型问题。但是,当问题规模变大,或者说成为连续型问题时,维护表格的方法就不合适了。例如,下围棋和自动驾驶汽车,一个是超大的状态空间,一个是连续的状态空间,显然不适合使用表格处理。

一个可行的方法是使用参数化的方式来近似价值函数 Vθ(s),Qθ(s,a)V_\theta(s), Q_\theta(s, a),其中 θ\theta 是可学习的参数,用强化学习的方法进行更新。显然,可以使用深度神经网络的方法作为价值函数的近似。这个想法解决了状态空间或动作空间规模过大的问题,适用于离散型或连续型问题

对于连续型问题,状态或动作可以用特征向量表示 s=[s1,s2,],a=[a1,a2,]\mathbf{s} = [s_1, s_2, \dots]^\top, \mathbf{a} = [a_1, a_2, \dots]^\top

5.1.2 梯度下降法更新参数实现策略评估#

类似深度学习,可以使用随机梯度下降法 (SGD) 来更新价值函数。目标是找到能最小化损失函数的参数 θ\theta

minθJ(θ)=Eπ[12(Vπ(s)Vθ(s))2]\min_\theta J(\theta) = \mathbb{E}_\pi\left[\frac{1}{2}(V_\pi(s) - V_\theta(s))^2 \right]

更新公式为

θθαJ(θ)θ=θ+αEπ[(Vπ(s)Vθ(s))Vθ(s)θ]\theta \leftarrow \theta - \alpha \frac{\partial J(\theta)}{\partial \theta} = \theta + \alpha \mathbb{E}_\pi\left[(V_\pi(s) - V_\theta(s)) \frac{\partial V_\theta(s)}{\partial \theta}\right]

具体的更新方式类似深度学习,用数据样本去预测全局真实梯度,进行更新。

θθαJ^(θ)θ=θ+α1Ni=1N(Vπ(si)Vθ(si))Vθ(si)θ\theta \leftarrow \theta - \alpha \frac{\partial \hat{J}(\theta)}{\partial \theta} = \theta + \alpha \frac{1}{N}\sum_{i=1}^N(V_\pi(s_i) - V_\theta(s_i)) \frac{\partial V_\theta(s_i)}{\partial \theta}

但是,强化学习中,Vπ(s)V_\pi(s) 是未知的,因此需要使用 MC 方法或 TD 方法来估计 Vπ(s)V_\pi(s)。实际上,类似策略评价算法,这里真实的 Vπ(s)V_\pi(s) 就用 r+γVθ(s)r + \gamma V_\theta(s') (TD) 或 GtG_t (MC) 替代了。

  • TD 更新
θθ+α(r+γVθ(s)Vθ(s))Vθ(s)θ\theta \leftarrow \theta + \alpha \left(r + \gamma V_\theta(s') - V_\theta(s)\right) \frac{\partial V_\theta(s)}{\partial \theta}
  • MC 更新
θθ+α(rt+γrt+1+γ2rt+2+Vθ(s))Vθ(s)θ\theta \leftarrow \theta + \alpha \left(r_t + \gamma r_{t+1} + \gamma^2 r_{t+2} + \cdots - V_\theta(s)\right) \frac{\partial V_\theta(s)}{\partial \theta}

类似地,有动作价值函数的近似和更新(以 SARSA 为例)

Qθ(s,a)Qθ(s,a)+α(r+γQθ(s,a)Qθ(s,a))Qθ(s,a)θQ_\theta(s, a) \leftarrow Q_\theta(s, a) + \alpha \left(r + \gamma Q_\theta(s', a') - Q_\theta(s, a)\right) \frac{\partial Q_\theta(s, a)}{\partial \theta}

可以看出,这里是使用了深度学习的方式来近似价值函数,但是策略的更新仍然是前面的方法。例如,使用贪心策略,可以不用显式地维护一个策略函数,直接用动作价值函数即可实现智能体的控制等任务。当然也可以用神经网络去拟合一个策略函数 πθ(as)\pi_\theta(a|s),然后使用策略梯度方法来更新参数,这在后面会介绍。

需要注意的一点是,参数近似方法和表格型方法的一大不同在于,在表格型方法中,更新了某个状态的价值函数是不会影响和改变其他状态的价值函数的,而在参数近似方法中,更新了某个状态的价值函数会影响到其他状态的价值函数,因为参数是共享的。

5.2 深度 Q 网络 (DQN)#

深度 Q 网络 (DQN) 是一种基于深度学习的强化学习方法,使用深度神经网络来近似动作价值函数 Q(s,a)Q(s, a)。DQN 的基本思想是使用深度神经网络来处理高维状态空间,并通过经验回放和目标网络等技术来提高训练的稳定性和效率。

本质的强化学习方法还是 Q 学习,只是用深度神经网络来近似动作价值函数 Q(s,a)Q(s, a)

5.2.1 经验回放 (Experience Replay)#

经验回放是 DQN 中的一个重要技术,它通过将智能体在环境中经历的状态、动作、奖励和下一个状态存储在一个经验池中,然后从中随机抽取小批量的经验进行训练。这样做的好处是可以打破数据之间的相关性,提高训练的稳定性和效率。

打破数据的相关性是因为,强化学习中,数据是时序相关的,st,ats_t, a_tst+1,at+1,st+2,at+2s_{t+1}, a_{t+1}, s_{t+2}, a_{t+2} 有关,直接使用会导致数据之间的相关性很强,导致训练不稳定。经验回放可以将数据存储在一个经验池中,然后随机抽取小批量的数据进行训练,这样就可以打破数据之间的相关性。

经验回放池(replay buffer)中存放的是一个个的状态转移信息例如 (st,at,rt,st+1)(s_t, a_t, r_t, s_{t+1}),具体实现方式是使用一个 FIFO 队列来存储经验,当经验池满了之后,新的经验会覆盖最旧的经验。通常经验池的大小设置为 10510610^5 \sim 10^6

在训练时,从经验池中随机抽取小批量的经验进行训练,例如 3232 个经验来训练 Q 网络。

实现经验回放池#

class ReplayBuffer:
    def __init__(self, capacity):
        self.buffer = collections.deque(maxlen=capacity)

    def add(self, state, action, reward, next_state, done):
        self.buffer.append((state, action, reward, next_state, done))

    def sample(self, batch_size):
        transitions = random.sample(self.buffer, batch_size)
        state, action, reward, next_state, done = zip(*transitions) # 注意是有batch的,不可以直接展开
        return np.array(state), action, reward, np.array(next_state), done
    
    def size(self):
        return len(self.buffer)
    
    def clear(self):
        self.buffer.clear()

优先经验回放#

并非所有的经验都同样重要,可以用 TD 误差来衡量重要性。

pt=δt=rt+γmaxaQ(st+1,a)Q(st,at)p_t = |\delta_t| = |r_t + \gamma \max_{a'} Q(s_{t+1}, a') - Q(s_t, a_t) |

然后用概率采样的方式来选择经验进行训练。

5.2.2 目标网络#

Q-Learning类算法大部分都存最大化偏差问题。偏差的存在并不是一定是有害的,如果偏差是均匀的,即对所有的状态-动作的估计都有相同的偏差,那么就相当于给价值函数加上了常数,并不会影响策略选择动作。但是,通常偏差并不是均匀的,这对学习而言是有影响的。

可以使用目标网络来解决这个问题。目标网络是一个与 Q 网络结构相同的神经网络,但是参数是固定的,通常每隔 CC 步更新一次,更新的方式就是把 Q 网络的参数复制到目标网络中。因为维护了两个 Q 网络,因此叫 Double-DQN。设目标网络的参数为 θ\theta^-, Q 网络的参数为 θ\theta,则每隔 CC 步更新一次目标网络的参数为

θθ (直接覆盖)或者θτθ+(1τ)θ (软更新)\begin{align*} \theta^- \leftarrow \theta \text{ \quad (直接覆盖)} \\ \text{或者} \quad \theta^- \leftarrow \tau \theta + (1 - \tau) \theta^- \text{ \quad (软更新)} \\ \end{align*}

此外,在每个时间步中,使用 Q 网络来控制智能体和收集经验,但是使用目标网络来计算 TD 目标,更新 Q 网络的参数。

yt=rt+γmaxaQθ(st+1,a)θθ+α(ytQθ(st,at))Qθ(st,at)θ更新目标网络,则θθ\begin{align*} y_t &= r_t + \gamma \max_{a'} Q_{\theta^-}(s_{t+1}, a') \\ \theta &\leftarrow \theta + \alpha \left(y_t - Q_\theta(s_t, a_t)\right) \frac{\partial Q_\theta(s_t, a_t)}{\partial \theta} \\ \text{若} &\text{更新目标网络,则} \quad \theta^- \leftarrow \theta \end{align*}

5.2.3 Double DQN#

类似使用目标网络的 DQN,不过这里的更新公式有些变化

yt=rt+γQθ(st+1,argmaxaQθ(st+1,a))θθ+α(ytQθ(st,at))Qθ(st,at)θ更新目标网络,则θθ\begin{align*} y_t &= r_t + \gamma Q_{\theta^-}(s_{t+1}, \arg\max_{a'} Q_{\theta}(s_{t+1}, a')) \\ \theta &\leftarrow \theta + \alpha \left(y_t - Q_\theta(s_t, a_t)\right) \frac{\partial Q_\theta(s_t, a_t)}{\partial \theta} \\ \text{若} &\text{更新目标网络,则} \quad \theta^- \leftarrow \theta \end{align*}

具体算法流程为

  1. 收集数据,使用 Q 网络来控制智能体,存储经验到经验池中。
  2. 采样经验池中的小批量数据
  3. 更新网络,计算 TD 目标,使用目标网络来计算 TD 目标,更新 Q 网络的参数。
  4. 每隔 CC 步更新目标网络的参数。

使用目标网络的方法可以有效地减少最大化偏差问题,提高训练的稳定性和效率,但是仍然不能完全消除最大化偏差问题。

Double DQN 算法

Input:经验池容量 NN,小批量大小 BB,折扣因子 γ\gamma,学习率 α\alpha,目标网络更新频率 CC,探索率 ϵ\epsilon
Output:训练好的 Q 网络参数 θ\theta
1:初始化:评估网络参数 θ\theta、目标网络参数 θ=θ\theta^-=\theta、经验池 D\mathcal{D}
2:对每个回合循环:
3:  初始化状态 s0s_0
4:  对每个时间步 tt 循环:
5:    以概率 ϵ\epsilon 随机选择动作 ata_t,否则 at=argmaxaQθ(st,a)a_t = \arg\max_a Q_\theta(s_t, a)
6:    执行动作 ata_t,观察奖励 rtr_t 和下一个状态 st+1s_{t+1}
7:    将经验 (st,at,rt,st+1)(s_t, a_t, r_t, s_{t+1}) 存入经验池 D\mathcal{D}
8:    从 D\mathcal{D} 中随机采样大小为 BB 的小批量数据
9:    对批量中的每个样本 (si,ai,ri,si+1)(s_i, a_i, r_i, s_{i+1}) 执行:
10:      最优动作选择:a=argmaxaQθ(si+1,a)a^* = \arg\max_a Q_\theta(s_{i+1}, a)
11:      计算目标:yi=ri+γQθ(si+1,a)y_i = r_i + \gamma Q_{\theta^-}(s_{i+1}, a^*)
12:    计算损失:L=1Bi(yiQθ(si,ai))2L = \frac{1}{B}\sum_i (y_i - Q_\theta(s_i, a_i))^2
13:    使用梯度下降更新 θ\thetaθθαθL\theta \leftarrow \theta - \alpha \nabla_\theta L
14:    每 CC 步更新目标网络:θθ\theta^- \leftarrow \theta
15:    若 st+1s_{t+1} 为终止状态,结束当前回合
16:  结束循环
17:结束循环

需要注意的是 Double-DQN 与 Double Q-Learning 是不同的!Double-DQN 中两个 Q 网络更新速度快慢不同,而 Double Q-Learning 中是随机选择两个 Q 表格中的一个用于计算 TD 目标,然后更新另一个 Q 表格,更新速度是相同的。

5.2.4 Dueling DQN (对抗 DQN)#

Dueling DQN 是另一种改进的 DQN 方法,它通过将 Q 函数分解为两个部分来提高训练的效率和稳定性。由于动作价值函数 Q(s,a)Q(s, a) 的均值是状态 ss 处的状态价值函数 V(s)V(s),因此考虑将动作价值函数进行分解

Q(s,a)=V(s)+A(s,a)Q(s, a) = V(s) + A(s, a)

其中 V(s)V(s) 是状态价值函数,是动作价值函数的均值;A(s,a)A(s, a) 是优势函数,表示在状态 ss 下,动作 aa 的优势。

此外,对于最优策略,优势函数 A(s,a)A(s, a) 的均值为 00,即 1AaA(s,a)=0\frac{1}{|A|}\sum_a A(s, a) = 0。 因此可以将优势函数进行归一化处理,得到最终的 Q 函数

Q(s,a)=V(s)+A(s,a)maxaA(s,a)Q(s, a) = V(s) + A(s, a) - \max_{a'} A(s, a')

于是 Q 网络可以用两个神经网络来实现,一个用于计算状态价值函数 Vθ(s)V_\theta(s),另一个用于计算优势函数 Aϕ(s,a)A_\phi(s, a)

  1. 为什么要分离 V(s)V(s)A(s,a)A(s, a) 呢?因为在训练时,状态价值函数 V(s)V(s) 是相对稳定的,而优势函数 A(s,a)A(s, a) 是相对不稳定的,将它们分开训练,可以提高训练的效率和稳定性。
  2. 为什么要减去 maxaA(s,a)\max_{a'} A(s, a') 呢?因为这样可以使得优势函数的均值为 00,从而保证 Q 函数的均值为状态价值函数 V(s)V(s)
强化学习 Chapter 5 - 基于价值的深度强化学习
https://adalovelemon.github.io/blog/en/posts/content/coursenotes/reinforcementlearning/basicrl/chapter5/
Author
Ada Lovelemon
Published at
2025-04-19

Comments Section