第 5 讲:价值函数逼近与深度 Q 网络(DQN)

Reinforcement Learning · Lecture 05。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应:Stanford CS234 Lecture 4 后半 / Lecture 5 前半(Value Function Approximation, Deep Q-Learning) 配套代码:code/lecture05/(前 3 个文件只需 numpy;第 4 个文件需要 pip install torch gymnasium) 预计阅读时间:4–5 小时


0. 本讲导航

0.1 本讲要回答的问题

状态太多(甚至是连续的),一张表存不下,而且每个状态几乎只会出现一次。怎样学习价值函数和策略?

前四讲的所有算法都是表格型的:每个状态(或状态–动作对)一个格子。这在网格世界里没问题,但真实世界的问题:

  • Atari 游戏:状态是 210×160 的彩色画面,可能的画面数是天文数字;
  • 机器人:状态是连续的关节角度和速度,同一个状态几乎不可能出现两次;
  • 围棋:约 1017010^{170} 个合法局面。

表格不仅存不下,更致命的是不会泛化:学会了一个画面,对只差一个像素的另一个画面一无所知。回忆第 1 讲 2.4 节,泛化正是 RL 的四个核心特征之一。

本讲的答案:用一个带参数的函数来表示价值,V^(s;w)≈Vπ(s)\hat V(s; w) \approx V^\pi(s) 或 Q^(s,a;w)≈Qπ(s,a)\hat Q(s, a; w) \approx Q^\pi(s, a)。参数的个数远少于状态数,更新一个状态会影响”相似”的其他状态。

0.2 学完本讲,你应该能够

  1. 解释为什么需要函数逼近,以及”泛化”带来的偏差–方差权衡。
  2. 写出梯度下降和随机梯度下降的更新公式,理解学习率的作用。
  3. 把价值函数逼近写成监督学习问题;推导梯度 MC 和半梯度 TD 的更新公式,解释”半梯度”的含义。
  4. 说出线性函数逼近下 MC 和 TD 分别收敛到哪里(最小均方误差解 vs TD 不动点)。
  5. 比较几种常见的特征构造方法(状态聚合、多项式、傅里叶、瓦片编码),理解”能表示”与”好学习”的区别。
  6. 解释”致命三角”(函数逼近 + 自举 + 异策略)为什么会导致发散。
  7. 写出 DQN 算法,解释经验回放和目标网络分别解决了什么问题。
  8. 说出 Double DQN、Dueling DQN、优先经验回放等改进的核心思想。
  9. 用 PyTorch 实现 DQN,并知道常见的实现陷阱(终止 vs 截断、评估方式、多种子)。

0.3 先修知识

知识点用在哪里最低要求
第 3 讲:MC、TD、偏差–方差第 3 节必须
第 4 讲:SARSA、Q-learning、异策略、Double Q-learning第 5–8 节必须
微积分:导数、偏导数、链式法则第 2、3 节知道”梯度指向函数增长最快的方向”
向量点积 w⋅x=∑iwixiw \cdot x = \sum_i w_i x_i全讲会算即可
神经网络基础第 7 节知道”多层线性变换 + 非线性激活”即可;PyTorch 用法代码注释里会讲

0.4 本讲地图

第1节 为什么需要函数逼近?泛化的偏差–方差权衡
   │
第2节 预备知识:梯度下降与随机梯度下降
   │
第3节 价值函数逼近 = 监督学习(但没有标签)→ 梯度 MC、半梯度 TD
   │
第4节 线性函数逼近:收敛到哪里?
   │
第5节 特征构造 + 控制:瓦片编码 + 半梯度 SARSA 解决高山小车
   │
第6节 致命三角:为什么会发散?(Baird 反例)
   │
第7节 DQN:经验回放 + 目标网络
   │
第8节 DQN 之后:Double DQN、Dueling、优先经验回放、Rainbow
   │
第9节 深度 RL 的实践要点

1. 为什么需要函数逼近?

1.1 表格的两个根本问题

  1. 存储:状态数太多,存不下。
  2. 泛化:即使存得下,每个格子只能从”恰好访问到这个状态”的数据中学习。状态越多,每个格子分到的数据越少,估计越不准;而且完全没见过的状态,估计就是初始值——毫无信息。

但现实中,相似的状态往往有相似的价值。车在路上开,位置差 1 厘米,前景几乎一样;游戏画面差一个像素,局势几乎一样。表格方法完全浪费了这种结构。

1.2 函数逼近的思路

用一个带参数 ww 的函数来表示价值:

V^(s;w)≈Vπ(s),Q^(s,a;w)≈Qπ(s,a)\hat V(s; w) \approx V^\pi(s), \qquad \hat Q(s, a; w) \approx Q^\pi(s, a)
  • 参数个数 dd 远小于状态数 ∣S∣|S|;
  • 调整 ww 去拟合一个状态的价值,会同时改变其他状态的估计——好的函数形式会让”相似”的状态一起变化,这就是泛化。

常见的函数形式:线性函数(特征的加权和)、神经网络、决策树、最近邻……本讲关注可微的函数(线性函数和神经网络),因为可以用梯度下降来调参数。

1.3 泛化的代价:又一次偏差–方差权衡

参数比状态少,就不可能让每个状态都完全准确——必然存在近似误差(偏差)。换来的是:每个参数能利用很多状态的数据,**估计噪声(方差)**大大降低。

代码验证:01_linear_vfa_random_walk.py 实验 4,1000 状态随机游走,同样 5000 个回合的数据:

  • 表格型 MC(1000 个参数,没有近似误差):RMS 价值误差 0.108;
  • 状态聚合(10 个参数,价值函数被迫是”台阶”形状):RMS 价值误差 0.062。

参数少了 100 倍,误差反而更小。在数据有限时,适度的泛化是有益的。


2. 预备知识:梯度下降与随机梯度下降

(已经熟悉的读者可以跳过。)

2.1 梯度下降

假设我们想找到使某个函数 J(w)J(w) 最小的参数 ww。梯度 ∇wJ(w)\nabla_w J(w) 是一个向量,指向 JJ 增长最快的方向:

∇wJ(w)=(∂J∂w1,∂J∂w2,…,∂J∂wd)\nabla_w J(w) = \left( \frac{\partial J}{\partial w_1}, \frac{\partial J}{\partial w_2}, \dots, \frac{\partial J}{\partial w_d} \right)

要让 JJ 减小,就沿着梯度的反方向走一小步:

w←w−α ∇wJ(w)w \leftarrow w - \alpha\, \nabla_w J(w)

α>0\alpha > 0 是学习率(步长)。直觉:蒙着眼睛下山,每一步都朝脚下最陡的下坡方向迈一小步。步子太大可能越过谷底甚至”飞出去”(发散),太小则走得很慢。

