ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

SLAC实战:潜变量模型+actor-critic提升强化学习样本效率

SLAC实战:潜变量模型+actor-critic提升强化学习样本效率

强化学习在连续控制任务里有个老毛病:样本效率低得让人抓狂。尤其是那些高维观测、奖励稀疏的场景,一个策略从随机初始化到勉强能用,动辄要几百万步交互。我做机器人抓取和仿真控制那几年,最头疼的就是看着训练曲线在头几十万步里几乎纹丝不动。Stochastic Latent Actor-Critic(后面我简称 SLAC)这个工作,就是冲着这个痛点来的——它把潜在变量模型和actor-critic 框架缝在一起,用随机潜变量去压缩高维观测、建模不确定性,从而把样本效率往上拉了一大截。这篇博文我不打算复述论文,而是从一线实操的角度,把这个方法的核心思路、关键实现细节、踩过的坑和可复现的配置掰开揉碎讲清楚。适合谁看?如果你已经写过基础的 SAC 或 PPO,想搞明白“潜变量 + 强化学习”到底怎么落地,或者你正在做基于图像的连续控制、需要提升样本效率,那这篇应该能帮你省下不少试错时间。

1. 为什么要在强化学习里塞一个潜变量模型

1.1 高维观测下的样本效率困境

先说清楚问题背景。连续控制任务里,观测往往是图像、点云或者一堆传感器读数,维度高、冗余大、还带噪声。直接把原始观测喂给策略网络,网络要花大量参数和样本去“学会看”,这部分开销和真正的控制学习混在一起,训练效率自然低。更麻烦的是部分可观测性——你看到的单帧画面并不能完整反映系统状态,比如机械臂的速度信息在单张图里是缺失的,策略如果只依赖当前观测,就会做出短视的决策。

传统做法有两种。一种是堆模型容量,用更大的卷积网络硬吃高维输入,代价是样本需求暴涨;另一种是手工设计低维状态特征,把图像压成几个关键量,但这依赖领域知识,换个任务就得重来。SLAC 走的是第三条路:用一个随机潜在变量模型(stochastic latent variable model)自动从观测序列里学出一个紧凑的隐状态表示,这个隐状态既压缩了信息,又显式建模了不确定性。策略和价值网络都在这个低维潜空间里工作,学习负担一下子轻了很多。

这里的关键词是“随机”。很多表示学习方法学的是确定性编码,给定观测就输出一个固定向量。但真实系统里状态估计本身就有不确定性,尤其是部分可观测时,同一帧观测可能对应多个潜在状态。SLAC 用随机潜变量(通常是高斯分布)来捕捉这种多义性,采样出来的隐状态带有方差信息,策略在做决策时能感知到“我现在对状态的把握有多大”。这个设计不是花架子,后面我会讲到它在训练稳定性上的实际作用。

1.2 潜变量模型与 actor-critic 的耦合逻辑

把潜变量模型和 actor-critic 拼在一起,不是简单地把两个模块串起来就完事。核心难点在于:潜变量模型的训练信号从哪来?如果只用重构损失(比如从潜变量重建观测),那学到的表示是“有利于重建”的,不一定“有利于控制”。SLAC 的巧妙之处在于让策略优化和价值估计的梯度反过来影响表示学习,形成一个闭环。

具体来说,整个系统包含几个部分:一个编码器把观测序列映射到潜变量的后验分布,一个转移模型描述潜变量随时间的演化,一个解码器负责从潜变量重构观测,然后是 actor 和 critic 在潜空间里做策略优化。训练时,重构损失保证表示不丢失关键信息,而 critic 的时序差分误差通过潜变量回传到编码器和转移模型,让表示朝着“有利于价值估计”的方向调整。这种耦合让潜空间不是单纯的信息压缩,而是任务驱动的抽象。

我一开始担心这种耦合会让训练不稳定——两个优化目标互相拉扯,容易崩。实测下来,只要把损失权重和梯度截断处理好,耦合反而是优势:表示学习和控制学习互相促进,收敛比分开训练快不少。后面在实操部分我会给出具体的损失组合方式和权重设置。

1.3 和常见方案的对比取舍

为了让你更清楚 SLAC 的定位,我列个对比。下面这张表是我根据自己复现和调参的经验整理的,参数是常见设置下的量级,具体任务会有出入。

方案表示来源是否建模不确定性样本效率(相对)实现复杂度
原始观测直接喂 SAC无(端到端)否低低
确定性自编码器 + SAC重构驱动否中中
世界模型(如基于 RSSM 的方案)转移+重构是高高
SLAC重构+时序+控制梯度是高中高

