
























本篇主要介绍 DrQ 和 VICE,

注:
真实机器人任务的 reward specification 是 SERL 重点解决的问题之一。
某些任务可以用机器人状态直接定义,例如 PCB 插入可以根据末端或物体位置设计奖励;在这种情况下,奖励函数可以由一个二元分类器提供,该分类器接收状态观测 s 并输出一个二元” 事件”e发生的概率,对应于任务的成功完成。奖励随后由 r(s) = log p(e|s) 给出。
但多数任务需要从图像中判断是否完成。比如"电缆是否正确卡入槽位""物体是否被放到正确 bin 里",往往需要视觉判定,手工设计一个好的奖励函数本身就是一个耗时且需要领域专长的任务。
SERL 支持三类奖励方式:

用户可以采集少量成功与失败图片,训练一个轻量视觉分类器。该分类器在训练过程中输出成功概率或二值 reward。即,人只需要定义成功 / 失败样本,之后系统就能自动在训练中判断 reward。这就是自动裁判(Success Classifier):
Success Classifier 是离线训练专用,是简单的端到端结构:
这里需要注意:SERL 不是完全不需要 reward,而是提供了工具让 reward specification 更容易、更自动化。SERL 的目标不是消除 reward 设计,而是降低 reward engineering 的成本。
VICE 将奖励学习看成类似 GAN 的过程:策略像 generator,不断产生新样本;reward classifier 像 discriminator,判断哪些状态是成功事件。这样,随着策略分布变化,classifier 可以用策略产生的新负样本继续训练,避免只在初始数据上过拟合。
这种设计让奖励系统能够自适应策略的进化。初始阶段,classifier 在人类标注的样本上训练;随着策略能力的提升,classifier 可以从策略产生的经验中学习更细粒度的成功模式,实现奖励的持续改进。
VICE 是在线训练, 支持 return_encoded / classify_encoded 模式
在具身智能和强化学习的语境下,DrQ 和 VICE 是两套针对不同痛点的经典 Agent(代理)架构。
简单来说:DrQ 是为了 "看得更清",而 VICE 是为了 "罚得更准"。
这样可以视觉与硬件包装:眼手合一。
用途:解决 "从图像直接学习动作(Pixel-to-Action)" 时的样本效率和泛化问题。
它的痛点: 如果直接把原始图片丢给 RL 模型,机器人很容易 "只看局部",或者因为光线变了一点就完全不会动了。
核心特色:图像增强(Data Augmentation)+ 一致性。
优点:
用途: 解决 "自动定义奖励(Reward)" 的问题,特别是针对那些难以用数值描述的 "事件"。
它的痛点: 你怎么告诉机器人 "盖子盖紧了"?你很难写代码去算角度。
核心特色:反向学习(Inverse RL)+ 事件判定。
优点:
在 SERL 中,SACAgent 是核心基类。
| SACAgent 核心机制 | 功能 |
|---|---|
critic_loss_fn() |
Clipped Double Q + ensemble min + 可选 entropy backup |
policy_loss_fn() |
标准 SAC actor 目标:Q−a⋅logπ |
temperature_loss_fn() |
Lagrange 乘子自动调温 |
update_high_utd() |
关键优化:UTD ratio 多次 critic 更新 + 1 次 actor 更新,用 jax.lax.scan 实现 JIT 内循环 |
update() |
支持选择性更新子网络(networks_to_update 参数) |
DrQAgent 和 VICEAgent 是 SACAgent 的子类。这意味着它复用了 SAC 的所有稳定机制(双 Q、熵自动调节),只是在输入端加了一层图像处理逻辑。
DrQAgent 增强 (drq.py)
VICEAgent 奖励学习 (vice.py)
sigmoid(logit) >= 0.5 → reward=1, 否则 reward=0SACAgent (sac.py:21)
├─ create_pixels() → 像素输入,共享/独立编码器
└─ create_states() → 状态输入,无编码器
└─ DrQAgent (drq.py:23) 继承 SACAgent
├─ create_drq() → 支持 small/resnet/resnet-pretrained 编码器
├─ data_augmentation_fn() → 随机裁剪增强
├─ update_high_utd() → 高 UTD 比率训练(关键优化)
└─ update_critics() → 仅更新 Critic
└─ VICEAgent (vice.py:26) 继承 DrQAgent
├─ create_vice() → 额外 VICE 分类器网络
├─ update_vice() → BCE + Mixup + Label Smoothing + 梯度惩罚
├─ vice_reward() → 用分类器替代手工奖励
└─ update_high_utd() → 用 VICE 奖励替换环境奖励
| 特性 | DrQ Agent | VICE Agent |
|---|---|---|
| 主要任务 | 视觉表征学习(把图看透)。 | 奖励函数生成(把分打准)。 |
| 核心技术 | 随机裁剪、平移(Augmentation)。 | 基于正负样本的对抗学习 / 判别。 |
| 解决的难题 | 图像噪声、过拟合、泛化差。 | 奖励函数难写、信号稀疏。 |
| 在 SERL 里的位置 | 作为视觉主干(Backbone)的增强。 | 作为自动裁判(Reward Classifier)的原型。 |
真实机器人通常使用图像观测。如果直接用像素训练,视觉过拟合会非常严重。DrQ 的核心是对图像做数据增强,例如 random crop,让策略不要记住某个固定像素位置,而是学到更鲁棒的视觉特征。
SERL 的 DrQAgent 在 SAC 基础上增加了图像增强和视觉编码器支持。
DrQ 最重要的特性是 random crop 数据增强。这在真实机器人环境中尤为关键:
特色解释:为什么 DrQ 在 SERL 中不可或缺?
论文实验中使用了 ImageNet 预训练 ResNet-10 作为视觉 backbone,并连接到 MLP。观测包含相机图像和机器人本体信息,例如末端位姿、速度、力、力矩等。
EncodingWrapper 是 SERL 处理视觉和本体感知输入的核心封装:
rearrange(image, "T H W C -> H W (T C)") 和 rearrange(image, "B T H W C -> B H W (T C)")stop_gradient 支持:允许冻结视觉编码器编码器选项:
Spatial Softmax / Spatial Learned Embeddings 是一个关键设计:它们将卷积特征图转为空间坐标的加权期望,保留空间信息同时大幅降维。这比全局池化更能保留空间位置信息,对机器人视觉任务至关重要。
在 SERL 中,观测数据结构如下:
observations = {
"image1": (T, H, W, C), # 相机1图像帧栈
"image2": (T, H, W, C), # 相机2图像帧栈
"state": (T, D), # 本体感受 (tcp_pose, tcp_vel, gripper, force, torque)
}
EncodingWrapper 的处理流程如下:

Late Fusion 设计:视觉和本体感受各自独立编码,最后拼接。这不是 Early Fusion,而是有深刻的设计考量:
stop_gradient,冻结视觉特征只训练本体感受分支代码中预留了但未使用的多任务接口:
| 功能 | 状态 | |
|---|---|---|
| GCEncodingWrapper | Goal-Conditioned: obs + goal 图像 fusion | 代码存在但未被任何 Agent 使用 |
| LCEncodingWrapper | Language-Conditioned: obs + 语言指令 fusion | 代码存在但未被任何 Agent 使用 |
这些接口为未来的多任务学习或条件策略扩展预留了空间。
由于 DrQAgent 继承 SACAgent,其网络架构基本相同,但有以下关键差异:
| 特性 | SACAgent | DrQAgent |
|---|---|---|
| Actor架构 | 编码器+MLP[256,256] | 相同 |
| Critic架构 | 编码器+Ensemble MLP[256,256]×2 | 相同 |
| 数据增强 | 无 | 随机裁剪(4像素填充) |
| 训练稳定性 | 标准SAC | 增强提高泛化 |
DrQAgent 支持多种编码器类型:
async_drq_sim.py代码细节以 async_drq_sim.py 为例,SERL 的训练流程是典型的异步 actor-learner 架构:
1. Learner 初始化:创建 TrainerServer,注册 replay buffer,等待数据填充
2. Actor 初始化:创建 TrainerClient,连接 Learner
3. Actor 循环:
env.step() → 收集 transition → data_store.insert()client.update() → 推送数据evaluate() → 发送 stats4. Learner 循环:
training_startsupdate_critics() × (UTD-1) 次 → update_high_utd(utd_ratio=1) × 1 次server.publish_network() 同步参数这种异步架构让机器人控制的高实时性要求和训练的高吞吐量要求解耦,互不干扰。