2.2 随机梯度下降(SGD)

如果 JJ 是一个期望(对数据分布的平均),比如 J(w)=Es∼μ[ℓ(s;w)]J(w) = \mathbb{E}_{s \sim \mu}[\ell(s; w)],精确计算梯度需要遍历所有数据。随机梯度下降每次只用一个(或一小批)样本来估计梯度:

w←w−α ∇wℓ(s;w),s∼μw \leftarrow w - \alpha\, \nabla_w \ell(s; w), \qquad s \sim \mu

单个样本的梯度是真实梯度的无偏估计(期望相等),虽然有噪声,但只要学习率适当地减小,SGD 仍然会收敛。这和第 3 讲”用采样代替期望”是同一个思想。

2.3 条件数:为什么有些问题梯度下降走不动

如果 JJ 的等高线是”圆”的,梯度直指谷底,梯度下降很快;如果等高线是”又窄又长的椭圆”,梯度几乎垂直于谷底的方向,梯度下降会在两壁之间来回”之”字形震荡,前进极慢。衡量这种”狭长程度”的指标叫条件数(二次函数的 Hessian 矩阵最大特征值与最小特征值之比)。第 4.4 节会看到这在特征选择中的实际影响。


3. 价值函数逼近:没有标签的监督学习

3.1 如果有”先知”

假设有一个先知,能告诉我们任何状态的真实价值 Vπ(s)V^\pi(s)。那问题就变成了普通的监督学习(回归):让 V^(s;w)\hat V(s; w) 尽量接近 Vπ(s)V^\pi(s)。目标函数:

J(w)=Es∼μ[(Vπ(s)−V^(s;w))2]=∑sμ(s)(Vπ(s)−V^(s;w))2J(w) = \mathbb{E}_{s \sim \mu}\left[ \big( V^\pi(s) - \hat V(s; w) \big)^2 \right] = \sum_s \mu(s) \big( V^\pi(s) - \hat V(s; w) \big)^2

这叫均方价值误差(mean squared value error, VE)。

为什么要按 μ(s)\mu(s) 加权? 参数比状态少,不可能让所有状态都准确,必须有所取舍。自然的取舍是:经常访问的状态更重要。μ(s)\mu(s) 是策略 π\pi 下各状态被访问的比例(同策略分布,回忆第 1 讲 7.6 节的状态分布)。

对 ww 求梯度(链式法则):

∇wJ(w)=−2 Es∼μ[(Vπ(s)−V^(s;w))∇wV^(s;w)]\nabla_w J(w) = -2\, \mathbb{E}_{s \sim \mu}\left[ \big( V^\pi(s) - \hat V(s; w) \big) \nabla_w \hat V(s; w) \right]

SGD(把常数 2 吸收进 α\alpha):

w←w+α(Vπ(s)−V^(s;w))∇wV^(s;w)w \leftarrow w + \alpha \big( V^\pi(s) - \hat V(s; w) \big) \nabla_w \hat V(s; w)

3.2 没有先知:用目标代替 Vπ(s)V^\pi(s)

现实中没有先知。第 3 讲已经告诉我们怎样得到 Vπ(s)V^\pi(s) 的”替身”——把第 3 讲的更新目标填进去:

方法用什么代替 Vπ(st)V^\pi(s_t)更新公式
梯度 MC回报 GtG_tw←w+α(Gt−V^(st;w))∇wV^(st;w)w \leftarrow w + \alpha \big( G_t - \hat V(s_t; w) \big) \nabla_w \hat V(s_t; w)
半梯度 TD(0)rt+γV^(st+1;w)r_t + \gamma \hat V(s_{t+1}; w)w←w+α(rt+γV^(st+1;w)−V^(st;w))∇wV^(st;w)w \leftarrow w + \alpha \big( r_t + \gamma \hat V(s_{t+1}; w) - \hat V(s_t; w) \big) \nabla_w \hat V(s_t; w)

表格方法是特例:如果 V^(s;w)=ws\hat V(s; w) = w_s(每个状态一个参数),则 ∇wV^(s;w)\nabla_w \hat V(s; w) 是只在第 ss 个位置为 1 的向量,上面的公式退化为第 3 讲的 V(s)←V(s)+α(目标−V(s))V(s) \leftarrow V(s) + \alpha(\text{目标} - V(s))。

3.3 梯度 MC:真正的随机梯度下降

GtG_t 是 Vπ(st)V^\pi(s_t) 的无偏估计(第 3 讲),所以梯度 MC 的更新方向是真实梯度 −∇wJ(w)-\nabla_w J(w) 的无偏估计——它是真正的 SGD。只要学习率满足 Robbins–Monro 条件,就收敛到 J(w)J(w) 的一个局部最小值(线性情况下是全局最小值)。

3.4 半梯度 TD:为什么叫”半”梯度?

TD 目标 rt+γV^(st+1;w)r_t + \gamma \hat V(s_{t+1}; w) 本身也依赖 ww。但在求梯度时,我们假装它是一个常数,只对 V^(st;w)\hat V(s_t; w) 求导。如果老老实实地对整个误差 (rt+γV^(st+1;w)−V^(st;w))2\big(r_t + \gamma \hat V(s_{t+1}; w) - \hat V(s_t; w)\big)^2 求导,应该还有一项 γ∇wV^(st+1;w)\gamma \nabla_w \hat V(s_{t+1}; w)。我们忽略了它,所以只算了”一半”的梯度。

后果:

  1. 半梯度 TD 不是任何目标函数的梯度下降,所以不能套用”SGD 收敛到最小值”的结论。
  2. 线性、同策略时它仍然收敛,但收敛到的是 TD 不动点,而不是 VE 的最小值(4.3 节)。
  3. 在某些条件下它会发散(第 6 节)。

那为什么还要用它? 因为它保留了 TD 的全部优点:在线更新、方差小、学得快(第 3 讲)。而且”老老实实求全梯度”的方法(叫残差梯度法)在实践中通常学得更慢,而且在随机环境中会收敛到错误的答案。


4. 线性函数逼近

4.1 特征与线性函数

把每个状态表示成一个特征向量 x(s)=(x1(s),…,xd(s))x(s) = (x_1(s), \dots, x_d(s)),价值是特征的加权和:

V^(s;w)=w⋅x(s)=∑i=1dwi xi(s)\hat V(s; w) = w \cdot x(s) = \sum_{i=1}^d w_i\, x_i(s)

线性函数的梯度特别简单:∇wV^(s;w)=x(s)\nabla_w \hat V(s; w) = x(s)。所以:

梯度 MC:w←w+α(Gt−w⋅x(st))x(st)\text{梯度 MC:} \quad w \leftarrow w + \alpha \big( G_t - w \cdot x(s_t) \big) x(s_t) 半梯度 TD(0):w←w+α(rt+γ w⋅x(st+1)−w⋅x(st))x(st)\text{半梯度 TD(0):} \quad w \leftarrow w + \alpha \big( r_t + \gamma\, w \cdot x(s_{t+1}) - w \cdot x(s_t) \big) x(s_t)

更新的直觉:误差是正的(实际比预期好),就沿着”当前状态的特征方向”增大参数——下次再遇到具有这些特征的状态,预测就会更高。

4.2 实验:1000 状态随机游走(Sutton & Barto 例 9.1)

  • 1000 个状态,从中间出发;每步等概率向左或向右跳 1~100 格;跳出左边界得 −1,右边界得 +1;γ=1\gamma = 1。
  • 真实价值从约 −0.92(最左)到 +0.92(最右)平滑变化,可以用第 1 讲的解析法精确算出。
  • 状态聚合:把 1000 个状态按顺序分成 10 组,每组共享一个参数(特征是”属于哪一组”的独热向量)。

梯度 MC(代码 01 实验 1,20000 个回合):

  状态              1   101   201   301   401   501   601   701   801   901  1000
  真实价值       -0.92 -0.75 -0.57 -0.38 -0.19  0.00  0.19  0.38  0.57  0.75  0.92
  梯度 MC        -0.84 -0.66 -0.48 -0.24 -0.05  0.15  0.35  0.50  0.63  0.82  0.82
  最优聚合解     -0.83 -0.65 -0.47 -0.28 -0.09  0.09  0.28  0.47  0.65  0.83  0.83

价值函数变成了”台阶”。梯度 MC 的收敛点就是这组特征下 VE 最小的解(每组取组内真实价值按 μ\mu 加权的平均)。学到的结果(RMS 误差 0.071)与理论最优(0.054)之间的差距来自常数步长的噪声。

4.3 TD 不动点

半梯度 TD(代码 01 实验 2,20000 个回合):

  半梯度 TD(学到的)  -0.73 -0.54 -0.38 -0.24 -0.12 -0.00  0.15  0.30  0.48  0.69  0.69
  TD 不动点(解析)    -0.73 -0.54 -0.39 -0.25 -0.12  0.00  0.15  0.30  0.48  0.69  0.69
  最优聚合解           -0.83 -0.65 -0.47 -0.28 -0.09  0.09  0.28  0.47  0.65  0.83  0.83

RMS 误差:半梯度 TD 0.119,TD 不动点 0.117,最优 0.054。

TD 收敛到的解在两端”更平”,误差约为最优的 2 倍。这不是没训练够——学到的结果已经和解析算出的不动点几乎一样。这是”自举 + 函数逼近”的固有偏差。

TD 不动点是什么? 线性半梯度 TD 的期望更新量是

E[(r+γ w⋅x(s′)−w⋅x(s)) x(s)]=b−Aw,A=E[x(s)(x(s)−γx(s′))⊤],  b=E[r x(s)]\mathbb{E}\big[ (r + \gamma\, w \cdot x(s') - w \cdot x(s))\, x(s) \big] = b - A w, \quad A = \mathbb{E}\big[ x(s) (x(s) - \gamma x(s'))^\top \big], \; b = \mathbb{E}[r\, x(s)]

令期望更新为 0,得到 AwTD=bA w_{TD} = b,即 wTD=A−1bw_{TD} = A^{-1} b。

直觉:在 TD 不动点上,“用自己的估计当目标”达到了自洽——估计值与它自举出来的目标在平均意义上一致。但”自洽”不等于”正确”:函数逼近的误差会通过自举传播和累积。在上面的例子中,靠近边界的组的估计被相邻组”拉平”了。

理论保证(Tsitsiklis & Van Roy, 1997):线性函数逼近、同策略分布下,半梯度 TD(0) 以概率 1 收敛到 TD 不动点,且

VE(wTD)≤11−γmin⁡wVE(w)\mathrm{VE}(w_{TD}) \le \frac{1}{1 - \gamma} \min_w \mathrm{VE}(w)

γ\gamma 接近 1 时这个界很松(本例 γ=1\gamma = 1,界没有意义),但至少保证了收敛。

4.4 特征的选择:“能表示”与”好学习”

几种常见的特征:

特征定义(uu 为缩放到 [0,1][0,1] 的状态)特点
状态聚合“属于哪一组”的独热向量最简单;价值是台阶形状
多项式基1,u,u2,…,un1, u, u^2, \dots, u^n表示能力强,但高阶项彼此高度相关
傅里叶基cos⁡(0),cos⁡(πu),cos⁡(2πu),…,cos⁡(nπu)\cos(0), \cos(\pi u), \cos(2\pi u), \dots, \cos(n\pi u)不同频率的余弦波叠加;彼此近似正交
瓦片编码多层错开的网格(5.2 节)稀疏、计算快、泛化平滑;连续控制中很常用
径向基函数(RBF)exp⁡(−∥s−ci∥2/2σ2)\exp(-\lVert s - c_i \rVert^2 / 2\sigma^2)以若干”中心”为基准的平滑特征

实验(代码 01 实验 3,梯度 MC,10000 个回合,3 个种子平均):

特征参数数理论最优误差学到的误差条件数 cond(X⊤DX)\mathrm{cond}(X^\top D X)
多项式 5 阶60.00100.12032.5×1072.5 \times 10^7
多项式 10 阶110.00040.11397.8×10147.8 \times 10^{14}
多项式 20 阶210.00020.10942.9×10172.9 \times 10^{17}
傅里叶 5 阶60.00790.02607.5
傅里叶 10 阶110.00280.02989.8
傅里叶 20 阶210.00080.031812

“理论最优误差”是用加权最小二乘直接求出的该特征下最好的线性逼近(需要知道真实价值,不是学习算法)。

这张表的教训:

  • 表示能力不是问题:两种特征都能把价值函数表示得非常准,多项式基甚至更准。
  • 可学习性才是问题:多项式基学到的误差比理论最优差上百倍,而且阶数越高也没改善。原因在最后一栏:u,u2,…,u20u, u^2, \dots, u^{20} 在 [0,1][0, 1] 上长得非常像,条件数高达 101710^{17},梯度下降在这个”又窄又长的山谷”里几乎走不动(2.3 节)。傅里叶特征近似正交,条件数只有 10 左右。

实践启示:选特征时,除了”能不能表示”,还要看”好不好学”——把输入缩放到合适范围、让特征尽量不相关。这些工程细节在神经网络中同样重要(输入归一化、合适的初始化、批归一化等)。


5. 函数逼近下的控制:瓦片编码 + 半梯度 SARSA

