开篇先交代一个背景。我自己在去年跑过一组多智能体协作实验训练过程中奖励信号稀疏得可怜Agent 在几十万步里几乎学不到梯度可用的反馈后来把对比学习损失接到观测编码器上相当于给 Agent 开了一扇“自监督窗口”收敛速度肉眼可见地提了一个档次。那之后我意识到AI Agent 的表示学习不是一个辅助模块而是很多场景下真正的主力引擎。这篇博客就围绕“AI Agent 的自监督表示学习技术”展开把它的核心动机、常用方法、工程落地要点和调参踩坑记录一次性讲清楚适合正在做强化学习、模仿学习或多智能体系统的研究者、算法工程师以及打算把 Agent 用于实际项目但又苦于奖励设计的同学。内容里不会堆公式吓人重点放在“为什么这么做”和“怎么做才有效”上。1. 任务拆解Agent 的表示学习到底在解决什么问题1.1 稀疏奖励之外的真实困境凡是动手训练过 Agent 的人大概都经历过这种场景环境把真实状态压缩成高维像素或长序列传感器数据Agent 只能看到观测却不知道哪些维度值得关注。深度强化学习的经典做法是让策略网络直接从原始观测映射到动作理论上没问题可一旦奖励很稀疏整个梯度信号就断断续续。我见过一个典型的物流调度环境Agent 每完成一个订单才能拿到一次正奖励中间几千个决策步骤全都是零反馈。这时无论你调多大学习率、换哪种策略优化器模型都很难通过“试错”凭空发现动作和长期收益之间的关联。自监督表示学习在这里起到的作用简单说就是先不依赖奖励让 Agent 学会把观测压缩成结构化的特征空间再用这个特征空间去辅助策略学习。就好比给一个人一张模糊地图之前先教会他识别地图上的颜色和图例。1.2 自监督信号从哪来自监督学习的本质是从数据自身构造监督信号。对图像来说我们可以让模型预测图像旋转角度、恢复被遮住的色块对 Agent 来说监督信号可以从观测序列本身挖掘。常见思路有几种利用同一时刻不同视角的观测构造正样本对做对比学习利用下一时刻观测来预测当前表示训练一个转移预测头利用回放缓冲里的跨时间步样本让表示具备时间一致性在多 Agent 场景里用智能体之间的交互记录构造预测目标我在实验里最常用的是对比学习家族。它的核心操作是拉近同一状态不同增强视角的表示距离同时推开不同状态之间的表示距离。你不需要手工标注“这个状态属于哪一类”只需要自己定义哪些样本算相似、哪些算不相似。1.3 表示学习如何改善探索效率探索是强化学习的另一个硬骨头。随机噪声策略在高维连续动作空间里基本等于瞎碰但如果 Agent 已经拥有一个好的表示空间它就可以在这个更平滑的流形上估计状态的新奇度从而把探索集中在“没见过”的区域。一个很直观的类比是你第一次进一个大型实验室如果只看墙上的仪器和路线牌很难快速找到目标设备如果先有人给你一张抽象的楼层地图把区域按功能划分好你自然就知道该往哪个方向找。自监督表示就在扮演“楼层地图”的角色它把原始观测映射成有空间结构的特征让后续的探索策略可以更聪明地行动。2. 主流技术路线从对比学习到世界模型预测2.1 对比学习的核心组件与实现逻辑在 Agent 场景里应用对比学习通常不是把现成的图像对比学习框架原封不动搬来而是在它的基础上做两层改动第一正样本对的构造方式要符合 MDP 的时序结构第二编码器的训练要和策略网络共享或部分共享计算开销需要控制。最基本的实现逻辑包含四个组件编码器 f把观测 o 映射为表示 z数据增强模块对同一状态生成两个不同视角 o_i 和 o_j投影头 g把 z 映射到对比损失计算的低维空间对比损失函数最常用的是 InfoNCE 或它的变体训练时对一个小批次里的 N 个观测每个观测生成一对正样本那么批次里就有 2N 个增强样本。把某个样本的另一个视角当作正样本其他 2N-2 个样本都当作负样本计算交叉熵式的对比损失。我经常在实现里用一个相对小的投影头比如两层 MLP输出维度设置在 64 到 128 之间。这个投影头只用于计算损失推理阶段可以丢弃策略网络直接使用编码器的输出 z。很多刚开始接触对比学习的同学会忽略投影头的作用直接把高维表示拿去算相似度结果性能明显下降——这是因为高维特征里存在大量与任务无关的冗余信息直接算相似度容易被这些冗余维度主导。2.2 时间序列上的自监督预测任务对比学习擅长压缩静态观测但它并不天然理解“状态的顺序变化”。为了捕捉动态信息我会在对比学习之外再加一个辅助预测目标常见的是让 Agent 基于当前表示预测未来若干步的表示或观测摘要。这里有一个实用的技巧不要把预测目标设为原始像素而是设为一个低维的表示目标。原因是原始观测的噪声很大逐像素预测会逼着编码器去记忆大量无关细节。更合理的做法是先通过慢速更新的目标编码器生成未来观测的表示然后当前编码器去预测这个目标表示。目标编码器的参数不通过梯度更新而是用当前编码器的指数移动平均来维护。这种做法在自监督领域有一个很形象的名字叫“动量编码器”。在稀疏奖励的多步导航任务里这个预测头能起到“虚拟奖励”的作用。Agent 虽然在环境中没有得到奖励但它每成功预测一步未来状态辅助损失就会下降等价于获得了一种稠密的自我监督反馈。我在一个迷宫探索环境中对比过加上预测头之后Agent 大约提前了 35% 的时间到达终点区域。2.3 基于世界模型的表示学习方法再进阶一点的路线是把自监督表示学习放进一个世界模型里。这类方法通常用一个循环状态空间模型来建模环境动态同时让表示空间满足一定的先验约束比如高斯分布。Agent 的观测通过编码器映射成隐状态隐状态再通过预测模型推进到未来最后用解码器重构观测或奖励。世界模型的好处在于它天然拥有“想象”能力。Agent 可以在隐空间里做规划而不必每一步都与真实环境交互。自监督在这里体现在训练世界模型时并不依赖奖励信号只依赖观测序列的重构误差和 KL 散度约束。策略可以在模型训练到一定程度后在“想象出来的轨迹”上学习。不过我必须提醒一句世界模型的训练复杂度和计算开销明显高于对比学习路线。我自己的经验是对于刚开始尝试自监督表示学习的团队先别急着上世界模型把对比学习加预测头跑通再考虑扩展。2.4 多 Agent 场景的特殊设计当任务里不止一个 Agent 时表示学习还需要额外考虑交互信息。一个简单有效的做法是让每个 Agent 的编码器学习“预测伙伴行为”的辅助任务。具体来说Agent i 在时刻 t 的表示不仅用于自己的决策还输入到一个轻量级的行为预测头预测 Agent j 在下一时刻的动作分布或位置偏移。这个设计的关键价值在于它在没有中心化训练或额外通信协议的情况下让每个 Agent 都隐式地学会对同伴建模。我在一个协作搬运任务里测试过加入行为预测头之后Agent 之间的路径冲突明显减少协作完成度提升了约 18%。原理也不难理解一旦表示特征中编码了伙伴的行为模式后续策略网络在决定动作时就有了“换位思考”的依据而不是各走各的。3. 工程落地细节编码器、数据增强与优化器选型3.1 编码器结构选择与参数量控制Agent 观测形态差异很大。处理图像观测我会优先用 ResNet 或 Impala CNN处理向量观测直接用两层 MLP 就能得到不错的表示处理混合观测就需要先把不同模态编码到同一维度再融合。参数量控制上有一个原则表示编码器可以比策略网络稍大一些但不能大得离谱。比如策略网络如果是两层 256 单元的 MLP编码器用 4 层 256 单元再加上一个 128 维表示层整体参数量还在可控范围内。如果编码器太复杂训练时会抢占大量算力反而拖慢策略更新的频率。一个值得注意的细节是编码器参数的更新频率往往和策略网络不同步。在分布式训练框架里比如 IMPALA 或异步 PPO策略网络的更新频率较高但表示编码器的梯度可以每几个环境步聚合一次。这样既能降低通信开销又能保证表示空间相对稳定避免策略每更新一次表示就剧烈抖动一次。3.2 数据增强策略不能照搬图像领域的标配图像自监督学习常用的增强手段包括随机裁剪、颜色抖动、旋转、模糊等。但把整套增强搬到 Agent 的像素观测上时一定要小心奖励和状态语义可能对颜色或光照不敏感但对空间结构和关键物品位置极其敏感。如果随机裁剪太猛把一个场景中本来就不大的目标物体裁掉一半正样本对就会失去语义一致性表示学习反而学出坏的特征。我的做法是对增强强度设置一个随训练进度衰减的概率。训练初期用较强的增强帮助编码器建立稳健特征训练中后期逐渐减弱保证表示空间和真实状态分布尽可能贴合。这个方法听上去有点反直觉但实测下来收敛稳定性和最终性能都更好。对于向量观测我一般不用图像那套增强而是采用加噪声、遮蔽部分特征、时序平移三种方式。比如把某个维度的值随机置零或者把整条观测序列在时间轴上平移一步都能逼着编码器学会不依赖单一特征做判断。3.3 优化器、学习率与温度系数的调参经验对比学习中有一个关键超参数温度系数。它控制着对负样本的惩罚强度。温度太低模型过度关注特别难的负样本训练容易不稳定温度太高所有负样本的区分度都被抹平表示空间又缺乏判别力。我一般在 0.07 到 0.5 之间搜索先在 0.1 附近起步观察损失曲线的形状再做微调。优化器我倾向直接用 Adam学习率设置在 3e-4 附近并配合一个线性预热。如果表示学习任务和策略共享同一个优化器要注意梯度可能存在冲突建议给自监督损失单独配一份梯度尺度。我在实现里会给自监督损失乘一个权重范围通常在 0.1 到 1.0 之间权重太大容易让编码器只顾着做对比任务而忘了为策略服务。另外批大小对对比学习影响极大。负样本数量实际上等于批次内样本数减一批次太小负样本不够表示容易坍塌到常数解批次太大显存又会爆。我通常在 256 到 1024 之间选配合梯度累积解决显存不足的问题。3.4 对比损失计算中的数值稳定性细节InfoNCE 损失本质上是 softmax 的对数形式如果实现时直接用大数指数运算很容易出现数值溢出。正确的做法是先把 logits 减去最大值再做 softmax或者在 PyTorch 中直接使用带稳定选项的函数比如基于 LogSumExp 的实现。投影头输出的表示最好做 L2 归一化。一旦归一化logits 的取值范围就只受温度系数影响梯度大小也更可控。我自己踩过的一个坑是早期没有做归一化损失曲线一开始正常跑到中段突然出现 NaN排查了很久才发现是特征范数差异太大导致梯度爆炸。4. 实操一个可复现的 A2C对比学习改造流程4.1 环境选择与任务定义为了把整条技术栈串起来我选了一个比较典型的环境视觉迷宫导航。Agent 需要在一个第一人称视角的迷宫里找到目标点每步施加小的时间惩罚找到目标时给一个大的正奖励。地图大小是 15x15起点随机目标位置固定但每次环境重置时也会随机到不同房间。直接用原始像素做 A2C 训练几千步内基本学不到任何有效行为。整个改造目标很明确在共享编码器上同时优化策略损失、价值损失和对比损失让编码器同时具备“感知压缩”和“策略服务”的能力。我下面给出具体的代码骨架和关键参数这份配置我用了很多次稳定性和效果都经得起复现。4.2 编码器与自监督头的具体实现编码器用四层卷积加一个全连接层输出 128 维表示。投影头是两层 MLP中间层 256 维输出层 64 维计算完损失后直接丢弃。目标编码器采用动量更新动量系数设为 0.99。代码结构大致如下import torch import torch.nn as nn class Encoder(nn.Module): def __init__(self, obs_shape, repr_dim128): super().__init__() self.conv nn.Sequential( nn.Conv2d(obs_shape[0], 32, 8, stride4), nn.ReLU(), nn.Conv2d(32, 64, 4, stride2), nn.ReLU(), nn.Conv2d(64, 64, 3, stride1), nn.ReLU(), ) self.fc nn.Sequential( nn.Flatten(), nn.Linear(64 * 7 * 7, 256), nn.ReLU(), nn.Linear(256, repr_dim), ) def forward(self, obs): return self.fc(self.conv(obs)) class Projector(nn.Module): def __init__(self, repr_dim, out_dim64): super().__init__() self.net nn.Sequential( nn.Linear(repr_dim, 256), nn.ReLU(), nn.Linear(256, out_dim), ) def forward(self, z): return self.net(z)4.3 A2C 策略与自监督损失的联合优化A2C 策略主体保留常规实现区别在于编码器部分和策略头共享。也就是说原始观测先经过 Encoder得到 z然后 z 同时输入策略头、价值头和投影头用于对比损失。训练循环里的关键步骤是采样一个批次的经验生成正样本对算 InfoNCE 损失再和 A2C 的目标函数合并。正样本对的生成方式我采用“同一状态的两个随机增强”。增强函数里包含随机亮度调整、随机小幅平移和随机擦除但平移幅度限制在原始图像尺寸的 10% 以内避免破坏空间语义。InfoNCE 损失实现的重点在于相似度矩阵的计算。假设批次内有 N 个观测每个观测经过两种增强后得到两个表示拼在一起构成 2N 个表示。计算所有表示两两之间的相似度取第 i 个表示的真正样本为其对应的另一个增强视角其余都作为负样本。损失函数的 PyTorch 实现写出来不长但理解矩阵索引是关键def info_nce_loss(features, temperature0.1): batch_size features.shape[0] // 2 features nn.functional.normalize(features, dim1) logits torch.matmul(features, features.T) / temperature mask torch.eye(batch_size * 2, dtypetorch.bool) # 屏蔽自身 logits.masked_fill_(mask, float(-inf)) positive_indices torch.arange(batch_size * 2).roll(batch_size) labels positive_indices return nn.functional.cross_entropy(logits, labels)4.4 训练流程与关键监控指标训练过程推荐采用分布式采样多个环境并行跑每个环境独立采样采样得到的观测统一送进编码器计算表示、策略和价值头损失回传梯度后更新所有共享参数。我一般开 16 个并行环境每次训练迭代采样 256 条经验。训练时需要监控三个关键指标策略损失、价值损失、对比损失。其中对比损失的变化趋势最有信号意义。如果对比损失前期下降但后期回升说明表示空间开始萎缩或者增强策略与当前分布不匹配如果对比损失一直不下降大概率是正样本对构造有问题。另外我强烈建议在训练过程中周期性地把表示空间可视化一次用 PCA 或 t-SNE 映射到二维平面。如果同一个场景下的不同观测聚成明显的簇而不同场景区域分得开说明表示学习方向正确。5. 常见问题速查表与避坑技巧5.1 模型坍塌怎么办模型坍塌是对比学习的经典失败模式编码器把所有输入都映射到同一个输出损失表面看起来很小但表示毫无区分度。检测办法很简单随机抽一批观测算一下特征的标准差如果接近零基本可以判定坍塌。修复通常有四种路径增大负样本数量也就是增大批大小让模型无法轻易把所有样本都映射到同一点引入动量编码器当前编码器的参数不再直接影响目标表示切断快速坍塌的路径降低温度系数有效提升困难负样本的惩罚权重逼着编码器保留更多判别信息给投影头加一个预测任务比如让它同时预测该观测的未来一步表示增加优化目标的约束5.2 对比损失降了但策略效果变差这是最让人头疼的情况。理论上下游任务应该受益于更好的表示但在实际训练里可能出现对比损失下降、策略回报反而下降的情况。我遇到过两次最终定位到的原因都是表示空间过于“任务无关”。表示学习阶段太强编码器把观测中所有细节都压缩成泛化特征反而把和决策强相关的细微线索磨掉了。解决方案是给自监督损失加一个很小的权重或者缩短编码器只在初期参与自监督训练的时间。还可以换一种做法策略梯度计算时使用一个不经过自监督损失的独立编码器副本自监督损失只作用于一个旁路编码器最后通过某种融合机制把两部分特征合并。5.3 训练速度明显变慢自监督表示学习毕竟多了一套损失和前向计算训练速度变慢是正常的但如果慢到原来的两倍以上就得关注实现效率。常见瓶颈是数据增强太耗时。图像增强如果跑在 Python 里且不并行会很拖速度建议把增强操作放到数据加载器的子进程里或者把一部分增强放到 GPU 上执行。另一个优化点是对比损失的计算频率。不需要每一步训练都对每个样本计算对比损失可以每 4 个梯度步计算一次其他步数直接优化策略。实验表明这样既保留了表示学习的效果又把整体训练耗时压缩到单策略训练的 1.3 倍左右。5.4 正样本对选择不当导致训练震荡再强调一下正样本对的选择这是最容易被忽视的坑。Agent 观测是连续变化的如果两个不同时间步的观测差异太大把它们当作正样本对只会给优化器制造大量矛盾梯度。比较稳妥的做法是把正样本对限制在同一时刻的同一状态的不同增强视角而不是时间上相邻的不同状态。后者需要保证时间步之间的状态变化足够小否则容易导致表示空间崩塌成一条沿着轨迹方向的线性流形缺乏局部分辨力。6. 自监督表示学习的扩展思考6.1 从单任务到跨任务迁移一个训练好的自监督编码器往往能迁移到同一环境下其他相关任务。比如我在导航场景里训练的编码器直接把权重迁移到同类地图的“物品收集”任务里只重新训练策略头收敛速度比从头训练快了很多。原因是底层感知特征和运动特征并不随任务目标变化只有高层决策模块需要重新适应。要做到这一点编码器训练时要尽量避免和特定任务的奖励分布耦合太深。对比学习天然具备某种解耦优势因为它不直接读取奖励只挖掘观测自身的内在结构。6.2 与分层强化学习的结合分层强化学习通常需要上层智能体先设定子目标再让下层智能体完成子目标。这个过程中的一个难题是如何定义有意义的子目标空间。自监督表示学习可以提供一个好的答案把观测映射到语义空间再在这个语义空间里做聚类或采样把聚类中心当作候选子目标。我尝试过的一个方案是用对比学习训练编码器得到 128 维表示后用简单的 K-Means 聚类得到 20 个聚类中心每次上层策略就从这 20 个类别里选一个作为下一步的子目标。效果比手工设计子目标函数稳定得多。6.3 离线强化学习中的表示学习价值离线强化学习依赖固定数据集不去和环境实时交互这时表示学习的价值更加突出。因为它可以从大量离线数据里学到的特征空间中挖掘状态转移结构在数据缺乏奖励标注的区域照样学到有意义的表征。很多离线 RL 算法效果不理想根因是状态表示无法泛化到数据覆盖之外的区域自监督的分布内预训练能有效缓解这个问题。我在一个离线机器人控制数据集上对比过“先做表示预训练再离线训练”和“直接离线训练”两种方案前者的最终成功率高了大约 22 个百分点。这个差距主要来自表示空间的平滑性——一个好的表示空间让价值函数可以在没有数据的区域做合理推断。6.4 结合大模型的语义表示最近的一个热门方向是把预训练大模型的语义特征引入 Agent 的表示空间。比如用大模型的文本编码器给观测生成语义标签或者让 Agent 的观测表示和大模型的输出做对齐。这类方法很适合包含自然语言指令的任务因为 Agent 需要理解“把红色方块放到绿色区域”这句话的空间含义。自监督信号在这里变成了语义一致性约束同一个指令对应的不同视觉状态它们的表示应该在语义空间里相互靠近。我近期的一个模拟项目里试过用轻量级文本编码器来正则化视觉编码器的输出指令跟随的准确率提升很可观但引入大模型后推理耗时也随之上升。实际选型时需要权衡实时性和语义丰富度。个人实操体会回头看这几个月的实验我最深的体会是不要指望自监督表示学习是银弹它能解决的是“反馈信号不足”和“观测空间过拟合”这两类问题但如果你把整个强化学习系统的优化器、采样效率、环境并发设计都做得一塌糊涂单靠加一个对比损失也不会力挽狂澜。比较务实的做法是把表示学习当成一套和策略训练并行的“感知基建”先用它把观测空间的结构摸清再让策略在上面做精细搜索。我在工程实现上还有一个小技巧想分享每次调完自监督部分的超参数不要只看最终回报还要留意表示空间在训练中期的演化轨迹。我习惯每 5000 次环境步存储一次编码器输出的均值向量然后画成一条时间序列曲线。如果这条曲线在某次调整后波动明显变大那基本意味着表示空间在发生剧烈重构后续策略头的输入也跟着神经崩溃哪怕最终回报暂时没掉后续也大概率要翻车。宁可让表示空间缓慢稳定地变化也不要追求一下子的剧烈跳变。如果你正准备在自己的 Agent 项目里加入自监督表示学习可以从一个小规模的对比学习模块开始先保住策略不回退再逐步增加动量编码器、行为预测头这类复杂模块。每一步都要有对比实验支撑不要一口气把所有新东西全叠上去。这条路线的天花板很高但台阶也很密稳扎稳打才是工程里最值得坚持的做法。
阅读完成 · 觉得有帮助?