【机器人 / 强化学习】QAM:基于伴随匹配的 Q-learning 流策略优化
0x00 概要
有了 DIVL 提供的价值函数,下一步是策略提升——如何让 VLA 策略输出更高价值的动作?这就是 QAM(Q-learning with Adjoint Matching)要解决的问题。它巧妙地将 Flow Matching 的表达能力与 Q-learning 的优化目标结合,同时解决了扩散模型在强化学习中通过时间反向传播(BPTT)带来的不稳定问题。
1.1 核心问题:Flow 策略的优化困境
1.1 为什么 Flow 策略难以用 RL 优化?
现代视觉-语言-动作(VLA)模型常采用 Flow Matching 或 Diffusion 架构生成动作。这类模型表达能力强,可以生成平滑、多峰、符合物理规律的连续动作序列。但问题在于:动作并非单步直接输出,而是通过多步去噪/ODE 积分逐步迭代生成。
这意味着整个计算图是一条长链式结构——每一步计算都依赖上一步的结果。如果我们想用 Q 函数梯度来优化最终生成的动作,梯度就必须沿着整条生成链路反向传播。由此引发两大问题:
计算开销大:多步迭代链路需要全程保留所有中间状态,显存占用极高
数值不稳定:长链路反向传播极易出现梯度消失、梯度爆炸、更新方差过大,最终导致训练崩溃
这是基于扩散/流匹配的强化学习策略在真机场景中难以收敛的核心原因。
1.2 三种候选方案
面对"如何优化 flow policy"这个问题,有三种可能的路径:
方案 A:优势加权回归(AWR)。 需要计算
log
π
(
a
∣
s
)
,但 flow 多步去噪过程下难以获得解析密度,高维 action chunk 下归一化常数不可积。
方案 B:直接反向传播
∇
θ
Q
(
s
,
x
1
(
x
0
;
θ
)
)
。 需要穿过整条 ODE 反传,计算昂贵且数值不稳定,对大型 VLA 模型不实际。
方案 C:QAM(采用此方案)。 将轨迹级优化转化为流路径上的局部回归,无需穿过 ODE 反传,只需终点梯度。这正是我们要深入讲解的方案。
0x02 核心思想:Adjoint Matching
2.1 一句话理解
不让梯度"穿越"整个生成过程(太贵太不稳定),而是在终点拿到 Critic 的"修改意见"后,沿着生成路径反向传递这份意见,逐步微调每一步的生成方向。
传统方式与 QAM 的对比:
传统做法(BPTT,不可行):
噪声 → [ODE 积分 N 步] → 动作 → ∇_a Q → [反向穿过 N 步 ODE] → 更新 θ
QAM 做法(高效稳定):
- 用冻结的参考策略 π_β 跑一条前向流轨迹 {a_w}(无需梯度)
- 在终点 a_1 处计算 Critic 梯度: g̃_1 = -∇_a[Q(s, a_1)/λ]
- 沿参考轨迹反向积分伴随方程,得到每个时间点 w 的局部目标 g̃_w
- 用 ||f_θ(s,a_w,w) - f_β(s,a_w,w) + σ_w·g̃_w||² 做局部回归更新 θ
2.2 伴随变量的直觉
在控制理论中,伴随变量(Adjoint)可以理解为终点目标函数对轨迹中间状态的敏感度。
在 QAM 框架下,优化目标是提升动作对应的 Q 价值。终点动作处的 Critic 梯度
∇
a
Q
(
s
,
a
final
)
的含义是:对最终动作做微小偏移时,Q 价值的变化趋势。但最终动作由完整的流生成轨迹推导而来,我们需要求解一个关键问题:
为了让最终动作向高 Q 值方向优化,流生成过程中每一个时间步的向量场需要做出怎样的调整?
伴随法正是用来求解该问题的工具。它会将终点处的 Q 梯度,按照伴随方程反向映射到流轨迹的每一个时间步,生成逐步的局部监督信号。至此,原本复杂的端到端 RL 优化问题,被转化为简单的逐歩监督回归任务:在每个时间步,让当前向量场去匹配经过 Q 梯度修正后的目标向量场。
2.3 一个比喻
我们可以用流水线上的工头来理解 QAM:
直接端到端反传就像拉一根很长的绳子,希望绳子末端的反馈能准确传到每一个中间节点。绳子越长,抖动越大,越难控制。
QAM则像是在流水线的每个工位安排一个工头。每个工头只告诉当前这一步的向量场应该往哪里微调,不需要整条链路一起承担不稳定的反向传播。
2.4 数学框架
QAM 的目标是让策略
π
逐渐靠近一个更好的分布:
π
(
a
∣
s
)
∝
π
behavior
(
a
∣
s
)
⋅
exp
(
Q
(
s
,
a
)
)
为了实现这个目标,QAM 定义的目标速度场是:
v
target
(
x
1
−
x
0
)
保持现状(模仿行为)
+
α
⋅
∇
a
Q
(
s
,
x
t
)
寻找更好(Q 的指引)
这里的
α
控制了"模仿行为"和"追求 Q"之间的平衡。
QAM 没有把 RL 梯度硬塞进整个生成链条,而是用伴随匹配把全局优化问题拆成 flow 每一步的局部回归问题。论文中特别说明:
f
β
保持固定,作为离线 RL 前由行为克隆初始化得到的参考流;离线和在线训练过程中优化的是
f
θ
。
关键注意点:QAM 不是部署推理时"每一帧实时调用 critic 梯度"。论文强调的是训练阶段:把 critic gradient 转换为 flow 模型的 step-wise supervision。训练后的策略在部署时仍然是前向生成动作,只是其动作分布已经被价值函数引导过。
0x03 网络架构
3.1 三大核心网络
Velocity Network(
v
θ
):导航员
这是 QAM 的执行灵魂。在传统 RL(如 PPO/SAC)中,策略网络是一个"瞬移器"——输入状态
s
,直接跳出动作
a
。但在 QAM 这种基于 Flow Matching 的算法中,策略网络是一个"导航员":
输入:
(
s
,
x
t
,
t
)
——状态、当前位置、当前时间刻度
输出:速度矢量,表示当前位置的切线方向
作用:通过 Adjoint Matching 学习如何在 Q 的指引下生成最优的速度场
在数学上,动作的生成遵循一个常微分方程:
d
x
t
d
t
v
θ
(
x
t
,
t
,
s
)
输入
(
s
,
x
t
,
t
)
:需要知道现在的环境
s
、自己现在在哪
x
t
、以及现在是第几秒
t
。输出
v
:返回一个和动作维度一样的矢量,代表当前位置的切线方向。
在推理时,Velocity Network 被反复调用:
x = torch.randn_like(action) # 从噪声开始
dt = 1.0 / num_steps
for i in range(num_steps):
t = i * dt
v = v_theta(x, t, s) # 问导航员
x = x + v * dt # 迈一小步
循环结束后的 x 就是最终动作 a
Critic(Q):价值网络
Q 网络负责评估动作的好坏。输入
(
s
,
a
)
,输出 Q 值。它的作用是为 Adjoint Matching 提供梯度信息
∇
a
Q
。
Target Q 网络
Target Q 是 Q 的一个慢更新副本(软更新/Polyak Averaging)。为什么需要它?如果在计算更新目标时使用正在频繁变动的 Q,会导致学习目标不断"逃跑",引发模型震荡甚至发散。使用平滑变化的 Target 网络能极大提高训练稳定性。
3.2 Slow / Fast 双 Actor 设计
QAM 代码中最有特色的设计是双流 Actor 架构:
Actor 训练目标 Loss 来源 作用 特点
actor_slow(慢流) Behavior Cloning flow_loss 匹配
x
1
−
x
0
学习数据集的先验,保证轨迹大致形状 稳定、保守
actor_fast(快流) RL 策略提升 adj_loss(Q 梯度) 在 actor_slow 的基础上给出修正矢量 激进、追求卓越
这种"双流"设计本质是一种残差设计,解决了强化学习中一个经典的矛盾:如何既保持数据中的稳定行为,又追求更高的奖励?
两者的结合方式由一个 residual 参数控制:
Residual 模式(推荐):生成的总速度
v
v
slow
+
v
fast
。就像老司机在开车,旁边坐着一个精算的导航员,不断在老司机的方向盘上施加微小的力,让车开得更完美。
Non-residual 模式:actor_fast 尝试直接去匹配一个已经融合了 Q 梯度的总目标速度。
3.3 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) # t ~ U(0, 1)
x_0 = torch.randn_like(x_1) # x_0 ~ N(0, I)
# 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. 构造目标速度(核心:匹配)
# 基础速度 + Q 梯度修正 = 目标速度
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。
0x04 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 等增强机制。
总体流程图如下:
QAM-1-总体流程图
4.1 训练主循环
训练入口是 update() 和 batch_update():
单步更新 和 批量 scan 更新 最终都会调用 _update():
total_loss() 把 critic loss 和 actor loss 相加:
loss = critic_loss + actor_loss
训练时,critic loss 和 actor loss 协同工作,就像"老师"和"学生":
QAM-训练主循环
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)