5.1 从评估到控制

把 V^(s;w)\hat V(s; w) 换成 Q^(s,a;w)\hat Q(s, a; w),把第 4 讲的 SARSA 目标填进去:

w←w+α[r+γQ^(s′,a′;w)−Q^(s,a;w)]∇wQ^(s,a;w)w \leftarrow w + \alpha \big[ r + \gamma \hat Q(s', a'; w) - \hat Q(s, a; w) \big] \nabla_w \hat Q(s, a; w)

这就是半梯度 SARSA。把目标换成 r+γmax⁡a′Q^(s′,a′;w)r + \gamma \max_{a'} \hat Q(s', a'; w) 就是带函数逼近的 Q-learning。

5.2 瓦片编码

对于低维连续状态,**瓦片编码(tile coding)**是一种简单有效的特征:

  一层网格(= 状态聚合)         多层错开的网格(瓦片编码)
  ┌───┬───┬───┬───┐            ┌───┬───┬───┬───┐
  │   │   │   │   │            │ ┌─┼─┐ │   │   │     ● = 一个状态
  ├───┼───┼───┼───┤            ├─┼─┼─┼─┼───┼───┤     它在每一层网格中各落在一个格子里,
  │   │ ● │   │   │            │ │ │●│ │   │   │     激活 n 个特征(每层一个)
  ├───┼───┼───┼───┤            ├─┼─┴─┼─┘   │   │
  │   │   │   │   │            │   │   │   │   │
  └───┴───┴───┴───┘            └───┴───┴───┴───┘
  • 每层网格把状态空间切成格子,状态落在哪个格子,那个特征就是 1;
  • 用 nn 层互相错开的网格,每个状态激活 nn 个特征;
  • 两个状态越接近,共同激活的特征越多,价值就越相似——泛化是平滑的;
  • 有效分辨率比单层网格细 nn 倍,参数只多 nn 倍;
  • 特征是稀疏的(只有 nn 个 1),计算 w⋅x(s)w \cdot x(s) 只需把 nn 个参数相加,非常快。

代码验证:02_mountain_car_tile_coding.py 演示 1:8 层 9×9 网格,共 648 个特征。状态 (x=−0.50,v=0)(x = -0.50, v = 0) 与 (−0.49,0)(-0.49, 0) 共享全部 8 个特征,与 (−0.30,0)(-0.30, 0) 只共享 1 个。

5.3 高山小车

Sutton & Barto 例 10.1:小车在山谷里,要开到右边山顶。状态是位置 x∈[−1.2,0.5]x \in [-1.2, 0.5] 和速度 v∈[−0.07,0.07]v \in [-0.07, 0.07],两个连续数;动作是向左加速、不踩油门、向右加速;每步奖励 −1。难点:发动机太弱,直接向右冲不上去,必须先向左倒车爬坡、借助下滑的势能再冲向右边——“为了达到目标,先要远离目标”。

学习曲线(每回合到达山顶所需步数,5 次运行平均,代码 02 演示 2):

α\alpha第 1 回合2–1011–5051–100101–200201–300
0.129361226365230183152
0.51516487209148137128

(α\alpha 是总步长,分到每个激活特征上是 α/8\alpha / 8。参数初始化为 0;因为每步奖励是 −1,0 是一个”乐观”的初始值,驱动智能体去尝试没试过的动作,所以不需要 ε\varepsilon-贪心——回忆第 4 讲 7.1 节的乐观初始化。)

学到的策略大致按”速度的正负”来决定:速度向右就向右踩油门,速度向左就向左踩油门——荡秋千:顺着当前运动方向加速,一来一回积累能量。用贪心策略跑一个回合:先向左退到约 −0.8,冲向右边但没冲上去;再退到约 −1.17,第二次才借着更大的势能冲上山顶,共 145 步。智能体从没被告诉”要先倒车”,只知道”每步 −1”,它自己发现了这个策略。


6. 致命三角:为什么会发散?

6.1 三个因素

表格型 Q-learning 保证收敛;线性同策略 TD 也保证收敛。但 Sutton & Barto 指出,当下面三个因素同时出现时,可能发散:

  1. 函数逼近:参数被多个状态共享;
  2. 自举:用自己的估计当目标(TD、Q-learning);
  3. 异策略:更新所依据的状态分布,与目标策略自己的状态分布不同。

这三者被称为致命三角(deadly triad)。去掉任意一个,就恢复稳定。

注意:Q-learning + 函数逼近恰好三者俱全——而这正是 DQN 要做的事。

6.2 Baird 反例

Baird(1995)构造了一个小得不能再小的例子:7 个状态、8 个参数、所有奖励都是 0(真实价值全是 0,而且 w=0w = 0 就能精确表示)。

   上面 6 个状态:V(i) = 2 w_i + w_7         ○  ○  ○  ○  ○  ○
                                              ╲  ╲  │  │  ╱  ╱     实线:去下面的状态
   下面的状态:   V(6) = w_6 + 2 w_7                  ●               虚线:去上面某个状态
  • 目标策略:永远走实线。行为策略:6/7 概率走虚线、1/7 概率走实线。
  • 异策略半梯度 TD,用重要性采样比 ρ=π(a∣s)/b(a∣s)\rho = \pi(a \mid s)/b(a \mid s) 修正(实线 ρ=7\rho = 7,虚线 ρ=0\rho = 0): w←w+α ρ (r+γV^(s′;w)−V^(s;w))x(s)w \leftarrow w + \alpha\, \rho\, \big( r + \gamma \hat V(s'; w) - \hat V(s; w) \big) x(s)

结果(代码 03,γ=0.99\gamma = 0.99,α=0.01\alpha = 0.01,初始 w=[1,1,1,1,1,1,10,1]w = [1,1,1,1,1,1,10,1]):

步数∥w∥\lVert w \rVert(异策略半梯度 TD,采样)∥w∥\lVert w \rVert(半梯度期望更新,无噪声)
010.310.3
20052.229.6
600166.8140.0
1000416.3436.9

参数一路增长,没有收敛的迹象。即使完全没有采样噪声(右列:每一步都是精确的期望更新),也照样发散——问题不在噪声,而在”更新的分布”与”自举 + 函数逼近”的相互作用。

去掉任意一角:

  • 去掉函数逼近(换成表格):各状态的价值先向 γV(6)\gamma V(6) 靠拢,然后缓慢而稳定地衰减到 0(20 万步后最大值 0.70),始终有界。
  • 去掉异策略(按目标策略自己的状态分布更新——它只会访问状态 6):V(6)V(6) 从 12 平稳下降(1000 步后 7.3),参数不再爆炸。

6.3 发散的直觉

  • V(6)=w6+2w7V(6) = w_6 + 2 w_7,上面每个状态 V(i)=2wi+w7V(i) = 2 w_i + w_7,它们共享 w7w_7。
  • 从上面的状态走实线到状态 6 时(ρ=7\rho = 7),TD 误差 δ=γV(6)−V(i)\delta = \gamma V(6) - V(i)。为了让 V(i)V(i) 追上 γV(6)\gamma V(6),更新会增大 wiw_i 和 w7w_7——而 w7w_7 增大又让 V(6)V(6) 变大,于是下一次的目标 γV(6)\gamma V(6) 更高……”追目标”的同时把目标推得更远。
  • 同策略时,状态 6 自己会被频繁更新,把 V(6)V(6) 拉回来,形成负反馈;但在行为策略的分布下,从状态 6 出发的实线转移太少,这个”刹车”不够用。
  • 表格情况下没有参数共享,更新一个状态不会影响别的状态的目标,也就没有这个正反馈。

6.4 收敛性一览

算法表格线性非线性(神经网络)
MC 评估(同/异策略)✓✓✓(收敛到局部最优)
TD 评估(同策略)✓✓✗
TD 评估(异策略)✓✗✗
MC 控制 / SARSA✓(✓)✗
Q-learning✓✗✗

✓ = 保证收敛;(✓) = 在接近最优的价值附近震荡;✗ = 没有收敛保证(存在发散的例子)。

Q-learning + 神经网络在最右下角:没有任何收敛保证。 DQN 的贡献就在于:用工程手段让这个”理论上不保证”的组合在实践中稳定下来。


7. DQN:深度 Q 网络

7.1 背景

2013 年(NeurIPS 研讨会论文)和 2015 年(Nature 论文),DeepMind 的 Mnih 等人提出 DQN,第一次让一个智能体直接从原始像素学会玩 Atari 2600 游戏:

  • 输入:最近 4 帧游戏画面(缩放为 84×84 灰度图,叠在一起让状态近似马尔可夫——回忆第 1 讲 3.5 节);
  • 网络:卷积神经网络,输出每个动作(最多 18 个)的 Q 值;
  • 同一套网络结构和超参数,在 49 个游戏上训练,许多游戏达到或超过人类专业测试员的水平。

这被普遍视为深度强化学习时代的开端。它的核心就是 Q-learning + 神经网络 + 两个稳定化技巧。

7.2 技巧一:经验回放

问题:直接用在线 Q-learning 训练神经网络,每一步用刚刚经历的一条转移做一次梯度更新。

  • 样本高度相关:连续的游戏画面几乎一样,用相关的数据做 SGD,梯度估计偏差很大,网络会”过拟合”最近的经历、忘掉之前学到的东西。
  • 数据只用一次:每条经验用完就扔,样本效率极低。

解决:把经历过的转移 (s,a,r,s′,done)(s, a, r, s', \text{done}) 存进一个大的回放缓冲区(replay buffer),训练时从中均匀随机抽取一小批(mini-batch)来学习。

  • 打破相关性:一个批次里的样本来自很多不同的时间、不同的回合,近似独立同分布;
  • 数据复用:每条转移可以被抽中很多次;
  • 平滑分布:训练数据是过去很多个策略的混合,不会因为策略的一点变化而剧烈摆动。

为什么这样做是合法的? 因为 Q-learning 是异策略的(第 4 讲 4.3 节):旧策略收集的数据,同样可以用来学最优策略的 Q 值。同策略算法(如 SARSA)不能直接使用经验回放——旧数据来自旧策略,与当前要评估的策略不匹配。

7.3 技巧二:目标网络

问题:Q-learning 的目标 r+γmax⁡a′Q(s′,a′;θ)r + \gamma \max_{a'} Q(s', a'; \theta) 依赖于正在训练的参数 θ\theta。每更新一次 θ\theta,目标也跟着变——“追着自己的尾巴跑”。用神经网络时尤其糟糕:更新一个状态的 Q 值会影响所有状态(包括 s′s')的 Q 值,这正是 6.3 节发散机制的来源。

解决:维护一个参数为 θ−\theta^- 的目标网络,用它来计算 TD 目标:

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

θ−\theta^- 在一段时间内冻结不变,每隔 CC 步才从在线网络复制一次:θ−←θ\theta^- \leftarrow \theta。

这样,在 CC 步之内,学习问题就变成了一个**目标固定的监督学习(回归)**问题,稳定得多。可以把它看成”每隔 CC 步做一次近似的价值迭代”。

7.4 损失函数

在线网络参数 θ\theta,目标网络参数 θ−\theta^-,从缓冲区抽取的一批转移 {(si,ai,ri,si′,di)}\{(s_i, a_i, r_i, s'_i, d_i)\}:

yi=ri+γ (1−di)max⁡a′Q(si′,a′;θ−)y_i = r_i + \gamma\, (1 - d_i) \max_{a'} Q(s'_i, a'; \theta^-) L(θ)=1B∑iℓ(yi−Q(si,ai;θ))L(\theta) = \frac{1}{B} \sum_i \ell\big( y_i - Q(s_i, a_i; \theta) \big)
  • di=1d_i = 1 表示 si′s'_i 是真正的终止状态(没有未来);
  • ℓ\ell 常用 Huber 损失:误差小时是平方 12e2\frac12 e^2,误差大时是线性 ∣e∣−12|e| - \frac12,对偶尔出现的超大 TD 误差不那么敏感;
  • 目标 yiy_i 不参与求导(在 PyTorch 中放在 torch.no_grad() 里)——这正是 3.4 节的”半梯度”。

7.5 算法

算法:DQN
初始化:在线网络 Q(·; θ),目标网络 θ⁻ ← θ,回放缓冲区 D(容量 N)
s ← env.reset()
对 step = 1, 2, ..., T:
    ε ← 按计划衰减(例如从 1.0 线性降到 0.05)
    a ← ε-贪心(Q(s, ·; θ))
    执行 a,得到 r, s', terminated, truncated
    把 (s, a, r, s', terminated) 存入 D
    s ← s';如果回合结束,s ← env.reset()
    如果 D 中数据足够:
        从 D 中均匀抽取一批 B 条转移
        y ← r + γ (1 - terminated) max_a' Q(s', a'; θ⁻)        (不求导)
        对 L(θ) = mean(Huber(y - Q(s, a; θ))) 做一步梯度下降
    每隔 C 步:θ⁻ ← θ

7.6 实现中的陷阱:终止 vs 截断

CartPole 最多 500 步。第 500 步时回合”结束”了,但杆子还立着——未来本来还有奖励,只是因为时间限制被人为截断。

  • 真正终止(terminated,杆子倒了):没有未来,y=ry = r;
  • 时间截断(truncated):有未来,应当继续自举 y=r+γmax⁡a′Q(s′,a′;θ−)y = r + \gamma \max_{a'} Q(s', a'; \theta^-)。

如果把截断也当成终止,智能体会以为”第 500 步之后一切归零”,价值估计会被系统性地压低。Gymnasium 用 terminated 和 truncated 两个标志区分这两种情况,只把 terminated 存进缓冲区。

一个有用的检查:CartPole 学会之后,杆子永远不倒,每步 +1,γ=0.99\gamma = 0.99,所以 Q 值应当接近 11−0.99=100\frac{1}{1 - 0.99} = 100。代码 04 训练结束时平均 Q 值约为 100.6 ✓。如果错误地把截断当终止,Q 值会明显偏低。

7.7 实验:CartPole 上的 DQN 与消融

04_dqn_cartpole.py:两层 128 单元的 MLP,Adam(学习率 5e-4),缓冲区 1 万,批大小 64,目标网络每 250 步同步,ε\varepsilon 在 1 万步内从 1.0 线性降到 0.05,共 8 万步。每 5000 步用贪心策略评估 10 个回合。4 个随机种子:

设置首次评估达到 500 的步数(4 个种子)平均最后 3 次评估的平均(4 个种子)保存的最好网络重新评估
DQN50k, 40k, 55k, 30k43.8k500, 500, 242, 330全部 500
Double DQN45k, 65k, 40k, 40k47.5k500, 230, 394, 474全部 500
无经验回放60k, 80k, 80k, 75k73.8k500, 381, 481, 472全部 500
无目标网络从未达到—约 9约 9

解读:

  1. 去掉目标网络:彻底失败。平均回报只有 9 左右(几乎一开始就倒)。打印训练日志会看到平均 Q 值在 3 万步内爆炸到 10810^8 量级(真实值不超过 100)——这就是第 6 节的致命三角发散,在真实的深度 RL 中活生生地出现了。
  2. 去掉经验回放(只用最近 64 条连续转移训练):在 CartPole 这个简单问题上仍然能学会,但明显更慢(平均 73.8k 步才首次达到 500,而完整 DQN 是 43.8k)。需要说明的是,在更难的 Atari 游戏上,DQN 原论文的消融实验显示经验回放的作用非常大——去掉它,很多游戏的得分会大幅下降。不同问题上,各个组件的重要性可能不同,不要从一个简单问题上的消融得出普遍结论。
  3. 性能会波动:即使学到了满分,之后也可能突然下降(DQN 种子 2 最后 3 次评估平均只有 242)。所以实践中要定期评估并保存最好的模型——4 个种子保存的最好网络,在 20 个新回合上全部达到 500。
  4. Double DQN 在这个问题上与 DQN 相当。它的优势在动作多、奖励噪声大、高估问题严重的任务上更明显(第 4 讲第 6 节)。

8. DQN 之后的改进

DQN 发表后,大量工作对它进行了改进。几个最重要的:

改进解决的问题核心思想
Double DQN(van Hasselt et al., 2016)最大化偏差导致 Q 值高估用在线网络挑动作、目标网络评估:y=r+γQ(s′,arg⁡max⁡a′Q(s′,a′;θ);θ−)y = r + \gamma Q(s', \arg\max_{a'} Q(s', a'; \theta); \theta^-)。只需改一行代码
Dueling DQN(Wang et al., 2016)很多状态下”选哪个动作”不太重要,但网络仍要为每个动作单独学 Q 值网络分两路输出:状态价值 V(s)V(s) 和优势 A(s,a)A(s, a),再组合成 $Q(s,a) = V(s) + A(s,a) - \frac{1}{A}\sum_{a’} A(s,a’)$
优先经验回放(Schaul et al., 2016)均匀抽样浪费在”已经学会”的转移上按 TD 误差大小抽样(误差大的更”值得学”),并用重要性权重修正偏差
多步回报1 步 TD 传播信息慢用第 3 讲的 nn 步回报作为目标
分布式 RL(C51 等)只学期望丢失了回报分布的信息学习回报的整个分布,而不只是均值
Noisy Netsε\varepsilon-贪心的探索很粗糙在网络参数中加入可学习的噪声来驱动探索
Rainbow(Hessel et al., 2018)—把以上六种改进组合在一起,在 Atari 上显著超过每一种单独的改进

9. 深度 RL 的实践要点

  1. 一定要用多个随机种子(至少 3~5 个)。本讲 DQN 的实验中,同一个设置在不同种子上”首次达到满分”的时间从 3 万步到 5.5 万步不等。
  2. 对超参数敏感。代码 04 的超参数是在 3 个种子上试了十几种组合后选出来的;学习率、缓冲区大小、目标网络更新频率稍变,结果就可能差很多。
  3. 评估要用贪心策略、单独的环境。训练时的回报包含了 ε\varepsilon 探索的噪声。
  4. 监控 Q 值。Q 值远超理论上限(如 Rmax⁡1−γ\frac{R_{\max}}{1 - \gamma})是发散或高估的信号。
  5. 保存最好的模型。深度 RL 的性能常常在学好之后又突然下降。
  6. 区分终止与截断(7.6 节)。
  7. 从简单问题开始调试。先在 CartPole 这样几十秒就能跑完的问题上验证代码正确,再去跑需要几小时、几天的问题。

10. 本讲总结

10.1 核心概念清单

  1. 函数逼近用带参数的函数表示价值,实现泛化;参数少于状态,用近似误差(偏差)换来方差的降低。
  2. 价值函数逼近 = 用 RL 目标代替标签的监督学习:梯度 MC 用 GtG_t,半梯度 TD 用 r+γV^(s′;w)r + \gamma \hat V(s'; w)。
  3. 半梯度:TD 目标也依赖 ww,但求导时把它当常数。
  4. 线性函数逼近:梯度就是特征 x(s)x(s);梯度 MC 收敛到最小 VE 解;半梯度 TD 收敛到 TD 不动点,误差 ≤11−γ×\le \frac{1}{1-\gamma} \times 最优。
  5. 特征选择:既要”能表示”,也要”好学习”(条件数);瓦片编码适合低维连续状态。
  6. 致命三角:函数逼近 + 自举 + 异策略可能发散;Q-learning + 神经网络三者俱全。
  7. DQN:Q-learning + 神经网络 + 经验回放(打破相关性、复用数据)+ 目标网络(冻结目标、避免追尾)。
  8. 实现细节:Huber 损失、终止 vs 截断、贪心评估、保存最好模型、多种子。
  9. 改进:Double DQN、Dueling、优先经验回放、多步回报、分布式 RL、Noisy Nets → Rainbow。

10.2 公式速查表

名称公式
梯度下降w←w−α∇wJ(w)w \leftarrow w - \alpha \nabla_w J(w)
均方价值误差VE(w)=∑sμ(s)(Vπ(s)−V^(s;w))2\mathrm{VE}(w) = \sum_s \mu(s) (V^\pi(s) - \hat V(s; w))^2
通用 VFA 更新w←w+α(目标−V^(s;w))∇wV^(s;w)w \leftarrow w + \alpha (\text{目标} - \hat V(s; w)) \nabla_w \hat V(s; w)
线性价值V^(s;w)=w⋅x(s)\hat V(s; w) = w \cdot x(s),∇wV^=x(s)\nabla_w \hat V = x(s)
梯度 MC(线性)w←w+α(Gt−w⋅x(st))x(st)w \leftarrow w + \alpha (G_t - w \cdot x(s_t)) x(s_t)
半梯度 TD(线性)w←w+α(rt+γw⋅x(st+1)−w⋅x(st))x(st)w \leftarrow w + \alpha (r_t + \gamma w \cdot x(s_{t+1}) - w \cdot x(s_t)) x(s_t)
TD 不动点Aw=bA w = b,A=E[x(s)(x(s)−γx(s′))⊤]A = \mathbb{E}[x(s)(x(s) - \gamma x(s'))^\top],b=E[r x(s)]b = \mathbb{E}[r\, x(s)]
TD 误差界VE(wTD)≤11−γmin⁡wVE(w)\mathrm{VE}(w_{TD}) \le \frac{1}{1-\gamma} \min_w \mathrm{VE}(w)
半梯度 SARSAw←w+α[r+γQ^(s′,a′;w)−Q^(s,a;w)]∇wQ^(s,a;w)w \leftarrow w + \alpha [r + \gamma \hat Q(s', a'; w) - \hat Q(s, a; w)] \nabla_w \hat Q(s, a; w)
异策略 TD(重要性采样)w←w+αρ δ x(s)w \leftarrow w + \alpha \rho\, \delta\, x(s),ρ=π(a∣s)/b(a∣s)\rho = \pi(a \mid s) / b(a \mid s)
DQN 目标y=r+γ(1−d)max⁡a′Q(s′,a′;θ−)y = r + \gamma (1 - d) \max_{a'} Q(s', a'; \theta^-)
Double DQN 目标y=r+γ(1−d) Q(s′,arg⁡max⁡a′Q(s′,a′;θ);θ−)y = r + \gamma (1 - d)\, Q(s', \arg\max_{a'} Q(s', a'; \theta); \theta^-)
DuelingQ(s,a)=V(s)+A(s,a)−1∣A∣∑a′A(s,a′)Q(s,a) = V(s) + A(s,a) - \frac{1}{\lvert A\rvert} \sum_{a'} A(s,a')

10.3 中英术语对照表

中文英文中文英文
函数逼近Function approximation价值函数逼近Value function approximation (VFA)
泛化Generalization特征向量Feature vector
梯度下降Gradient descent随机梯度下降Stochastic gradient descent (SGD)
学习率Learning rate条件数Condition number
均方价值误差Mean squared value error (VE)同策略分布On-policy distribution
梯度 MCGradient Monte Carlo半梯度 TDSemi-gradient TD
TD 不动点TD fixed point残差梯度Residual gradient
状态聚合State aggregation多项式基Polynomial basis
傅里叶基Fourier basis瓦片编码Tile coding
径向基函数Radial basis function (RBF)高山小车Mountain Car
致命三角Deadly triadBaird 反例Baird’s counterexample
重要性采样比Importance sampling ratio深度 Q 网络Deep Q-Network (DQN)
经验回放Experience replay回放缓冲区Replay buffer
目标网络Target networkHuber 损失Huber loss
终止 / 截断Terminated / Truncated消融实验Ablation study
双 DQNDouble DQN对决网络Dueling network
优先经验回放Prioritized experience replay灾难性遗忘Catastrophic forgetting

11. 练习题

练习 1(概念):为什么说”表格方法是线性函数逼近的特例”?写出对应的特征向量,并验证梯度 MC 的更新公式退化为第 3 讲的形式。

参考答案

取 x(s)=esx(s) = e_s(第 ss 个位置为 1 的独热向量),则 V^(s;w)=w⋅es=ws\hat V(s; w) = w \cdot e_s = w_s。梯度 MC 更新 w←w+α(Gt−wst)estw \leftarrow w + \alpha(G_t - w_{s_t}) e_{s_t} 只改变第 sts_t 个分量:wst←wst+α(Gt−wst)w_{s_t} \leftarrow w_{s_t} + \alpha(G_t - w_{s_t}),正是第 3 讲的 V(s)←V(s)+α(G−V(s))V(s) \leftarrow V(s) + \alpha(G - V(s))。代码 01 实验 4 验证了这一点。

练习 2(手算):特征 x(s1)=[1,0]x(s_1) = [1, 0],x(s2)=[1,1]x(s_2) = [1, 1],当前 w=[0.5,0.5]w = [0.5, 0.5],α=0.1\alpha = 0.1,γ=1\gamma = 1。观察到转移 s1→r=1s2s_1 \xrightarrow{r = 1} s_2。计算半梯度 TD(0) 更新后的 ww,以及更新后 V^(s1)\hat V(s_1) 和 V^(s2)\hat V(s_2) 的值。注意 V^(s2)\hat V(s_2) 也变了吗?

参考答案

V^(s1)=0.5\hat V(s_1) = 0.5,V^(s2)=1.0\hat V(s_2) = 1.0。TD 误差 δ=1+1.0−0.5=1.5\delta = 1 + 1.0 - 0.5 = 1.5。 w←[0.5,0.5]+0.1×1.5×[1,0]=[0.65,0.5]w \leftarrow [0.5, 0.5] + 0.1 \times 1.5 \times [1, 0] = [0.65, 0.5]。 更新后 V^(s1)=0.65\hat V(s_1) = 0.65,V^(s2)=0.65+0.5=1.15\hat V(s_2) = 0.65 + 0.5 = 1.15。

V^(s2)\hat V(s_2) 也变了(从 1.0 变成 1.15),虽然我们只更新了 s1s_1——因为它们共享参数 w1w_1。这就是泛化;在 Baird 反例中,同样的机制导致了发散(更新 ss 会改变 s′s' 的价值,从而改变目标)。

练习 3(半梯度):写出”完整梯度”版本的 TD 更新(对 (r+γV^(s′;w)−V^(s;w))2(r + \gamma \hat V(s'; w) - \hat V(s; w))^2 求全导数)。它和半梯度 TD 差在哪一项?

参考答案

∇w12δ2=δ (γ∇wV^(s′;w)−∇wV^(s;w))\nabla_w \frac12 \delta^2 = \delta\, (\gamma \nabla_w \hat V(s'; w) - \nabla_w \hat V(s; w)),所以完整梯度更新为 w←w+α δ (∇wV^(s;w)−γ∇wV^(s′;w))w \leftarrow w + \alpha\, \delta\, (\nabla_w \hat V(s; w) - \gamma \nabla_w \hat V(s'; w))。 与半梯度相比多了 −γ∇wV^(s′;w)-\gamma \nabla_w \hat V(s'; w) 这一项(线性时是 −γx(s′)-\gamma x(s'))。这叫残差梯度法。它是真正的梯度下降、收敛性更好,但在随机环境中会收敛到错误的解(因为 E[δ2]\mathbb{E}[\delta^2] 包含了转移随机性带来的方差),实践中也学得较慢。

练习 4(瓦片编码):用 4 层网格、每层 10×10 格子的瓦片编码表示一个二维状态空间,一共有多少个特征?每个状态激活几个特征?如果动作有 3 个,用”每个动作一组参数”的方式表示 Q^(s,a)\hat Q(s, a),一共需要多少个参数?

参考答案

每层 100 个格子(如果考虑偏移,实现中常用 11×11 = 121),4 层共 400(或 484)个特征。每个状态激活 4 个。Q^\hat Q 需要 3×400=12003 \times 400 = 1200(或 3×484=14523 \times 484 = 1452)个参数。每次更新只改变其中的 4 个。

练习 5(致命三角):下面每种情况,致命三角的哪几角存在?是否有发散的风险? (a) 表格型 Q-learning;(b) 线性函数逼近 + 同策略 MC 评估;(c) 线性函数逼近 + SARSA;(d) 神经网络 + Q-learning + 经验回放。

参考答案

(a) 自举 + 异策略,没有函数逼近 → 收敛。 (b) 函数逼近,没有自举、同策略 → 收敛(真正的梯度下降)。 (c) 函数逼近 + 自举,同策略 → 线性时在最优附近震荡但不发散(表 6.4)。 (d) 三者俱全 → 有发散风险。经验回放让更新分布更接近”过去策略的混合”,一定程度上还加重了异策略程度;目标网络是 DQN 用来缓解发散的主要手段(7.7 节:去掉目标网络后 Q 值爆炸到 10810^8)。

练习 6(DQN 设计):为什么 SARSA 不能直接使用经验回放,而 Q-learning 可以?

参考答案

SARSA 是同策略的:它的目标 r+γQ(s′,a′)r + \gamma Q(s', a') 中的 a′a' 必须来自当前要评估的策略。缓冲区里的 a′a' 是很久以前的旧策略选的,用它会学成”旧策略的价值”。Q-learning 的目标 r+γmax⁡a′Q(s′,a′)r + \gamma \max_{a'} Q(s', a') 不依赖于数据中的下一个动作,(s,a,r,s′)(s, a, r, s') 只取决于环境的转移,与收集数据的策略无关,所以旧数据照样可用。(Expected SARSA 如果对当前策略求期望,也可以使用经验回放。)

练习 7(终止 vs 截断):CartPole 中,如果把”到达 500 步”也当作终止(y=ry = r),学到的 Q 值会怎样?对策略有什么影响?

参考答案

智能体会认为”第 500 步之后没有未来”。但状态中并不包含”现在是第几步”,所以对同一个状态,有时目标是 r+γQ(s′)r + \gamma Q(s')(未到 500 步),有时是 rr(恰好第 500 步),这些样本互相矛盾,Q 值会被系统性地压低,并且带有额外的噪声。在 CartPole 中通常仍能学会平衡,但学得更不稳定;在其他问题中可能导致明显次优的策略。可以修改代码 04,把 buffer.add(..., terminated) 改成 buffer.add(..., terminated or truncated) 观察平均 Q 值的变化(正确实现时约为 100)。

练习 8(动手)★:运行 python 04_dqn_cartpole.py --no-target,观察”平均 Q 值”一列。它最终大约是多少?CartPole 中 Q 值的理论上限是多少?这说明了什么?

参考答案

平均 Q 值会迅速增长到 107∼10810^7 \sim 10^8 量级。理论上限是 Rmax⁡1−γ=10.01=100\frac{R_{\max}}{1-\gamma} = \frac{1}{0.01} = 100。Q 值比上限大了上百万倍,说明价值估计完全发散了——在线网络每更新一次,目标跟着变,“追目标的同时把目标推得更远”(6.3 节)。这是致命三角在深度 RL 中的直接体现,也说明了目标网络的必要性。


12. 延伸阅读

  • Sutton & Barto,Reinforcement Learning: An Introduction(第 2 版):第 9 章(同策略预测的函数逼近,1000 状态随机游走、特征构造、瓦片编码)、第 10 章(同策略控制,高山小车)、第 11 章(异策略方法与致命三角,Baird 反例)。
  • CS234 Spring 2024 Lecture 4–5 录像与课件。
  • Mnih et al. (2015),Human-level control through deep reinforcement learning(Nature):DQN 原始论文,附录中有经验回放和目标网络的消融实验。
  • Tsitsiklis & Van Roy (1997),An Analysis of Temporal-Difference Learning with Function Approximation:线性 TD 收敛性与误差界。
  • Hessel et al. (2018),Rainbow: Combining Improvements in Deep Reinforcement Learning:DQN 各种改进的系统比较。
  • CleanRL(GitHub):单文件、注释清晰的深度 RL 算法实现,适合对照学习。

13. 下一讲预告

到目前为止,所有控制算法都是基于价值的:先学 QQ,再用 arg⁡max⁡aQ(s,a)\arg\max_a Q(s, a) 得到策略。这条路有几个局限:

  • 连续动作(比如机器人关节的力矩)时,arg⁡max⁡a\arg\max_a 本身就是一个难以求解的优化问题;
  • QQ 的一点点变化可能让 arg⁡max⁡\arg\max 突然跳到另一个动作,策略变化不平滑;
  • 有些问题的最优策略是随机的(比如石头剪刀布、部分可观测的环境),而对 QQ 贪心只能得到确定性策略。

下一讲换一个思路:直接参数化策略 πθ(a∣s)\pi_\theta(a \mid s),用梯度上升最大化期望回报。你会看到:

  • 如何对”期望回报”求梯度——似然比技巧;
  • REINFORCE 算法;
  • 为什么策略梯度方差很大,以及基线如何在不引入偏差的情况下降低方差。

下一讲之前,建议你:跑通 code/lecture05/ 下的 4 个脚本(第 4 个需要先安装 torch 和 gymnasium),完成练习 2、5、6,并尝试练习 8 的消融实验。

← 返回课程目录