扩散策略这几年在机器人学习和离线强化学习里算是热词了,原因很简单:真实控制任务的动作分布往往是连续、多模态的,不是高斯策略能描述的。U-Net 或者 DiT 把动作当图像一样去噪生成,效果确实好,但随之而来的问题是——策略怎么改进?
传统 RL 里策略改进是拿 Q 函数做贪心或者软贪心,一步一个脚印往上推。到了扩散策略这里,动作是从噪声里一步步采样出来的,不是查表能查到的,贪心操作没有闭合解。CFGRL 这篇工作给了一个挺优雅的答案:把图像生成里用烂了的 classifier-free guidance 拿过来,当作一个推理时直接生效的策略改进算子,而且改进幅度是可控的。
这篇文章我会从我的理解角度拆一下它到底做了什么、为什么成立、落地的时候有哪些细节点需要注意。无论你是做机器人控制、自动驾驶策略,还是单纯关注扩散模型和 RL 的结合,这篇都能给你一个比较完整的参考。
1. 背景:扩散策略为什么需要改进算子
1.1 扩散模型是如何成为策略的
先对齐基本设定。强化学习里策略 π(a|s) 的任务是给定状态 s,输出一个动作 a 的分布。在连续控制任务里,动作是高维连续向量——比如机械臂各关节的力矩、双足机器人的足端力、自动驾驶的方向盘转角和油门开度。传统做法用高斯分布去拟合,但真实策略往往是多模态的:同一个状态下可能是“向左绕障碍”也可能是“向右绕障碍”,高斯拟合会强行得到一个骑在两个峰中间的均值,执行出来完全不是那么回事——往左不彻底,往右不到位。
扩散策略换了个思路:把动作 a 当成一张从纯噪声开始、经过多步去噪得到的“图像”。训练时学一个噪声预测模型,给定状态 s 和某个加噪程度 t,模型预测当前动作里混入的噪声;推理时从一个随机高斯噪声出发,迭代去噪几十步,最终得到一个动作。因为去噪过程本身能表达极其复杂的分布,扩散策略天生就支持多模态动作,这也是它在模仿学习里明显优于高斯策略的原因。
这个设定在不少工作中已经证明了有效性。比如机器人操作任务里,用扩散策略做行为克隆,成功率能比 Gaussian MLP 策略高出一大截,尤其在那些“一个状态有多个可行解法”的任务里。可问题也随之而来:在 RL 框架下,光会模仿还不够,策略是需要迭代改进的,而改进这件事在扩散策略上特别别扭。
1.2 传统策略改进算子为什么失效
策略改进算子是 RL 理论的核心概念。给定当前策略 π_old 和动作价值函数 Q(s,a),改进后的策略 π_new 要满足:在同样的状态下,π_new 采样出的动作在 Q 值上比 π_old 更好。经典做法有这么几类:
- 贪心改进:π_new = argmax_a Q(s,a),直接选最优动作,简单粗暴但对连续空间不可行
- 玻尔兹曼/软贪心改进:π_new(a|s) ∝ π_old(a|s) · exp(Q(s,a)/α),能保留多样性但需要算概率密度
- 信任域类更新:TRPO/PPO 在参数空间里沿 KL 约束方向迭代,每一步改进一点点
这些操作都有一个隐含前提:你能对动作空间做某种形式的搜索,或者能显式写出策略的密度函数。对离散动作可以穷举,对低维连续动作可以跑优化器,但扩散策略的动作是几十步去噪采样出来的——每一步都是随机过程,你没法对最终动作做 argmax。更麻烦的是,扩散策略的概率密度虽然理论上可以算(通过积分消去中间变量),但没有任何解析形式,softmax 式的改进根本写不出来。
当然,你可以把去噪过程当一个随机计算图,用重参数化梯度直接去优化策略。这条路是能走通的,但非常难调。PPO 的 clip 范围、优势归一化、信任域约束在扩散策略里都变得格外敏感,稍微调不好就发散。我见过不少团队在这上面耗了几周,最后发现还不如用一个简单的无梯度方法在推理时修动作。
1.3 CFGRL 的切入点:绕过重训练
CFGRL 是标题里那个名字的缩写,我理解它想表达的核心是 Classifier-Free Guidance for Reinforcement Learning 这条技术路线。它的核心主张很直接:与其费劲地重训练扩散策略来融入 Q 函数的信息,不如直接在推理时用 CFG 公式引入价值引导。这么一来,策略改进算子就在推理那一刻完成了,不需要额外的策略更新,改进的幅度还能用一个标量权重连续调节。
这个想法初看有点“偷懒”,但它实际上对应了一个很深刻的理论观察:CFG 的数学结构和 RL 里的策略改进算子存在同构关系。接下来的部分我会展开讲这个对应关系,以及它在实操中到底意味着什么。
2. 核心思想:把 CFG 看作策略改进算子
2.1 CFG 在图像生成里是怎么用的
Classifier-free guidance 最早是 2022 年 Ho 和 Salimans 在图像生成里提出的。当时的痛点是:条件生成模型直接训练时,生成结果经常不够“贴题”。如果用外部分类器做梯度引导(classifier guidance),虽然贴题了,但得额外训练一个分类器,而且噪声图像上分类器的梯度噪声很大,工程上非常麻烦。
CFG 的解法是:训练时同时让模型学会条件生成和无条件生成,推理时把两个预测做线性外推。写成公式就是:
ε_guided = ε_uncond + w · (ε_cond − ε_uncond)
这里 w 是引导强度。w = 1 时就是纯条件生成,w > 1 时生成结果会更明显地向条件信息倾斜,图像质量和文本遵从度都会有明显提升。文生图领域后来几乎所有产品都在用这个公式,因为它简单、稳定、效果好。
我这些年用 CFG 的感受是:它最妙的地方在于只用条件分数和无条件分数的差值,就把“服从条件”和“保持多样性”的平衡变成了一个旋钮。你不需要知道条件信息长什么样,只需要知道“加了条件之后概率分布往哪个方向偏了”。偏多少,由 w 说了算。
2.2 从分数匹配到策略改进:数学上的同构
现在把视角切到 RL。扩散策略训练出来的是一个条件动作生成模型 p(a|s)——给定状态 s 生成动作 a。如果我们同时训一个无条件动作模型 p(a),它的含义是“不管状态是什么,动作整体的先验分布是什么样的”。推理时做 CFG 引导,动作生成过程变成:
score_guided(a|s) = score_uncond(a) + w · (score_cond(a|s) − score_uncond(a))
这个式子放到 RL 语境里做概率解读会非常有意思:条件分数减去无条件分数,刻画的是“在状态 s 下,哪些动作比平均动作更可能被当前策略选中”。把它当作增量加到无条件分数上,等价于在动作空间上施加了一个与状态相关的漂移,漂移的方向正是策略认为“在 s 下值得做”的方向。
CFGRL 的洞察在于:如果把“值得做”的标准从行为克隆里的被示范动作,替换成由 Q 函数或奖励信号定义的“高价值动作”,那么 CFG 引导就变成:
score_guided = score_base + w · (score_high_value − score_base)
这不就是软策略改进吗?玻尔兹曼改进 π_new ∝ π_old · exp(Q/α) 在分数空间里恰好就是给原本的分数加上一个与 Q 相关的梯度项。所谓策略改进算子,本质上就是把分布往高价值区域推一推;CFG 做的也是这件事,只是它是通过去噪过程中的分数外推来实现的,不需要重新训练策略。
这里补一句我的个人理解:为什么它能做到“可控”而不是直接贪心到 argmax。关键在于 w 不是无限大,而且每个去噪步的引导都是以原有分数为基础的——改进始终贴着原分布走,不会像 argmax 那样一步跳出分布外。这个性质在精神上和 TRPO 里的信任域约束是一致的:每一步只改进一点,但不跨出安全边界。
2.3 “可控”到底体现在哪里
控制性可以从三个维度来理解。
第一,改进强度可控。w 小的时候,生成的动作基本和原策略保持一致,只轻微向高价值方向偏移;w 大的时候,动作会非常激进地涌向 Q 值高的区域。你可以根据任务风险来调:高风险场景用低 w,追求上限的场景用高 w。
第二,作用时机可控。CFG 引导是推理时操作,不碰训练过程。这意味着你可以在一个训练好的策略上随时开启或关闭引导,甚至部署中途动态调整 w。这对线上策略灰度发布特别有用——今天发现环境变了,不用重新训练,只要把引导权重调一调。
第三,作用维度可控。引导信号可以只施加在部分动作维度上,比如只引导与安全相关的动作分量,其他维度保持原样。图像生成里做区域引导是常规操作,RL 里这种灵活性同样成立。
3. 方法细节与实操原理
3.1 训练阶段需要准备什么
要复现这套方案,训练阶段需要准备的东西并不复杂。
第一件事,训练一个条件扩散策略 p(a|s)。过程和普通扩散策略没有区别,用行为克隆或者 TD 类 RL 目标训练都行。输入状态 s 作为条件,预测动作 a 的噪声。
第二件事,让同一个模型同时具备无条件生成能力。最省事的做法是条件丢弃:把状态 s 以一定概率(通常 10% 左右)替换成特殊的空状态嵌入,这样同一个模型既能输出条件预测,也能输出无条件预测。推理时从同一套参数里取两个预测做组合,不需要维护两份模型权重。
第三件事,如果你想引入 Q 值引导,就需要一个价值网络。用标准 TD 学习或者 Monte Carlo 回报回归训练一个 Q(s,a) 网络,它的作用是在推理时为每一步去噪提供引导方向。如果只是做纯行为克隆加 CFG,这个可以省掉。
3.2 推理时的引导组合方式
推理时,一个典型的去噪步长得像这样:
# 假设 denoiser 同时支持条件输入和无条件输入 # state 正常传入是条件模式, empty_state 传空嵌入是无条件模式 noise_cond = denoiser(noisy_action, t, state) noise_uncond = denoiser(noisy_action, t, empty_state) # 基础 CFG 组合, w_cfg 是条件引导强度 noise_cfg = noise_uncond + w_cfg * (noise_cond - noise_uncond) # 可选: 加入价值引导, 用 Q 对动作的梯度指向高价值区域 q_grad = grad_q_value(noisy_action, state) noise_final = noise_cfg + w_value * normalize(q_grad) # 单步去噪 noisy_action = denoise_step(noisy_action, noise_final, t)每一步都重复这个循环,直到 t=0 得到最终动作。强调一点:价值引导和 CFG 引导的组合方式实际可以有多种变体,这里写的是最容易调通、最符合直觉的一种。如果你的任务里价值信号噪声大,可以把w_value设小一点,或者干脆只用 CFG 部分、把 Q 信息通过条件编码融合进去,也是可行的。
3.3 与相关方案的效果对比
| 方案 | 是否需要重训练 | 改进幅度控制 | 推理开销 | 对 Q 函数的需求 |
|---|---|---|---|---|
| 标准 RL 策略梯度 | 需要 | 通过 KL/熵正则间接控制 | 低 | 需要 |
| 推理时 argmax 动作优化 | 不需要 | 基本不可控,容易崩 | 高(要跑优化器) | 需要 |
| 扩散策略 + CFGRL | 不需要 | 通过 w 直接控制 | 低(只多一次前向) | 可选 |
| 分层规划类方法 | 需要 | 中等 | 很高 | 通常需要 |
从这个表能看出,CFGRL 类方案的核心价值是:把“改进策略”这个动作从训练期搬到了推理期,成本低,而且改进幅度像音量旋钮一样随时可调。
4. 适合哪些场景、怎么落地
4.1 部署阶段的策略微调
最直接的应用场景是策略上线之后的微调。训练环境(仿真)和部署环境(真实世界)总有偏差,或者任务目标在部署时发生了变化。举个例子:机器人搬运任务,仿真里要求速度优先,部署时客户说更看重平稳性。这时候如果用 CFGRL 思路,你只需要在推理引导里加一条“对急停急转惩罚、对平稳奖励”的价值信号,然后扫一遍 w,找一个折中强度即可,完全不需要重训策略。
这个场景的收益非常明显:省掉大规模重训练的算力和时间成本,可以针对线上数据快速迭代。我个人的建议是:上线之前,先在离线数据集上扫一遍 w 曲线,记录不同 w 下的关键指标变化,选一个保守值上线,之后根据线上监控再微调。千万不要一上来就调大 w 追求极限指标。
4.2 安全约束与保守性控制
另一个很实用的方向是安全约束。很多控制任务里,“改进策略”不仅要追求高回报,还要保证不违反安全约束——机械臂不能碰到人,自动驾驶不能压实线。传统做法要引入约束优化,大概率又要重新训练。
如果把安全约束也编码成价值信号(准确说是惩罚信号),CFG 引导就可以把动作从原分布推向“满足约束”的区域。而且因为它始终贴着原策略分布走,偏离不会太远,天然带保守性。这里要清醒一点:这种保守性的上限取决于原策略本身能不能生成安全动作。如果原策略生成的安全动作概率本身就很低,引导也无能为力——它做的是重新加权,不是凭空创造。
4.3 多目标切换与策略迁移
还有一种玩法是多目标场景的动态切换。把原策略当作一个通用策略,部署时希望它今天执行“目标 A”的行为模式,明天切换成“目标 B”。传统做法要么训多个策略,要么做条件化策略且任务条件要提前定好。CFGRL 思路下,你可以在同一份模型权重上,通过切换推理时的引导信号来切换行为模式,用 w 控制切换的果断程度。
听起来很美好,但注意:引导信号的质量决定了行为的上限。如果价值函数噪声大、覆盖不全,引导就会把动作带偏。实践中我强烈建议对价值信号做预处理:z-score 归一化、分位数裁剪、或者按窗口做平滑。这些操作能显著降低极端 Q 值把引导项拉爆的风险。
5. 常见问题与踩坑记录
5.1 引导强度太大导致动作退化
这是最容易踩的坑,没有之一。w 调大的时候,生成的动作会显著偏向高价值区域,但过大的代价非常明显:动作分布坍缩到少数几个模式,多样性几乎消失;生成的轨迹出现明显抖动或者不连续;在机器人控制里表现为动作频率响应异常,甚至出现超出执行器限位的输出。
我调试时的经验是:w 从 0 开始,每次翻倍,同时观察动作熵和奖励两条曲线。当奖励增长速度明显放缓而动作熵快速下降时,说明已经接近临界点,回退到上一档。记住一个原则:不同任务的最佳 w 差异极大,动作维度、状态维度、价值函数尺度都会影响它,不能一套参数通吃。
5.2 条件模型和无条件模型预测尺度不一致
CFG 公式成立的前提是条件分支和无条件分支在同一个数据分布锚点上工作。如果训练时无条件分支的输入处理和条件分支差距太大——比如空状态嵌入的取值方式不对,两个分支的预测尺度不一致,那组合出来的噪声预测会非常奇怪,生成的动作用户会明显感觉“发飘”。
解决办法有几点:无条件分支用单独训练出来的空嵌入向量,不要让状态向量直接全部置零,这一点很关键;训练时的条件丢弃概率要适中,太低则无条件分支没学好,太高则条件分支性能下降,10% 左右是我用过最稳的默认值;两个分支输出的噪声特征最好做同样的标准化处理,确保量纲一致。
5.3 价值引导梯度噪声大
如果加了 Q 梯度引导,第二个高频问题是梯度噪声。Q 网络是一个回归模型,它对输入动作的梯度天然带有噪声,尤其在动作空间的边缘区域。直接拿这个梯度当引导,生成的动作会时好时坏,肉眼看着就抖。
我的处理套路是三步:第一,对梯度做 L2 归一化,限制单步引导的更新范数;第二,对 Q 输出做裁剪,比如限制在数据集的分位数 5% 到 95% 之间,把异常大值压掉;第三,去噪过程中对引导方向做一次 EMA 平滑,防止相邻去噪步之间的引导方向来回震荡。做完这三步,动作质量会稳很多。
5.4 采样步数与额外前向开销
CFG 要求每个去噪步做两次前向预测(条件和无条件),这让采样开销翻倍。如果采样步数本身很少(比如 10 步的 DPM 采样),翻倍还可以接受;如果用了 100 步的 DDIM,翻倍就比较肉疼。实践中有两个折中方案。
第一个方案:用少步数采样器配合 CFG,图像生成领域已经有大量成熟经验,DPM-Solver、DDIM 这类采样器配 10 到 20 步完全够用。第二个方案:只在最后若干步施加引导,前面的去噪步走普通条件生成。我在部分任务上试过,最后 20% 的步数加引导,效果损失很小,但计算开销能省一大截。这两个方案可以叠加使用,效果一般不会让你失望。
5.5 对价值函数质量的敏感度
最后再说一个容易被忽视的问题:CFGRL 类方法的成败高度依赖价值信号的质量。如果 Q 函数是在一个覆盖很差的离线数据集上训的,它对动作空间某些区域的估值就是凭空猜测,引导会把动作推向那些不靠谱的区域。
遇到这种情况,我一般会做两件事:一是检查引导方向的动作集合在实际环境里的回报,如果发现引导后平均回报反而低于无引导,强烈怀疑 Q 函数在那些区域是错的;二是降低 w,把引导当成一个“滤波器”而不是“放大器”来用——只用来剔除明显差的动作,而不是强行逼近 Q 的最高区域。
6. 最后再分享一点我对这套思路的体会
说实话,“策略改进算子”这个名字理论味道很重,但它的工程价值恰恰在于简单。CFG 的训练方式在图像生成里已经被验证得滚瓜烂熟,推理时的实现也不复杂,数据需求只是多训练一个价值函数而已。相比重训扩散策略动辄几万 GPU 小时的算力成本,这种推理期改进方案的性价比很能打。
但我也要泼一盆冷水:它替代不了真正的 RL 训练。如果原策略和最优策略的差距太大——比如任务完全变了,动作分布基本不重叠——引导只能在原分布和高价值区域之间做插值,做不了从失败到成功的质变。这类方法最合适的定位是:已经有一个不错的策略,想让它更好、更适合新环境或者新目标。
如果你是从业者,我的建议是:先用一个中小规模任务把链路完全跑通,再谈规模化。具体路径是,先训一个带 10% 条件丢弃的扩散策略,再训一个简单的 Q 网络,然后在评测环境里扫一遍 w——从 0 开始逐步加大。你很快会感受到这类方法的实用程度,也会对“改进算子”和“分布外推”之间的关系有自己的判断。