摘要:
在 Offline RL 中,传统的 Q-Learning 往往因为过度乐观(Overestimation)而导致失败。之前的算法(如 BCQ)试图通过限制策略(Policy)来解决问题,操作繁琐。而 Conservative Q-Learning (CQL) 另辟蹊径,它选择直接修改价值函数(Q-Function)的更新方式,通过在 Loss 中加入“惩罚项”,迫使 Q 值对未见过的动作保持悲观(Pessimistic)。本文将拆解 CQL 的核心直觉,展示几行代码如何实现这一 SOTA 算法。
目录 (Table of Contents)
- 引言:乐观是魔鬼,悲观保平安
- 为什么要对 Q 做保守估计?
- OOD 的陷阱
- 下界保证 (Lower Bound Guarantee)
- CQL Loss 的直觉拆解
- 核心公式:压制冒进,锚定真实
- 物理图像:造一个“碗”
- 理论变体:CQL(H) vs CQL®
- PyTorch 代码实现 (核心片段)
- 总结与实战建议
1. 引言:乐观是魔鬼,悲观保平安
在标准的在线强化学习(Online RL)中,我们鼓励“乐观”——面对未知的动作,给他一个较高的探索红利(Exploration Bonus),去试试看,万一单车变摩托呢?
但在 Offline RL 中,乐观是致命的。因为你不能真的去试。如果你误以为“冲向悬崖”能得高分,你就会一直想冲向悬崖,而永远无法被纠正。
CQL 的哲学非常简单:在没有证据证明某个动作好之前,我默认它是坏的。
2. 为什么要对 Q 做保守估计?
2.1 解决 Q 值高估 (Overestimation)
上一篇提到,由于 Extrapolation Error,Q 网络会对 OOD(分布外)动作输出错误的、往往偏高的 Q 值。
标准 Q-Learning 的 max 操作会选中这些错误的 Q 值,导致策略跑偏。
2.2 寻找 Q 值的下界 (Lower Bound)
CQL 的数学目标是学习一个保守的 Q 函数
Q
^
\hat{Q}
Q^,使得它成为真实 Q 值
Q
π
Q^\pi
Qπ 的下界:
Q
^
(
s
,
a
)
≤
Q
π
(
s
,
a
)
\hat{Q}(s, a) \le Q^\pi(s, a)
Q^(s,a)≤Qπ(s,a)
只要我们能保证学习到的 Q 值永远不高于真实的 Q 值,那么:
- 我们可能错过一些好动作(因为太保守)。
- 但我们绝不会跌入由于高估带来的陷阱(安全第一)。
在 Offline RL 中,宁可错过,绝不犯错。
3. CQL Loss 的直觉拆解
CQL 不需要训练 VAE,也不需要计算 MMD,它只需要在标准的 Bellman Error 基础上,加两项正则化。
3.1 核心公式
CQL 的 Loss 函数由三部分组成:
L C Q L ( θ ) = α ⋅ ( E s ∼ D , a ∼ μ ( s ) [ Q ( s , a ) ] ⏟ ① 压制项 − E s ∼ D , a ∼ D [ Q ( s , a ) ] ⏟ ② 提升项 ) + 1 2 ( Q − T Q ) 2 ⏟ ③ 标准 TD Error L_{CQL}(\theta) = \alpha \cdot ( \underbrace{\mathbb{E}_{s \sim \mathcal{D}, a \sim \mu(s)} [Q(s, a)]}_{\text{① 压制项}} - \underbrace{\mathbb{E}_{s \sim \mathcal{D}, a \sim \mathcal{D}} [Q(s, a)]}_{\text{② 提升项}} ) + \underbrace{\frac{1}{2} (Q - \mathcal{T}Q)^2}_{\text{③ 标准 TD Error}} LCQL(θ)=α⋅(① 压制项 Es∼D,a∼μ(s)[Q(s,a)]−② 提升项 Es∼D,a∼D[Q(s,a)])+③ 标准 TD Error 21(Q−TQ)2
- μ ( s ) \mu(s) μ(s):当前的策略(可能会选出 OOD 动作)。
- D \mathcal{D} D:数据集(真实动作)。
3.2 逐项解析
- ① 压制项 (Minimize Q under Policy):
- 对于当前策略 μ \mu μ 想要选择的动作,疯狂压低它的 Q 值。
- 如果 μ \mu μ 选了一个 OOD 动作,这个项会把它的 Q 值压得很低(惩罚)。
- ② 提升项 (Maximize Q under Data):
- 对于数据集里的真实动作,努力抬高它的 Q 值。
- 为什么要这一项? 如果只压低不抬高,Q 网络会把所有动作的 Q 值都变成负无穷大。我们需要数据作为“锚点 (Anchor)”,告诉网络:“别的地方都是地狱,但这几个数据点是安全的。”
- ③ 标准 TD Error:
- 保证 Q 值还要符合 Bellman 方程的迭代逻辑,不仅仅是简单的极大极小。
3.3 物理图像:造一个“碗”
想象一个 Q 值曲面:
- CQL 强行把所有非数据集区域(OOD)按下去,变成低谷。
- 把数据集区域(Data)顶起来,变成山峰。
- 这样,当策略去
argmax Q时,自然就会落在数据集覆盖的范围内(山峰处),而不会跑偏。
4. 理论变体:CQL(H) vs CQL(R)
在论文中,你可能会看到不同的 CQL 写法。
- CQL®: μ \mu μ 是简单的均匀分布或者随机采样。这是一种比较粗糙的保守。
- CQL(H):
μ
\mu
μ 是当前的策略分布,并且引入了熵正则化 (Entropy Regularization)。
min Q log ∑ a exp ( Q ( s , a ) ) − E a ∼ D [ Q ( s , a ) ] \min_Q \log \sum_a \exp(Q(s, a)) - \mathbb{E}_{a \sim \mathcal{D}}[Q(s, a)] Qminloga∑exp(Q(s,a))−Ea∼D[Q(s,a)]- 第一项 log ∑ exp \log \sum \exp log∑exp 实际上就是 Soft-maximum。它意味着:压低所有动作的 Q 值(特别是 Q 值高的那些)。
- 这通常用于连续动作空间,且效果最好,是目前代码库中的默认实现。
5. PyTorch 代码实现 (核心片段)
CQL 的实现非常简单,这(相比于 BCQ 的复杂架构)是它流行的主要原因。以下是基于 SAC 的 CQL 实现逻辑:
def calc_cql_loss(q_net, current_obs, action_batch):
"""
q_net: Q 网络
current_obs: 当前状态 batch
action_batch: 数据集里的真实动作 batch
"""
# 1. 获取 OOD 动作 (通过当前策略采样)
# 这里的 new_action 就是公式里的 mu(s)
# 为了更强的保守性,通常会采样多个动作
with torch.no_grad():
new_action, _, _ = policy_net(current_obs)
# 2. 计算 Q 值
# Q_data: 数据集动作的 Q 值 (锚点)
q1_data = q_net(current_obs, action_batch)
# Q_ood: 策略生成的动作的 Q 值
q1_ood = q_net(current_obs, new_action)
# --- CQL 核心 Loss ---
# log_sum_exp(Q_ood) 对应 "压制所有动作"
# q_data 对应 "提升数据动作"
# 这里的实现是 logsumexp 变体,常用于连续动作空间
# 将 random action, current policy action 等拼在一起做 logsumexp
# 简化的直观写法:
cql_loss_term = torch.logsumexp(q1_ood, dim=1).mean() - q1_data.mean()
# 3. 加上标准的 TD Error
# target_q 由 Bellman 计算得出
bellman_error = F.mse_loss(q1_data, target_q)
# 4. 总 Loss
# alpha_cql 是超参数,通常取 5.0 或 10.0
total_loss = alpha_cql * cql_loss_term + bellman_error
return total_loss
(注:实际工程实现中,为了更好的估计,通常会混合 Random Action 和 Policy Action 一起作为 OOD 样本进行压制)
6. 总结与实战建议
什么时候 CQL 表现最好?
- 数据分布极其复杂:比如 D4RL 的 AntMaze 任务,数据充满了噪音和多模态。BCQ 这种试图生成数据的模型很难训练,但 CQL 直接操作 Q 值,鲁棒性极强。
- 不想写复杂的生成模型:如果你现有的代码是 SAC 或 DQN,改造成 CQL 只需要改几行 Loss 函数。
优缺点总结
- 优点:
- 代码改动极小:即插即用。
- 理论扎实:有严格的下界证明。
- SOTA 性能:在大多数 Benchmark 上碾压 BC 和早期算法。
- 缺点:
- 对 α \alpha α 敏感:保守程度的系数 α \alpha α 需要细调。如果 α \alpha α 太大,Q 值会被压得过低,导致策略完全不敢动(变成 BC);如果太小,压不住 OOD。
- Q 值数值扭曲:训练出来的 Q 值往往远小于真实的 Return(因为一直在被惩罚),这使得 Q 值失去了物理意义(虽然相对大小是对的,依然能选出好动作)。
一句话总结:
CQL 告诉我们,在充满未知的 Offline RL 世界里,不要盲目自信,先给所有未尝试的动作泼一盆冷水,只有亲眼见过(数据集中有)的动作才值得信任。
CQL 虽然好,但有没有一种方法既不需要像 BCQ 那样训练 VAE,又不需要像 CQL 这样引入额外的超参数 α \alpha α 呢?下一篇,我们将介绍 Offline RL 的极简主义流派:IQL (Implicit Q-Learning)。 🤖
1957

被折叠的 条评论
为什么被折叠?



