想象一下,我们手头已经有了一个能评估动作好坏的价值函数(DIVL),接下来最关键的一步就摆在了眼前:如何真正引导VLA模型(视觉-语言-动作模型)去生成那些价值更高的动作?这恰恰是QAM(Q-learning with Adjoint Matching)要解决的核心问题。它的思路很巧妙:把Flow Matching这种强大的生成表达能力,和Q-learning这种以最大化累积奖励为目标的优化框架揉在一起。同时,它还解决了一个长期困扰研究者的问题——扩散模型在强化学习中因为要进行时间反向传播(BPTT)而带来的训练不稳定性。
值得一提的是,QAM的背后是OpenVLA团队的持续探索,他们通过一系列工作(DIVL、QAM、QGF)逐步构建了一整套“离线RL + 生成式策略”的技术栈,QAM正是这个体系中连接价值评估与策略提升的核心桥梁。
核心问题:Flow 策略的优化困境
为什么 Flow 策略难以用 RL 优化?
现在流行的VLA模型,比如像Octo、RT-2这类,生成动作时大多采用Flow Matching或Diffusion架构。这类模型的优势很明显,它们生成的动作平滑、多样,还能很好地遵循物理规律。但问题恰恰出在这里:动作不是一步到位的,而是通过多步去噪或ODE积分,一步步“迭代”出来的。
这意味着,整个计算过程构成了一条长长的链条——下一步依赖于上一步的结果。如果我们想用Q函数的梯度来优化最终生成的动作,这个梯度就必须原路返回,穿过整个生成链条。这就引出了两个让人头疼的问题:
- 计算开销巨大:每一步迭代都得保留所有中间状态,显存根本扛不住。
- 数值极度不稳定:这么长的反传链路,梯度消失、梯度爆炸几乎是家常便饭,更新方差大得吓人,训练很容易就崩溃了。
这才是基于扩散/流匹配的强化学习策略,在真实机器人场景中迟迟难以收敛的根源。
三种候选方案
面对“如何优化 flow policy”这个问题,摆在我们面前的有三条路:
- 方案 A:优势加权回归(AWR)。这个方案需要计算动作的对数概率密度,但在flow多步去噪的过程中,想获得解析密度几乎不可能,而且面对高维的动作块(action chunk),归一化常数根本无法求解。
- 方案 B:直接反向传播。这个方案需要让梯度穿过整个ODE反传链,计算又贵又不稳定,对于大型VLA模型来说,基本不现实。
- 方案 C:QAM。这正是我们要深入讨论的方案。它把复杂的轨迹级优化,巧妙地转化成了流路径上的一系列局部回归问题,完全绕开了穿透ODE反传的麻烦,只需要终点处的梯度信息即可。
核心思想:Adjoint Matching
一句话理解
核心思路就是:别让梯度“硬闯”整个生成过程(又贵又不稳定),而是在生成动作的终点拿到Critic的“修改意见”,然后顺着生成路径,把这份意见反向传递回去,用来微调路径上每一步的生成方向。
传统做法和QAM做法的对比大致如下:
传统做法(BPTT,不可行):
噪声 → [ODE 积分 N 步] → 动作 → ∇ₐ Q → [反向穿过 N 步 ODE] → 更新 θ
QAM 做法(高效稳定):
1. 用冻结的参考策略 π_β 跑一条前向流轨迹 {a_w}(无需梯度)
2. 在终点 a₁ 处计算 Critic 梯度: g̃₁ = -∇ₐ[Q(s, a₁)/λ]
3. 沿参考轨迹反向积分伴随方程,得到每个时间点 w 的局部目标 g̃_w
4. 用 ||f_θ(s,a_w,w) - f_β(s,a_w,w) + σ_w·g̃_w||² 做局部回归更新 θ
伴随变量的直觉
在控制理论中,“伴随变量”可以理解成一个指标:终点目标函数对轨迹中间状态的敏感度。
在QAM框架下,我们的优化目标就是提升动作对应的Q价值。终点动作处的Critic梯度,其含义是:如果我对最终动作做微小的偏移,Q价值会如何变化?但最终动作是由一整条流生成轨迹推导出来的,所以我们得解决一个关键问题:
为了让最终动作往高Q值的方向优化,流生成过程中每一个时间步的向量场,需要做出怎样的调整?
伴随法正是用来解决这个问题的工具。它会将终点处的Q梯度,按照伴随方程反向映射到流轨迹的每一个时间步,生成一步步的局部监督信号。这样一来,原本复杂的端到端RL优化问题,就变成了一连串简单的逐歩监督回归任务:在每个时间步,让当前的向量场去匹配经过Q梯度修正后的目标向量场。
一个比喻
可以想象成流水线上的工头。端到端反传就像试图拉一根很长的绳子,希望绳子末端的反馈能精准地传到每一个中间节点。绳子越长,抖动就越大,越难控制。而QAM则像是在流水线的每个工位都安排了一个工头。每个工头只告诉当前这一步的向量场该往哪个方向微调,完全不需要整条链路一起承担不稳定的反向传播压力。
数学框架
QAM的目标是让策略 π_θ 逐渐靠近一个更好的分布。为了实现这个目标,它定义的目标速度场是:结合保持现状(模仿行为) 和 寻找更好(Q的指引) 两部分。
这里的参数控制着“模仿行为”和“追求Q”之间的平衡。
QAM的高明之处在于,它没有把RL梯度硬塞进整个生成链条,而是通过伴随匹配,把一个全局优化问题拆解成了flow每一步的局部回归问题。论文里特别强调,π_β 是保持固定不变的,它扮演了参考流的角色,在离线RL阶段由行为克隆初始化而来。真正要优化的,是离线和在线训练过程中的 π_θ。
需要特别注意的是,QAM并不是在部署推理时每一帧都实时调用critic梯度。论文强调的是在训练阶段,把critic gradient转换为flow模型的step-wise supervision。训练好的策略在部署时依然是前向生成动作,只不过它的动作分布已经被价值函数巧妙地引导过了。
网络架构
三大核心网络
Velocity Network:导航员
这是QAM的执行灵魂。在传统的RL(比如PPO或SAC)中,策略网络像一个“瞬移器”——输入状态 s,直接输出动作 a。但在基于Flow Matching的QAM里,策略网络更像一个“导航员”:
- 输入:(s, x_w, w)——环境状态、当前位置、当前时间刻度
- 输出:速度矢量,告诉你在当前位置应该往哪个方向走
- 作用:通过Adjoint Matching学习如何在Q的指引下,生成最优的速度场
数学上,动作的生成遵循一个常微分方程。在推理时,Velocity Network会被反复调用:从噪声开始,一步步地问它“该往哪走”,然后迈出一小步,如此循环,直到生成最终动作。
Critic:价值网络
Q网络负责评估动作的好坏。它输入 (s, a),输出Q值。它的核心作用,是为Adjoint Matching过程提供关键的梯度信息 ∇ₐ Q。
Target Q 网络
Target Q是Q的一个慢更新副本(通过软更新/Polyak A veraging)。为什么需要它?想象一下,假如我们在计算更新目标时,使用的是正在频繁变动的Q,那么学习目标就会像个“移动靶”,不断逃跑,极易导致模型震荡甚至发散。使用平滑变化的Target网络,能极大地提高训练稳定性。
Slow / Fast 双 Actor 设计
QAM代码中最有特色的设计,我认为就是双流Actor架构:
| Actor | 训练目标 | Loss 来源 | 作用 |
|---|---|---|---|
| actor_slow(慢流) | Beha vior Cloning | flow_loss 匹配数据速度场 | 学习数据集的先验,保证轨迹大致形状 |
| actor_fast(快流) | RL 策略提升 | adj_loss(Q 梯度) | 在 actor_slow 的基础上给出修正矢量 |
这种“双流”设计本质是一种残差设计,它巧妙地解决了一个经典矛盾:如何既保持从数据中学到的稳定行为,又去追求更高的奖励?
两者的结合方式由一个residual参数控制。推荐使用Residual模式,即总速度 = actor_slow的速度 + actor_fast的修正速度。这就像一位经验丰富的老司机在开车,旁边坐着一位精算的导航员,导航员不断地在老司机的方向盘上施加微小的力,让车开得更完美。
QAM 的伴随匹配损失
下面这段伪代码是QAM损失函数的核心实现,它清晰地展示了Adjoint Matching是如何将Q梯度转换为目标速度向量的:
def qam_loss(v_net, q_net, s, x_1, eta=1.0):
batch_size = s.shape[0]
# 1. 采样 t 和噪声 x_0
t = torch.rand(batch_size, device=s.device)
x_0 = torch.randn_like(x_1)
# 2. 构造中间点 x_t(线性插值)
t_expanded = t.view(-1,1)
x_t = (1- t_expanded) * x_0 + t_expanded * x_1
# 3. 计算 Q 对 x_t 的梯度(Adjoint 项)
x_t.requires_grad_(True)
q_val = q_net(s, x_t)
grad_a_q = torch.autograd.grad(outputs=q_val.sum(), inputs=x_t, create_graph=True)[0]
# 4. 构造目标速度(核心:匹配)
v_base = x_1 - x_0
v_target = v_base + eta * grad_a_q
# 5. 预测速度并计算 MSE Loss
v_pred = v_net(s, x_t, t)
loss = F.mse_loss(v_pred, v_target.detach())
return loss
这段代码的精髓在于:
“Adjoint” 对应的是 grad_a_q。它没有让梯度穿过ODE链条反传,而是直接把Q的梯度作为一个伴随信号提取出来。
“Matching” 对应的是 F.mse_loss(v_pred, v_target)。Velocity网络不再是直接去最大化Q,而是去匹配那个已经被Q梯度修正过的理想速度 v_target。这就把问题从一个复杂的优化问题,变成了一个简单的回归问题。
QAM 作者实现细节
qam.py 的实现本质是一个 Q-learning + flow policy + adjoint matching 的强化学习Agent。它用 actor_slow 学习数据的动作分布,用 critic 学习价值函数,用 actor_fast 通过critic梯度进行Q引导的flow修正,还集成了best-of-n、action chunking、one-step蒸馏和edit policy等增强机制。
训练主循环
训练时,critic loss 和 actor loss 协同工作,就像“老师”和“学生”:
- Critic Loss(老师在备课):训练Q函数,使当前Q值尽可能接近TD target。它采用了一种保守Q学习策略(
mean - ρ * std),这能有效缓解由OOD(分布外)动作导致的Q值过估计问题。它的唯一任务就是把 (s,a) → r 的数值关系算准。 - Actor Loss(学生在考试):学生调用已经训练好的Critic网络,通过对老师求导,拿到梯度(伴随状态)。然后,学生(actor_fast)就去匹配这个梯度方向。它同时包含了flow matching loss(让slow actor做基础模仿学习)和 adjoint matching loss(让fast actor学习Q梯度的修正方向),以及其他可选的loss项。
Critic Loss 流程:
| 步骤 | 操作 | 说明 |
|---|---|---|
| A | batch 输入 | 批量输入数据 |
| B | action_chunking? | 判断是否需要动作分块 |
| C | reshape actions 为动作块 | 将动作重塑为块结构 |
| D | 取 actions[..., 0, :] | 取第一个动作 |
| E | sample_actions 采样 next_actions | 采样下一步动作 |
| F | clip next_actions 到 [-1, 1] | 裁剪动作值范围 |
| G | target_critic 计算 next_qs | 目标网络计算 Q 值 |
| H | next_q = mean - ρ * std | 保守 Q 值估计 (CQL风格) |
| I | 计算 target_q | TD 目标:reward + γ^H × mask × next_q |
| J | critic 计算当前 q | 当前网络计算 Q 值 |
| K | MSE(q, target_q) × valid | 均方误差损失,乘以有效掩码 |
| L | 返回 critic_loss 和统计信息 | 输出损失和诊断信息 |
Actor Loss 流程:
- slow actor 的行为克隆 flow matching loss。
- fast actor 的 adjoint matching loss。
- 可选的 FQL one-step actor loss。
- 可选的 edit policy loss。
Flow Matching 部分(Slow Actor)
这部分是slow actor的基础模仿学习目标。它的逻辑非常直接:从标准高斯噪声出发,取数据集里的真实动作作为目标,随机采样一个中间时刻t,在噪声和动作的线性插值路径上采样一个中间点,真实速度就是“动作减去噪声”。然后训练actor_slow去预测这个速度。这个部分的目标,就是让actor_slow学会如何从噪声“流向”数据中的动作分布。
Adjoint Matching 部分(Fast Actor)
adj_matching() 是整个代码中最核心的函数。它利用critic对最终动作的梯度来构造adjoint state,再沿着flow轨迹反向传播,用来训练actor_fast。这个过程包括:
- 正向Flow Rollout:从噪声动作开始,进行积分,生成一条完整轨迹。
- Critic 梯度初始化 Adjoint:在轨迹终点,用critic对最终动作求梯度,得到adjoint的初始值。
- 反向传播 Adjoint:利用VJP(Vector-Jacobian Product)技术,从最后一步开始,一步步向前反推adjoint值。这一步确保了Q的指引信号能够穿过整个Flow动力学系统,精准地分配到每一个时间步上。
动作采样流程
sample_actions() 会一次生成多个候选动作,然后用critic选出Q值最高的那个。这是一种简单但非常有效的推理阶段(inference-time)策略提升方法。
Flow 动作生成
compute_flow_actions() 从噪声开始,按设定的步数做欧拉积分。这里的model参数可以灵活选择:"slow"(只用actor_slow),"fast"(只用actor_fast),或者"slow,fast"(两者速度场相加)。
六大核心特性
Slow/Fast 双 Actor 结构
如前所述,这种分离设计将“保持数据分布”和“追求更高奖励”这两个目标解耦,结构非常清晰。
Adjoint Matching 注入 Critic 梯度
不是简单地最大化Q值,而是先生成动作轨迹,在终点计算critic梯度,再反向传播,最后训练fast vector field去匹配这个adjoint信号。这比普通的确定性策略梯度(DPG)更适合基于流的策略。
Pessimistic Critic Ensemble
Critic使用集成(ensemble)并采用“均值减ρ倍标准差”的策略来估计target Q。这是一种保守Q学习策略,非常适合离线RL,能有效缓解OOD动作带来的Q值过高估计问题。
Best-of-N 动作选择
在采样时生成多个候选动作,再用critic选出Q值最高的那个。这相当于在推理阶段做了一次轻量级的策略提升。
可插拔的 FQL One-Step Policy
当启用fql_alpha时,模型会训练一个one_step_actor,将flow policy蒸馏成一步策略。优点是推理速度更快,同时能保留flow policy的动作质量,并通过Q loss进一步提高动作价值。
可选 Edit Policy Refinement
当启用edit_scale时,模型会在flow action基础上学习一个小的修正项。这让策略可以在保持flow policy主体输出的同时,进行局部的Q值提升。
QAM 与相关方法的对比
QAM vs IQL
| 维度 | IQL | QAM |
|---|---|---|
| 策略形式 | 单步高斯/确定性策略 | 多步 Flow/Diffusion 生成策略 |
| Q 引导方式 | Advantage 加权行为克隆 | Critic gradient + Adjoint Matching |
| 优化信号 | 标量权重:这个动作好多少 | 矢量方向:动作往哪里改更好 |
| 表达能力 | 相对有限 | 能表达多峰、连续、长程动作分布 |
| 计算开销 | 较低 | 较高,需要 flow 积分和伴随计算 |
通俗点说,IQL是:“这个动作得分高,多模仿它。” 而QAM是:“当前动作如果往这个方向偏一点,分数会更高;请你让生成过程的每一步都朝这个方向调整。” 这就是QAM比advantage加权BC更适合复杂生成式VLA策略的原因。
QAM vs RECAP
| 维度 | RECAP | QAM / LWD |
|---|---|---|
| 改进信号 | 二值 improvement indicator | 连续 critic action gradient |
| 策略更新 | Advantage-conditioned imitation / MLE | Adjoint Matching 回归目标 |
| 优势 | 稳定、易训练 | 能利用连续方向信息,适合 flow policy |
| 风险 | 标签粗粒度、依赖阈值 | 依赖 critic 梯度质量、计算更复杂 |
RECAP就像老师告诉你:“这张卷子是优秀答案,请按这种风格去写。” QAM则像老师直接握着你的手说:“这一笔往左偏一点,分数会更高。” 两者之间不是谁取代谁的关系,而是不同工程取舍下的产物。
QAM vs QGF
QGF(Q-Guided Flow)是Sergey Levine团队的另一项成果,两者最根本的区别在于策略优化发生的时机不同。
| 维度 | QAM | QGF |
|---|---|---|
| 策略优化时机 | 训练时 | 测试/推理时 |
| 是否更新策略参数 | 是,RL 训练中更新 actor | 否,测试时不再训练 |
| 对 Q 梯度的使用 | Adjoint Matching 构造稳定目标 | 采样时直接用 ∇ₐQ 引导生成 |
| 训练复杂度 | 更高(actor+critic 联合优化) | 更低(actor 可用纯 BC 稳定训练) |
| 稳定性 | 解决“穿过多步去噪反传不稳定” | 规避训练期 actor-critic 不稳定 |
| 典型优势 | 理论上可学到更“内生”的高价值策略 | 简单、便宜、可扩展 |
工程选择建议:
- 如果你追求端到端RL学出最终策略,追求性能上限 → 偏QAM。
- 如果你更看重训练稳定性、实现简单、计算资源更友好 → 偏QGF。
- 两者其实可以组合使用:先用QAM训练出一个更好的critic/actor,再在推理阶段叠加QGF式的guidance。
通俗版理解
风谷城每年都有一场比赛:谁能骑着“流风马”穿过迷雾峡谷,谁就能拿到全城的粮仓钥匙。城里两位年轻驯马师——阿井(QAM)和阿舟(QGF)——选择了不同的路径。
阿井的做法(QAM): 他每次训练都带着裁判老秦(Q函数)。老秦不只在终点打分,还会在每个弯道说:“往左一点会更值钱。”可流风马动作连着动作,直接反向传播经常算晕。于是阿井请来“回声匠”(Adjoint Matching),把老秦的方向建议翻译成一系列稳定的练习目标。他不是等到最后才改,而是每一步都学“该往哪边更好”。慢慢地,阿井和马在训练里就越骑越聪明。
阿舟的做法(QGF): 他先让马老老实实学名骑手的录像(BC预训练),把基本功练稳。同时单独训练了一个“价值罗盘”(Critic)。到比赛那天,阿舟不再重新训练马,只在骑行当下拿出罗盘:“往这边多拽一点,价值更高。”马边跑边被推着修正路线,省钱、省时。
优劣: 在面对全新赛道时,阿舟的方法因为不用临时重练,所以能快速适配。而阿井的方法,在长期训练充分的赛道上,其性能上限依然很高。
总结
QAM可以说是离线强化学习和生成式策略融合的典范之作。它的核心创新在于:
- 避免了BPTT的梯度问题:通过Adjoint Matching,把长链路的梯度反向传播问题,巧妙地转化成了一个稳定的监督学习问题。
- 融合了Q的指引:在保留数据稳定性的同时,利用Q函数引导策略向更高奖励的方向探索。
- 巧妙的双流设计:通过actor_slow(模仿)和actor_fast(优化)的平衡,在稳定性和进取心之间找到了一个很好的平衡点。
- 精密的数学设计:通过伴随动力学,在轨迹的起止点强制模仿,中间阶段则允许进行适度的探索。
QAM证明了,即使在离线设定下,我们也可以通过巧妙的统计方法,将生成式模型强大的表达能力与强化学习的目标导向能力结合起来。它为大规模VLA模型在真实机器人上进行RL训练,奠定了一个切实可行的工程基础。

