从Q-learning到DQN:小车倒立摆的智能控制进阶

文章目录

    • [1. 问题从哪里开始:智能体怎样学会做决定?](#1. 问题从哪里开始:智能体怎样学会做决定?)
      • [1.1 先约定状态和动作](#1.1 先约定状态和动作)
      • [1.2 倒立摆为什么会自己倒下?](#1.2 倒立摆为什么会自己倒下?)
      • [1.3 控制器究竟在做什么?](#1.3 控制器究竟在做什么?)
      • [1.4 用奖励函数告诉智能体什么叫"控制得好"](#1.4 用奖励函数告诉智能体什么叫“控制得好”)
      • [1.5 先分清两个"优化目标":控制目标与训练目标](#1.5 先分清两个“优化目标”:控制目标与训练目标)
    • [2. Q 值:给每个"状态---动作"组合打分](#2. Q 值:给每个“状态—动作”组合打分)
    • [3. Q-learning:一边试错,一边修改行动指南](#3. Q-learning:一边试错,一边修改行动指南)
      • [3.1 TD 目标与 TD 误差](#3.1 TD 目标与 TD 误差)
      • [3.2 为什么叫"时序差分":它站在蒙特卡洛与动态规划之间](#3.2 为什么叫“时序差分”:它站在蒙特卡洛与动态规划之间)
      • [3.3 探索与利用:为什么不能永远选当前最优动作?](#3.3 探索与利用:为什么不能永远选当前最优动作?)
      • [3.4 Sarsa 与 Q-learning:下一步按"实际行动"算,还是按"最佳行动"算?](#3.4 Sarsa 与 Q-learning:下一步按“实际行动”算,还是按“最佳行动”算?)
      • [3.5 为什么 Q-learning 是离策略算法?](#3.5 为什么 Q-learning 是离策略算法?)
    • [4. 一张 Q 表是怎样学会控制的?](#4. 一张 Q 表是怎样学会控制的?)
      • [4.1 表格 Q-learning 为什么有机会收敛?](#4.1 表格 Q-learning 为什么有机会收敛?)
    • [5. Q-learning 的"表格墙"](#5. Q-learning 的“表格墙”)
    • [6. 函数近似:从背答案到学规律](#6. 函数近似:从背答案到学规律)
    • [7. 朴素神经网络 Q-learning 为什么不稳定?](#7. 朴素神经网络 Q-learning 为什么不稳定?)
    • [8. DQN 的第一块稳定器:经验回放](#8. DQN 的第一块稳定器:经验回放)
    • [9. DQN 的第二块稳定器:目标网络](#9. DQN 的第二块稳定器:目标网络)
      • [9.1 一批倒立摆经验,怎样变成神经网络的训练标签?](#9.1 一批倒立摆经验,怎样变成神经网络的训练标签?)
    • [10. 从 Q-learning 到 DQN,究竟变了什么?](#10. 从 Q-learning 到 DQN,究竟变了什么?)
    • [11. DQN 完整训练流程](#11. DQN 完整训练流程)
    • [12. 第一处改进:Double DQN 怎样给"最优动作"降温?](#12. 第一处改进:Double DQN 怎样给“最优动作”降温?)
      • [12.1 DDQN 的做法:一套网络选动作,另一套网络复核](#12.1 DDQN 的做法:一套网络选动作,另一套网络复核)
      • [12.2 DDQN 怎样构造标签并更新网络?](#12.2 DDQN 怎样构造标签并更新网络?)
    • [13. 第二处改进:Dueling DQN 怎样区分"状态好"与"动作好"?](#13. 第二处改进:Dueling DQN 怎样区分“状态好”与“动作好”?)
      • [13.1 一张网络,分成两条价值流](#13.1 一张网络,分成两条价值流)
      • [13.2 Dueling 网络怎样前向传播和反向更新?](#13.2 Dueling 网络怎样前向传播和反向更新?)
      • [13.3 用数字感受"状态好"与"动作好"](#13.3 用数字感受“状态好”与“动作好”)
    • [14. DDQN 与 Dueling DQN 能一起用吗?](#14. DDQN 与 Dueling DQN 能一起用吗?)
      • [14.1 回到小车:四种算法究竟各自在优化什么?](#14.1 回到小车:四种算法究竟各自在优化什么?)
    • [15. 它们仍然保留哪些边界?](#15. 它们仍然保留哪些边界?)
    • [16. 三个常见误区](#16. 三个常见误区)
    • [17. 最后一幅图:小车倒立摆控制器如何一步步升级](#17. 最后一幅图:小车倒立摆控制器如何一步步升级)
    • 参考资料

想象一辆只能沿水平轨道左右移动的小车,车顶用铰链连着一根细杆。控制器不能直接扶杆,只能左右推车,让支点追到杆的下方。Q-learning、DQN、Double DQN 和 Dueling DQN,就像这位控制器在一次次倒杆之后学会的四代本领。

本文始终跟随这套小车倒立摆。读到每个新算法时,我们先看控制器碰到了什么麻烦,再看新算法如何替它解围。

理论主线以《动手学强化学习》第 5、7、8 章为准:先从时序差分与 Q-learning 出发,再沿着函数近似、经验回放和目标网络进入 DQN,最后讨论 Double DQN 与 Dueling DQN。为便于形成完整直觉,书中的公式与结论会结合小车倒立摆重新推演,而不是脱离案例逐条摘录。

1. 问题从哪里开始:智能体怎样学会做决定?

小车倒立摆由小车、水平轨道和铰接在小车上的杆组成。普通钟摆自然垂在下方,偏离后还会被重力拉回;倒立摆却要停在正上方,任何微小扰动都会让它继续倒下。控制器必须不断移动小车,把支点送到杆的下方,因此这是控制理论与强化学习中很经典的入门任务。

图 1 小车倒立摆的结构与控制量。

图中编号含义如下:

  1. 小车的平移状态 : x x x 表示小车在轨道上的位置, x ˙ \dot x x˙ 表示小车速度;水平箭头的正方向指向右侧。
  2. 摆杆角度 : θ \theta θ 表示摆杆相对竖直方向的偏角,图中展示的是向右倾斜的状态。
  3. 摆杆角速度 : θ ˙ \dot\theta θ˙ 表示角度变化的方向与快慢,弧形箭头表示当前旋转方向。
  4. 控制动作:左右两个橙色箭头表示施加在小车上的水平力,分别对应"向左推车"和"向右推车"两个离散动作。

1.1 先约定状态和动作

本文采用下面的符号:

  • x x x:小车在轨道上的位置;
  • x ˙ \dot x x˙:小车速度;
  • θ \theta θ:杆偏离竖直方向的角度, θ = 0 \theta=0 θ=0 表示竖直向上;
  • θ ˙ \dot\theta θ˙:杆的角速度;
  • F F F:施加在小车上的水平力,正负号表示向右或向左。

因此,控制器看到的状态是一个四维向量:

s = ( x , x ˙ , θ , θ ˙ ) s=(x,\dot x,\theta,\dot\theta) s=(x,x˙,θ,θ˙)

只知道杆向哪边倾还不够:同样是向右倾,杆可能正在倒向右侧,也可能刚被小车追上、正在向左回正;同样是杆接近竖直,小车可能已冲向轨道边界。位置和速度共同决定了下一步应向哪边推车,这也是状态必须包含四个量的原因。

经典 CartPole 环境本身就提供两个离散动作:

A = { 向左推车 , 向右推车 } \mathcal A=\{\text{向左推车},\text{向右推车}\} A={向左推车,向右推车}

动作施加的是大小固定、方向相反的水平力。它天然适合 Q-learning 和 DQN:网络只需为两个动作分别输出一个 Q 值,再选择较大的那个。

1.2 倒立摆为什么会自己倒下?

设小车质量为 M M M,杆质量为 m m m,铰链到杆质心的距离为 l l l,重力加速度为 g g g。杆与小车互相耦合:推车不只改变 x x x,也会通过铰链改变 θ \theta θ;杆的倾斜和转动反过来又影响小车加速度。

忽略摩擦并采用经典 CartPole 模型时,可以先定义一个中间量:

T = F + m l θ ˙ 2 sin ⁡ θ M + m T=\frac{F+ml\dot\theta^2\sin\theta}{M+m} T=M+mF+mlθ˙2sinθ

这里约定 θ = 0 \theta=0 θ=0 表示杆竖直向上,角度正方向与图 1 保持一致;若换用其他角度方向,方程中的部分符号也会随之改变。上述形式与经典 CartPole 仿真使用的动力学约定一致。

然后得到杆的角加速度和小车加速度:

θ ¨ = g sin ⁡ θ − cos ⁡ θ   T l ( 4 3 − m cos ⁡ 2 θ M + m ) , x ¨ = T − m l θ ¨ cos ⁡ θ M + m . \begin{aligned} \ddot\theta &=\frac{g\sin\theta-\cos\theta\,T} {l\left(\frac{4}{3}-\frac{m\cos^2\theta}{M+m}\right)},\\ \ddot x &=T-\frac{ml\ddot\theta\cos\theta}{M+m}. \end{aligned} θ¨x¨=l(34−M+mmcos2θ)gsinθ−cosθT,=T−M+mmlθ¨cosθ.

这些方程透露了一个很直观的控制原则:杆向右倾时,通常要把小车向右推,让支点跑到杆的下方;但若小车已经高速向右或快到轨道边界,控制器又必须提前减速。正确动作取决于四个状态量的组合,而非只看倾斜方向。

当杆只偏离竖直位置一个很小的角度时, sin ⁡ θ ≈ θ \sin\theta\approx\theta sinθ≈θ、 cos ⁡ θ ≈ 1 \cos\theta\approx1 cosθ≈1。重力仍会放大倾斜,所以竖直向上是一个开环不稳定平衡点。控制器必须不断观察和纠偏;稍晚一步,小角度偏差就可能迅速发展成倒杆。

仿真器按照一个很小的时间间隔 Δ t \Delta t Δt 更新状态,例如:

x t + 1 = x t + Δ t   x ˙ t , x ˙ t + 1 = x ˙ t + Δ t   x ¨ t , θ t + 1 = θ t + Δ t   θ ˙ t , θ ˙ t + 1 = θ ˙ t + Δ t   θ ¨ t . \begin{aligned} x_{t+1}&=x_t+\Delta t\,\dot x_t,\\ \dot x_{t+1}&=\dot x_t+\Delta t\,\ddot x_t,\\ \theta_{t+1}&=\theta_t+\Delta t\,\dot\theta_t,\\ \dot\theta_{t+1}&=\dot\theta_t+\Delta t\,\ddot\theta_t. \end{aligned} xt+1x˙t+1θt+1θ˙t+1=xt+Δtx˙t,=x˙t+Δtx¨t,=θt+Δtθ˙t,=θ˙t+Δtθ¨t.

强化学习算法通常不需要显式知道这些方程。它只观察执行动作 a t a_t at 后得到的 ( r t , s t + 1 ) (r_t,s_{t+1}) (rt,st+1),再从大量交互中反推怎样控制更好。这正是"无模型"一词的含义。

1.3 控制器究竟在做什么?

经典 CartPole 通常从接近竖直的状态开始,任务不是把下垂的杆摆起来,而是尽可能长时间地保持平衡。每一步都在同时处理三个目标:

  1. 追杆:杆向哪边倾,小车就要及时向哪边移动,让支点回到杆的下方;
  2. 刹车:小车不能只顾追杆,否则速度越来越大,很快就会冲出轨道;
  3. 留出空间:即使杆暂时竖直,也要避免小车长期偏在轨道一侧,否则下一次纠偏将没有余量。

图 2 小车倒立摆的连续纠偏。A:杆向左倾,小车向左追赶;B:杆接近竖直,小车需要减小速度并回到轨道中部;C:杆向右倾,小车向右追赶。实际动作还必须结合小车速度和角速度判断。

1.4 用奖励函数告诉智能体什么叫"控制得好"

经典 CartPole 的奖励设计很简单:每执行一步获得 + 1 +1 +1,因此未折扣累计奖励可以直接表示坚持了多少步。常见终止条件包括杆倾角超过约 12 ∘ 12^\circ 12∘,或小车位置越过轨道允许范围;达到时间上限通常属于截断,而不是倒杆或越界造成的环境终止。Gymnasium 的 CartPole 文档给出了当前环境定义。

这种"存活奖励"没有直接告诉控制器应该向哪边推车,只说明"多坚持一会儿就是好"。动作规律必须由智能体从失败与成功的轨迹中自行发现。动力学决定"动作会发生什么",奖励函数决定"哪些结果值得追求"。

1.5 先分清两个"优化目标":控制目标与训练目标

这是理解后续四种算法最关键的一步。

第一层是小车任务的控制目标 :智能体希望找到策略 π \pi π,让期望累计折扣奖励最大:

J ( π ) = E π ∑ k = 0 ∞ γ k r t + k J(\pi)=\mathbb E_{\pi}\left \\sum_{k=0}\^{\\infty}\\gamma\^k r_{t+k} \\right J(π)=Eπk=0∑∞γkrt+k

经典 CartPole 每执行一步就给 + 1 +1 +1。只要杆没有因倾角过大而倒下,小车也没有越过轨道边界,回合就能继续。因此,最大化 J ( π ) J(\pi) J(π) 在这个环境中基本等价于让小车尽可能长时间地把杆保持住。

这里有一个容易误解的地方:经典环境并不会因为 θ \theta θ 恰好等于 0 0 0 就额外奖励,也不会直接告诉智能体"角度越小越好"。杆接近竖直、小车远离边界、速度不过大,通常能够带来更多未来的 + 1 +1 +1,所以这些状态会通过长期回报获得更高的 Q 值。换句话说,角度接近 0 0 0 是延长存活时间的手段,而不是经典奖励函数直接写出的目标。

如果我们希望控制器不仅"不倒",还要尽量保持杆竖直、小车居中、运动平稳,可以自行设计更稠密的奖励。例如:

r t = 1 − w θ ( θ t θ max ⁡ ) 2 − w x ( x t x max ⁡ ) 2 − w θ ˙ ( θ ˙ t θ ˙ r e f ) 2 − w x ˙ ( x ˙ t x ˙ r e f ) 2 − λ f a i l d t \begin{aligned} r_t={}&1 -w_\theta\left(\frac{\theta_t}{\theta_{\max}}\right)^2 -w_x\left(\frac{x_t}{x_{\max}}\right)^2\\ &-w_{\dot\theta}\left(\frac{\dot\theta_t}{\dot\theta_{\mathrm{ref}}}\right)^2 -w_{\dot x}\left(\frac{\dot x_t}{\dot x_{\mathrm{ref}}}\right)^2 -\lambda_{\mathrm{fail}}d_t \end{aligned} rt=1−wθ(θmaxθt)2−wx(xmaxxt)2−wθ˙(θ˙refθ˙t)2−wx˙(x˙refx˙t)2−λfaildt

其中各权重均为非负数, d t = 1 d_t=1 dt=1 表示倒杆或越界。 θ max ⁡ \theta_{\max} θmax 和 x max ⁡ x_{\max} xmax 可取任务允许的最大倾角和最大位移,例如经典 CartPole 约为 12 ∘ 12^\circ 12∘ 和 2.4   m 2.4\,\mathrm m 2.4m;速度参考值用于把不同量纲归一化到相近尺度。每一项都对应一个具体愿望:

  • 1 1 1:活着就有基础奖励;
  • θ t 2 \theta_t^2 θt2:杆越偏离竖直,扣分越多;
  • x t 2 x_t^2 xt2:小车越靠近轨道边界,扣分越多;
  • θ ˙ t 2 \dot\theta_t^2 θ˙t2:杆转得越快,说明倒下风险越大;
  • x ˙ t 2 \dot x_t^2 x˙t2:小车速度过大时,未来刹车空间会变小;
  • λ f a i l d t \lambda_{\mathrm{fail}}d_t λfaildt:倒杆或越界时给予额外惩罚。

例如只考虑角度项,取 w θ = 0.5 w_\theta=0.5 wθ=0.5。当杆偏角为允许上限的一半时,角度扣分为 0.5 × ( 1 / 2 ) 2 = 0.125 0.5\times(1/2)^2=0.125 0.5×(1/2)2=0.125,这一步得到 0.875 0.875 0.875;当 θ = 0 \theta=0 θ=0 时角度项不扣分。但即使角度正好为 0 0 0,若小车正在高速冲向边界,速度项和位置项仍会扣分------"这一刻竖直"并不等于"未来安全"。

这种奖励塑形能提供更及时的学习信号,但它也改变了任务:控制器优化的不再只是存活时间,还会权衡居中程度和运动平稳性。不同权重可能诱导出不同策略。若希望在理论上不改变原任务的最优策略,可以使用势函数形式的塑形项 F ( s , s ′ ) = γ Φ ( s ′ ) − Φ ( s ) F(s,s')=\gamma\Phi(s')-\Phi(s) F(s,s′)=γΦ(s′)−Φ(s);本文后面的算法公式同时适用于经典奖励和自定义奖励。

第二层是算法内部的训练目标。Q-learning 用 TD 误差修正一格 Q 值;DQN、DDQN 和 Dueling DQN 则用神经网络最小化 TD 损失。训练损失只是逼近长期控制目标的手段,不能把"损失变小"直接等同于"小车一定控制得更好"。真正的控制效果仍要看每回合累计奖励、存活步数、最大倾角和越界率等指标。

抽象地说,控制器就是智能体(agent),倒立摆及其物理规律是环境。智能体不断观察状态、选择动作、获得奖励,并进入新的状态。它希望学会一套长期来看最有效的控制策略。

一次交互可以写成:

s t → a t ( r t , s t + 1 ) s_t \xrightarrow{a_t} (r_t, s_{t+1}) stat (rt,st+1)

其中:

  • s t s_t st 是时刻 t t t 的状态;
  • a t a_t at 是智能体采取的动作;
  • r t r_t rt 是环境立即给出的奖励;
  • s t + 1 s_{t+1} st+1 是动作执行后的下一状态。

关键在于,控制器不能只看眼前一刻。杆向右倾时,把小车向右推通常有助于追到杆的下方;但若小车本来就在高速向右运动或已接近轨道边界,继续向右推可能很快失败。因此我们用折扣回报衡量一连串未来奖励:

G t = r t + γ r t + 1 + γ 2 r t + 2 + ⋯ G_t=r_t+\gamma r_{t+1}+\gamma^2r_{t+2}+\cdots Gt=rt+γrt+1+γ2rt+2+⋯

γ ∈ [ 0 , 1 ) \gamma\in[0,1) γ∈[0,1) 是折扣因子。它像控制器的"时间视野": γ \gamma γ 越大,越关心未来能坚持多久; γ \gamma γ 越小,越在意下一瞬间是否还能保持平衡。于是,第一个问题来了:怎样给"在当前状态下向右推车"这样的选择打一个包含未来收益的分数?

2. Q 值:给每个"状态---动作"组合打分

动作价值函数 Q π ( s , a ) Q^\pi(s,a) Qπ(s,a) 的含义是:处在状态 s s s 时先做动作 a a a,之后按照策略 π \pi π 行动,预期一共能得到多少折扣回报。

Q π ( s , a ) = E π G t ∣ S t = s , A t = a Q^\pi(s,a)=\mathbb{E}_\piG_t\\mid S_t=s,A_t=a Qπ(s,a)=EπGt∣St=s,At=a

这就是控制器要学的 Q 值。 Q ( s , a ) Q(s,a) Q(s,a) 表示在当前小车位置、车速、杆角度和角速度下先执行动作 a a a,随后继续合理控制,预计能获得多少长期回报。如果已经知道最优动作价值 Q ∗ ( s , a ) Q^*(s,a) Q∗(s,a),决策就很简单:

π ∗ ( s ) = arg ⁡ max ⁡ a Q ∗ ( s , a ) \pi^*(s)=\arg\max_a Q^*(s,a) π∗(s)=argamaxQ∗(s,a)

也就是每次选择评分最高的动作。

最优 Q 函数满足贝尔曼最优方程:

Q ∗ ( s , a ) = E r + γ max ⁡ a ′ Q ∗ ( s ′ , a ′ ) ∣ s , a Q^*(s,a)=\mathbb{E}\leftr+\\gamma\\max_{a'}Q\^\*(s',a')\\mid s,a\\right Q∗(s,a)=Er+γa′maxQ∗(s′,a′)∣s,a

这句话非常重要:一个动作的长期价值,等于眼前奖励,加上到达下一状态后能够取得的最佳未来价值。这里默认终止状态的后续价值为 0 0 0;在显式实现中,后文会用 ( 1 − d ) (1-d) (1−d) 屏蔽终止后的自举项。但控制器既没有倒立摆的精确动力学模型,也不知道每种发力方式的长期效果。它该怎样得到这些 Q 值?

3. Q-learning:一边试错,一边修改行动指南

Q-learning 优化什么? 外层仍是让小车的累计奖励最大;内层没有神经网络和反向传播,而是用 TD 误差把当前表格值 Q ( s , a ) Q(s,a) Q(s,a) 推向贝尔曼目标。

一种直接办法是先把 x x x、 x ˙ \dot x x˙、 θ \theta θ、 θ ˙ \dot\theta θ˙ 各自划分成有限区间,再建立 Q 表:每种离散状态占一行,"向左推"和"向右推"占两列。控制器每试一次,就根据实际结果修改对应格子的评分。这就是 Q-learning 的基本做法。它不需要预先掌握状态转移模型,而是直接用交互经验 ( s , a , r , s ′ ) (s,a,r,s') (s,a,r,s′) 学习,因此是一种无模型(model-free)的时序差分方法。

它的更新公式是:

Q ( s , a ) ← Q ( s , a ) + α r + γ ( 1 − d ) max ⁡ a ′ Q ( s ′ , a ′ ) − Q ( s , a ) Q(s,a)\leftarrow Q(s,a)+\alpha\leftr+\\gamma(1-d)\\max_{a'}Q(s',a')-Q(s,a)\\right Q(s,a)←Q(s,a)+αr+γ(1−d)a′maxQ(s′,a′)−Q(s,a)

其中 d = 1 d=1 d=1 表示 s ′ s' s′ 是真正的终止状态,否则 d = 0 d=0 d=0。公式看着复杂,读成一句话很简单:新评分 = 旧评分 + 学习率 ×(这次经历提示的评分 − 旧评分)。控制器只修改这次离散状态与推车动作所对应的一格。

严格地说,表格 Q-learning 并不像神经网络那样先规定一个全局可微损失再做反向传播。它的理论目标是找到贝尔曼最优算子的不动点 Q ∗ = T Q ∗ Q^*=\mathcal TQ^* Q∗=TQ∗,每次更新都是用一条随机经验对这个不动点做随机逼近。单步 TD 误差可以写成平方误差来帮助理解,但不能因此把表格 Q-learning 与 DQN 的端到端梯度优化完全等同起来。

3.1 TD 目标与 TD 误差

Q-learning 先构造一个临时学习目标:

y = r + γ ( 1 − d ) max ⁡ a ′ Q ( s ′ , a ′ ) y=r+\gamma(1-d)\max_{a'}Q(s',a') y=r+γ(1−d)a′maxQ(s′,a′)

这里的 y y y 被称为时序差分目标(TD target)。当前估计是 Q ( s , a ) Q(s,a) Q(s,a),两者之差为:

δ = y − Q ( s , a ) = r + γ ( 1 − d ) max ⁡ a ′ Q ( s ′ , a ′ ) − Q ( s , a ) \delta=y-Q(s,a) =r+\gamma(1-d)\max_{a'}Q(s',a')-Q(s,a) δ=y−Q(s,a)=r+γ(1−d)a′maxQ(s′,a′)−Q(s,a)

δ \delta δ 就是 TD 误差。若 δ > 0 \delta>0 δ>0,说明这次经历比预想更好,应上调评分;若 δ < 0 \delta<0 δ<0,说明现实给了智能体一记"差评",应下调评分。学习率 α \alpha α 决定每次改多少:

Q ( s , a ) ← Q ( s , a ) + α δ Q(s,a)\leftarrow Q(s,a)+\alpha\delta Q(s,a)←Q(s,a)+αδ

举个可以手算的例子:杆略向右倾,"向右推车"原先得分 Q ( s , 向右 ) = 8 Q(s,\text{向右})=8 Q(s,向右)=8。执行后系统仍未终止,所以得到 r = 1 r=1 r=1;下一状态的最佳价值估计为 12 12 12。取 γ = 0.9 \gamma=0.9 γ=0.9、 α = 0.2 \alpha=0.2 α=0.2,则 TD 目标是 1 + 0.9 × 12 = 11.8 1+0.9\times12=11.8 1+0.9×12=11.8,误差是 11.8 − 8 = 3.8 11.8-8=3.8 11.8−8=3.8,新评分为 8 + 0.2 × 3.8 = 8.76 8+0.2\times3.8=8.76 8+0.2×3.8=8.76。这次动作让系统继续保持平衡,而且进入了一个更有希望的状态,因此评分上升。

若改用上一节的稠密奖励,这里的 r r r 就不再固定为 1 1 1。假设根据角度、位置和速度算得本步奖励为 0.7 0.7 0.7,TD 目标便变为 0.7 + 0.9 × 12 = 11.5 0.7+0.9\times12=11.5 0.7+0.9×12=11.5。Q-learning 的更新规则没有改变,改变的是我们用奖励函数向它表达的控制偏好。

一个容易忽略的细节是:TD 目标也包含一个尚未完全准确的估计 Q ( s ′ , a ′ ) Q(s',a') Q(s′,a′)。这叫自举(bootstrapping):控制器用"下一状态下目前看来最好的动作",提前估算刚才这次推车的价值。它不必等一整轮控制结束才学习,但也可能把下一状态的判断误差传回来。

3.2 为什么叫"时序差分":它站在蒙特卡洛与动态规划之间

《动手学强化学习》第 5 章把时序差分放在两种方法之间理解,这能看清 Q-learning 的来路:

方法 是否需要环境模型 何时能更新 学习目标
动态规划(DP) 需要状态转移概率与奖励模型 可对已知模型反复计算 对所有可能下一状态求期望
蒙特卡洛(MC) 不需要 必须等一条轨迹结束 实际得到的完整回报 G t G_t Gt
时序差分(TD) 不需要 每走一步即可 r + γ r+\gamma r+γ × 下一状态的当前估计

假设小车倒立摆刚开始摇晃。蒙特卡洛方法像"等整场表演结束再复盘":杆最终在第 37 步倒下后,才回头评价此前每次推车。TD 则像站在场边的教练:看到这一步的奖励和下一瞬间的状态,就立刻修正刚才的判断。

以状态价值为例,最简单的一步 TD 目标是:

y t T D = r t + γ V ( s t + 1 ) y_t^{\mathrm{TD}}=r_t+\gamma V(s_{t+1}) ytTD=rt+γV(st+1)

它既像蒙特卡洛一样从真实交互中采样,不要求知道倒立摆的完整动力学模型;又像动态规划一样使用下一状态的价值估计进行自举。Q-learning 只是把这套思想用在动作价值上,并在下一状态取最大的动作价值。因此,"TD"不是某个装饰性名词,而是算法能够边控制、边学习的根本原因。

3.3 探索与利用:为什么不能永远选当前最优动作?

如果智能体永远选择当前 Q 值最大的动作,它可能因为早期的偶然经历,反复走一条"看起来不错但并非最好"的路。常见办法是 ε \varepsilon ε-贪婪策略:

a = { 随机动作 , 以概率 ε arg ⁡ max ⁡ a Q ( s , a ) , 以概率 1 − ε a=\begin{cases} \text{随机动作}, & \text{以概率 }\varepsilon\\ \arg\max_a Q(s,a), & \text{以概率 }1-\varepsilon \end{cases} a={随机动作,argmaxaQ(s,a),以概率 ε以概率 1−ε

这相当于大多数时候采用当前得分较高的推车方向,偶尔随机尝试另一个方向。若从不探索,早期的偶然经验可能让控制器形成"只要杆右倾就永远向右推"的僵硬规则,学不会在接近轨道边界时提前刹车;若始终随机尝试,又无法稳定控制。探索负责发现新技巧,利用负责使用已有知识。

这也是一种"策略评估---策略改进"交替进行的过程:根据经验更新 Q 值,是在评估当前认识;用新的 Q 值指导更贪婪的动作,是在改进策略。两件事不必各自完全收敛后再切换,而可以像两只咬合的齿轮一样同步推进,这就是广义策略迭代的思想。

3.4 Sarsa 与 Q-learning:下一步按"实际行动"算,还是按"最佳行动"算?

在引出 Q-learning 的离策略性质前,先看同属 TD 控制的 Sarsa。它用五元组 ( s , a , r , s ′ , a ′ ) (s,a,r,s',a') (s,a,r,s′,a′) 更新:

Q ( s , a ) ← Q ( s , a ) + α r + γ ( 1 − d ) Q ( s ′ , a ′ ) − Q ( s , a ) Q(s,a)\leftarrow Q(s,a)+\alpha\leftr+\\gamma(1-d)Q(s',a')-Q(s,a)\\right Q(s,a)←Q(s,a)+αr+γ(1−d)Q(s′,a′)−Q(s,a)

其中 a ′ a' a′ 是行为策略在下一状态实际选择 的动作。若当前采用 ε \varepsilon ε-贪婪探索,Sarsa 会把"下一步仍可能随机试探"的风险也算进价值里。Q-learning 则使用:

r + γ ( 1 − d ) max ⁡ a ′ Q ( s ′ , a ′ ) r+\gamma(1-d)\max_{a'}Q(s',a') r+γ(1−d)a′maxQ(s′,a′)

它问的不是"我下一步实际上会怎么做",而是"如果下一步开始总选当前看来最好的动作,会有多好"。放到小车倒立摆中,Sarsa 学的是带着探索噪声操纵小车时的价值;Q-learning 瞄准的是贪婪控制策略的价值。两者都从真实转移中学习,但对下一动作的处理不同。

3.5 为什么 Q-learning 是离策略算法?

与环境交互时,行为策略因为要探索,可能选了一个随机动作;但更新时,Q-learning 使用的是下一状态中的最大 Q 值:

max ⁡ a ′ Q ( s ′ , a ′ ) \max_{a'}Q(s',a') a′maxQ(s′,a′)

也就是说,"实际操纵倒立摆来收集数据的行为策略"和"算法要评估、改进的目标策略"可以不同。前者可以带着 ε \varepsilon ε 随机试探,后者仍然瞄准贪婪最优策略。因此 Q-learning 属于离策略(off-policy)算法。这一性质也为后面的经验回放埋下伏笔:早期探索得到的旧经验仍能用于更新当前的价值判断。需要注意,"离策略"不等于不与环境交互的离线强化学习;前者描述行为策略与目标策略是否一致,后者描述训练阶段能否继续收集新数据。

4. 一张 Q 表是怎样学会控制的?

为了让 Q 表放得下,先将四个状态量粗略分桶,例如把小车位置分为"左、中、右",车速分为"向左、较慢、向右",杆角度和角速度也作类似处理。每种组合状态对应 Q 表中的一行:

离散状态 向左推车 向右推车
车居中,杆左倾且向左转 18.2 11.4
车居中,杆近竖直且运动较慢 24.6 25.1
车居中,杆右倾且向右转 12.7 19.3
车靠右且仍向右高速运动 9.8 3.1

开始时整张表可以全为 0。控制器随机推车,杆常常很快倒下。某些动作让系统多坚持几步,于是这些状态---动作对积累到更大的 Q 值;"这样推车能继续存活"的消息再通过 γ max ⁡ Q ( s ′ , a ′ ) \gamma\max Q(s',a') γmaxQ(s′,a′) 一步步传回更早状态。训练足够久后,追杆、刹车和避免边界逐渐连成一套策略。

表格法有三个鲜明优点:

  1. 表达精确,每个状态---动作对有独立的存储位置;
  2. 更新简单,改一个单元格即可;
  3. 在有限、较小的离散问题中,理论与行为都容易分析。

在这个经过离散化的版本中,一格格记账很直观。但真实的四个状态量都是连续数值,Q 表必须先把它们切成有限区间才能使用。桶究竟应该划多粗,正是接下来要面对的"表格墙"。

4.1 表格 Q-learning 为什么有机会收敛?

书中从贝尔曼最优算子解释了表格 Q-learning 的理论基础。定义:

( T Q ) ( s , a ) = E r + γ max ⁡ a ′ Q ( s ′ , a ′ ) ∣ s , a (\mathcal TQ)(s,a)=\mathbb E\leftr+\\gamma\\max_{a'}Q(s',a')\\mid s,a\\right (TQ)(s,a)=Er+γa′maxQ(s′,a′)∣s,a

当 0 ≤ γ < 1 0\le\gamma<1 0≤γ<1 时,这个算子在最大范数下具有压缩性:两套 Q 估计经过一次贝尔曼更新后,最大差距至多变成原来的 γ \gamma γ 倍。不断应用它,就像每轮都把误差按比例压小,唯一的不动点正是 Q ∗ Q^* Q∗。

不过,"Q-learning 一定收敛"不能脱离条件单独说。典型结论要求有限状态与动作、奖励有界、每个状态---动作对被充分访问,并让学习率随访问次数衰减且满足:

∑ t α t ( s , a ) = ∞ , ∑ t α t 2 ( s , a ) < ∞ \sum_t\alpha_t(s,a)=\infty,\qquad \sum_t\alpha_t^2(s,a)<\infty t∑αt(s,a)=∞,t∑αt2(s,a)<∞

第一项保证学习不会过早停住,第二项保证后期噪声能够被压下去。 ε \varepsilon ε-贪婪探索有助于覆盖不同动作,但还必须保证探索不会衰减得过快,才能满足"每个状态---动作对被无限次访问"这一理论条件。后面把 Q 表换成神经网络后,这套表格情形的收敛保证不能原封不动地搬过去:网络会同时改变许多状态的估值,训练目标和采样分布也在变化,因此 DQN 首先要解决的是经验上的稳定性。

5. Q-learning 的"表格墙"

经典 CartPole 的动作只有向左、向右两种,动作空间并不大。真正让 Q 表为难的是四维连续状态:

s = ( x , x ˙ , θ , θ ˙ ) s=(x,\dot x,\theta,\dot\theta) s=(x,x˙,θ,θ˙)

例如,下面两个状态几乎一样:

s 1 = ( 0.10 , 0.25 , 2.0 ∘ , 0.08 ) , s 2 = ( 0.11 , 0.24 , 2.1 ∘ , 0.07 ) . \begin{aligned} s_1&=(0.10,\ 0.25,\ 2.0^\circ,\ 0.08),\\ s_2&=(0.11,\ 0.24,\ 2.1^\circ,\ 0.07). \end{aligned} s1s2=(0.10, 0.25, 2.0∘, 0.08),=(0.11, 0.24, 2.1∘, 0.07).

对控制器而言,它们通常应该采用相近的动作;但精确查表会把 s 1 s_1 s1 和 s 2 s_2 s2 当成毫无关系的两行。状态数值几乎不可能重复出现,智能体刚学到的经验便很难再次命中。

可以继续采用分桶,但会遇到两难:

  • 分桶太粗 :例如把 − 3 ∘ -3^\circ −3∘ 到 3 ∘ 3^\circ 3∘ 都归为"接近竖直",控制器看不出杆正在向左倾还是向右倾,动作会变得粗糙;
  • 分桶太细 :每个维度的桶数相乘,表格规模迅速增长。每维 20 桶时已有 20 4 × 2 = 320000 20^4\times2=320000 204×2=320000 个状态---动作表项;每维 100 桶时则达到 100 4 × 2 = 2 × 10 8 100^4\times2=2\times10^8 1004×2=2×108 个表项。

还有一个更隐蔽的问题:表格在桶边界处是不连续的。 1.99 ∘ 1.99^\circ 1.99∘ 和 2.01 ∘ 2.01^\circ 2.01∘ 可能只差 0.02 ∘ 0.02^\circ 0.02∘,却被分到两个格子;一个格子学得很好,并不会自动改善旁边的格子。这就是 Q 表缺乏泛化能力。

于是问题从"怎样更新 Q 表"变成了:

能不能让控制器学会"小车和杆处于什么运动趋势时应该向哪边推",而不是记住每一个精确状态?

6. 函数近似:从背答案到学规律

我们用带参数的函数 Q ( s , a ; θ ) Q(s,a;\theta) Q(s,a;θ) 近似真实的动作价值:

Q ( s , a ; θ ) ≈ Q ∗ ( s , a ) Q(s,a;\theta)\approx Q^*(s,a) Q(s,a;θ)≈Q∗(s,a)

这就是函数近似。参数 θ \theta θ 可以属于线性模型或神经网络。当函数是深度神经网络时,它就是 Deep Q-Network,即 DQN 中的"网络"。控制器从"逐格查询状态表",变成"输入四维状态,直接给左右动作打分"。

对于离散动作,最常见的结构是:输入一个状态,网络一次输出所有动作的 Q 值。

text 复制代码
状态 s=(x, ẋ, θ, θ̇) ──> Q 网络 ──> [Q(s,向左推), Q(s,向右推)]
                                      │
                                      └── argmax 选动作

与书中 CartPole 示例一致,一个足够直观的网络可以是"4 维输入---128 个 ReLU 隐藏单元---2 维输出"。四个输入对应 x , x ˙ , θ , θ ˙ x,\dot x,\theta,\dot\theta x,x˙,θ,θ˙,两个输出分别对应向左、向右推车。128 并不是理论规定,只是这个小任务上常用、易于理解的配置;DQN 的关键是用同一套参数为相似状态共享规律。

这一步带来了泛化能力。神经网络不再为每个状态准备独立抽屉,而是从大量状态中提取共性。例如,它可能学到"杆略向右倾且继续向右倒时,通常应把小车向右推;若小车已靠近右边界,则要更早反向刹车"。即使眼前的精确数值此前没有出现过,也能给出估计。

不过,刚换上神经网络,控制器就遇到新问题:它可能刚认为此刻应该向左推车,下一轮训练又突然改口。原因在于,连续采集的状态高度相关,网络容易只记住最近一段运动;更棘手的是,它还在用自己不断变化的估值给自己出"标准答案"。这两种不稳定必须分别处理。

7. 朴素神经网络 Q-learning 为什么不稳定?

若直接模仿表格更新,可以令网络最小化:

L ( θ ) = 1 2 y − Q ( s , a ; θ ) 2 L(\theta)=\frac{1}{2}\lefty-Q(s,a;\\theta)\\right^2 L(θ)=21y−Q(s,a;θ)2

其中:

y = r + γ ( 1 − d ) max ⁡ a ′ Q ( s ′ , a ′ ; θ ) y=r+\gamma(1-d)\max_{a'}Q(s',a';\theta) y=r+γ(1−d)a′maxQ(s′,a′;θ)

这看似只是普通回归,实际上有两处危险。

危险一:连续经验高度相关

小车倒立摆的相邻时刻非常相似:车的位置只移动一点,杆角度也只变化一点。如果按产生顺序立即训练,就像连续复习几十张几乎相同的运动照片。网络会强烈迎合最近一小段轨迹,随后又被另一段数据拉向别处,容易遗忘和震荡。

危险二:预测者同时改写标准答案

同一个网络既计算当前预测 Q ( s , a ; θ ) Q(s,a;\theta) Q(s,a;θ),又生成目标中的 Q ( s ′ , a ′ ; θ ) Q(s',a';\theta) Q(s′,a′;θ)。刚更新一次参数,预测变了,标准答案也跟着变。它像控制器每修订一次动作评分,立刻又用新评分重写训练目标:每次快追上目标时,目标又挪走了。

于是,控制器需要两项安排:把不同时间的控制经验打散后复习;让评分标准在一段时间内保持相对固定。这就引出了经验回放和目标网络,也让"用神经网络做 Q-learning"成为更稳定的 DQN。

8. DQN 的第一块稳定器:经验回放

DQN 把每次交互得到的转移存进经验回放池:

D = { ( s t , a t , r t , s t + 1 , d t ) } \mathcal{D}=\{(s_t,a_t,r_t,s_{t+1},d_t)\} D={(st,at,rt,st+1,dt)}

d t d_t dt 表示这次转移是否到达真正的终止状态。训练时不只使用刚发生的经验,而是从 D \mathcal{D} D 中随机抽取一个小批量(mini-batch)。时间上限造成的截断是否写成 d t = 1 d_t=1 dt=1,取决于任务是否把时间限制定义为终止;在常见的 Gymnasium CartPole 处理中,应把它与倒杆、越界区分开。

它像一个被打乱顺序的实验记录库:这次抽到小车向右追杆的经历,下次抽到靠近轨道边界提前刹车的经历,训练不再被刚刚发生的一小段运动占满。

随机抽样主要带来三点好处:

  • 削弱时间相关性:随机抽样让相邻转移不再总是连续进入同一批数据,使训练样本更接近独立同分布的假设,但并不会让它们严格独立;
  • 提高样本利用率:一次昂贵的环境交互可以被多次学习;
  • 平滑数据分布:网络同时复习新旧经验,不容易被最近一小段轨迹牵着走。

但经验回放不是越旧越好。若缓冲区充满很久以前、与当前策略差异极大的经验,数据分布也可能变得不合时宜。因此缓冲区通常有固定容量,采用先进先出的方式淘汰最旧样本。

这里也能看见离策略学习的实际价值:回放池中的样本可能来自许多历史版本的 ε \varepsilon ε-贪婪策略,DQN 仍可用它们学习当前目标策略。但"可以复用"不代表"任何旧数据都同样好";持续加入当前策略产生的新样本,能避免训练分布与正在执行的策略相距过远。

9. DQN 的第二块稳定器:目标网络

DQN 优化什么? 小车层面仍要最大化累计奖励;网络训练层面则最小化在线网络预测与 DQN 自举标签之间的 TD 损失。奖励决定想学成什么样,损失函数决定网络怎样逼近这个目标。

DQN 维护两个结构相同、职责不同的网络:

  • 在线网络 Q ( s , a ; θ ) Q(s,a;\theta) Q(s,a;θ):负责选择动作并通过梯度下降持续学习;
  • 目标网络 Q ( s , a ; θ − ) Q(s,a;\theta^-) Q(s,a;θ−):负责产生相对稳定的 TD 目标。

目标变为:

y = { r , 若 s ′ 是终止状态 r + γ max ⁡ a ′ Q ( s ′ , a ′ ; θ − ) , 否则 y=\begin{cases} r, & \text{若 }s'\text{ 是终止状态}\\ r+\gamma\max_{a'}Q(s',a';\theta^-), & \text{否则} \end{cases} y={r,r+γmaxa′Q(s′,a′;θ−),若 s′ 是终止状态否则

在线网络的损失为:

L ( θ ) = 1 N ∑ i = 1 N y i − Q ( s i , a i ; θ ) 2 L(\theta)=\frac{1}{N}\sum_{i=1}^{N} \lefty_i-Q(s_i,a_i;\\theta)\\right^2 L(θ)=N1i=1∑Nyi−Q(si,ai;θ)2

网络虽然一次输出两个动作的 Q 值,但单条经验只监督当时真正执行的动作 a i a_i ai。实现中通常先得到形如 [batch, 2] 的全部输出,再用动作索引取出 Q ( s i , a i ; θ ) Q(s_i,a_i;\theta) Q(si,ai;θ)。这正对应表格 Q-learning"每次只改所访问格子"的神经网络版本;差别在于参数共享使一次梯度更新也会间接影响相似状态的预测。

训练时只对 θ \theta θ 求梯度, y i y_i yi 被当成固定标签,不让梯度通过目标值反向传播;每隔 C C C 次梯度更新,再把在线网络参数复制给目标网络:

θ − ← θ \theta^-\leftarrow\theta θ−←θ

这像安排一位"慢半拍的控制教练"。在线网络不断练习,教练用于评估下一状态的标准暂时保持不变;每隔一阵,教练再复制在线网络的最新知识。这样,控制器可以先朝一个相对固定的目标学习。

9.1 一批倒立摆经验,怎样变成神经网络的训练标签?

监督学习通常已有人工标签,例如"这张图是猫"。DQN 没有现成的正确 Q 值,它的标签是根据贝尔曼方程临时构造的。因此,DQN 的一次训练可以拆成"先造标签,再拟合标签"两段。

假设从回放池抽出 N N N 条经验:

{ ( s i , a i , r i , s i ′ , d i ) } i = 1 N \left\{(s_i,a_i,r_i,s'i,d_i)\right\}{i=1}^{N} {(si,ai,ri,si′,di)}i=1N

对 CartPole 而言,状态批量 states 的形状为 N , 4 N,4 N,4。在线网络一次前向传播后输出:

Q o n l i n e ( S ; θ ) ∈ R N × 2 Q_{\mathrm{online}}(S;\theta)\in\mathbb R^{N\times2} Qonline(S;θ)∈RN×2

每一行都有"向左推"和"向右推"两个分数。但第 i i i 条经验只执行了动作 a i a_i ai,所以不能把另一动作的输出也当成本条经验的预测。需要按动作索引取出:

q i = Q o n l i n e ( s i , a i ; θ ) q_i=Q_{\mathrm{online}}(s_i,a_i;\theta) qi=Qonline(si,ai;θ)

这一步在代码中通常叫 gather。接着,将下一状态 s i ′ s'_i si′ 输入目标网络。普通 DQN 在目标网络的两个输出中选最大值,并构造标签:

y i D Q N = r i + γ ( 1 − d i ) max ⁡ a ′ Q t a r g e t ( s i ′ , a ′ ; θ − ) y_i^{\mathrm{DQN}} =r_i+\gamma(1-d_i)\max_{a'}Q_{\mathrm{target}}(s'_i,a';\theta^-) yiDQN=ri+γ(1−di)a′maxQtarget(si′,a′;θ−)

y i y_i yi 不是永远正确的"真值",而是当前目标网络提供的自举估计,所以也常被称为 TD 标签或 TD 目标。构造标签时必须停止梯度:优化器只能调整在线网络参数 θ \theta θ,不能沿着 y i y_i yi 去修改目标网络。

批量均方误差为:

L ( θ ) = 1 N ∑ i = 1 N ( y i D Q N − q i ) 2 L(\theta)=\frac1N\sum_{i=1}^{N} \left(y_i^{\mathrm{DQN}}-q_i\right)^2 L(θ)=N1i=1∑N(yiDQN−qi)2

本文沿用《动手学强化学习》中的均方误差写法。实际工程也常使用 Huber 损失(PyTorch 中的 SmoothL1Loss):TD 误差较小时采用平方惩罚,误差特别大时近似线性增长,从而减弱少量异常目标对梯度的冲击。无论选择 MSE 还是 Huber,标签构造和网络更新关系都不变。

反向传播计算 ∇ θ L \nabla_\theta L ∇θL,优化器执行一次参数更新:

θ ← θ − η ∇ θ L ( θ ) \theta\leftarrow\theta-\eta\nabla_\theta L(\theta) θ←θ−η∇θL(θ)

其中 η \eta η 是神经网络优化器的学习率。它与表格 Q-learning 公式中的 α \alpha α 扮演相似角色,但两者不宜机械地视为同一个量:神经网络通常由 Adam 等优化器根据梯度历史调整实际步长。

一段贴近张量运算的伪代码如下:

python 复制代码
# states: [N, 4],actions: [N, 1]
# 两个网络的输出均为 [N, 2]
all_q = online_net(states)
q = all_q.gather(1, actions)                    # [N, 1]

with torch.no_grad():
    next_all_q = target_net(next_states)        # [N, 2]
    next_q = next_all_q.max(dim=1, keepdim=True).values
    not_terminal = 1.0 - terminateds.float()    # [N, 1]
    labels = rewards + gamma * not_terminal * next_q

loss = F.mse_loss(q, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()                                # 只更新在线网络

举一个单样本例子。小车当前执行"向右推",在线网络输出 7.2 , 8.0 7.2,8.0 7.2,8.0,所以参与损失的是 q = 8.0 q=8.0 q=8.0,不是整个向量。下一状态的目标网络输出 9.0 , 10.0 9.0,10.0 9.0,10.0;若 r = 1 r=1 r=1、 γ = 0.9 \gamma=0.9 γ=0.9 且尚未终止,则标签为 y = 1 + 0.9 × 10 = 10 y=1+0.9\times10=10 y=1+0.9×10=10,单样本平方误差为 ( 10 − 8 ) 2 = 4 (10-8)^2=4 (10−8)2=4。反向传播会推动在线网络提高当前状态下"向右推"的预测。由于隐藏层参数被不同状态和动作共享,其他输出也可能间接受到影响。

这里的 r = 1 r=1 r=1 来自经典 CartPole 的存活奖励。若自定义奖励认为当前杆角度过大、小车又靠近边界,只给出 r = 0.2 r=0.2 r=0.2,那么标签会降为 0.2 + 0.9 × 10 = 9.2 0.2+0.9\times10=9.2 0.2+0.9×10=9.2。网络因而不会只学习"这一动作让回合继续",还会学习"虽然没倒,但进入的姿态并不理想"。

经过若干次这样的在线网络更新后,再执行 θ − ← θ \theta^-\leftarrow\theta θ−←θ。因此,DQN 实际上有两个不同节奏:在线网络每个训练批次都学习,目标网络每隔 C C C 次更新才整体追上一次。

10. 从 Q-learning 到 DQN,究竟变了什么?

二者共享同一个贝尔曼最优思想,区别主要在 Q 值如何表示、数据如何使用以及如何稳定学习。

维度 表格 Q-learning DQN
Q 函数表示 表格 Q s , a Qs,a Qs,a 神经网络 Q ( s , a ; θ ) Q(s,a;\theta) Q(s,a;θ)
适合的状态 小规模、离散状态 高维或连续状态
动作空间 离散 通常仍要求离散
泛化能力 几乎没有 相似状态可共享特征
单次更新 改一个表格单元 对一批样本反向传播
数据使用 常见形式下用完即走 回放池中反复采样
TD 目标中的下一状态价值 当前 Q 表产生 延迟更新的目标网络产生
稳定性 小型问题中通常较好 需经验回放和目标网络稳定
计算成本 低 较高,需要训练神经网络

最本质的变化可以压缩成一句话:

Q-learning 逐格记录离散状态下的动作价值;DQN 从连续四维状态中概括控制规律,再用经验回放和目标网络稳定训练。

11. DQN 完整训练流程

将"实验记录库""在线网络"和"控制教练"组装起来,DQN 的训练循环如下:

  1. 随机初始化在线网络参数 θ \theta θ;
  2. 复制参数得到目标网络: θ − ← θ \theta^-\leftarrow\theta θ−←θ;
  3. 初始化经验回放池 D \mathcal D D;
  4. 观察状态 s s s,按 ε \varepsilon ε-贪婪策略选择动作;
  5. 执行动作,得到 ( r , s ′ , d ) (r,s',d) (r,s′,d),将转移存入回放池;
  6. 当回放池中已有足够样本时,随机采样一个 mini-batch;
  7. 用目标网络计算 TD 目标 y y y;
  8. 用在线网络计算被选择动作的 Q ( s , a ; θ ) Q(s,a;\theta) Q(s,a;θ);
  9. 最小化二者之间的损失,更新 θ \theta θ;
  10. 每隔 C C C 次训练更新同步目标网络;
  11. 令 s ← s ′ s\leftarrow s' s←s′,继续与环境交互。

对应的伪代码是:

text 复制代码
初始化在线网络 Qθ、目标网络 Qθ-、回放池 D
θ- ← θ

for 每个 episode:
    s ← 环境初始状态
    while episode 未结束:
        以 ε 的概率随机选动作,否则 a ← argmax_a Qθ(s, a)
        执行 a,观察 r、s'、terminated、truncated
        d ← terminated                 # 是否屏蔽自举项
        将 (s, a, r, s', d) 放入 D

        若 D 中已有足够样本:
            从 D 随机采样一批转移
            y ← r + γ(1-d) max_a' Qθ-(s', a')
            q ← Qθ(s, a)
            最小化 mean[(y - q)²],更新 θ

        每隔 C 次训练更新:θ- ← θ
        若 terminated 或 truncated:结束本回合
        否则:s ← s'

式中的 ( 1 − d ) (1-d) (1−d) 很关键。 d d d 应准确表示"不能再从下一状态获得后续回报"的终止,而不能不加区分地把所有回合结束都设为 1。Gymnasium 将倒杆或越界记为 terminated,将时间上限记为 truncated;对于单纯的时间截断,下一状态在任务本身的马尔可夫过程里仍可能有价值,通常应保留自举项。若任务把时间限制本身纳入终止定义,则需按该定义处理。

到这里,控制器已经能直接处理连续状态,也能比较稳定地学习。但它又发现一个毛病:左右两个动作的估值都有误差时,它总容易被其中较高的那个数字吸引。下一次升级,就从这个过分乐观的"最高分"开始。

12. 第一处改进:Double DQN 怎样给"最优动作"降温?

DDQN 优化什么? 它没有更换小车奖励,也没有更换损失函数;它只改变 TD 标签的构造方式,让在线网络负责选动作、目标网络负责评价动作,从而减轻 max ⁡ \max max 带来的高估倾向。

控制器每一步都要从"向左推"和"向右推"中挑一个长期价值较高的动作。这很合理;但如果估计带有噪声,被挑中的动作往往也恰好是"碰巧被估得太好"的那个。普通 DQN 正面临这个问题:计算下一状态的目标值时,它让同一个目标网络完成两件事,选出估值最高的动作,再给这个动作打分。

y D Q N = r + γ ( 1 − d ) max ⁡ a ′ Q ( s ′ , a ′ ; θ − ) y_{\mathrm{DQN}}=r+\gamma(1-d)\max_{a'}Q(s',a';\theta^-) yDQN=r+γ(1−d)a′maxQ(s′,a′;θ−)

把 max ⁡ \max max 拆开,就能看见这个问题:

a D Q N ∗ = arg ⁡ max ⁡ a ′ Q ( s ′ , a ′ ; θ − ) , y D Q N = r + γ ( 1 − d ) Q ( s ′ , a D Q N ∗ ; θ − ) a^*{\mathrm{DQN}}=\arg\max{a'}Q(s',a';\theta^-),\qquad y_{\mathrm{DQN}}=r+\gamma(1-d)Q(s',a^*_{\mathrm{DQN}};\theta^-) aDQN∗=arga′maxQ(s′,a′;θ−),yDQN=r+γ(1−d)Q(s′,aDQN∗;θ−)

目标网络的估值总有误差。假设向左、向右推车的真实未来价值都是 20 20 20,目标网络却估成 22 22 22 和 18 18 18。DQN 会挑出 22 22 22,并把这个偏高的数作为学习目标的一部分。下一次即使误差换了动作, max ⁡ \max max 仍容易挑到正向误差:这就是"取最大值"带来的过高估计倾向。它并不意味着每次估计都会偏高,而是说在有噪声的估计中,挑最大值会偏爱被高估的候选者 。若每步奖励为 1 1 1、折扣因子为 γ \gamma γ,无限时域回报的上界是 1 / ( 1 − γ ) 1/(1-\gamma) 1/(1−γ);若还剩至多 H H H 步,上界则是 ( 1 − γ H ) / ( 1 − γ ) (1-\gamma^H)/(1-\gamma) (1−γH)/(1−γ)。明显超过相应上界的 Q 值,是估值异常的直接信号。

可以把它想成一场动作选拔:同一位裁判既负责挑出冠军,又把自己刚才的最高分当成冠军的真实水平。偶然被打高分的动作更容易胜出,于是最佳动作看起来常常比实际更好。

12.1 DDQN 的做法:一套网络选动作,另一套网络复核

Double DQN(常缩写为 DDQN)让在线网络 Q ( s , a ; θ ) Q(s,a;\theta) Q(s,a;θ) 选择动作,让目标网络 Q ( s , a ; θ − ) Q(s,a;\theta^-) Q(s,a;θ−) 评价被选中的动作:

a D D Q N ∗ = arg ⁡ max ⁡ a ′ Q ( s ′ , a ′ ; θ ) a^*{\mathrm{DDQN}}=\arg\max{a'}Q(s',a';\theta) aDDQN∗=arga′maxQ(s′,a′;θ)

y D D Q N = r + γ ( 1 − d ) Q ( s ′ , a D D Q N ∗ ; θ − ) y_{\mathrm{DDQN}}=r+\gamma(1-d)Q(s',a^*_{\mathrm{DDQN}};\theta^-) yDDQN=r+γ(1−d)Q(s′,aDDQN∗;θ−)

看一个完整例子。假设左右两个动作的真实价值都约为 20 20 20,两套网络给出的估计如下:

动作 在线网络 目标网络
向左推车 22 19
向右推车 18 21

普通 DQN 让目标网络同时选与评,会选择向右推车,并把 21 21 21 带入 TD 目标。DDQN 让在线网络先选择向左推车,再让目标网络评价该动作,带入目标的是 19 19 19。这个例子展示的是两种计算方式的差别,并不表示 DDQN 每一步都更接近真实值。两套网络的误差也并非完全独立,因为目标网络定期复制在线网络的参数;但选与评的部分解耦,通常能减轻最大值操作造成的高估。

从实现看,DDQN 不需要再加第三个网络。DQN 原本就有的两套网络足够了;经验回放、损失函数、优化器和目标网络同步机制都可以沿用。接下来把这处差异放进一次完整的神经网络更新中观察。

12.2 DDQN 怎样构造标签并更新网络?

DDQN 的网络输入、gather、损失函数、反向传播和目标网络同步都与 DQN 相同。真正变化的只有下一状态标签的构造方式。

对同一个下一状态 s i ′ s'_i si′,先让在线网络给出两个动作的估计,并只取最大值所在的动作索引:

a i ∗ = arg ⁡ max ⁡ a ′ Q o n l i n e ( s i ′ , a ′ ; θ ) a_i^*=\arg\max_{a'}Q_{\mathrm{online}}(s'_i,a';\theta) ai∗=arga′maxQonline(si′,a′;θ)

再把这个动作索引交给目标网络取值:

y i D D Q N = r i + γ ( 1 − d i ) Q t a r g e t ( s i ′ , a i ∗ ; θ − ) y_i^{\mathrm{DDQN}} =r_i+\gamma(1-d_i) Q_{\mathrm{target}}(s'_i,a_i^*;\theta^-) yiDDQN=ri+γ(1−di)Qtarget(si′,ai∗;θ−)

最后仍然拟合在线网络对已执行动作的预测:

L ( θ ) = 1 N ∑ i = 1 N y i D D Q N − Q o n l i n e ( s i , a i ; θ ) 2 L(\theta)=\frac1N\sum_{i=1}^{N} \lefty_i\^{\\mathrm{DDQN}}-Q_{\\mathrm{online}}(s_i,a_i;\\theta)\\right^2 L(θ)=N1i=1∑NyiDDQN−Qonline(si,ai;θ)2

例如,下一状态的在线网络输出 12 , 9 12,9 12,9,目标网络输出 8 , 11 8,11 8,11。普通 DQN 直接取目标网络最大值 11 11 11;DDQN 先由在线网络选择第一个动作,再从目标网络取出该动作的估值 8 8 8。两者的当前预测 Q o n l i n e ( s i , a i ; θ ) Q_{\mathrm{online}}(s_i,a_i;\theta) Qonline(si,ai;θ) 可以完全相同,差别只出现在标签一侧。

python 复制代码
q = online_net(states).gather(1, actions)

with torch.no_grad():
    next_actions = online_net(next_states).argmax(dim=1, keepdim=True)
    next_q = target_net(next_states).gather(1, next_actions)
    not_terminal = 1.0 - terminateds.float()
    labels = rewards + gamma * not_terminal * next_q

loss = F.mse_loss(q, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()

注意,online_net(next_states) 虽参与了动作选择,但它位于 no_grad 环境中;动作索引本身也不可微。梯度仍只来自左侧预测 Q o n l i n e ( s i , a i ; θ ) Q_{\mathrm{online}}(s_i,a_i;\theta) Qonline(si,ai;θ)。DDQN 不是同时训练两套网络,而是用两套估计分工生成更稳妥的标签。它针对的是目标值的高估倾向,但不能保证每一个估值都更准确。

13. 第二处改进:Dueling DQN 怎样区分"状态好"与"动作好"?

Dueling DQN 优化什么? 它通常仍使用 DQN 或 DDQN 的 TD 损失;改变的是 Q 网络的表示方式。一个 TD 误差同时训练共享层、状态价值头和动作优势头。

当杆几乎竖直、小车位于轨道中央,所有速度也接近零时,当前状态本身就很好,短时间内左右推车的价值可能相近。可当杆明显向右倾且仍在向右倒时,两个动作的后果就会相差很大。

普通 DQN 直接为每个动作输出 Q ( s , a ) Q(s,a) Q(s,a)。Dueling DQN 把价值判断拆成两部分:

  • 状态价值流 V ( s ) V(s) V(s):当前小车与杆的整体处境有多好;
  • 动作优势流 A ( s , a ) A(s,a) A(s,a):在当前状态下,向左或向右推车相对有多好。

先从概念定义看,在给定策略 π \pi π 下,真正的优势函数是:

A π ( s , a ) = Q π ( s , a ) − V π ( s ) A^\pi(s,a)=Q^\pi(s,a)-V^\pi(s) Aπ(s,a)=Qπ(s,a)−Vπ(s)

由于 V π ( s ) = ∑ a π ( a ∣ s ) Q π ( s , a ) V^\pi(s)=\sum_a\pi(a\mid s)Q^\pi(s,a) Vπ(s)=∑aπ(a∣s)Qπ(s,a),严格定义下的优势函数满足 ∑ a π ( a ∣ s ) A π ( s , a ) = 0 \sum_a\pi(a\mid s)A^\pi(s,a)=0 ∑aπ(a∣s)Aπ(s,a)=0:优势衡量的是某个动作相对该策略平均水平高出或低了多少。

而 Dueling 网络中的 V ( s ) V(s) V(s) 和 A ( s , a ) A(s,a) A(s,a) 是为重构 Q 值而学习的两个参数化输出分支。不能仅凭分支名字,就断言它们在训练过程中始终分别等于某个策略的严格价值函数与优势函数。

13.1 一张网络,分成两条价值流

网络前面几层共同提取四维状态特征,最后分成两个分支:一条输出一个数 V ( s ) V(s) V(s),另一条输出左右两个动作对应的 A ( s , a ) A(s,a) A(s,a)。

text 复制代码
                         ┌──> 价值流 V(s) ───────┐
状态 s ──> 共享特征层 ──┤                         ├──> 合成各动作 Q(s, ·)
                         └──> 优势流 A(s, ·) ────┘

最直接的合成方式是 Q ( s , a ) = V ( s ) + A ( s , a ) Q(s,a)=V(s)+A(s,a) Q(s,a)=V(s)+A(s,a),但这会出现"拆账不唯一":把 V V V 加上 10 10 10,同时让所有 A A A 减去 10 10 10,最终 Q 值完全不变。网络无法判断两条分支各该承担多少。

常用办法是先让同一状态下的优势值减去它们的平均值:

Q ( s , a ; θ ) = V ( s ; θ V ) + A ( s , a ; θ A ) − 1 ∣ A ∣ ∑ b ∈ A A ( s , b ; θ A ) Q(s,a;\theta)=V(s;\theta_V) +A(s,a;\theta_A) -\frac{1}{|\mathcal A|}\sum_{b\in\mathcal A}A(s,b;\theta_A) Q(s,a;θ)=V(s;θV)+A(s,a;θA)−∣A∣1b∈A∑A(s,b;θA)

其中 A \mathcal A A 是可选动作集合。减去均值后,所有动作的优势输出以零为中心, V V V 不再能和优势分支任意"挪账"。在有限动作且采用这一聚合式时,合成 Q 值在动作上的算术平均值恰好等于网络输出的 V ( s ) V(s) V(s);这仍不意味着它自动等于策略定义的 V π ( s ) V^\pi(s) Vπ(s)。

也有减去最大优势值的聚合方式,使 max ⁡ a Q ( s , a ) = V ( s ) \max_a Q(s,a)=V(s) maxaQ(s,a)=V(s)。两者都处理了分解不唯一的问题;实践中常用减均值形式,因为它让各动作的优势相对于整体水平来表达。

13.2 Dueling 网络怎样前向传播和反向更新?

Dueling DQN 改变的是在线网络和目标网络的内部结构,而不是另造一种损失函数。以一批 N N N 个状态为例,共享层先提取特征:

H = f ( S ; θ s h a r e d ) H=f(S;\theta_{\mathrm{shared}}) H=f(S;θshared)

随后分成两个头:

V ( H ; θ V ) ∈ R N × 1 , A ( H ; θ A ) ∈ R N × 2 V(H;\theta_V)\in\mathbb R^{N\times1},\qquad A(H;\theta_A)\in\mathbb R^{N\times2} V(H;θV)∈RN×1,A(H;θA)∈RN×2

将 V V V 广播到两个动作,再对每一行的优势减去该行均值:

Q ( S , ⋅ ) = V ( H ) + A ( H , ⋅ ) − mean ⁡ a A ( H , a ) Q(S,\cdot)=V(H)+A(H,\cdot) -\operatorname{mean}_{a}A(H,a) Q(S,⋅)=V(H)+A(H,⋅)−meanaA(H,a)

得到的 Q 张量仍是 N , 2 N,2 N,2。从这里开始,训练过程与普通 DQN 完全兼容:按实际动作 gather 当前预测,用目标网络构造 TD 标签,再最小化均方误差。若采用普通 DQN 标签,则:

y i = r i + γ ( 1 − d i ) max ⁡ a ′ Q t a r g e t d u e l i n g ( s i ′ , a ′ ) y_i=r_i+\gamma(1-d_i)\max_{a'} Q_{\mathrm{target}}^{\mathrm{dueling}}(s'_i,a') yi=ri+γ(1−di)a′maxQtargetdueling(si′,a′)

若同时采用 DDQN,则改为在线 Dueling 网络选动作、目标 Dueling 网络估值:

a i ∗ = arg ⁡ max ⁡ a ′ Q o n l i n e d u e l i n g ( s i ′ , a ′ ) , y i = r i + γ ( 1 − d i ) Q t a r g e t d u e l i n g ( s i ′ , a i ∗ ) . \begin{aligned} a_i^*&=\arg\max_{a'}Q_{\mathrm{online}}^{\mathrm{dueling}}(s'i,a'),\\ y_i&=r_i+\gamma(1-d_i) Q{\mathrm{target}}^{\mathrm{dueling}}(s'_i,a_i^*). \end{aligned} ai∗yi=arga′maxQonlinedueling(si′,a′),=ri+γ(1−di)Qtargetdueling(si′,ai∗).

无论使用哪一种标签,损失仍是:

L ( θ ) = 1 N ∑ i y i − Q o n l i n e d u e l i n g ( s i , a i ; θ ) 2 L(\theta)=\frac1N\sum_i \lefty_i-Q_{\\mathrm{online}}\^{\\mathrm{dueling}}(s_i,a_i;\\theta)\\right^2 L(θ)=N1i∑yi−Qonlinedueling(si,ai;θ)2

反向传播时,梯度从被选动作的 Q 值流向三部分:共享特征层、价值头和优势头。由于聚合式中包含优势均值,一个动作的 TD 误差还会通过均值项影响同一状态下的其他优势输出;价值头的一个标量则同时构成所有动作 Q 值的共同基线。

python 复制代码
class DuelingQNet(nn.Module):
    def forward(self, states):
        h = self.shared(states)                  # [N, hidden]
        v = self.value_head(h)                   # [N, 1]
        a = self.advantage_head(h)               # [N, 2]
        return v + a - a.mean(dim=1, keepdim=True)

因此,Dueling DQN 的"价值流"和"优势流"不是两个分别拥有标签、分别计算损失的网络。训练数据只提供一个 TD 标签,两个分支通过合成后的 Q 值共同接受同一个 TD 误差,并由反向传播自动分配参数更新。

13.3 用数字感受"状态好"与"动作好"

假设小车居中、杆接近竖直时,价值流输出 V ( s ) = 20 V(s)=20 V(s)=20,优势流给"向左推、向右推"输出 1 , − 1 1,-1 1,−1。优势均值为 0 0 0,合成的 Q 值就是 21 , 19 21,19 21,19:当前状态整体不错,但向左推车稍占优势。

若小车已靠近右边界,价值流只输出 V ( s ) = 4 V(s)=4 V(s)=4,优势流输出 3 , − 3 3,-3 3,−3,合成 Q 值为 7 , 1 7,1 7,1。虽然向左推车比向右推车好得多,当前整体仍是一个危险状态。"当前最好的动作"与"当前状态很好"是两件事。

这种结构尤其适合多个动作价值相近的状态。某个样本更新时,价值流学到的"这个状态总体不错"可影响所有动作的 Q 输出,而优势流继续表达动作间的细微差异。相比之下,普通 DQN 虽也会共享前层参数,却没有显式的状态价值分支。Dueling DQN 的优势是表示方式更贴合这类场景,并非保证所有环境都会更快收敛。

后续仍然对合成的 q_values 按实际动作取值,并沿用经验回放、目标网络和 TD 损失。也就是说,Dueling DQN 改的是Q 网络内部的表示结构,而不是另行发明一套标签和优化规则。

14. DDQN 与 Dueling DQN 能一起用吗?

可以。控制器既能让在线网络与目标网络分工,也能让每套网络在内部区分"整体状态好坏"与"左右动作相对好坏"。DDQN 规定怎样构造 TD 目标 ;Dueling DQN 规定网络怎样输出 Q 值。把在线网络和目标网络都换成 Dueling 结构,再按 DDQN 的"在线网络选动作、目标网络估值"计算目标,就得到常说的 Dueling Double DQN。

14.1 回到小车:四种算法究竟各自在优化什么?

四种算法面对的是同一个外层控制目标 :最大化小车获得的期望累计奖励 J ( π ) J(\pi) J(π)。若采用经典奖励,它们都在设法延长平衡时间;若采用自定义稠密奖励,它们都会同时追求杆角度小、小车靠近中央以及速度平稳。算法升级并没有自动改变"什么叫控制得好",这个定义始终来自奖励函数。

它们真正不同的是怎样估计能够带来高累计奖励的 Q 值:

算法 小车的外层目标 一次样本的学习目标 更新对象 改进点
Q-learning 最大化累计奖励,尽量不倒、不越界 让 Q ( s , a ) Q(s,a) Q(s,a) 靠近 r + γ ( 1 − d ) max ⁡ a ′ Q ( s ′ , a ′ ) r+\gamma(1-d)\max_{a'}Q(s',a') r+γ(1−d)maxa′Q(s′,a′) Q 表中当前状态---动作的一格 用真实交互进行 TD 自举
DQN 与 Q-learning 相同 最小化 y D Q N − Q o n l i n e ( s , a ) 2 y\^{\\mathrm{DQN}}-Q_{\\mathrm{online}}(s,a)^2 yDQN−Qonline(s,a)2 在线神经网络参数 θ \theta θ 用网络泛化,并以回放池和目标网络稳定训练
DDQN 与 DQN 相同 最小化 y D D Q N − Q o n l i n e ( s , a ) 2 y\^{\\mathrm{DDQN}}-Q_{\\mathrm{online}}(s,a)^2 yDDQN−Qonline(s,a)2 在线神经网络参数 θ \theta θ 在线网络选动作、目标网络估值,减轻过高估计
Dueling DQN 与 DQN 相同 最小化合成 Q 值与 TD 标签之间的误差 共享层、价值头和优势头 把"状态整体好坏"与"动作相对好坏"分开表示

用一个具体状态来理解。假设小车靠近中央,杆仅向右偏 1 ∘ 1^\circ 1∘,速度也很小:

  • 奖励函数先决定这一步有多好。经典环境仍给 r = 1 r=1 r=1;稠密奖励也会给接近满分的奖励。
  • Q-learning 把这次经验写回对应的离散表格,逐渐提高合适推车动作的 Q 值。
  • DQN 用神经网络预测左右动作价值,并让实际动作的预测逼近 DQN 标签。
  • DDQN 不改变这一步的奖励,也不改变当前预测;它只更谨慎地计算下一状态的标签。
  • Dueling DQN 可能让价值头学到"这是一个总体安全的状态",再让优势头判断此刻向左还是向右略好。

再看一个危险状态:杆角度暂时接近 0 0 0,但小车已经靠近右边界且仍高速向右。经典奖励在这一瞬间仍可能给 + 1 +1 +1,可是下一状态很可能越界,未来奖励会突然中断,因此该状态下继续向右推的 Q 值会很低。若采用稠密奖励,位置和速度惩罚还会立刻降低当前奖励。这个例子说明,Q 值优化的不是"当前角度最小",而是从当前状态和动作出发,未来总共能得到多少奖励。

方法 构造 TD 目标时由谁选择下一动作 由谁估计该动作价值 Q 网络结构
DQN 目标网络 目标网络 直接输出各动作 Q 值
DDQN 在线网络 目标网络 直接输出各动作 Q 值
Dueling DQN 目标网络 目标网络 价值流 + 优势流
Dueling Double DQN 在线网络 目标网络 价值流 + 优势流

要记住的是:DDQN 的两套网络不是 Dueling DQN 的两条分支。前者是在线与目标两份网络 ,后者是每份网络内部的价值流与优势流。

若只盯住一次 mini-batch 更新,三者的关系可以进一步压缩为:

方法 当前预测 TD 标签 损失与梯度更新
DQN 在线普通 Q 网络的 Q ( s , a ) Q(s,a) Q(s,a) 目标网络同时选动作、估价值 MSE;只更新在线网络
DDQN 在线普通 Q 网络的 Q ( s , a ) Q(s,a) Q(s,a) 在线网络选动作,目标网络估价值 MSE;只更新在线网络
Dueling DQN 在线 Dueling 网络合成的 Q ( s , a ) Q(s,a) Q(s,a) 可采用 DQN 或 DDQN 标签 MSE;更新在线网络的共享层、价值头和优势头

所以,DDQN 改的是标签算法 ,Dueling DQN 改的是网络结构;损失函数和"只对在线网络反向传播"的训练原则并没有改变。

15. 它们仍然保留哪些边界?

这两项改进不改变 DQN 对离散动作的基本要求,也不消除探索不足、样本分布变化或超参数敏感等问题。均匀经验回放仍把所有经验同等对待;优先经验回放则尝试让高 TD 误差或稀有经验被更频繁地抽到。训练时仍需关注奖励尺度、学习率、探索率、回放池大小和目标网络同步频率。

因此,遇到实际任务时可以按症状判断:Q 估值明显偏高,先考虑 DDQN;左右动作在许多平稳状态下价值相近,可考虑 Dueling 结构;两种现象并存,就把两种改进组合起来。如果四个状态量都只取少数离散值,Q 表依然是清晰可靠的基线。

16. 三个常见误区

误区一:DQN 一定比 Q-learning 好

不一定。在四个状态量都被粗略离散的小型实验中,Q 表直接、快速、可解释;DQN 反而引入优化误差、超参数和额外算力。DQN 的优势是在表格难以承受的连续或高维状态中进行函数泛化。

误区二:DQN 能直接解决连续动作问题

标准 DQN 需要计算 max ⁡ a Q ( s , a ) \max_a Q(s,a) maxaQ(s,a)。当动作有限时,网络可以一次输出所有动作的 Q 值并直接取最大值;动作连续时,无法枚举无穷多个候选动作。此时通常转向 DDPG、TD3、SAC 等算法。

误区三:目标网络是另一个独立学习的模型

标准 DQN 中,目标网络不通过自己的优化器独立训练。它只是在线网络的延迟副本,作用是让 TD 目标在一段时间内保持相对稳定。DDQN 沿用这两套网络,Dueling DQN 则改变每套网络内部的结构。

17. 最后一幅图:小车倒立摆控制器如何一步步升级

回顾这条演化路径:

text 复制代码
贝尔曼最优方程
      │
      ▼
Q-learning:用 TD 误差逐格修改离散状态表
      │
      ├── 状态过多或连续:表格爆炸
      ▼
函数近似:根据四维连续状态预测左右动作价值
      │
      ├── 连续样本相关,训练易偏
      ├── 目标随网络变化,追逐不稳
      ▼
DQN:神经网络 + 随机经验回放 + 延迟更新的目标网络
      │
      ├── DDQN:在线网络选动作,目标网络估值
      └── Dueling DQN:区分状态价值与动作优势

回看小车倒立摆控制器的升级过程,每一步都有明确起因。它不知道动力学模型,于是用 Q-learning 从真实交互中修订离散状态的动作评分;四维连续状态多到无法逐格记录,于是让 DQN 从位置、速度、角度和角速度中学习共同规律;相邻轨迹高度相关,经验回放便打乱并复用记录;评分标准总在变化,目标网络就暂时固定标准。

当"选最高分"容易选中被高估的推车方向,DDQN 把动作选择与价值复核交给两套网络;当控制器需要区分"当前整体状态好不好"和"向左、向右哪个动作相对更好",Dueling DQN 用价值流与优势流来表达。这些算法都沿着同一个目标前进:让有限的交互经验,逐渐变成可靠的长期控制策略。

参考资料

  1. 俞勇等,《动手学强化学习》,第 5 章"时序差分算法"、第 7 章"DQN 算法"、第 8 章"DQN 改进算法"。本文的理论主线、算法公式与主要术语以这些章节为准。本地资料:《动手学强化学习》电子版.pdf
  2. 知乎专栏:https://www.zhihu.com/tardis/bd/art/35882937
  3. https://zhuanlan.zhihu.com/p/110620815
  4. Mnih, V. et al. "Playing Atari with Deep Reinforcement Learning." NIPS Deep Learning Workshop, 2013.
  5. Mnih, V. et al. "Human-level control through deep reinforcement learning." Nature, 2015, 518: 529--533.
  6. van Hasselt, H., Guez, A. & Silver, D. "Deep Reinforcement Learning with Double Q-learning", 2015.
  7. Wang, Z. et al. "Dueling Network Architectures for Deep Reinforcement Learning", 2015.
  8. Farama Foundation, Gymnasium CartPole-v1 环境文档。
相关推荐
zh路西法1 天前
【上手一只MicroDuck】:(一)从机器人结构到强化学习训练框架
python·强化学习·huggingface·ppo·mujoco·microduck
阿里云大数据AI技术2 天前
云栖2026|Agentic AI Infra,加速模型与智能体创新
人工智能·强化学习
AI模力圈9 天前
On-Policy Distillation:原理、变体与工程实现解析
大模型·强化学习·知识蒸馏
xx_xxxxx_10 天前
论文阅读-Search-R1
人工智能·深度学习·机器学习·强化学习
xx_xxxxx_11 天前
论文阅读-REINFORCE++与Lessons of Developing PRMs
人工智能·深度学习·机器学习·强化学习
爱听歌的周童鞋11 天前
强化学习的数学原理 | 赵世钰 | 西湖大学 | 笔记 | Lecture 9 | Part 1 | 策略梯度方法(该方法的基本思路)
强化学习·policy gradient·metric·policy-based
盼小辉丶11 天前
PyTorch强化学习实战——分布式策略梯度
人工智能·pytorch·深度学习·强化学习
爱听歌的周童鞋12 天前
强化学习的数学原理 | 赵世钰 | 西湖大学 | 笔记 | Lecture 8 | Part 7 | 值函数近似(DQN-Experience replay)
强化学习·deep q-learning·experience·replay buffer
爱听歌的周童鞋14 天前
强化学习的数学原理 | 赵世钰 | 西湖大学 | 笔记 | Lecture 8 | Part 5 | 值函数近似(Sarsa 和 Q-learning)
强化学习·sarsa·q-learning·value function·approximation