做视觉强化学习项目时,很多人会遇到一个诡异的现象:算法代码没有改,任务还是同一个任务,只是把策略网络从两层 MLP 换成三层,训练曲线就完全变形。更麻烦的是,一旦加入多模态输入,比如在图像之外再接入机器人关节角度、速度或力觉信息,视觉特征的梯度贡献经常会被动作分支“吃掉”。最后学出来的策略虽然能跑,但换个背景、光照或相机角度,性能立刻崩盘。
这不是玄学,而是在线策略训练中双重问题的叠加:视觉表征不稳定,以及模态之间的梯度不均衡。最近被频繁讨论的 OPD-V(Visual On-Policy Self-Distillation with Modality Balance),正是冲着这两个问题来的。它的核心思路不是设计一个更花哨的网络结构,而是通过策略内自蒸馏让视觉表征在在线训练中保持自洽,再通过模态平衡机制把不同信息来源的优化节奏拉齐。
本文会从问题动机、核心概念、方法拆解、最小实现到验证排错,完整讲清楚 OPD-V 这类方法的价值边界。读完你会明白:它到底解决了什么,适合什么场景,以及在真实项目里应该如何接入、如何验证、如何避免踩坑。
1. 这篇文章真正要解决的问题
1.1 痛点一:视觉表征在策略训练中不稳定
基于像素的强化学习里,视觉编码器通常是一个 CNN 或 ViT,前面接策略头、价值头或 Actor-Critic 头。表面上看,这是一个标准的“感知 + 决策”结构,但在训练过程中,一个常被忽略的问题是:网络每一层都在同时承担表示学习和策略优化的任务。
策略目标的梯度会不断要求编码器提取与动作收益相关的特征,而价值目标的梯度又要求它提取与未来回报相关的特征。两个目标不是天然一致的。更麻烦的是,RL 的训练数据分布是由当前策略生成的,策略一变,下一批观测分布就变,编码器面临的是典型的非平稳表示学习问题。
没有约束时,视觉特征可能在一轮更新内发生剧烈漂移。表现到训练曲线上,就是 loss 下降得很快,但评测时成功率忽高忽低;表现到部署阶段,就是模型在训练环境里表现尚可,换到真实场景直接失效。
传统办法是引入数据增强、辅助任务或者预训练视觉编码器。但它们各自有代价:数据增强改变了观测分布,辅助任务引入了额外网络分支,预训练模型可能和仿真环境或真实机器人数据分布不匹配。OPD-V 这类方案的切入点,是让策略网络在训练过程中自己给自己提供稳定的表征监督信号,不需要外部数据集,也不需要冻结的预训练模型。
1.2 痛点二:多模态输入的梯度失衡
很多视觉 RL 任务并不是“只给一张图”。机器人控制场景里,除了相机图像,通常还有关节角度、关节速度、力/力矩传感器,甚至语言指令。多模态输入看起来只是把不同特征拼在一起,真正实现时却很容易失衡。
失衡的机理不复杂:动作模态和本体感觉模态的信号维度低、噪声小,网络很容易从中找到与奖励直接相关的捷径,收敛速度非常快;而视觉模态维度高、信息冗余,特征提取器需要更长时间才能学到有效模式。在同一个反向传播过程中,梯度会优先流向那些“好优化”的分支。久而久之,策略网络开始依赖低成本模态,视觉编码器得不到有效梯度,表达能力退化。
这个现象也被称为模态捷径学习。它不只在 RL 中存在,多模态分类、视觉语言模型里同样会出现。区别在于,RL 里策略不断更新,这种捷径依赖会被放大,最终导致泛化能力极差。
OPD-V 的 Modality Balance 就是针对这一点而设计。它不只是简单地把各模态 loss 相加,而是希望从优化层面去控制每个模态对最终目标的贡献,避免某个模态在早期训练中“垄断”梯度。
1.3 你最适合在什么场景下关注这个方法
如果你是做视觉抓取、机械臂操作、仿真到真实迁移、机器人导航这类任务的开发者,OPD-V 非常值得关注。
如果你是做游戏 AI、推荐系统或 NLP 强化学习,视觉表征和多模态平衡的问题也存在,但落地方式会有差异。本文介绍的概念和代码思路仍然有参考价值,但不要期待直接复制到非视觉任务中。
如果你只是希望找一个“稳定提升几个点”的现成算法,那么请降低预期。OPD-V 更重要的价值是改善训练过程的稳定性,提升样本效率与泛化能力,而不是在每一个 benchmark 上都创造明显收益。它的收益通常体现在:训练曲线更平滑、最终性能更稳、换环境后掉点更少。
2. 核心概念:On-Policy Self-Distillation 与 Modality Balance
2.1 自蒸馏:同一个网络自己教自己
知识蒸馏的传统做法是:一个预训练好的大模型作为教师,一个小模型作为学生,用教师输出的软标签指导学生学习。教师网络通常更大、更稳定,训练过程是静态的。
但 OPD-V 属于自蒸馏,教师和学生来自同一个网络,甚至就是网络自身。它不需要额外训练一个教师模型,也没有离线阶段。在线训练过程中,网络把某一视角、某一分支或某一时刻输出的特征作为监督目标,去约束另一视角、另一分支的特征。
这听起来有点绕。打个比方:一个学生一边做题一边对答案,但答案不是来自老师,而是来自他自己刚刚做过的另一份同类题目。如果两份题目出得足够接近,自我对照就能让解题思路更稳定。放在神经网络里,就是让视觉特征在数据增强扰动、不同网络分支之间保持一致。
2.2 On-Policy 为什么关键
RL 里有 on-policy 和 off-policy 的经典区分。on-policy 方法使用当前策略采集的数据进行更新,比如 PPO;off-policy 方法会复用历史数据,比如 DQN、SAC。
OPD-V 中的 On-Policy 强调的是:自蒸馏过程发生在策略在线更新期间,并且蒸馏数据来自当前策略产生的观测分布。
这个设计背后的原因是,视觉特征需要与当前策略的决策需求保持一致。如果使用离线数据集或者历史 buffer 做蒸馏,特征可能对齐的是旧策略下的分布。当策略快速迭代时,旧分布中的特征已经不能准确反映当前状态空间,蒸馏反而会拖慢策略更新。
所以,On-Policy Self-Distillation 不能简单替换成“加一个表示一致性损失”。它的关键约束在于,蒸馏目标和输入样本必须跟随当前策略一起演化。在这个前提下,视觉编码器获得的监督信号才真正与策略优化同频。
2.3 模态平衡:不只是“多模态融合”
多模态融合解决的是“如何把不同模态信息组合起来”,而模态平衡解决的是“不同模态在优化过程中如何被公平对待”。
假设总损失为:
[ L_{total} = L_{policy} + L_{value} + L_{distill} ]
如果所有 loss 直接相加,那么数值尺度更大的 loss 会主导梯度。即使把 loss 归一化到同一尺度,不同模态反向传播到各自编码器的梯度幅度也可能相差一个甚至几个数量级。
模态平衡有两种常见落地方式:
第一种是损失级平衡。通过可学习参数或者统计量,自动调整不同损失项的权重,让每个模态对最终梯度的贡献相对均衡。这类方法在 multi-task learning 中非常常见。
第二种是特征级对齐。在共享表示空间里,对不同模态的输出特征做归一化或一致性约束,让视觉特征和本体感觉特征处在相近的分布区间,从而避免某个模态因为特征尺度过大而获得过高的“话语权”。
OPD-V 中所说的 Modality Balance,更接近两者结合:既在损失层面控制权重,也在特征层面做对齐。
2.4 与对比学习、数据增强的关系
很多读者会问:这个自蒸馏和对比学习有什么区别?和 BYOL、SimCLR 又是什么关系?
简单来说,这几个方向共享同一个思想:让网络对输入扰动保持表征不变。
对比学习需要构造正负样本对,正样本靠近、负样本拉远;BYOL 则不需要负样本,通过预测头和 stop-gradient 机制避免坍塌;OPD-V 的自蒸馏在思路上更接近 BYOL,但约束条件更特殊,因为它要在 RL 策略优化框架内工作,并且要处理多个模态之间的平衡。
可以用表格做对比:
| 方法 | 监督来源 | 负样本 | 是否在线 | 模态处理 |
|---|---|---|---|---|
| SimCLR | 数据增强后的自身视图 | 需要 | 离线预训练 | 单模态 |
| BYOL | 自身增强视图 + momentum encoder | 不需要 | 离线预训练 | 单模态 |
| 传统知识蒸馏 | 外部预训练教师 | 不需要 | 离线/在线 | 单模态 |
| OPD-V | 当前策略网络自身的在线视图 | 不需要 | 在线 RL 训练 | 多模态平衡 |
这里的关键差异是“在线”和“多模态”。也正是这两点,让 OPD-V 不能简单套用现成的自监督学习代码。
3. OPD-V 方法的整体拆解
3.1 总体结构
从设计动机来看,OPD-V 可以抽象成这样的结构:
- 一个视觉编码器,负责把图像观测映射为视觉特征。
- 一个状态/动作分支,负责处理本体感觉、动作信息等其他模态。
- 一个策略头和价值头,输出动作分布和状态价值。
- 一个蒸馏目标生成器,从当前策略网络某个视角生成视觉特征目标。
- 一个模态平衡模块,自动调节多路损失对网络参数的梯度贡献。
这种结构并不复杂,但难点在于各部分之间如何协作。如果只是简单地把这两个模块加到 PPO 里,很可能出现“蒸馏 loss 降得很低,但策略收益完全没变化”的尴尬结果。
3.2 蒸馏目标怎么来
对同一批视觉观测,可以构造两个不同视角:原图和经过随机数据增强的图,或者在线特征和目标特征两个分支。自蒸馏会让两个视角的特征保持一致。
需要注意:目标分支不应该接收梯度。否则网络会同时优化“被比较的特征”和“用于比较的特征”,最终导致表示坍塌,把所有样本都映射到同一个点。实际实现中,目标特征要 detach,或者使用动量编码器更新。
在 RL 场景中,自蒸馏目标还可以来自策略不同更新的时序关系。比如当前轮次的视觉特征去对齐历史某一轮的特征,相当于给非平稳的 RL 训练增加一个小的时间一致性约束。但这类做法需要保存旧表示,工程复杂度更高。
3.3 平衡机制怎么设计
模态平衡模块的核心目标是解决一个问题:当不同模态的损失量纲和收敛速度差异很大时,如何自动决定每个损失项的权重。
最简单的是固定权重,但固定权重本质上还是在赌超参数。训练初期视觉损失可能很大,而策略损失相对很小,固定权重会让训练变成“先做表示学习,再做策略优化”,这种阶段性切换容易导致策略不稳定。
更常见的设计是不确定性加权:把每个损失项的方差当作可学习参数,方差越大,自动降低该损失项的权重。优点是实现简单,不需要额外统计信息。
另一种思路是梯度范数匹配:对每个模态分支的梯度范数做归一化,让各分支在每一轮更新中拥有相近的更新幅度。缺点是需要额外计算梯度,训练开销更大。
从工程角度讲,不确定性加权更容易落地,也更容易和主流 RL 框架集成。
3.4 从方法到代码的映射
如果你打算在 PyTorch 里实现,不需要“复刻”论文的全部细节。先按以下四个模块搭建即可:
- 视觉编码器。
- 自蒸馏损失计算。
- 模态平衡加权。
- RL 训练循环集成。
下面第 5 节会给出一个 PyTorch 风格的最小实现。再次强调,这是演示思路的参考代码,不是论文官方实现,也不应该直接用于 benchmark 结果对比。
4. 环境准备与实验设置建议
4.1 软件环境
本文示例代码基于 PyTorch,依赖都比较基础。建议环境如下:
- Python 3.9 或 3.10
- PyTorch 2.x
- gymnasium 或其他 RL 环境库
- 仿真环境:MuJoCo、Isaac Gym、Meta-World 等,任选其一
如果你的项目还在使用 PyTorch 1.x,也不一定要升级。示例代码用到的 API 在 1.13 之后都可用,关键是理解模块设计思路,而不是绑定某个版本号。
4.2 仿真任务选择
建议从你现有任务开始,而不是一上来搭一个完整机器人任务。最稳妥的方式是选一个相对简单、但确实包含图像输入和多模态状态输入的任务。
比如:
- 机械臂视觉抓取:图像 + 关节角度 + 夹爪状态。
- 四足机器人运动:图像 + 关节角度 + 角速度。
- 灵巧手操作:多相机图像 + 指尖力传感器。
任务越接近你的最终部署场景,验证结果越有说服力。
4.3 对照实验怎么设计
判断 OPD-V 是否有效,至少要跑三组对比:
- 基线:原始 PPO 或 SAC,不做任何自蒸馏。
- 基线 + 自蒸馏,但不加模态平衡。
- 基线 + 自蒸馏 + 模态平衡。
只有同时对比这三组,才能看出“自蒸馏”和“模态平衡”各自贡献了多少。如果只跑一组完整方案,即使效果好,你也不知道是哪个模块在起作用。
5. 完整示例:PyTorch 风格的最小实现
5.1 自蒸馏损失模块
自蒸馏损失采用类似 BYOL 的对称化设计,但要根据我们的场景做简化。在线分支通过一个 predictor 预测目标分支的特征,目标分支的梯度被切断。
# 文件:self_distill.py # 说明:自蒸馏损失模块,用于对齐同源视觉特征。 # 注意:这是思路演示代码,不是任何论文的官方实现。 import torch import torch.nn as nn import torch.nn.functional as F class SelfDistillLoss(nn.Module): def __init__(self, feat_dim: int = 256, hidden_dim: int = 512): super().__init__() self.predictor = nn.Sequential( nn.Linear(feat_dim, hidden_dim), nn.SiLU(), nn.Linear(hidden_dim, feat_dim), ) def forward(self, online_feat: torch.Tensor, target_feat: torch.Tensor) -> torch.Tensor: # 特征归一化,避免尺度差异主导距离 online_feat = F.normalize(online_feat, dim=-1) target_feat = F.normalize(target_feat, dim=-1) pred = self.predictor(online_feat) pred = F.normalize(pred, dim=-1) # 目标特征不接收梯度,防止表示坍塌 loss = -(pred * target_feat.detach()).sum(dim=-1).mean() return loss这里的关键逻辑是detach()。目标特征只作为监督信号,不参与反向传播。predictor 的作用是给在线分支提供一个不对称变换,避免网络走捷径,直接把 online_feat 复制成 target_feat。
如果你在 RL 训练中发现蒸馏 loss 很快就降到接近 -1,但策略性能没有提升,通常意味着目标分支设计得太简单,或者 predictor 容量过大。
5.2 模态平衡模块
模态平衡模块使用不确定性加权方式。注意:在 PyTorch 里,log_var为什么要作为可学习参数?因为网络可以自己学习到每个损失项的置信度,而不是靠人工调静态权重。
# 文件:modality_balance.py # 说明:基于同方差不确定性的模态平衡模块。 import torch import torch.nn as nn class ModalityBalance(nn.Module): def __init__(self, num_losses: int = 3): super().__init__() # log_var 初始化为 0,等价于初始权重为 1 self.log_vars = nn.Parameter(torch.zeros(num_losses)) def forward(self, losses): # losses: list of scalar tensors,顺序要固定 total_loss = 0.0 for i, loss in enumerate(losses): precision = torch.exp(-self.log_vars[i]) total_loss = total_loss + precision * loss + 0.5 * self.log_vars[i] return total_loss使用时要特别注意:log_vars所在的网络分支必须能够收到梯度。如果你在训练循环里把它和策略网络一起优化,就能自动更新。如果把log_var放在torch.no_grad()的上下文里,它不会工作。
这个模块的优点是完全“无监督”,不需要人为判断当前哪个模态更重要。缺点是损失数量变化时,需要重新初始化参数。
5.3 嵌入 RL 训练循环
下面是一个 PPO 风格训练循环中的关键片段。这里的重点是展示“自蒸馏 loss 和 modal balance 如何与 policy loss、value loss 一起构成总损失”,并不是完整可运行的 PPO 实现。
# 文件:train_loop.py # 说明:将自蒸馏和模态平衡嵌入 on-policy RL 训练循环的伪代码片段。 def train_one_iter(batch, encoder, policy_head, value_head, self_distill, modality_balance, optimizer): obs_img, obs_state, action, old_logp, returns, advantages = batch # 同一批图像生成两个增强视角 obs_a = augment(obs_img) obs_b = augment(obs_img) # 视觉编码器共享参数 feat_a = encoder(obs_a) feat_b = encoder(obs_b) # 自蒸馏损失 distill_loss = self_distill(feat_a, feat_b) # 策略与价值损失 feats = encoder(obs_img) dist = policy_head(feats, obs_state) logp = dist.log_prob(action) ratio = (logp - old_logp).exp() policy_loss = -(ratio * advantages).mean() value_pred = value_head(feats, obs_state) value_loss = nn.functional.mse_loss(value_pred, returns) # 模态平衡加权 total_loss = modality_balance([distill_loss, policy_loss, value_loss]) optimizer.zero_grad() total_loss.backward() nn.utils.clip_grad_norm_(encoder.parameters(), max_norm=1.0) optimizer.step()这段代码最核心的一点是:total_loss不是简单相加,而是经过modality_balance自动加权。同时,视觉编码器会同时收到来自蒸馏、策略和价值的梯度。如果没有模态平衡,策略和价值损失很可能淹没蒸馏损失,让自蒸馏变成摆设。
5.4 梯度诊断工具
为了判断模态平衡是否真的生效,你需要观察各个分支的梯度范数。下面这个工具函数可以帮你快速打印网络不同模块的梯度情况。
# 文件:grad_diag.py # 说明:梯度诊断工具,用于观察不同分支的梯度范数。 def print_grad_norms(model, prefix="train"): global_norm_sq = 0.0 for name, param in model.named_parameters(): if param.grad is not None: norm_sq = param.grad.norm().item() ** 2 global_norm_sq += norm_sq if norm_sq ** 0.5 > 0.1: print(f"[{prefix}] {name}: grad_norm={norm_sq ** 0.5:.4f}") global_norm = global_norm_sq ** 0.5 print(f"[{prefix}] global_grad_norm={global_norm:.4f}")如果加了模态平衡后,视觉编码器那一层的梯度范数仍然远小于 action 分支,说明平衡权重没有起到作用。你需要检查log_vars是否更新,或者把权重初始值调整到更接近实际需求的区间。
6. 运行与效果验证
6.1 怎么运行
在仿真环境里,建议先跑短实验。例如,使用固定随机种子,训练 50 万步或 100 万步,对比三组实验的曲线。这里的“50 万步”“100 万步”不是固定标准,应当根据任务复杂度调整。
记录以下内容:
- 每一轮的平均回报。
- 蒸馏 loss 变化。
- 各模态分支的梯度范数。
- 模态平衡模块中
log_var的数值变化。
6.2 看哪些指标
首先看训练曲线稳定性。原始 PPO 可能在中间出现突然掉点,加入自蒸馏后,曲线通常更平滑。如果加入自蒸馏后曲线反而更震荡,说明蒸馏目标设置有问题。
其次看最终采样阶段的泛化能力。把训练环境里的光照、背景或物体颜色做一点变化,再对网络进行零样本评测。OPD-V 这类方法预期能减少性能掉落,但不会完全消除 domain gap。
最后看梯度分布。这是很多人忽略的一点。记录 visual encoder 与 state encoder 的梯度范数比。理想情况下,模态平衡会让这个比值维持在一个相对稳定的区间,而不是一个模态的梯度比另一个大几个数量级。
6.3 如何判断方法是否生效
一个比较可靠的判断方式是:单独关闭蒸馏 loss,看训练曲线是否明显变差。
如果关闭后性能几乎不变,说明自蒸馏不是在起作用,模型可能只是在“硬学”蒸馏目标,并没有把知识迁移到策略中。此时优先检查目标特征是否被detach,以及增强强度是否过大。
如果关闭后性能明显下降,说明自蒸馏对当前任务有效。接下来再关闭模态平衡模块,观察梯度范数分布和最终性能,判断模态平衡的增量贡献。
7. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 蒸馏 loss 快速收敛到 -1,但策略收益不涨 | predictor 过于复杂,目标分支没有有效约束 | 查看特征可视化,检查目标是否 detach | 减小 predictor 容量,增加特征维度,或加强 augmentation |
| 加入自蒸馏后训练曲线更震荡 | 增强强度过大,蒸馏目标与当前策略差异太大 | 降低增强强度,观察蒸馏 loss 与策略 loss 的相对尺度 | 使用较小的蒸馏权重,或先冻结蒸馏损失训练少量轮次 |
| 视觉编码器梯度范数始终远小于其他模态 | 模态平衡没生效,或反向传播路径断开 | 用梯度诊断工具打印各分支梯度范数 | 检查 log_vars 是否可学习,确认 encoder 参数确实在 total_loss 中 |
| 模态平衡权重出现极端负值或正值 | 某个损失项数值异常 | 打印每个 loss 的数值和 scale | 对各 loss 做归一化,或调整log_vars初始化 |
| 固定随机种子后多次结果差异大 | RL 本身方差大,也可能是特征起始点不稳定 | 多次跑 seed,统计均值与方差 | 加入自蒸馏后观察方差是否收窄,若方差仍大则检查采样流程 |
| 仿真有效,换真实环境效果下降 | 视觉域差异过大,自蒸馏只能在训练分布内保证一致性 | 在真实环境小样本采集测试,观察特征分布偏移 | 结合域随机化、图像归一化或真实数据微调 |
表格里的排查思路,正好对应 OPD-V 最容易被误用的几个地方。特别提醒:自蒸馏不是标准正则化,不要把增强强度设得和离线自监督学习一样大。RL 中观测分布本身就在变,过强的增强会让蒸馏目标失去参考价值。
8. 工程最佳实践与生产环境提醒
8.1 超参数调节顺序
不要一上来同时调蒸馏权重、模态平衡权重和增强强度。这样出问题很难定位。
推荐的顺序是:
- 先不加蒸馏,确认基线策略表现稳定。
- 加上自蒸馏,使用固定权重,调节增强强度。
- 确认蒸馏有效后,再引入模态平衡模块。
- 最后微调目标特征的更新方式,比如是否使用动量更新。
每一步都是增量验证。如果某一步出现性能回落,就回退到上一步的状态,不要硬调后面的参数。
8.2 特征设计和归一化
多模态特征必须先做归一化。图像特征来自 CNN 或 ViT 的输出,通常不是天然单位范数;关节角度和速度的量纲也完全不同。如果不做归一化,模态平衡模块会花很多时间去适应特征尺度,而不是真正平衡梯度。
建议在特征进入蒸馏损失之前,统一做 L2 归一化。这能让蒸馏距离只关注方向,不关注模长。策略网络内部的特征拼接层也要做 LayerNorm 或 BatchNorm,避免个别模态主导。
8.3 与预训练视觉模型结合
如果你的项目已经使用 ImageNet 预训练视觉模型,OPD-V 依然可以叠加使用,但要注意两点。
第一,预训练模型的特征已经比较稳定,自蒸馏给它的额外收益可能变小。这时候可以适当降低蒸馏损失权重。
第二,冻结预训练编码器可以降低训练成本,但也会限制策略对特殊状态的适应能力。推荐的做法是:预训练编码器微调,但学习率小于策略网络其他部分。这相当于让视觉基础能力保持稳定,同时允许任务相关的特征逐步更新。
8.4 分布式训练中的注意点
视觉 RL 往往需要多环境并行采样,然后集中更新。自蒸馏损失本身不复杂,但多卡训练时要注意log_vars这类可学习参数在所有进程中要保持同步。
使用 PyTorch DDP 时,ModalityBalance的参数必须被正确地放进模型的parameters()中,并参与梯度同步。如果log_vars只在 rank 0 上更新,其他进程的 loss 加权方式会不一致,最终影响策略收敛。
此外,如果用了混合精度训练,要留意特征归一化操作是否在 fp16 下出现数值不稳定的问题。建议蒸馏损失部分使用 fp32 计算,避免精度损失传给策略头。
8.5 安全与回滚
一旦方法进入真实机器人部署,必须遵守最低风险原则。
- 先在仿真中跑通完整训练和评测流程。
- 再在真实设备上只做短期小范围验证。
- 每次实验前备份模型权重和训练配置。
- 为策略设置动作幅度限制或安全过滤层。
- 如果部署阶段出现异常动作,立即回滚到上一版模型。
自蒸馏和模态平衡属于训练阶段技术,不会主动引入部署时的新风险,但它们会改变训练策略的行为模式。因此,模型上线前必须重新做安全测试,不能因为训练指标好就直接部署。
9. 总结与后续学习方向
OPD-V 给视觉强化学习带来的核心启发是:与其不断设计新的网络结构来拟合更复杂的特征,不如让策略网络在训练过程中自己约束自己的视觉表征。On-Policy Self-Distillation 解决的,正是 RL 中视觉表征随策略演化而漂移的问题;Modality Balance 解决的,则是视觉信息和其他模态信息在优化过程中争夺梯度的问题。
如果你要落地这个方法,不要急着改造完整算法。先用本文第 5 节的模块在小型视觉 RL 任务上做 A/B 测试,配合梯度诊断工具看模态平衡是否真的生效。这个步骤带来的理解深度,会比直接在一个大工程里调参快得多。
后续值得深入的方向包括:自蒸馏目标特征的更新策略、模态平衡与 reward shaping 的联合调优、以及如何把类似机制扩展到语言条件控制任务。视觉 RL 的表示学习问题不会因为某一个方法而终结,但“在线自蒸馏”和“模态平衡”这两件事,会越来越频繁地出现在真实机器人项目的工程方案里。