如果你训练过 DQN、SAC、IMPALA 这类偏离策略的强化学习模型,大概率遇到过一种磨人的状况:loss 曲线前几万步看着还行,后面突然开始飘,评估回报反而往下掉。很多人第一反应是调学习率、改回放比例、动网络结构,但我建议先做一件事:把当前算法在离策略更新过程中引入的偏差,逐项列成一张表。这个动作看起来琐碎,却往往能直接定位到问题根源。所谓离策略更新偏差,就是当用来产生数据的策略,和我们要优化的策略不是同一个策略时,更新目标与真实目标之间产生的系统偏离。它不是单一数值,而是来自重采样权重、目标截断、自举近似、分布覆盖等多条路径的误差总和。这篇文章就把这些路径展开,整理成实战排查表,并给出对应的修正方法,适合正在调 RL 算法、或者刚入门想真正理解离策略原理的同学参考。
1. 离策略更新的根基:为什么说偏差是躲不掉的
1.1 行为策略和目标策略的错位,导致期望对不上
在离策略学习里,我们通常有两个策略:一个是行为策略 b(a|s),负责在环境里采集数据;一个是目标策略 π(a|s),是真正要被优化部署的策略。训练时我们拿 b 收集的 transition 去更新 π,这就产生了一个本质错位:样本分布并不服从 π 的分布,而是服从 b 的。最直接的后果是,损失函数里的期望算符用错了分布。
用生活化的类比来说,这相当于你想评估一家新选址门店的营业额,但手里拿的全是老店的销售记录。老店的数据有价值,但不能直接当新店的预期,必须做一些加权换算。离策略里的加权换算,就是重要性采样权重 ρ_t = π(a_t|s_t) / b(a_t|s_t)。每个样本乘上这个权重之后,理论上可以把期望拉回目标策略下。问题在于,这个权重非常挑条件:b 必须在 π 可能选择的每一个动作上都有非零概率。现实里我们经常用 epsilon-greedy 当行为策略,动作空间稍微大一点,采样到的状态一稀疏,这个条件就容易失效。分母趋近于零时,权重爆炸;即便期望无偏,方差也大到无法训练。
1.2 偏差和方差之间的配平是一门必修课
注意,许多刚接触离策略的读者会把偏差当成一个需要被完全消除的东西。方向没错,但在实操里,偏差和方差是一对跷跷板:你越想减少偏差,往往就要保留更极端的重要性权重,方差就会指数级上升;反过来,你为了抑制方差去截断那些过大的权重,偏差又回来了。
我们在设计算法时真正要做的,是把不可控的方差转化成可控的偏差。比如对重要性权重做截断,看似引入了偏差,但这个偏差有明确上界、有可分析的表达,训练过程反而更稳定。这一点在第三部分结合 V-trace、Retrace 细讲。先把结论放在前头:一个实用的离策略更新框架,不是追求零偏差,而是追求偏差可预测、对最终策略影响有限、方差在样本效率能接受的范围内。下面这张表给出了三种常见策略的取舍:
| 策略 | 做法 | 偏差 | 方差 | 适用场景 |
|---|---|---|---|---|
| 完全 IS | 不截断权重 | 理论无偏 | 极高 | 短轨迹、小状态空间 |
| 加权 IS | 对权重归一化 | 少量偏差 | 显著降低 | 回放池样本分布不均时 |
| 截断 IS | 将权重裁至上限 | 有界偏差 | 受控 | 大多数离策略更新框架 |
2. 离策略更新偏差的六大核心来源和对应公式
2.1 最大化偏差:max 算子天然把估计值顶高
Q-learning 家族的更新目标里几乎都有一个 max 算子,用来选最优动作。但这个 max 会带来一个非常隐蔽的系统性偏差:当我们用带噪声的估计 Q 去取最大值时,噪声项被当成“优势项”给挑了出来。统计上这就是 E[max_i X_i] >= max_i E[X_i] 的典型现象。如果某个动作的真实值很低,但只要一次估计被噪声顶高,它就可能长期霸占 max 的位置。
这个偏差在离策略场景下会更严重,因为回放池里的样本可能都来自一个覆盖面较宽的行为策略,噪声水平更高。我第一次调 DQN 的时候,就观察到 Q 值一路乐观上浮,但真实累计回报却跟不上。后来用 Double DQN 把动作选择和价值估计拆开,差距立刻小了一截。Double Q 在很多实现里已经变成了标配,连续动作算法里的 Clipped Double Q 就是同一思想。
2.2 重要性采样裁剪偏差:用方差换偏差的经典交易
截断式重要性采样看起来简单,直接把 ρ 限制在某个上限 c,但它的偏差方向值得说清楚。设 ρ̂_t = min(c, ρ_t),那么新的目标期望和真实期望之间满足:
E[ρ̂_t G_t] = E[ρ_t G_t] - E[1_{ρ_t > c}(ρ_t - c) G_t]
右边第一项是理论无偏的项,第二项是一个被“裁剪掉”的尾项。由于被裁掉的部分只发生在 ρ 超过阈值的高权重样本上,这些样本通常对应行为策略下的罕见但高价值动作。直接裁剪会系统性低估这类样本的贡献,所以整体目标会产生一个负向的偏差。
这个偏差有没有风险?看你怎么用。如果只是为了让训练稳定,这点负偏差可以接受;但如果你在做一个对高回报尾事件特别敏感的任务,比如稀疏奖励环境,过度裁剪会让智能体学不到那些“难得一遇”的好轨迹。我的经验是:先设置一个比较高的 c 让训练跑通,再看训练后的平均权重。如果平均 ρ 长期高于 c 的一半,说明裁剪过猛,需要把 c 往上抬。
2.3 自举与函数近似的结合:死亡三要素的偏差路径
离策略学习加函数近似加自举,这三个条件凑齐之后,理论上会出现一个叫“死亡三要素”的困境。Sutton 和 Barto 的书里用 Baird 反例展示过:一个简单的线性价值函数,在离策略更新下不仅不收敛,还会沿着某个方向越走越远,直到数值发散。本质原因是,这种组合下的 TD 算子谱半径可能大于 1,迭代不断放大某些方向的误差。
对应到深度 RL,就是 loss 曲线没有明显原因地持续上升。很多人会以为是学习率太大,但实际上把学习率调小只是延缓症状,算法可能依然无法收敛到正确价值函数。常用缓解手段包括 target network 制造更“硬”的目标、对网络权重加正则、降低 update-to-data ratio,甚至改用带投影的线性价值优化算法。严格讲,这些手段并不能把偏差清零,但能让偏差的方向变得可控、幅度变得有限。
2.4 覆盖不足:行为策略不够宽导致的无解缺口
离策略更新的前提是行为策略能“覆盖”目标策略可能访问的区域。如果行为策略在某些状态下只输出少数动作,而目标策略恰好需要其他动作,这组数据就无法为那些动作提供有效监督。更麻烦的是,当 b(a|s) 极小时,重要性权重 ρ 会异常放大,个别样本可能贡献超过正常值的几十倍梯度,训练曲线出现一个尖峰后立刻崩坏。
处理覆盖不足的思路有两个方向:一是让行为策略更宽,比如提高探索噪声、降低贪心阈值;二是用软行为策略,也就是在环境交互时对策略输出做熵正则化,保证低频动作也有一定概率被采到。实际操作里,我会定期记录行为策略和目标策略之间的 KL 散度。KL 持续增大,基本可以判定覆盖在劣化,离策略偏差会快速上升。
2.5 非平稳目标与旧数据过时:越来越旧的样本
经验回放让离线数据可以被反复使用,但它也带来一个老问题:回放池里的数据是“过去”的策略和环境状态产生的。目标策略在更新,π 在变,环境还在动态演化,回放数据与当前策略之间的错位会随时间累积。也就是说,离策略偏差本身还是一个随时间变化的量。
这个问题在策略剧烈更新时尤其明显。TRPO/PPO 用 KL 约束逐步限制每次更新的步幅,目的之一就是防止新旧策略差异过大。对回放池来说,更激进的做法是给样本打上“策略代际”标签,超过一定代际就让它们逐渐衰减或丢弃。我在实际项目里虽然没有用过很复杂的策略代际逻辑,但确实会把 replay buffer 里的平均 KL 或样本年龄写进日志,发现训练后期评估不稳定时,往往能看到旧数据占比过高。
2.6 截断回报和分布漂移:更隐蔽的偏差叠加
最后两个偏差点常常被忽略。其一是截断回报:当一条轨迹由于回合长度限制被截断时,截断点后面的真实回报只能由价值估计来替代。如果价值估计本身偏低,截断目标就整体偏低;如果偏高,则整体偏高。另一种是 GAE 中 λ 小于 1 时带来的偏差——它用偏置换方差,本质上和 IS 截断是同一类权衡。另一个偏差点是分布漂移:在分布式训练中,各个 actor 的行为策略各不相同,并且会随着训练推进不断切换,这使得目标分布不是一个固定分布。价值函数一直在追赶一个不断移动的靶子,偏差不再是一个常量,而是一个动态区间。
这六个来源叠加在一起,就能解释很多奇奇怪怪的训练现象。下面是一张速查表,方便在出问题时迅速定位方向:
| 偏差来源 | 触发条件 | 数学特征 | 典型症状 | 修法 |
|---|---|---|---|---|
| 最大化偏差 | 目标带 max 算子 | E[max X] > max E[X] | Q 值虚高、回报一般 | Double Q、target、ensemble |
| IS 裁剪偏差 | clip 重要性权重 | 产生负向有界偏差 | 高回报样本被低估 | 提高 clip 上限、归一化权重 |
| 死亡三要素 | 离策略+函数近似+自举 | 算子谱半径可能 > 1 | loss 发散 | target 网络、正则、降更新频率 |
| 覆盖不足 | b 在 π 支持下概率低 | 分母趋 0,权重爆炸 | 偶发极端梯度 | 行为策略熵、噪声、软行为策略 |
| 非平稳旧数据 | 策略更新速度快 | 目标随迭代漂移 | 评估曲线回撤 | KL 约束、按策略新鲜度衰减样本 |
| 截断/分布漂移 | 轨迹长度有限或分布式训练 | 回报由近似值替代 | 训练水平系统性偏低 | GAE、λ 调参、多 actor 稳定化 |
表格里的每一项都不是独立存在,通常至少两三个同时出现。
3. 可控偏差的设计思路与 V-trace / Retrace 修正
3.1 一个关键认知:先把不可控偏差变成可控偏差
离策略更新的核心工程问题,是在方差和偏差之间找到一个可控妥协。“可控”的意思很具体:要么能写出偏差的上界,要么能知道截断参数变化时,偏差单方向往哪里移动。经典 Q-learning 的最大化偏差很难分析,但 IS 截断后的偏差是能算出来的,Retrace、V-trace 这类算法本质上就是围绕这个思路建立起来的。
我习惯把这类方法称为“有预算的偏差”:允许算法引入一定偏差,但为偏差封顶。这样训练就算波动,也是在已知边界内波动,不会突然发散。对比之下,完全不加约束的 IS 权重虽然理论无偏,但它的方差没有边界,一张大权重样本就能毁掉整个策略更新。高方差错误一旦溢出到训练日志里,就是曲线崩溃,工程上完全不可接受。
3.2 V-trace 如何用截断比例换一个可量化的解
V-trace 是 IMPALA 解决离策略价值估计的核心目标。它把重要性权重拆成了两个角色:
ρ_s = min(ρ̄, π(a_s|x_s) / b(a_s|x_s)) c_s = min(c̄, π(a_s|x_s) / b(a_s|x_s))
V-trace 目标写成:
v_t = V(x_t) + Σ_{k>=0} γ^k (Π_{i=1..k} c_{t+i}) [ρ_{t+k}(r_{t+k} + γ V(x_{t+k+1}) - V(x_{t+k}))]
这里 ρ 控制每一步 TD 目标的截断,c 控制整个往回传导路径的截断。两者分开处理,就能分别调节“当前步修正”和“远处信息累积”。如果 c 很小,路径乘积衰减更快,远端偏差大幅降低但信息利用率也跟着下降;c 取大一些,上下文的信息压缩到位。与原始 IS 不同,V-trace 截断后的目标有一个上界偏差,是一个可以接受的近似。
实际布设 IMPALA 时,通常默认 ρ̄ = 5、c̄ = 1。我个人的偏好是前期 ρ̄ = 10、c̄ = 1,让高回报动作尽快被识别,后期再把 ρ̄ 降到 5 以减少不稳定性。需要注意的是,如果任务有稀疏奖励,ρ 截断过大容易丢失偶发高回报,我会把 ρ̄ 保持在 10 以上并配合更大的确定性 rollout 采样。
3.3 Retrace 和 Tree-Backup 的偏差取舍对比
Retrace 目标本质也是一个带累积截断的算子:
Q_ret = Q(s_t, a_t) + Σ_{k>=0} γ^k (Π_{s=1..k} c_s) δ_{t+k}
其中 c_s = λ min(1, π(a_s|s_s) / b(a_s|s_s)),δ 为 TD 误差。和 V-trace 不一样的是,Retrace 对每个 c_s 都做了一个 min(1, ·) 约束,而 V-trace 允许路径上的乘积超过 1;这样 Retrace 的偏差下偏更稳,方差更小,但有时会低估。
Tree-Backup 在 λ=0 时就是 Retrace 的极端情况,完全不使用行为策略的权重,只利用目标策略的 π 来展开树。下面的对照可以看出它们各自的位置:
| 方法 | 权重形式 | 偏差特征 | 方差特征 | 适合场景 |
|---|---|---|---|---|
| Q(λ) | 没有离策略修正 | 离策略偏差大 | 低 | 接近同策略的小幅更新 |
| Tree-Backup | 只用 π,无 IS | 依赖动作覆盖程度 | 低-中 | 离策略程度温和时 |
| Retrace | min(1, ρ) 累积 | 有界下偏 | 中 | 大程度离策略、要求稳定 |
| V-trace | 截断 ρ 和 c | 有界可控偏差 | 中 | 分布式异步 actor 数量大时 |
选择哪个算法,核心看你的行为策略到底“偏离”目标多少。偏离小,Tree-Backup 就够;偏离大,宁可选择 Retrace 这类带保护的算子,也不要用裸的 IS 权重。
3.4 实际调参中的几个有效建议
这里是我实际使用中的几条规则,未必写进教科书但很见效。
第一,不要把 ρ 上限和 c 上限当成同一个东西。ρ 管单步修正强度,c 管长期传导。想让价值函数更快贴合当前策略,调大 c;想让训练稳,优先调小 ρ。第二,记录平均权重。v-trace 中如果平均 ρ 经常接近 ρ̄,说明大多数样本都处于截断边界,这时“裁剪偏差”已经不小,价值估计会偏低。第三,λ 参数可以和 GAE 一起调,不要在离策略和同策略场景里用同一套。很多项目把 GAE 的 λ 默认成 0.95,但如果轨迹特别短,这一步产生的截断回报偏差会被放大。
4. 离策略偏差排查清单和踩坑记录
4.1 症状一:Q 值虚高,累计回报却跟不上
先说我个人的一个真实案例。有个网格导航任务,DQN 训练 10k 个 episode 后,网络输出的 Q 值稳定在 9 左右,但实跑测试累计回报只有 5 到 6。第一反应是奖励计算有 bug,查了一圈没有。后来把价值网络换成 Double DQN,同一份回放池重新训练,评估回报立刻上升到 7 附近。之后又把行为策略的噪声调高了一点,最终接近 8.5。
这个案例说明,Q 值与实际回报的长期偏差,最主要来源就是最大化偏差,而不是环境奖励。看到一个“乐观的高 Q”,优先想去验证 double Q 或者 ensemble,而不要急着调学习率。另一个相关的检查是:你是否把 Q 值当成离线评测指标在用?如果是,会系统性高估模型能力,务必同时记录真实评估回报。
4.2 症状二:训练和评估差距持续扩大
另一个常见症状是训练用的回报曲线和单独评估曲线都在涨,但两者的差距越拉越大。这时候通常不是过拟合,而是行为策略和目标策略分布分离导致的覆盖不足。我在一个连续控制任务里遇到类似现象,采样 KL 从 0.02 一路涨到 0.15,之后评估曲线就出现平台回落。
处理方式是把行为策略的熵阈值提回去,同时限制目标策略单次更新的 KL 上限。如果是 SAC 这类本身有熵项的训练,要确认行为噪声不是随着训练越来越小;如果噪声萎缩太快,覆盖就会劣化,整个离策略学习的数据质量会下降。这也不是模型本身在发散,而是采集数据的源头坏了。
4.3 症状三:提高 update-to-data 比例后 loss 开始震荡
有些团队为了加快学习,会把 update-to-data 比例调高,比如从一个 transition 更新一次变成更新四次。结果 loss 开始震荡,甚至出现周期性峰值。表面上是过拟合,本质上是因为更新次数提高后,价值网络对同一个批次的样本反复拟合,目标策略和价值目标的非平稳性被放大。这种行为在离策略下等于把“非平稳旧数据偏差”和“死亡三要素”两个风险同时推高。
我的建议是先降低更新频率,然后用 target network 的硬更新间隔作为稳定器,最后再考虑调 clip 上限。如果这三个都调完,loss 还在抖,那就要审视回放池里样本的策略代际分布了。在 torch/rllib 这类框架里,可以通过采样权重记录来判断:旧策略占比超过一定比例,优先清掉最老的一部分数据。
4.4 一份可以直接抄走的排查表
最后,我把日常排查优先级整理成一张表:
| 问题现象 | 优先检查 | 优先修正 |
|---|---|---|
| Q 值持续高于真实回报 | 是否使用 double Q / min 集成 | 开启 double Q,target 更新更慢 |
| Q 值持续低于真实回报 | IS 权重是否被过度裁剪 | 提高 ρ 上限,归一化权重 |
| loss 无原因发散 | 更新频率、网络正则、死亡三要素 | 降低 update-to-data,增加 target 间隔 |
| 评估曲线突然回撤 | KL 扩散、行为策略熵萎缩 | 扩大行为噪声,限制单步 KL |
| 偶发超大梯度 | 覆盖不足、权重爆炸 | 更宽行为策略,清理极端样本 |
这张表我在多个项目里都贴过,定位问题的时间基本能缩短一半。它不是给理论发烧友看的,是给必须在一两个小时内定位 bug 的人用的。
最后再说一点个人感受。离策略更新里的偏差,很多时候不是靠某一个神奇参数一次性解决的,而是需要把偏差来源拆开、逐个控制。我在维护的大型模型训练日志里单开了一个偏差记录文件,每天记下算法、可疑偏差、参数改动和结果。它会提醒你:一次训练崩溃背后,往往至少两个偏差点在同时叠加。把这个表建起来,很多玄学问题就会变成可排查、可复现的参数问题。如果你正在被某个训练曲线折磨,不妨先试着把偏差列出来,效果可能比再调一百次学习率都好。