可以看到,SLAC 在样本效率和实现复杂度之间取了个不错的平衡。相比完整的世界模型方案,它不需要在潜空间里做多步想象展开(rollout),训练流程更简单;相比确定性自编码器,它多了随机性和时序建模,表示质量更好。如果你的任务是图像输入、部分可观测、样本预算紧张,SLAC 这类方法值得优先考虑。

2. 核心模块拆解与关键实现细节

2.1 潜变量模型的三个组件:编码器、转移、解码

潜变量模型这块是整个方法的地基,我把它拆成三个组件来讲,每个都有实操上的讲究。

编码器负责从观测序列推断潜变量的后验。注意是“序列”不是“单帧”。SLAC 用的是时序卷积或者循环结构来聚合历史信息,这样潜变量里才带有时序上下文。我复现时用的是因果卷积(causal convolution),好处是并行计算快,且不会看到未来信息。编码器输出的是高斯分布的均值和方差,然后做重参数化采样。这里有个细节:方差要用 softplus 或者 exp 加下界约束,防止训练早期方差塌缩到零,那样随机性就没了,退化成确定性编码。

转移模型描述潜变量在相邻时间步之间怎么演化。通常用一个条件高斯:给定上一时刻的潜变量和当前动作,预测下一时刻潜变量的分布。这个模块是时序一致性的关键,它让潜空间里的轨迹是平滑、可预测的,而不是每帧乱跳。实操中转移模型的容量不用太大,两三层全连接足够,但输入要包含动作,否则模型学不会“动作如何影响状态”。

解码器从潜变量重构观测。它的作用相当于一个正则项,逼着潜变量保留足够的信息。重构目标的选择要看观测类型:图像用均方误差或者带权重的像素损失,向量观测直接用均方误差。我踩过一个坑:重构损失权重给太大,潜变量会过度关注像素细节(比如背景纹理),反而忽略了和控制相关的物理量。后来我把重构权重调低,让控制梯度占主导,效果明显好转。

提示:三个组件的容量要匹配。编码器太强、转移模型太弱,会导致潜空间轨迹不连贯;反过来转移模型太强,容易过拟合到训练数据里的伪相关。我一般让编码器和解码器容量相当,转移模型略小。

2.2 潜空间里的 actor 与 critic 设计

actor 和 critic 都工作在潜变量空间,输入是采样出来的隐状态(可以拼接动作)。这里有个设计选择:actor 的输入用潜变量的均值还是采样值?我的经验是训练时用采样值(保留随机性,利于探索),评估时用均值(稳定)。critic 同理。

网络结构上,actor 输出高斯策略的均值和标准差,标准差要有下界,防止探索过早收敛。critic 用双 Q 网络(clipped double Q)来缓解过估计,这是 SAC 系列的标配,SLAC 沿用了这个思路。两个 Q 网络取最小值作为目标,配合目标网络软更新,更新系数一般取 0.005 左右。

有个容易忽略的点:潜变量的维度。太低,表示能力不够,控制性能上不去;太高,样本效率反而下降,因为潜空间太大,策略要探索的空间也大。我试过 8 到 64 维的范围,多数任务在 16 到 32 维之间表现最好。这个可以作为一个初始搜索区间。

2.3 损失函数的组合与梯度流向

损失函数是 SLAC 最容易出问题的地方,我详细说。总损失大致分三块:重构损失、KL 正则(让后验靠近先验)、以及 actor-critic 的时序差分损失。前两块训练表示,第三块训练策略和价值。

梯度流向是这样的:critic 的 TD 误差对潜变量求导,这个梯度会回传到编码器和转移模型,让表示朝着“有利于价值估计”的方向调整。同时重构损失也从解码器回传到编码器。两股梯度在编码器处汇合。这里必须做梯度截断或者梯度缩放,否则控制梯度可能压过重构梯度,导致表示崩塌(潜变量退化成常数,重构完全失效)。我的做法是给控制回传的梯度乘一个小于 1 的系数,比如 0.1 到 0.3,具体看任务。

KL 正则的权重也要小心。权重太大,后验被强行拉向先验,潜变量携带的信息变少;权重太小,后验发散,采样出来的隐状态噪声太大。常用的做法是 KL 退火(annealing),训练初期权重小,让表示先学起来,后期逐渐加大。我一般从 0.1 线性升到 1.0,跨前十万步左右。

损失项作用典型权重调参要点
重构损失保留观测信息1.0(基准)图像任务可降到 0.5
KL 正则约束后验0.1 到 1.0 退火防止后验发散
TD 损失策略优化1.0梯度回传需缩放
控制梯度缩放平衡表示与控制0.1 到 0.3防表示崩塌

3. 从零搭一个可复现的训练流程

3.1 环境与数据管线的准备