def data_augmentation_fn(self, rng, observations):
for pixel_key in self.config["image_keys"]:
observations = observations.copy(
add_or_replace={
pixel_key: batched_random_crop(
observations[pixel_key],
rng,
padding=4,
num_batch_dims=2
)
}
)
return observations
训练时,会对观测和下一观测进行数据增强。
def update_high_utd(self, batch, utd_ratio, pmap_axis=None):
# 训练时对观测和下一观测进行数据增强
rng, obs_rng, next_obs_rng = jax.random.split(rng, 3)
obs = self.data_augmentation_fn(obs_rng, batch["observations"])
next_obs = self.data_augmentation_fn(next_obs_rng, batch["next_observations"])
batch = batch.copy(
add_or_replace={
"observations": obs,
"next_observations": next_obs,
}
)
# 调用父类SAC的更新
return SACAgent.update_high_utd(new_agent, batch, utd_ratio=utd_ratio, pmap_axis=pmap_axis)
update_critics 方法也有调用如下:
def update_critics(self, batch, pmap_axis=None):
# 数据增强
obs = self.data_augmentation_fn(obs_rng, batch["observations"])
next_obs = self.data_augmentation_fn(next_obs_rng, batch["next_observations"])
# 仅更新Critic网络
new_agent, critic_infos = new_agent.update(
batch,
pmap_axis=pmap_axis,
networks_to_update=frozenset({"critic"}) # 只更新Critic
)
编码器选择(create_drq):它提供了灵活的配置:
随机种子(随机裁剪偏移量):在计算数据增强时,它对 observations 和 next_observations 使用了两个不同的随机种子(obs_rng 和 next_obs_rng)。
共用视觉头(Shared Encoder)在 create_drq 中,shared_encoder 默认是 True。如果设为 False(Actor 和 Critic 各用各的视觉网络),其优势如下:
vice.py 是 SERL 中一个非常高级的组件,它实现了 VICE(Variational Inverse Control with Events)算法。它的核心任务是:当机器人没有明确的奖励信号时,通过观察"成功图片"来给自己打分。这在真实的机器人部署中极其重要,因为你无法在真实世界里写出一个完美的数学公式来判断"杯子是否抓稳了"。
VICE 通过将策略访问过的所有状态以负标签的形式加入分类器的训练集,并在每次迭代后更新分类器,从而解决该问题。这样,强化学习过程类似于生成对抗网络(GAN),其中策略充当生成器,奖励分类器则作为判别器。
VICE 是 RLPD 的"心跳"。在 train_rlpd.py 这种算法中,Demo 数据只是素材,而 VICE 的奖励才是灵魂。没了奖励,机器人就失去了进化的动力。
在仿真环境(如 MuJoCo)中,奖励函数很好写:奖励 = - 距离。
但在真实世界中:
VICE 的思路:人类只需要给机器人看几张"任务成功"的照片(Goal Images),剩下的让机器自己去悟。
变分推断是一种"用简单模型逼近复杂真相"的方法。
它的核心逻辑是:
一句话总结:变分推断就是"用一个可调的简化模型,去逼近一个复杂但无法直接计算的真相"。
在贝叶斯统计中,我们想计算后验分布:p(z|x) = p(x|z) * p(z) / p(x)
其中:
问题:p(x) 需要对所有可能的 z 积分,这在复杂模型中几乎不可能计算。
既然无法直接计算 p(z|x),那就用一个简单的 q(z) 来近似它。
VICE 是一种"从专家示范中学习评判标准"的方法。VICE 不是教你"怎么走路",而是教你"什么算走到了目的地"。一旦你知道目的地在哪,你自然就知道该往哪走了。
它的核心逻辑是:
VICE 把强化学习变成了一个"找游戏"。
VICE 实际上是一个类似 GAN(生成对抗网络)的结构:
随着训练的进行,分类器变得越来越挑剔,机器人也随之变得越来越精准。
如果 VICE 坏了:
VICE Agent 在标准 Actor-Critic 基础上增加了基于视觉的奖励分类器,实现了从人类演示到稀疏奖励的迁移学习。
| 组件 | 编码器 | 主干网络 | 输出 | 特殊设计 |
|---|---|---|---|---|
| Actor | SmallEncoder/ResNet | MLP [256,256] | 动作分布 | tanh_squash |
| Critic | 共享Actor编码器 | Ensemble MLP [256,256]×2 | Q值 | 双Critic |
| Temperature | 无 | Lagrange | 标量温度 | 自动调节 |
| VICE Classifier | 独立编码器 | MLP [256] | 二分类logit | 预训练+微调 |
核心组件架构如下:
Actor 网络 :
policy_def = Policy(
encoder=encoders["actor"], # 视觉编码器
network=MLP(**policy_network_kwargs), # [256, 256]
action_dim=actions.shape[-1],
tanh_squash_distribution=True,
std_parameterization="uniform",
)
Critic 网络
critic_backbone = partial(MLP, **critic_network_kwargs) # [256, 256]
critic_backbone = ensemblize(critic_backbone, critic_ensemble_size)(
name="critic_ensemble" # 默认2个Critic
)
critic_def = partial(Critic, encoder=encoders["critic"], network=critic_backbone)
Temperature 网络
temperature_def = GeqLagrangeMultiplier(
init_value=1.0,
constraint_shape=(),
constraint_type="geq", # 大于等于约束
)
VICE Reward Classifier
vice_def = BinaryClassifier(
pretrained_encoder=pretrained_encoder, # 预训练ResNet
encoder=vice_encoder_def, # 独立的编码器
network=MLP(**vice_network_kwargs), # [256]
enable_stacking=True,
)
另外,VICE使用独立的编码器。
# VICE使用独立的编码器
vice_encoders = {
image_key: SmallEncoder(
features=(32, 64, 128, 256),
kernel_sizes=(3, 3, 3, 3),
strides=(2, 2, 2, 2),
padding="VALID",
pool_method="avg",
bottleneck_dim=256,
spatial_block_size=8,
name=f"vice_encoder_{image_key}",
)
for image_key in image_keys
}
在 VICEAgent 中,奖励(reward)的计算依赖于一个学习到的二分类器(即 vice 网络),该网络用于区分专家/目标状态与智能体的观测。具体计算过程如下:
前向传播与 Sigmoid 激活: 将 next_observations 输入 vice 网络(一个 BinaryClassifier),并通过 sigmoid 函数将输出映射为 0 到 1 之间的概率分数。此过程由 vice_reward 方法实现:
rews = nn.sigmoid(
self.state.apply_fn(
{"params": self.state.params},
observation,
name="vice",
train=False,
)
)
二值化(阈值截断): 在 Critic 更新阶段(如 update_critics 和 update_high_utd 方法中),连续的概率分数会被转换为离散的二值奖励。若概率分数大于或等于 0.5,则奖励设为 1.0,否则为 0.0:
rewards = (self.vice_reward(next_obs) >= 0.5) * 1.0
数据增强: 在计算奖励前,会先通过 data_augmentation_fn 对 next_observations 进行数据增强,以提升奖励信号的鲁棒性。
总结:奖励本质上是一个二值指标(1.0 或 0.0),其取值取决于 vice 分类器是否将 next_observation 判定为属于目标/专家状态分布(即 sigmoid 输出的概率 ≥0.5)。
在 VICEAgent 中,BinaryClassifier(在代码中实例化为 vice 网络)的训练逻辑主要集中在 update_vice 方法中。其训练过程使用了二元交叉熵(BCE)损失,并引入了 Mixup、标签平滑(Label Smoothing)和梯度惩罚(Gradient Penalty)等正则化技术来防止 GAN 模式崩溃。
具体训练步骤如下:
数据准备与标签平滑(Label Smoothing):
特征编码:
Mixup 正则化:
bce_loss = lam_θ * bce_loss_a + (1 - lam_θ) * bce_loss_b。梯度惩罚(Gradient Penalty):
参数更新:
总结:
BinaryClassifier 是在特征编码空间中进行二分类训练的,并通过 Mixup 和梯度惩罚来平滑决策边界,从而提高 VICE 奖励信号的稳定性和鲁棒性。
在 SERL 的流程中:
它是怎么被贴上标签的?在 train_rlpd.py 中,当你采样出一个 Batch(包含 Demo)时,系统会运行以下逻辑:
VICE Agent(自奖励分类器)流程图如下:

在 sac.py 或 rlpd.py 运行中,VICE 的核心合作伙伴是 Critic。合作方式如下:
VICE 本质上就是一个"奖励函数生成网络",它判断的是现在这一瞬间好不好,将"判断任务是否成功"转换成了一个二分类问题。
def update_critics(
self,
batch: Batch,
*,
pmap_axis: Optional[str] = None,
) -> Tuple["DrQAgent", dict]:
rewards = (self.vice_reward(next_obs) >= 0.5) * 1.0
batch = batch.copy(add_or_replace={"rewards": rewards})
类比:
VICE 的优越性:作为深度网络,它学到的是"特征空间的相似性(比如插头和插座的咬合关系),这种特征具有极强的泛化性和抗噪声能力。
为什么像素差异不行?
SERL 的策略:通常会先用之前提到的 BC(行为克隆)让机器人做出一些看起来像样的动作,从而给 VICE 提供高质量的"正样本"和"对比样本"。只有评价体系稳了,RL 的高速更新(UTD=20)才有意义。
直接训练分类器在 RL 中很容易崩。比如:机器人发现只要把手在摄像头前晃一下,挡住背景,画面特征就很像成功照片了(这叫 Reward Hacking)。
update_vice 函数用了几个大招来对付它:

此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。