前言
- 本系列将从模型式强化学习的基本原理出发,逐步介绍经典方法与现代世界模型,结合核心公式、算法架构与核心代码,讨论智能体如何在学习行动的同时预测行动的后果,并利用预测结果指导决策
- 上一期的 PETS 用概率集成模型预测一组动作对应的未来轨迹,再由交叉熵方法筛选动作序列,以模型预测控制的方式逐步执行
- 本期介绍的 MBPO(Model-Based Policy Optimization,基于模型的策略优化)与 Dyna 一脉相承,同样用学到的环境模型生成模拟数据来辅助策略训练;不同之处在于它不把模型用于规划,而是把模型生成的短轨迹直接并入 SAC(Soft Actor-Critic,软演员-评论家)的训练数据,其动力学模型的学习机制沿用 PETS 的概率集成
- 最终,本文以 HalfCheetah-v4 为实验环境,从学习曲线、达到目标回报所需的真实环境交互步数,以及动力学模型的开环预测能力三个方面,对 MBPO 与标准 SAC 进行对比实验。

文章目录
-
- 前言
- [1 回顾](#1 回顾)
-
-
- [1-1 离策略强化学习](#1-1 离策略强化学习)
- [1-2 SAC 回顾](#1-2 SAC 回顾)
-
- [1-2-1 最大熵强化学习](#1-2-1 最大熵强化学习)
- [1-2-2 随机策略](#1-2-2 随机策略)
- [1-2-3 双 Q 网络与目标网络](#1-2-3 双 Q 网络与目标网络)
- [1-2-4 自动熵调节](#1-2-4 自动熵调节)
-
- [2 MBPO](#2 MBPO)
-
-
- [2-1 介绍](#2-1 介绍)
- [2-2 整体流程](#2-2 整体流程)
- [2-3 概率神经网络集成](#2-3 概率神经网络集成)
-
- [2-3-1 回顾](#2-3-1 回顾)
- [2-3-2 环境模型精英筛选](#2-3-2 环境模型精英筛选)
- [2-3-3 随机采样输出](#2-3-3 随机采样输出)
- [2-4 模拟轨迹生成](#2-4 模拟轨迹生成)
- [2-5 对接 SAC](#2-5 对接 SAC)
- [2-6 完整训练流程](#2-6 完整训练流程)
- [2-7 与论文的对比实验](#2-7 与论文的对比实验)
-
- [3 实验](#3 实验)
-
-
- [3-1 介绍](#3-1 介绍)
- [3-2 HalfCheetah-v4](#3-2 HalfCheetah-v4)
- [3-3 实验一:学习曲线](#3-3 实验一:学习曲线)
- [3-4 实验二:达到目标回报所需的真实步数](#3-4 实验二:达到目标回报所需的真实步数)
- [3-5 实验三:模型预测与真实环境](#3-5 实验三:模型预测与真实环境)
- [3-6 实验小结](#3-6 实验小结)
-
- 总结
1 回顾
1-1 离策略强化学习
- 我们在往期的文章中【离策略强化学习】DDPG、TD3 与 SAC:核心公式推导与源码解析 提到过离策略强化学习
- 离策略(off-policy)是指行为策略与目标策略可以不同:智能体用行为策略 μ ( a ∣ s ) \mu(a\mid s) μ(a∣s) 与环境交互,把转移存入回放池,再用回放池中的样本更新目标策略 π ( a ∣ s ) \pi(a\mid s) π(a∣s)
- 以防你忘记:
- μ ( a ∣ s ) \mu(a\mid s) μ(a∣s):实际采样动作的行为策略
- π ( a ∣ s ) \pi(a\mid s) π(a∣s):正在学习、最终要部署的目标策略
- D e n v \mathcal{D}_{\mathrm{env}} Denv:真实环境转移构成的回放池
- 离策略方法的样本效率来自经验复用:同一条转移可以参与多次梯度更新,而不必重新采集
- 代价是行为策略与目标策略之间的分布偏移。当 π \pi π 与 μ \mu μ 差距过大时,回放池中的状态分布不再代表当前策略会访问的区域,价值估计会出现偏差
- 这个问题在模型式方法里会被放大:模型生成的转移并非来自真实环境,若模型在当前策略新访问的区域不准,偏差会随更新累积
- MBPO 选择 SAC 作为策略优化器,看中的正是 SAC 的离策略性质:真实数据与模型数据可以放进同一个回放池,按比例混合后反复使用
说人话:离策略就是"别人开车我记笔记",记下来的经验可以反复翻看;在策略(on-policy)则是"自己开、开完就忘"
1-2 SAC 回顾
- SAC 在离策略演员-评论家框架上加入最大熵目标,并用双 Q 网络、目标网络与自动熵调节稳定训练;前几期已经详细推导过,这里只回顾与 MBPO 直接相关的四个机制
1-2-1 最大熵强化学习
- 标准强化学习最大化折扣回报,SAC 在每一步额外加入策略熵:
J ( π ) = E π ∑ t = 0 ∞ γ t ( r t + α H ( π ( ⋅ ∣ s t ) ) ) J(\pi)=\mathbb{E}_{\pi}\left\\sum_{t=0}\^{\\infty}\\gamma\^{t}\\left(r_t+\\alpha\\mathcal{H}\\left(\\pi(\\cdot\\mid s_t)\\right)\\right)\\right J(π)=Eπt=0∑∞γt(rt+αH(π(⋅∣st))) - 其中 α \alpha α 是温度系数, H ( π ( ⋅ ∣ s ) ) = − E a ∼ π log π ( a ∣ s ) \mathcal{H}(\pi(\cdot\mid s))=-\mathbb{E}_{a\sim\pi}\left\\log\\pi(a\\mid s)\\right H(π(⋅∣s))=−Ea∼πlogπ(a∣s) 是策略熵
- 加入熵项后,最优策略不再只追求回报最高,而是在回报相近的动作之间保留多样性;这既改善探索,也降低策略过早塌缩到单峰的风险
- 对应的软价值函数为:
V ( s ) = E a ∼ π Q ( s , a ) − α log π ( a ∣ s ) V(s)=\mathbb{E}_{a\sim\pi}\leftQ(s,a)-\\alpha\\log\\pi(a\\mid s)\\right V(s)=Ea∼πQ(s,a)−αlogπ(a∣s) - 熵项进入自举目标后,Q 函数估计的是"回报加未来熵",因此策略在训练早期不会因为 Q 值噪声而迅速失去随机性
说人话:最大熵就是在"拿高分"之外再加一条"别把路走死",让策略在还没学明白时保留几种可能
1-2-2 随机策略
- SAC 的策略是连续高斯分布,采样后再经过 tanh \tanh tanh 压缩到动作区间:
u ∼ N ( μ ϕ ( s ) , σ ϕ 2 ( s ) ) , a = tanh ( u ) u\sim\mathcal{N}\left(\mu_\phi(s),\sigma_\phi^2(s)\right),\qquad a=\tanh(u) u∼N(μϕ(s),σϕ2(s)),a=tanh(u) - 压缩会改变概率密度,动作的对数概率必须加上雅可比修正:
log π ( a ∣ s ) = log N ( u ; μ ϕ ( s ) , σ ϕ 2 ( s ) ) − ∑ d log ( 1 − tanh 2 ( u d ) ) \log\pi(a\mid s)=\log\mathcal{N}\left(u;\mu_\phi(s),\sigma_\phi^2(s)\right)-\sum_{d}\log\left(1-\tanh^{2}(u_d)\right) logπ(a∣s)=logN(u;μϕ(s),σϕ2(s))−d∑log(1−tanh2(ud)) - 这个修正项在策略损失与熵项里都要用到;漏掉它会让熵的估计偏离真实值
- 与确定性策略相比,随机策略在模型式方法里还有一个作用:模型 rollout 时从策略采样动作,动作的多样性会让模型数据覆盖更宽的状态区域
1-2-3 双 Q 网络与目标网络
- SAC 同时训练两个 Q 网络,取较小值作为自举目标,抑制 Q 值高估:
y t = r t + γ ( 1 − d t ) ( min i = 1 , 2 Q θ ˉ i ( s t + 1 , a t + 1 ) − α log π ϕ ( a t + 1 ∣ s t + 1 ) ) , a t + 1 ∼ π ϕ ( ⋅ ∣ s t + 1 ) y_t=r_t+\gamma(1-d_t)\left(\min_{i=1,2}Q_{\bar\theta_i}(s_{t+1},a_{t+1})-\alpha\log\pi_\phi(a_{t+1}\mid s_{t+1})\right),\qquad a_{t+1}\sim\pi_\phi(\cdot\mid s_{t+1}) yt=rt+γ(1−dt)(i=1,2minQθˉi(st+1,at+1)−αlogπϕ(at+1∣st+1)),at+1∼πϕ(⋅∣st+1) - 两个 Q 网络用同一个目标 y t y_t yt 做回归;目标网络不直接复制当前网络,而是每次按 τ \tau τ 与 1 − τ 1-\tau 1−τ 的权重向当前网络靠近:
θ ˉ i n e w = ( 1 − τ ) θ ˉ i o l d + τ θ i \bar\theta_i^{\mathrm{new}}=(1-\tau)\bar\theta_i^{\mathrm{old}}+\tau\theta_i θˉinew=(1−τ)θˉiold+τθi - 对应的实现只比标准 TD(Temporal Difference,时序差分)目标多一项熵:
python
# 对应 1-2-3 节的软 Bellman 目标
with torch.no_grad():
next_action, next_log_prob = actor(next_obs)
next_q = torch.min(q1_target(next_obs, next_action),
q2_target(next_obs, next_action))
target_q = reward + gamma * (1.0 - done) * (next_q - alpha * next_log_prob)
- 这里的
alpha * next_log_prob就是最大熵目标里的熵项;MBPO 内层沿用同一套实现,模型数据只是换了采样来源
1-2-4 自动熵调节
- 温度系数 α \alpha α 不需要手工设定,SAC 把它当作可学习参数,最小化以下损失:
L ( α ) = − E a ∼ π log α ( log π ( a ∣ s ) + H ˉ ) \mathcal{L}(\alpha)=-\mathbb{E}_{a\sim\pi}\left\\log\\alpha\\left(\\log\\pi(a\\mid s)+\\bar{\\mathcal{H}}\\right)\\right L(α)=−Ea∼πlogα(logπ(a∣s)+Hˉ) - 其中 H ˉ \bar{\mathcal{H}} Hˉ 是目标熵,连续动作任务通常取动作维度的相反数;当策略熵低于目标时,损失推动 α \alpha α 增大,反之减小
- 自动调节让同一个算法在不同维度、不同奖励尺度的任务上都能维持相近的探索强度,这也是本文两个任务共用一组 SAC 超参的前提
2 MBPO
2-1 介绍

- MBPO 由 Janner 等人于 2019 年在 NeurIPS 上提出,论文题为 When to Trust Your Model: Model-Based Policy Optimization
- 论文的出发点是一个矛盾:MBRL(Model-Based Reinforcement Learning,模型式强化学习)样本效率高,但模型误差会限制策略的渐近性能;无模型方法渐近性能好,却需要大量真实交互
- MBPO 的回答是限制模型的使用范围:不从初始状态长时间推演,而是从真实回放池中的状态出发,只推演很短的几步,用大量短轨迹补充 SAC 的训练数据
- 因此它同时具备两个性质:模型只在小范围内提供额外监督,短分支把误差累积限制在单条模拟轨迹的少数几步内;策略仍然由 SAC 在混合数据上优化,最终性能不会被模型锁死
2-2 整体流程
- MBPO 的一次完整迭代包含四个步骤:
- 与真实环境交互:用当前策略采样动作,把转移 ( s t , a t , s t + 1 , r t ) (s_t,a_t,s_{t+1},r_t) (st,at,st+1,rt) 存入真实回放池
- 学习动力学模型:在真实回放池上重新拟合概率集成,预测下一状态变化量与奖励
- 从真实状态出发生成短轨迹:从回放池随机取状态,用当前策略与模型推演 k k k 步,把生成的转移存入模型回放池
- 更新策略:从真实池与模型池按比例混合采样,用 SAC 完成若干次梯度更新
- 四个步骤按不同频率交替执行:真实交互每个环境步都发生,模型拟合每隔若干步触发一次,策略更新可以每个环境步执行多次
说人话:从整体设计上看,动力学模型(PE)和 SAC 的策略学习是相对解耦的。PE 负责学习环境的状态变化规律,并利用学到的模型生成额外的训练数据;SAC 则从真实经验池和模型经验池中混合采样,利用这些数据更新策略。
- 二者通过经验数据联系起来:模型不直接生成策略参数,而是通过提供额外的训练样本,帮助 SAC 提高样本利用效率。随着策略不断更新,模型生成的数据也会随之变化,从而形成一个交替迭代的训练过程。
2-3 概率神经网络集成

2-3-1 回顾
- MBPO 的动力学模型沿用 PETS 的 PE(Probabilistic Ensemble,概率集成):由 B B B 个概率网络组成,每个成员输出下一状态变化与奖励的高斯分布
- 设状态维度为 d s d_s ds,第 i i i 个成员预测:
p θ i ( s t + 1 , r t ∣ s t , a t ) = N ( μ θ i ( s t , a t ) , diag ( σ θ i 2 ( s t , a t ) ) ) p_{\theta_i}(s_{t+1},r_t\mid s_t,a_t)=\mathcal{N}\left(\mu_{\theta_i}(s_t,a_t),\operatorname{diag}\left(\sigma_{\theta_i}^{2}(s_t,a_t)\right)\right) pθi(st+1,rt∣st,at)=N(μθi(st,at),diag(σθi2(st,at))) - 网络输出的是状态变化量 Δ s t = s t + 1 − s t \Delta s_t=s_{t+1}-s_t Δst=st+1−st 与奖励,下一状态由 s t + Δ s t s_t+\Delta s_t st+Δst 还原;这样网络不必把容量花在重建当前状态上
- 训练目标是 NLL(Negative Log-Likelihood,高斯负对数似然):
L ( θ ) = ∑ i = 1 B ∑ d = 1 d s + 1 ( y d − μ θ i , d ) 2 2 σ θ i , d 2 + 1 2 log σ θ i , d 2 \mathcal{L}(\theta)=\sum_{i=1}^{B}\sum_{d=1}^{d_s+1}\left\\frac{\\left(y_d-\\mu_{\\theta_i,d}\\right)\^{2}}{2\\sigma_{\\theta_i,d}\^{2}}+\\frac{1}{2}\\log\\sigma_{\\theta_i,d}\^{2}\\right L(θ)=i=1∑Bd=1∑ds+12σθi,d2(yd−μθi,d)2+21logσθi,d2 - 其中:
- i i i 表示第 i i i 个模型, B B B 是模型总数。
- d d d 表示预测向量中的某个维度,包括奖励和各维状态变化量。
- 每个模型都计算自己预测结果的 NLL 损失,最后将各模型、各维度的损失求和,作为整体训练目标。
- 集成成员之间用 bootstrap 重采样制造差异:每个成员在自己的重采样索引上训练,看到的数据子集不同,预测分歧就构成认知不确定性的近似
说人话:训练时,每个模型都会通过 bootstrap 重采样获得不同的训练数据,并分别计算自己的 NLL 损失。训练的整体目标是让所有模型的损失之和尽可能小。由于各个模型看到的数据不同,它们学到的动力学规律也可能存在差异,而这些预测差异可以用来近似衡量模型的认知不确定性。
- 方差项需要约束,否则网络会把 σ 2 \sigma^2 σ2 压向零来降低第一项。实现上让网络输出原始对数方差 ℓ ^ \hat{\ell} ℓ^,再用可学习的上下界做两次软约束:
ℓ = ℓ max − softplus ( ℓ max − ℓ ^ ) , ℓ = ℓ min + softplus ( ℓ − ℓ min ) \ell=\ell_{\max}-\operatorname{softplus}\left(\ell_{\max}-\hat{\ell}\right),\qquad \ell=\ell_{\min}+\operatorname{softplus}\left(\ell-\ell_{\min}\right) ℓ=ℓmax−softplus(ℓmax−ℓ^),ℓ=ℓmin+softplus(ℓ−ℓmin) - 对应的前向与损失如下:
python
def _forward(self, xb):
# xb: [E, B, obs_dim + act_dim],E 为集成成员数
out = self.net(xb)
mean, raw_logvar = out[..., :1 + self.obs_dim], out[..., 1 + self.obs_dim:]
# 对应 2-3 节的两次软约束,防止方差塌缩或发散
logvar = self.max_logvar - F.softplus(self.max_logvar - raw_logvar)
logvar = self.min_logvar + F.softplus(logvar - self.min_logvar)
return mean, logvar
mean, logvar = self._forward(xb)
inv_var = torch.exp(-logvar)
per_member = ((mean - yb).square() * inv_var + logvar).mean(dim=(1, 2))
loss = per_member.sum() + self._weight_decay() + 0.01 * self.max_logvar.sum() - 0.01 * self.min_logvar.sum()
- 损失里还有两处正则:每层权重衰减沿用官方实现的分层系数,
max_logvar与min_logvar各带一个 0.01 的线性项,防止边界本身无界漂移 - 每个成员都是 4 层 200 维的 swish 网络,输入先做标准化、输出不做标准化,优化器为 Adam,学习率 10 − 3 10^{-3} 10−3
- 训练时留出 20% 数据做验证,按验证均方误差早停并回滚到每个成员的最好参数
2-3-2 环境模型精英筛选
- 训练结束后按验证误差排序,保留前 E E E 个成员作为精英(本文取 B = 7 B=7 B=7、 E = 5 E=5 E=5)
- 精英即验证误差最小的一组成员:它们在没见过的转移上预测更准,用它们生成数据比用全部成员更可控
- 验证均方误差衡量的是单步预测,这次排序只筛选单步精度,不能保证多步推演同样可靠
- 每次重新拟合后精英集合都会按新的验证误差重排,因此随着真实数据增多,入选的成员可能发生变化
说人话:我们会训练 B B B 个环境模型,根据它们在验证集上的预测误差,选出表现最好的 E E E 个模型作为精英模型,后续生成模拟轨迹时,再从精英模型中随机选择模型进行预测。
- 与 PETS 相比,这里有一处差别:PETS 官方实现(handful-of-trials)的 TS1 与 TS∞ 都在全部成员中抽样,没有对成员做筛选;MBPO 的官方代码在每次拟合后按验证误差排序,只在精英中抽样(
self._model_inds = sorted_inds[:self.num_elites])- 两者表达不确定性的方式相同,都靠 bootstrap 成员的预测分歧;区别在于 MBPO 的实现会把验证误差最大的成员直接排除在生成环节之外
- 生成轨迹时,每条分支的每一步都从精英中随机抽一个成员,这是整个过程里的第一次随机采样
- 抽中的成员负责这一步的状态变化与奖励;下一步会重新抽,因此同一条分支的相邻两步可能来自不同成员
- 重抽方式与 PETS 的 TS1 一致:TS1 每一步重新抽成员,TS∞ 则沿整条轨迹固定同一个成员;区别在抽样范围,PETS 从全部成员中抽,这里只从精英中抽
- 这次抽样对应
step方法里的两行,model_inds即按验证误差保留的精英下标:
python
n = mean.shape[1] # 本步的分支数
member = torch.as_tensor(np.random.choice(self.model_inds, size=n), device=self.device) # 每个分支独立抽一个精英
- 官方
fake_env.py用model_inds = self.model.random_inds(batch_size)完成同一件事
2-3-3 随机采样输出
- 成员选定之后,输出决定这一步生成什么:单个成员给出一个 1 + d s 1+d_s 1+ds 维向量
- 第 0 维为奖励,其余 d s d_s ds 维为状态变化量
- 下一状态由 s t + 1 = s t + Δ s t s_{t+1}=s_t+\Delta s_t st+1=st+Δst 还原,在 HalfCheetah 上输出为 1 + 17 = 18 1+17=18 1+17=18 维
- 这个向量不是点估计,而是对角高斯:奖励与每一维状态变化量各有自己的均值与方差
- 第二次随机采样发生在这里:在该成员的高斯 N ( μ θ i , diag ( σ θ i 2 ) ) \mathcal{N}\left(\mu_{\theta_i},\operatorname{diag}\left(\sigma_{\theta_i}^{2}\right)\right) N(μθi,diag(σθi2)) 中采一个样本,而不是直接取均值
- 对应的代码同样来自
step方法;集成被写成一个批量张量,一次前向就算出全部成员,取样本时才按成员下标筛选:
python
mean, var = self.predict(obs, act) # [E, N, 1 + d_s]
mean = mean.clone()
mean[:, :, 1:] += torch.as_tensor(obs, device=self.device) # Δs 还原为 s'
samples = mean + torch.randn_like(mean) * var.sqrt() # 第二次随机采样
selected = samples[member, torch.arange(n, device=self.device)] # member 与 n 来自 2-3-2
reward, next_obs = selected[:, :1], selected[:, 1:]
- 这段代码对应三个操作:
mean[:, :, 1:] += obs把网络输出的状态变化量还原为下一状态,第 0 维的奖励不做这一步torch.randn_like(mean) * var.sqrt()按该成员给出的标准差加噪声,得到高斯分布的一个样本samples[member, rows]只取被抽中成员的预测,其余成员的输出不参与这一步
- 使用场景与 PETS 不同:PETS 在交叉熵方法筛选动作序列时做这种采样,用多条预测轨迹评估候选动作;MBPO 不筛选动作序列,模型输出直接写入模型回放池,作为 SAC 的训练数据
- 由于两次抽样都在每一步重新进行,同一批分支的起点不同,抽中的成员与噪声也不同;模型数据本身带有随机性,也避免了用集成平均替代预测:平均会把成员之间的分歧抹平,而分歧正是认知不确定性所在
- 需要区分本文的两种取输出方式:生成训练数据时逐样本抽成员并加噪声,服务于数据多样性;实验三的开环评测对精英取均值、把成员内方差与成员间方差合成阴影,服务于检查模型的平均预测是否可信
说人话:这里有两次随机采样。第一次,从精英模型中随机选出一个成员;第二次,根据该成员输出的高斯分布(均值和方差),再随机采样得到具体的奖励和状态变化量。
2-4 模拟轨迹生成
- 生成模型数据的方式决定了模型误差如何进入策略学习。最直接的做法是从初始状态推演整条轨迹,但这会把模型误差与任务时域绑在一起:任务越长,推演越长,误差越大
- MBPO 采用分支 rollout(branched rollout):起点从真实回放池采样,只向前推演 k k k 步:
s t ∼ D e n v , s ^ t + j + 1 = s ^ t + j + f θ i ( s ^ t + j , a t + j ) , a t + j ∼ π ϕ ( ⋅ ∣ s ^ t + j ) s_t\sim\mathcal{D}{\mathrm{env}},\qquad \hat{s}{t+j+1}=\hat{s}{t+j}+f{\theta_i}\left(\hat{s}{t+j},a{t+j}\right),\qquad a_{t+j}\sim\pi_\phi\left(\cdot\mid\hat{s}_{t+j}\right) st∼Denv,s^t+j+1=s^t+j+fθi(s^t+j,at+j),at+j∼πϕ(⋅∣s^t+j) - 其中成员编号 i i i 在每个样本的每一步独立抽取,同一条分支的不同步可以来自不同成员,即 2-3-2 中的 TS1 方式
- 奖励同样由模型预测,生成的转移 ( s , a , s ^ ′ , r ^ ) (s,a,\hat{s}',\hat{r}) (s,a,s^′,r^) 直接写入模型回放池
- 分支长度 k k k 不是固定的,而是随训练进程从 k 0 k_0 k0 线性增加到 k 1 k_1 k1: k ( e ) = min ( max ( k 0 + e − e 0 e 1 − e 0 ( k 1 − k 0 ) , k 0 ) , k 1 ) k(e)=\min\left(\max\left(k_0+\frac{e-e_0}{e_1-e_0}\left(k_1-k_0\right),k_0\right),k_1\right) k(e)=min(max(k0+e1−e0e−e0(k1−k0),k0),k1)其中:
- e e e:训练轮次或累计环境步数
- e 0 e_0 e0、 e 1 e_1 e1:调度开始与结束的位置
- k 0 k_0 k0、 k 1 k_1 k1:分支长度的下界与上界
说人话: MBPO 会随训练进度逐渐增大分支长度 k k k:早期模型不准,采用短轨迹以减少误差累积;后期模型更可靠,再延长轨迹以利用模型生成更多训练数据。
- 这个设计有理论依据。论文给出 k k k 步分支 rollout 的回报下界: η π ≥ η b r a n c h π − 2 r max γ k + 1 ϵ π ( 1 − γ ) 2 + γ k + 2 1 − γ ϵ π + k 1 − γ ( ϵ m + 2 ϵ π ) \eta\\pi\ge\eta^{\mathrm{branch}}\\pi-2r_{\max}\left\\frac{\\gamma\^{k+1}\\epsilon_\\pi}{(1-\\gamma)\^{2}}+\\frac{\\gamma\^{k}+2}{1-\\gamma}\\epsilon_\\pi+\\frac{k}{1-\\gamma}\\left(\\epsilon_m+2\\epsilon_\\pi\\right)\\right ηπ≥ηbranchπ−2rmax(1−γ)2γk+1ϵπ+1−γγk+2ϵπ+1−γk(ϵm+2ϵπ)其中:
- ϵ m \epsilon_m ϵm:模型与真实转移分布的全变差距离
- ϵ π \epsilon_\pi ϵπ:相邻策略的分布差异
- r max r_{\max} rmax :奖励上界
- 惩罚项中与 k ϵ m k\epsilon_m kϵm 成正比的部分随 k k k 线性增长:在其他误差界不变的前提下,分支越长,模型误差对回报下界的惩罚越大
- 但这个界没有计入模型数据的收益,直接按它优化会得到 k = 0 k=0 k=0,即完全不用模型;论文认为这是对模型误差的估计过于悲观,于是用当前策略分布下的模型误差 ϵ m ′ \epsilon_m' ϵm′ 替换 ϵ m + 2 ϵ π \epsilon_m+2\epsilon_\pi ϵm+2ϵπ,得到:
η π ≥ η b r a n c h π − 2 r max γ k + 1 ϵ π ( 1 − γ ) 2 + γ k ϵ π 1 − γ + k 1 − γ ϵ m ′ \eta\\pi\ge\eta^{\mathrm{branch}}\\pi-2r_{\max}\left\\frac{\\gamma\^{k+1}\\epsilon_\\pi}{(1-\\gamma)\^{2}}+\\frac{\\gamma\^{k}\\epsilon_\\pi}{1-\\gamma}+\\frac{k}{1-\\gamma}\\epsilon_m'\\right ηπ≥ηbranchπ−2rmax(1−γ)2γk+1ϵπ+1−γγkϵπ+1−γkϵm′ - 引入 ϵ m ′ \epsilon_m' ϵm′ 后,当当前策略分布下的模型误差足够小时,回报下界可能在 k > 0 k>0 k>0 处取得更优值,从而为使用非零长度的分支提供理论依据;直观上模型越准,延长分支越值得考虑,但实际分支长度仍需结合模型误差与训练效果确定
- 对应的实现如下:
python
def rollout_model(self, length):
# 分支起点全部来自真实回放池,避免从初始状态长距离推演
obs = self.buffer.real.sample_arrays(self.rollout_batch_size)["obs"]
for _ in range(length):
act = self.act(obs, deterministic=False) # 当前 SAC 策略采样动作
next_obs, rew, term = self.model.step(obs, act, termination_fn=self.termination_fn)
self.buffer.add_model_batch(obs, act, rew, next_obs, term)
mask = term.reshape(-1) < 0.5
if not mask.any():
break
obs = next_obs[mask] # 未终止的分支继续推演
model.step内部先对每个样本抽一个精英成员,再按该成员的均值与方差采样下一状态;因此同一条分支的相邻两步可能来自不同成员- 环境若有终止条件,模型 rollout 也要执行同样的终止判断;HalfCheetah 没有终止条件,这一步恒为 0
2-5 对接 SAC
- 模型数据与真实数据分开存放,每次 SAC 更新按固定比例混合:
B = B r e a l ∪ B m o d e l , ∣ B r e a l ∣ = ⌊ ρ ∣ B ∣ ⌋ \mathcal{B}=\mathcal{B}{\mathrm{real}}\cup\mathcal{B}{\mathrm{model}},\qquad \left|\mathcal{B}_{\mathrm{real}}\right|=\left\lfloor\rho\left|\mathcal{B}\right|\right\rfloor B=Breal∪Bmodel,∣Breal∣=⌊ρ∣B∣⌋ - ρ \rho ρ 称为真实数据比例,官方实现的 HalfCheetah 配置取 0.05,也就是每个 batch 只有约 5% 来自真实环境,其余 95% 来自模型
- 比例不能太低:真实数据是策略与模型之间唯一的锚点,比例过低会让策略过度适应模型偏差;比例也不能太高:模型数据的意义就是放大有限真实交互的监督量
- SAC 侧不需要任何改动,它只看到
sample返回的一个 batch;真实池与模型池的切分发生在采样函数内部
- 对应的实现如下:
python
def sample(self, batch_size, env=None):
# 模型池为空时退化为纯真实数据;否则按 real_ratio 切分
n_real = int(batch_size * self.real_ratio) if self.model.size() > 0 else batch_size
n_model = batch_size - n_real
parts = [self.real.sample_arrays(n_real)]
if n_model > 0:
parts.append(self.model.sample_arrays(n_model))
# cat 把两个来源按字段拼接成一个 batch,交给 SAC 的 critic 与 actor 更新
return ReplayBufferSamples(
observations=torch.as_tensor(cat("obs"), device=self.device),
actions=torch.as_tensor(cat("act"), device=self.device),
next_observations=torch.as_tensor(cat("next_obs"), device=self.device),
dones=torch.as_tensor(cat("done"), device=self.device),
rewards=torch.as_tensor(cat("rew"), device=self.device),
)
- SAC 的离策略性质使它可以从真实回放池与模型回放池中混合采样,并用统一的 Bellman 目标更新 Q 网络;但这并不意味着模型数据天然服从真实环境的动力学,模型存在预测误差时,混合训练仍会引入偏差
- 模型数据一方面扩充了可复用的训练样本,另一方面也可能带来系统性偏差:模型给出的下一状态与奖励偏离真实转移时,Q 网络的回归目标随之偏移,策略会被拉向模型虚构的区域
- MBPO 的关键因此不是简单地混合两类数据,而是通过使用方式控制模型误差的影响:集成刻画不确定性、短分支限制误差累积、真实数据比例约束模型偏差的权重
- 模型数据的有效性最终取决于动力学模型的准确程度及其使用方式;离策略性质只保证样本可以被复用,不保证样本的分布是对的
说人话:真实数据是"主粮",模型数据是"加餐";加餐能吃饱,但主粮不能断
2-6 完整训练流程
- 把上述模块串起来,得到 MBPO 的完整训练流程:
- 初始化策略 π ϕ \pi_\phi πϕ、Q 网络、概率集成 p θ p_\theta pθ、真实池 D e n v \mathcal{D}{\mathrm{env}} Denv 与模型池 D m o d e l \mathcal{D}{\mathrm{model}} Dmodel
- 用当前策略在真实环境中执行动作,把转移写入 D e n v \mathcal{D}_{\mathrm{env}} Denv
- 每隔 M M M 个环境步,在 D e n v \mathcal{D}_{\mathrm{env}} Denv 上重新拟合概率集成
- 从 D e n v \mathcal{D}{\mathrm{env}} Denv 采样起点,用当前策略与模型生成 k k k 步分支,写入 D m o d e l \mathcal{D}{\mathrm{model}} Dmodel
- 每个环境步执行 G G G 次 SAC 更新,每次按 ρ \rho ρ 混合两个回放池
- 重复第 2 步到第 5 步,直到达到真实交互预算
- 对应的外层循环可以写得很短:
python
for step in range(total_steps):
action = env.action_space.sample() if step < learning_starts else agent.act(obs)
next_obs, reward, terminated, truncated, _ = env.step(action)
# 只把真实终止写入 done;时间上限截断仍然参与自举
agent.buffer.add(obs, next_obs, action, reward, float(terminated))
if step + 1 >= learning_starts:
agent.train_policy(total_steps, n_updates=updates_per_step) # SAC 更新
if (step + 1) % model_train_freq == 0 and step + 1 >= model_start:
agent.train_model() # 重拟合集成
agent.rollout_model(rollout_length(step + 1, schedule)) # 生成模型数据
obs = next_obs if not (terminated or truncated) else env.reset()[0]
- 这里有三个频率需要区分:真实交互每个环境步一次,模型拟合约每几百步一次,策略更新每个环境步 G G G 次
- 论文在 HalfCheetah 上把 G G G 取 20,模型数据把可用的更新次数从"每样本一次"放大到"每样本多次";这也是 MBPO 与普通 SAC 最直接的算力差异
- 本文为了控制单机预算,把 G G G 缩小到 5,模型拟合频率与分支长度也相应缩小;具体设置在第 3 章给出
2-7 与论文的对比实验
-
论文在 InvertedPendulum、Hopper、Walker2d、Ant、HalfCheetah 与 Humanoid 六个连续控制任务上,把 MBPO 与 SAC、PPO、PETS 以及 STEVE(Stochastic Ensemble Value Expansion,随机集成价值展开)、SLBO(Luo 等人提出的模型式算法)做了比较
-
图 1 给出论文中的学习曲线,每条实线是五次试验的均值,阴影是标准差:

-
图中的虚线标出未在横轴范围内收敛的算法最终达到的水平
-
从曲线可以看到三点趋势:
- MBPO 在多数任务上取得了最高的渐近回报,其中 Hopper、Walker2d、Ant 与 Humanoid 上相对模型式基线的优势最明显
- 渐近性能与最好的无模型算法相当:在 MBPO 收敛的任务上,它的平台与 SAC 的收敛水平接近,说明使用模型没有牺牲最终性能
- 模型式基线的分化明显:PETS 在低维任务上起步很快,但在 Ant 这类高维任务上明显落后;SLBO 与 STEVE 在多数任务上的回报低于 MBPO
-
论文特别指出,Ant 上 MBPO 用三十万步达到的回报,相当于 SAC 用三百万步达到的水平;这一差距来自模型数据带来的更新次数放大,而不是来自更强的策略优化器
-
论文同时做了三项设计消融:
- 无模型对照:给 SAC 同样的每步更新次数但不给模型数据,性能仍明显低于 MBPO,说明收益来自模型数据本身
- 分支长度:把 k k k 固定为 1 仍能保留大部分收益,200 步分支略差,500 步分支失效;这与 2-4 节的下界一致
- 价值展开:把模型用于修正 TD 目标,即 MVE(Model-Based Value Expansion,基于模型的价值展开)与 STEVE 的做法,效果不如直接把模型转移送入策略更新
-
这些结果支撑了本文的实现选择:保留集成与短分支,把模型数据混入 SAC 的回放池
结论:模型的价值取决于使用方式;短分支、按比例混合、集成表示不确定性,三者共同把模型误差限制在策略可承受的范围内
3 实验
3-1 介绍
-
论文已经给出大规模基准对比,本文不再重复六个任务,而是在一个高维连续控制任务上做受控比较:两个算法使用同一条 SAC 实现、同一组超参、同样的真实交互预算与策略更新次数,唯一差别是 MBPO 的 batch 中有 95% 来自模型
-
环境选用 HalfCheetah-v4 :状态为 17 维,包含根节点高度与俯仰角、六个关节角,以及根节点与各关节的速度,不含前进方向的位置;动作为 6 维关节力矩;奖励由前进速度减去动作代价构成;回合长度固定为 1000 步,没有提前终止

- 选择这个任务的原因是它同时具备三个条件:状态维度足够高、动力学非线性强、模型误差会沿关节链累积;这三条正是 MBPO 的适用场景
-
实验设置如下:
| 项 | 设置 |
|---|---|
| 真实交互预算 | 100,000 步 |
| 每个真实步的 SAC 更新次数 | 5 |
| 模型拟合频率 | 每 500 步 |
| 分支长度 k k k,即向前推演的步数 | 从 1 线性增加到 5 |
| 每次拟合的分支数 | 2,000 |
| 真实数据比例 | 5% |
| 随机种子 | 2 个 |
| 曲线平滑 | 10 回合滑动平均 |
- 需要说明的是,本文按单机预算缩小了论文的规模:论文在 HalfCheetah 上每个环境步执行 20 次策略更新、每次拟合从 400 个起点生成分支,本文分别为 5 次与 2,000 个起点;这些差异会影响绝对回报,但不改变两个算法的对照关系
- 作为补充,本文也在 Pendulum-v1 上跑了同样的对照:
- 两个算法的学习曲线几乎重合,因为该任务只有 3 维状态、动力学接近确定,模型在数千条转移上就已经足够准确,模型数据不能提供额外信息;因此正文只展开 HalfCheetah 的结果
- 本章按三个层次检查算法:
| 实验 | 检查对象 | 主要问题 |
|---|---|---|
| 实验一 | 学习曲线 | 同等真实步数下回报如何变化 |
| 实验二 | 样本效率 | 达到同一回报需要多少真实交互 |
| 实验三 | 模型预测 | 单步与多步预测是否可信 |
3-2 HalfCheetah-v4
-
下图给出 HalfCheetah 在平面内的奔跑形态,躯干与前后两条腿通过关节联动:

-
HalfCheetah 是一个二维平面内的奔跑任务:躯干与前后两条腿由 9 个刚体和 8 个关节连接,其中 6 个关节由动作驱动,动作为施加在驱动关节上的力矩
-
奖励函数为前进速度减去动作幅度的二次惩罚:
r t = x ˙ t − 0.1 ∑ j = 1 6 a j , t 2 r_t=\dot{x}t-0.1\sum{j=1}^{6}a_{j,t}^{2} rt=x˙t−0.1j=1∑6aj,t2
- 这个奖励没有终止条件,智能体摔倒也不会结束回合,只会在剩余步数里持续获得较低的回报;因此策略必须学会在整条 1000 步的回合中维持稳定步态
-
对模型而言,这是一个困难的任务:关节角速度与下一时刻的关节角之间是强耦合的,单步误差会沿关节链与时间同时传播
-
两个算法使用相同的环境种子与相同的策略初始化;每个配置跑两个随机种子,曲线与柱状图给出两个种子的个体值与它们的均值
-
训练曲线记录的是训练过程中的回合回报,动作按随机策略采样,不是确定性策略的评测值;这一点在比较绝对水平时需要注意
3-3 实验一:学习曲线
-
实验内容:在相同的真实交互预算下,比较 SAC 与 MBPO 的回合回报随真实环境步数的变化
-
实验实现:两个算法共用 SB3(Stable-Baselines3)的 SAC 实现与超参,MBPO 只额外接入模型数据;每 1000 步记录一个回合,曲线取 10 回合滑动平均
-
图 2 给出两条学习曲线,浅色细线是两个随机种子的个体曲线,粗线是均值:

-
结果分析:训练前期两者的回报都接近零,MBPO 在约两万步后率先抬升,SAC 的抬升晚且更平缓;中段 MBPO 始终位于 SAC 之上,且两个种子的曲线更集中
-
SAC 在后期增长趋缓,两个种子的终点差距明显,其中一条在末段出现小幅回落;MBPO 的曲线持续上升,两个种子也更接近,说明模型数据在后期仍能提供有效监督
- 一个可能的解释见 2-5 节:两个算法每个真实步都执行 5 次 SAC 更新,但 MBPO 的 batch 大部分来自模型,等于在不增加真实交互的前提下放大了监督量;SAC 只能反复拟合有限的真实转移,后期更容易在有限样本上过拟合
- 早期的滞后同样有解释:PE 环境模型从一千条真实转移开始拟合,早期误差大,模型生成的转移质量低;随着真实池扩大,模型精度提高,MBPO 的优势才显现
-
需要说明的是,每组配置只有两个随机种子,上述差异反映的是这一设置下的趋势,尚不足以对两种算法的性能差异做统计推断
结论:在本实验设置下,MBPO 的学习速度快于 SAC,后期的走势也更平稳;前期的模型误差会拖慢起步,但不会抵消后期的收益
3-4 实验二:达到目标回报所需的真实步数
-
实验内容:固定一个目标回报,统计两个算法需要多少真实环境步才能达到,用来衡量样本效率
-
实验实现:目标回报取 4,000,理由是它位于两个算法都能达到的区间;用 10 回合滑动平均判断是否达到,记录首次达到的步数
-
图 3 给出两个算法的达到步数,柱子为两个种子的均值,散点为个体值:

-
结果分析:按两个种子的均值计,MBPO 在这组实验中达到目标所需的真实步数约为 SAC 的一半,且两个种子的散点几乎重合;SAC 的两个种子都接近预算末端才达到,种子之间的差距也更大
-
这条读数比学习曲线更直接:它把"曲线更高"换算成"省下多少真实交互",而真实交互正是模型式方法要优化的成本
-
需要说明目标回报是在看到结果之后确定的,属于事后选择;它适合描述本组实验的差距,不宜当作预注册指标
结论:在这组实验的设置下,MBPO 用约一半的真实交互达到同一回报,样本效率优势明确
3-5 实验三:模型预测与真实环境
-
实验内容:对若干真实初始状态,用训练后策略的动作序列同时驱动真实环境与模型,比较开环预测与真实轨迹
-
实验实现:取 MBPO 训练结束时的集成模型;对每个起点,先让真实环境走完 50 步并记录动作,再把同一串动作输入模型,模型每步取精英成员的均值推进,阴影由成员内方差与成员间方差合成;图中展示其中一组起点的结果
-
图 4 的前三个面板分别给出根节点高度、根节点俯仰角与第一个关节角,第四个面板是归一化均方根误差随预测步数的变化,虚线为"状态不变"基线:

-
结果分析:关节角在 50 步内基本跟住真实振荡的相位与幅值,说明模型学到了关节链的主要动力学;根节点高度在前半段基本贴合、之后逐渐偏高,俯仰角则从约十步起持续向正方向漂移
-
误差面板显示,模型的归一化误差在最初几步低于"状态不变"基线,随后被基线反超并持续上升;这条曲线是开环误差累积的直接证据:模型每一步的微小偏差进入下一步的输入,偏差被再次放大
- 这与 2-4 节的分析一致:单步精度高并不保证长时域可靠。MBPO 的分支长度只有 1 到 5 步,减少了长时域推演带来的误差累积风险;如果按整条回合推演,误差会远超策略可承受的范围
-
因此,实验三的结果与实验一、实验二并不矛盾:模型在短分支上足够准,所以能提供有效监督;在长开环上不可靠,所以不能替代真实环境做长程规划
结论:模型的可信范围是有限的,MBPO 的短分支设计正是把模型使用限制在这个范围内
3-6 实验小结
- 三个实验从不同层次检查了同一组模型:
- 学习曲线说明 MBPO 在同等真实步数下回报更高、后期增长更平稳
- 达到目标回报的步数说明在这组实验中这一优势可以换算成约一半的真实交互
- 开环预测说明模型的可信范围有限,短分支是必要设计
- 与图 1 给出的论文趋势一致:MBPO 在 HalfCheetah 上比 SAC 更早进入高回报区间,在本预算内取得了更高的回报;差别在于本文的预算约为论文的四分之一,曲线只覆盖论文的早期阶段
总结
- 本文从离策略学习与 SAC 的回顾出发,介绍了 MBPO 的概率集成模型、分支 rollout 与混合数据训练,并在 HalfCheetah-v4 上完成了三组对照实验
- 核心要点回顾:
- 模型只做短程预测:分支 rollout 从真实状态出发,只推演少数几步,把模型误差限制在可承受的范围内
- 集成表达不确定性:bootstrap 成员在数据稀疏处分歧增大,精英成员用于生成模型数据
- 模型数据按比例混合:每个 batch 保留少量真实转移作为锚点,其余由模型生成,兼顾监督量与偏差控制
- 策略仍由 SAC 优化:模型只在训练阶段出现,部署时不需要模型,渐近性能不被模型锁死
- 收益与可信范围同时存在:本组实验表明 MBPO 用更少的真实交互达到同一回报,但模型的长开环预测会随时间漂移
- 如有错误,欢迎指出!感谢观看!