我以图像输入的连续控制任务为例走一遍流程。环境用常见的仿真器,观测是 64x64 的灰度图或者 84x84 的 RGB 图,动作是连续的多维向量。数据管线要注意几点:经验回放池里存的是观测序列而不是单帧,因为编码器需要时序上下文。我一般存最近若干帧(比如 5 帧)作为一个样本单元,采样时按序列取。

回放池的容量不用太大,SLAC 样本效率高,几十万条序列足够。但要注意序列采样时的边界处理,别把不同 episode 的帧拼在一起,否则时序建模会学到错误关联。实现上给每条序列打个 episode id,采样时保证同一序列内 id 一致。

预处理方面,图像归一化到 [0,1] 或者 [-1,1] 都行,但要和重构损失匹配。如果用均方误差重构,归一化到 [0,1] 更自然。动作要做归一化到 [-1,1],因为策略输出用的是 tanh squash。

3.2 网络结构与超参数配置

下面给一套我实测比较稳的配置,任务不同需要微调,但可以作为起点。

# 潜变量维度 latent_dim = 32 # 编码器:因果卷积,通道数逐层递增 encoder_channels = [32, 64, 64] # 转移模型:两层全连接 transition_hidden = [256, 256] # 解码器:转置卷积,与编码器对称 decoder_channels = [64, 64, 32] # actor / critic 隐藏层 policy_hidden = [256, 256] # 学习率 lr_representation = 1e-4 # 表示学习 lr_policy = 3e-4 # 策略与价值 # 折扣因子与软更新 gamma = 0.99 tau = 0.005 # 批量大小 batch_size = 64 # 序列长度 seq_len = 5

学习率这块我要强调:表示学习和策略学习用不同的学习率很有必要。表示学习慢一点(1e-4),策略快一点(3e-4),这样表示稳定演化,策略能快速适应。我试过统一学习率,结果要么表示学得太慢拖累策略,要么策略更新太猛把表示带崩。

批量大小 64 看起来小,但因为是序列样本,实际计算量不小。显存紧张的话可以降到 32,但训练会稍微不稳,需要把学习率再调低一点。

3.3 训练循环的关键步骤

训练循环我按顺序拆解。每一步从回放池采一个批次的序列,先做表示学习的前向:编码器处理序列得到后验分布,采样潜变量,转移模型预测下一时刻分布,解码器重构观测。算重构损失和 KL 损失,反向传播更新编码器、转移、解码器。

然后是策略学习:用编码器(不更新参数,或者用 stop-gradient)得到潜变量,actor 输出动作,critic 算 Q 值,算 TD 损失更新 critic,算策略损失更新 actor。注意这一步的梯度要能回传到编码器,但要用缩放系数控制强度。

最后软更新目标网络。整个循环里,表示学习和策略学习的优化器是分开的,这点别搞混。

注意:表示学习和策略学习如果共用优化器,梯度会互相污染,训练极不稳定。我一开始图省事共用了,结果损失曲线剧烈震荡,分开之后立刻平稳。

3.4 训练监控与收敛判断

训练过程中要盯几个指标。重构损失应该稳步下降然后趋于平缓,如果一直不降,说明编码器或解码器有问题;如果降得太低然后策略性能不涨,说明表示过度关注重构、忽略了控制相关信息。KL 损失应该在退火后稳定在一个合理范围,太大说明后验发散,太小说明后验塌缩。

策略这边看 Q 值和策略熵。Q 值应该缓慢上升,如果剧烈波动或者爆炸,检查梯度缩放和 critic 的更新频率。策略熵在训练初期应该较高(探索),后期逐渐下降,如果一直不降,说明探索过度,可以调低目标熵或者加大策略学习率。

我一般每几千步做一次评估,用确定性策略(潜变量取均值)跑几个 episode,看平均回报。收敛的判断标准是评估回报连续多次评估不再提升,且 Q 值稳定。整个过程在图像任务上大概几十万步能看到明显效果,比端到端 SAC 快不少。

4. 实操中踩过的坑与排查手册

4.1 表示崩塌:潜变量退化成常数

这是最常见也最致命的问题。表现是重构损失居高不下,同时策略性能完全不动,检查潜变量会发现所有样本的隐状态几乎一样,方差趋近于零。原因通常是控制梯度太强,把编码器推向了“输出常数最省事”的退化解,或者 KL 权重太大把后验压塌了。

排查思路:先看潜变量的方差统计,如果均值附近方差极小,基本可以确认。解决方法是降低控制梯度缩放系数(比如从 0.3 降到 0.1),同时检查 KL 退火是否正常。还有一个隐蔽原因:重参数化采样时方差的下界设得太小,早期就塌了。把方差下界提到 1e-3 左右能缓解。

4.2 训练震荡:损失曲线像心电图

损失剧烈震荡,Q 值忽高忽低,策略性能反复横跳。我遇到过几次,原因各不相同。一次是表示学习和策略学习共用优化器,分开就好了;一次是批量太小(32)加上学习率偏高,调低学习率后平稳;还有一次是目标网络更新太频繁,tau 从 0.01 降到 0.005 后改善。

排查顺序建议:先确认优化器是否分开,再看批量大小和学习率的匹配,最后查目标网络更新系数。震荡如果伴随 Q 值爆炸,还要检查奖励尺度,奖励太大时要把 Q 值目标做归一化或者调低学习率。

4.3 样本效率不升反降的几种情形

有时候上了 SLAC,样本效率反而比端到端 SAC 还差,这就很打击人。我总结了几种情形。第一种是潜变量维度设太大(比如 128),潜空间探索成本高,策略学得慢,降到 32 就好了。第二种是重构损失权重过高,表示被像素细节绑架,控制相关信息被淹没,调低重构权重有效。第三种是序列长度太短(比如 2),时序上下文不足,潜变量质量差,加到 5 帧明显改善。

还有一种容易被忽略:环境本身的随机性很低,端到端方法已经够用,这时候潜变量模型的额外开销反而拖后腿。所以选方法前先评估任务的部分可观测程度,如果观测已经接近完整状态,没必要上这套。

4.4 常见问题速查表

现象可能原因排查动作解决方向
重构损失不降编码器/解码器容量不足或学习率过低检查网络结构和学习率加大容量或提高表示学习率
潜变量方差趋零控制梯度过强或 KL 权重过大统计潜变量方差降低梯度缩放、检查 KL 退火
Q 值爆炸奖励尺度大或学习率过高看奖励范围和 Q 值量级归一化奖励、调低学习率
策略熵不下降目标熵过高或探索过度看熵曲线调低目标熵
评估回报波动大评估用采样而非均值检查评估策略评估时潜变量取均值
训练后期性能回退过拟合或表示漂移看训练与评估差距加正则、冻结部分表示

5. 这套方法适合什么场景,以及怎么继续往下做

5.1 适用场景的边界判断

SLAC 不是万金油。它最适合的场景有几个特征:观测是高维的(图像、点云、多传感器融合),任务是部分可观测的(单帧信息不完整),样本预算紧张(真机训练或者仿真很慢)。在这类场景下,潜变量模型带来的表示压缩和不确定性建模能实打实提升效率。

反过来,如果观测本身就是低维完整状态(比如关节角度加角速度),端到端方法已经足够,上 SLAC 是杀鸡用牛刀,还增加调参负担。如果任务对实时性要求极高、推理延迟敏感,潜变量模型的额外前向计算也要考虑进去,虽然单次推理开销不大,但在高频控制回路里要评估。

还有一个边界是奖励设计。SLAC 解决的是表示和样本效率问题,不解决奖励稀疏问题。如果奖励极其稀疏,还是得配合奖励塑形或者分层结构,别指望潜变量模型能凭空变出学习信号。

5.2 可以继续扩展的方向

从工程角度,这套框架有几个自然的扩展点。一是把转移模型换成更强的时序结构(比如带门控的循环单元),提升长程依赖建模能力,适合那些状态演化跨度大的任务。二是在潜空间里做多步预测,用模型预测的轨迹辅助策略学习,这就往基于模型的强化学习靠了,样本效率还能再提,但训练复杂度也上去了。

三是把不确定性显式用于探索。现在潜变量的方差主要影响表示,如果把它接入策略的探索机制(比如方差大的时候加大动作噪声),可能对探索有帮助。这个方向我试过初步版本,效果不稳定,但思路值得挖。

四是多任务或者迁移场景。潜空间如果学得好,理论上可以跨任务复用,换任务时只微调策略头。这个我还没系统验证,但从表示学习的角度看有潜力。

5.3 一些实操上的个人体会

最后分享几点不那么“文档化”的经验。调这套方法,耐心比技巧重要——表示学习和策略学习的耦合让超参数搜索空间变大,别指望一套配置通吃。我习惯先固定表示学习部分(重构和 KL),把表示训到一个合理状态,再放开控制梯度联合训练,这样排查问题时分得清是表示的锅还是策略的锅。

另外,可视化潜变量很有用。把潜变量做降维画出来,看不同 episode 的轨迹是否连贯、不同状态是否分得开,比盯损失曲线直观得多。我几次定位表示崩塌都是靠可视化发现的。

还有就是别迷信论文里的超参数。论文的配置是针对特定任务调的,换个环境大概率要重调。把学习率、潜变量维度、梯度缩放这三个作为首要搜索对象,能覆盖大部分性能问题。

这个方向后续我打算在真机抓取任务上再验证一轮,重点看潜变量模型对真实传感器噪声的鲁棒性,以及推理延迟在控制频率下的表现。有新的结果再整理出来。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进