
当我们开始接触深度强化学习时最先学习的往往是 DQN、PPO、SAC 这类无模型Model-Free算法。它们靠大量试错与环境交互用奖励信号反向更新策略网络。随着项目复杂度上升你会发现一个问题真实环境中采样成本太高了。机器人每一次动作都要真实电机运转游戏里每次探索都要消耗大量算力这种情况下动辄几百万步的采样预算很多场景根本承受不起。基于模型的强化学习Model-Based Reinforcement Learning, MBRL正是针对这一痛点提出的思路。它试图先让智能体学会一个“环境模拟器”再通过这个模拟器来想象、规划、训练策略从而大幅减少真实交互次数。这篇文章围绕伯克利 2026 春季深度强化学习课程第 16 讲的内容完整拆解 MBRL 的核心原理、算法拆解、代码实战与工程落地中容易踩的坑。如果你正在为“采样效率太低”“真实环境交互成本太高”发愁或者已经入门强化学习、想把模型类方法加入算法选型这篇文章会给你一条相对完整的技术路径。1. 基于模型的强化学习到底是什么1.1 从一张“地图”说起无模型强化学习像是“盲人摸象”智能体不知道环境规律只能不断试错了就调整。基于模型的强化学习则更像“手里有一张地图”——我们先通过有限次探索把地图画出来之后大部分决策都在地图上推演。这里说的“地图”在数学上就是环境的动力学模型。它描述的是给定当前状态和动作下一刻状态会如何变化。掌握了这个模型智能体就可以在虚拟环境中预演未来而不是每次都要回到真实世界去试一次。MBRL 的核心流程可以拆成四个部分学习一个动力学模型输入当前状态和动作预测下一状态利用模型生成“想象中的轨迹”在想象轨迹上做规划或策略优化定期用真实交互数据更新模型。整个过程不断循环让模型越来越准策略越来越强。1.2 MBRL 与 Model-Free 的本质区别很多人会把这两者的关系理解成“模型只是加速工具”其实它们在决策逻辑上就有差别。无模型方法直接从交互数据中学习策略或价值函数不显式学习环境规则。它的优势是实现简单、数学上收敛性质相对清晰但样本效率往往比较低。基于模型的方法先把环境规律近似出来再通过“内脑推演”做出决策。它的最大优势是样本效率高代价是模型误差会被放大最终策略可能因为模型不准而表现崩坏。两者也经常结合。例如 Dyna 架构中真实交互数据同时用来更新价值函数和动力学模型再用模型补充生成“伪经验”这样既保住了 Model-Free 的稳定性又提升了数据利用率。1.3 典型应用场景哪些场景最适合用 MBRL通常有三个特点真实交互成本高机器人控制、自动驾驶、化学实验、医疗决策可以低成本构建模拟器游戏、仿真环境、机械臂仿真需要快速适应新环境迁移学习、领域自适应。课程里会反复提到一个例子在 MuJoCo 或真实机器人上跑一个简单的推动任务无模型强化学习可能需要几十万步而一个中等复杂度的 MBRL 算法可能只要几万步就能稳定完成任务。当然这不代表 MBRL 一定更好具体还要看模型误差和任务连续程度。2. 课程第 16 讲的知识框架与核心模块2.1 该讲在整门课中的位置伯克利 2026 春季深度强化学习课程的内容整体分几个阶段先讲基础 RL 概念然后深入 Model-Free 算法再转向 Model-Based 方法最后讨论前沿研究与安全决策。第 16 讲正好处在“从试错转向想象”的转折点所以你会看到很多课程里都在对比“用真实数据训练”和“用模型生成数据训练”的差异。这一讲通常从一个问题引入如果环境转移概率未知但又希望少跟环境交互怎么办答案是先学习环境模型再用它规划。整讲的展开顺序大致是为什么需要模型模型学习的目标与常见结构基于模型的规划算法MPC、树上搜索、轨迹优化Dyna 式框架模型在策略学习中的深度集成如 MBPO模型误差、复合误差与不确定性估计。2.2 核心数学描述在强化学习中环境可以描述为 MDP马尔可夫决策过程由以下几个元素构成状态空间 (S)动作空间 (A)转移概率 (P(s | s, a))奖励函数 (r(s, a))折扣因子 (\gamma)无模型强化学习不去显式建模 (P(s | s, a))而 MBRL 的核心就是学一个参数化的近似模型[ \hat{P}_\theta(s | s, a) \approx P(s | s, a) ]模型可以是概率分布模型、确定性映射模型也可以是带隐变量的 latent-space 模型。学习方式通常是监督学习——通过真实交互收集一批 ((s_t, a_t, s_{t1})) 样本然后最小化预测误差。为什么转移概率学习比奖励预测更重要因为状态预测的累计误差会直接影响到长期回报估计。哪怕每一步预测只有 1% 的偏差多步展开之后偏差可能滚雪球般扩大。2.3 模型与规划的关系有了模型后决策问题就变成了一个“在模型内部求解”的优化问题。举个例子模型预测控制MPC的做法是在每一步观察到当前状态后利用模型向前推演 (H) 步搜索出未来一段最优动作序列然后只执行第一个动作下一步再重新规划。这就是所谓的“滚动时域控制”。课程中会强调模型是未知的、估计出来的所以规划时还要考虑模型的不确定性。如果模型在某些区域很不准规划器就应该避开那些区域或者用保守策略对待。3. 环境准备与版本说明3.1 推荐的技术栈为了跑通本文后面的实战演示你需要准备以下环境操作系统Windows / macOS / Linux 均可推荐 LinuxPython3.8 或以上深度学习框架PyTorch 或 TensorFlow本文示例以 PyTorch 为例环境仿真库gymnasium新版 Gym额外工具numpy、matplotlib、tqdm。具体版本没有强制要求关键在于保持依赖兼容。PyTorch 官方安装页会根据你的 CUDA 版本和操作系统给出命令直接复制执行即可。如果你的电脑不支持 CUDA用 CPU 运行本文的 Demo 也足够因为我们的环境规模很小。3.2 安装命令如果你用的是 pip可以按顺序执行pip install torch --index-url https://download.pytorch.org/whl/cpu pip install gymnasium numpy matplotlib tqdm如果你已经有自己的深度学习环境不用全部重装补齐 gymnasium 即可。这里不建议同时装 gym 与 gymnasium——新版库已经取代旧版命名和接口都做了调整同时安装容易导致 API 冲突。3.3 示例项目结构为了让你看得更清楚接下来我们的实战代码会按下面的结构组织mbrl_demo/ ├── models.py # 动力学模型定义 ├── data_buffer.py # 经验缓存 ├── planner.py # MPC 规划器 ├── train.py # 主训练脚本 └── utils.py # 辅助函数实际工程中你可以把模型、缓存、规划器拆得更细不过作为 Demo这样已经足够表达核心逻辑。4. 核心原理拆解模型学习的四个关键点4.1 学习目标与损失函数动力学模型最简单的形式就是一个神经网络[ \hat{s}{t1} f\theta(s_t, a_t) ]训练时每个样本包含一组三元组 ((s_t, a_t, s_{t1}))损失函数可以选择均方误差MSE或高斯负对数似然。MSE 适用于确定性模型而概率模型则更多采用高斯分布输出用对数似然作为损失。import torch import torch.nn as nn class DeterministicDynamicsModel(nn.Module): def __init__(self, state_dim, action_dim, hidden_dim256): super().__init__() self.net nn.Sequential( nn.Linear(state_dim action_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, state_dim) ) def forward(self, state, action): x torch.cat([state, action], dim-1) return self.net(x)这个模型输入当前状态和动作输出预测的下一状态。注意这里没有加 BatchNorm因为小规模 Demo 里网络不深Norm 反而可能引入额外调试复杂度。4.2 多步预测与复合误差单步模型训练好了不代表多步预测就准。我们把模型的预测值作为下一步输入循环多次后误差会累积这就是“复合误差”Compounding Error问题。假设位置状态预测误差是 (\epsilon)第 (H) 步预测误差在最坏情况下可能达到 (H \cdot \epsilon) 的数量级。所以课程里反复强调一个概念单步精度不等于轨迹精度。有几种缓解方案训练模型时多步展开让损失反向传播跨越多步在规划时限制规划视界 (H)不要预测得太远用集成模型估计预测方差避开不确定性大的区域使用 latent-space 模型在小维度表示里做预测。4.3 模型集成与不确定性很多时候单个网络不但预测不准而且我们根本不知道它哪些地方不准。于是工程上常见做法是训练多个动力学模型例如 5 个初始化不同的网络用它们的均值作为预测用它们的方差衡量不确定性。这个方法非常实用方差小说明多模型意见一致预测可信方差大说明该区域数据覆盖不足规划器应该减少在这里置信。class EnsembleDynamicsModel(nn.Module): def __init__(self, num_models, state_dim, action_dim, hidden_dim): super().__init__() self.models nn.ModuleList([ DeterministicDynamicsModel(state_dim, action_dim, hidden_dim) for _ in range(num_models) ]) def predict_mean_var(self, state, action): preds [model(state, action) for model in self.models] preds torch.stack(preds, dim0) mean preds.mean(dim0) var preds.var(dim0) return mean, var集成不仅带来不确定性估计在经验上还经常直接提升预测精度。因为不同初始化的模型会弱化某一个网络过拟合带来的偏差。4.4 模型在哪里使用Dyna、MPC 与 MBPO有了模型之后使用方法大致分三个方向Dyna 框架模型被当成“数据增强器”。真实经验放入缓存模型生成虚拟经验两者一起交给一个标准 Model-Free 算法训练。MPC 规划模型不用来训练策略而是直接在每次动作时搜索最优动作序列。适合控制类任务实时性要求高。MBPOModel-Based Policy Optimization在模型生成的短视界轨迹上用 Soft Actor-Critic 这类算法优化策略兼顾模型误差和策略多样性。这三个方向没有绝对优劣。Dyna 简单、通用但虚拟数据质量受模型影响MPC 适合在线控制但计算量偏大MBPO 更适合连续控制任务但实现复杂度更高。5. 完整实战案例一个可运行的 MBRL Demo这一节我们做一个完整 Demo在一个简单的一维连续控制任务上先用真实交互数据学习动力学模型再用 MPC 做在线控制。目标是让你直观看到“模型学习 规划决策”的闭环。5.1 任务描述我们构造一个非常简单的环境一个小车在一维轨道上目标是移动到目标位置。环境用 gymnasium 的 API 风格编写但内部逻辑自定义。状态是位置和速度动作是施加的力范围为 [-1, 1]转移关系如下[ v_{t1} v_t a_t \cdot dt ] [ x_{t1} x_t v_{t1} \cdot dt ]奖励设计为负的距离[ r -|x_{t1} - goal| ]为了让问题有动力学建模的价值我们加了轻微的摩擦系数使得转移关系不是完全线性叠加模型必须学到这个阻尼项。5.2 自定义环境import gymnasium as gym import numpy as np from gymnasium import spaces class SimpleCarEnv(gym.Env): def __init__(self, goal1.0, dt0.1, friction0.1): super().__init__() self.goal goal self.dt dt self.friction friction self.action_space spaces.Box(low-1.0, high1.0, shape(1,), dtypenp.float32) self.observation_space spaces.Box(low-10.0, high10.0, shape(2,), dtypenp.float32) self.state None self.reset() def reset(self, seedNone): super().reset(seedseed) # 初始化位置在左侧速度为 0 self.state np.array([-1.0, 0.0], dtypenp.float32) return self.state.copy(), {} def step(self, action): x, v self.state a np.clip(action, -1.0, 1.0)[0] # 动力学带摩擦 v_new v a * self.dt - self.friction * v * self.dt x_new x v_new * self.dt self.state np.array([x_new, v_new], dtypenp.float32) reward -abs(x_new - self.goal) terminated abs(x_new - self.goal) 0.05 truncated False return self.state.copy(), reward, terminated, truncated, {}这个环境虽然简单但已经包含连续状态、连续动作和明确的目标信号适合展示模型预测误差对控制效果的影响。5.3 经验缓存模型训练需要数据。我们用最简单的缓存结构class ReplayBuffer: def __init__(self, capacity10000): self.capacity capacity self.data [] def add(self, state, action, next_state): self.data.append((state, action, next_state)) if len(self.data) self.capacity: self.data.pop(0) def sample(self, batch_size): indices np.random.choice(len(self.data), batch_size, replaceFalse) states np.array([self.data[i][0] for i in indices], dtypenp.float32) actions np.array([self.data[i][1] for i in indices], dtypenp.float32) next_states np.array([self.data[i][2] for i in indices], dtypenp.float32) return states, actions, next_states def __len__(self): return len(self.data)5.4 训练动力学模型训练函数的核心逻辑是从缓存中采样一批数据把状态和动作拼接后输入模型用 MSE 对齐真实下一状态。import torch.optim as optim def train_dynamics_model(model, buffer, batch_size256, epochs100): optimizer optim.Adam(model.parameters(), lr1e-3) loss_fn nn.MSELoss() for epoch in range(epochs): states, actions, next_states buffer.sample(batch_size) states torch.from_numpy(states) actions torch.from_numpy(actions) next_states torch.from_numpy(next_states) pred_next_states model(states, actions) loss loss_fn(pred_next_states, next_states) optimizer.zero_grad() loss.backward() optimizer.step() if (epoch 1) % 20 0: print(fEpoch {epoch1}, Loss: {loss.item():.6f})这里没有做训练/验证集划分因为 Demo 数据量很小主要展示流程。工程中必须拆分数据集并监控验证误差。5.5 MPC 规划器MPC 的思路是在每一步执行前随机采样 (N) 条候选动作序列用模型向前推演 (H) 步选择累计收益最高的那一条执行第一步。class MPCPlanner: def __init__(self, model, action_dim, horizon10, num_candidates200): self.model model self.action_dim action_dim self.horizon horizon self.num_candidates num_candidates def plan(self, state): state_tensor torch.from_numpy(state).float().unsqueeze(0) best_return -float(inf) best_action None for _ in range(self.num_candidates): candidate_actions np.random.uniform(-1.0, 1.0, size(self.horizon, self.action_dim)) s state_tensor total_return 0.0 for t in range(self.horizon): a torch.from_numpy(candidate_actions[t]).float().unsqueeze(0) with torch.no_grad(): next_s self.model(s, a) # 奖励用目标位置计算 x_next next_s[0, 0].item() reward -abs(x_next - 1.0) total_return reward s next_s if total_return best_return: best_return total_return best_action candidate_actions[0] return best_action这种随机采样规划器非常朴素不依赖梯度信息但它体现了模型预测在决策中的作用。更高级的做法是使用交叉熵方法CEM或 iCEM逐步精化候选分布。5.6 主训练闭环接下来把整个流程串起来。我们采用“先随机探索收集数据再训练模型再用 MPC 控制并继续收集数据”的循环。def run_training(env, planner, buffer, model, outer_iters5, explore_steps200): for it in range(outer_iters): # 阶段一随机探索收集数据 state, _ env.reset() for _ in range(explore_steps): action env.action_space.sample() next_state, _, terminated, truncated, _ env.step(action) buffer.add(state, action, next_state) state next_state if not (terminated or truncated) else env.reset()[0] # 阶段二训练模型 print(f--- Iteration {it1}: training dynamics model ---) train_dynamics_model(model, buffer, epochs100) # 阶段三用 MPC 跑一个 episode观察效果 state, _ env.reset() total_reward 0.0 for step in range(100): action planner.plan(state) next_state, reward, terminated, truncated, _ env.step(action) # 真实交互数据仍然加入缓存 buffer.add(state, action, next_state) total_reward reward state next_state if terminated or truncated: break print(fIteration {it1} MPC episode reward: {total_reward:.3f})运行过程中你会发现前几轮模型不准MPC 做出来的动作很笨episode 总奖励很低。随着随机探索数据变多模型逐渐学到摩擦阻尼MPC 规划的轨迹开始能够精准靠近目标。5.7 运行与结果解释在 main 函数中执行if __name__ __main__: env SimpleCarEnv(goal1.0) model DeterministicDynamicsModel(state_dim2, action_dim1, hidden_dim64) planner MPCPlanner(model, action_dim1, horizon10, num_candidates200) buffer ReplayBuffer(capacity20000) run_training(env, planner, buffer, model, outer_iters5)预期输出是每一轮迭代训练损失逐渐下降MPC episode 的累计奖励从负的十几慢慢涨到负数很小甚至接近 0。说明小车已经能在 MPC 规划的引导下不断靠近目标。需要特别说明这是一个学习性质的 Demo候选动作数量只有 200规划性能有限。真实场景中你要调整 horizon 与 num_candidates 平衡计算量同时模型结构和训练轮数也需要按任务的动态范围调整。6. 基于模型的强化学习常见问题与排查思路6.1 模型训练 Loss 很低但 MPC 控制效果却很差这个现象非常经典多数刚上手 MBRL 的人都遇到过。原因通常不在“模型没学会”而在“模型不擅长预测规划视界内的长期轨迹”。问题现象常见原因解决思路Loss 已收敛控制仍然失败单步误差在多步 rollout 中被放大限制 MPC 的 horizon训练模型时加入多步展开损失模型在某些状态下预测漂移严重该区域数据覆盖不足增加探索使用多个模型估计不确定性并回避高方差区域MPC 计算量太大控制频率低候选序列数过多或网络过大减小 horizon使用 CEM 方法替代纯随机采样缩短 rollout初始探索阶段模型崩溃数据量太少模型过拟合先用随机策略跑更多步增大 buffer 容量增加模型训练 epoch加入虚拟数据后训练震荡虚拟数据质量差且被重复使用限制虚拟 rollout 长度对虚拟样本设置较低优先级周期性更新模型6.2 模型为什么不收敛原因可能很直接数据没有归一化。状态范围与动作范围差异较大时神经网络不容易拟合。建议对状态、动作和下一状态都做标准化处理。模型容量不够。动力学复杂程度超过网络表达力需要增大网络宽度或深度。训练数据是强相关的序列采样没有随机化。从 ReplayBuffer 中均匀采样可以有效打破时间相关性。没有做数据清洗。一些终止状态后的“下一状态”并不是有效的动力学过渡需要注意过滤。6.3 如何判断模型是否真的准不要只盯着单步 MSE。工程上常用两个指标多步预测误差给定同一个初始状态和动作序列让模型连续 rollout H 步与真实轨迹逐点对比。回报预测准确度在某个策略下用模型预测累计回报与实际累计回报的差距。这两个指标更贴近“模型到底能不能用”。6.4 训练 MPC 时输出动作抖动怎么办MPC 本身是一个滚动优化的过程每一步都会重新采样和重新规划因此连续两步输出的动作不一定平滑。解决办法通常在两个方向在规划目标中加入动作变化惩罚项让相邻动作差异尽量小。对当前动作取多次规划结果的平均或使用指数滑动平均平滑输出。实际机器人控制中抖动不仅降低任务质量还会加剧机械磨损平滑处理都是必要的。7. 基于模型的强化学习最佳实践与工程建议7.1 优先考虑数据归一化这一步在 MBRL 里比在普通监督学习中更关键。原因很好理解模型预测的下一状态会作为下一次预测的输入一旦某个特征的尺度不一致误差就会在状态空间中放大。建议提前统计每个特征的均值方差def normalize_state(state, mean, std): return (state - mean) / (std 1e-8)在训练和推理时都使用同一组统计数据不要滚动更新否则会造成模型输入分布漂移。7.2 集成模型是性价比很高的改进单个模型容易在实际使用中盲目自信。5 个模型的集成配合“方差大就降低置信度”的原则是很多 MBRL 论文与工业实现的基础设置。即使不做完整的概率推断只是把集成模型的均值当作预测通常也能缓解单个模型过拟合带来的决策突变。7.3 控制模型的使用范围不管算法多好都不要让模型在完全陌生的状态区域里做长视界规划。一个务实的做法是当规划器发现某条候选轨迹经过高不确定性区域时直接降低该轨迹的评分或者转交控制给一个保守策略。把“模型的不确定性”纳入决策过程是 MBRL 从 Demo 走向工程落地的关键一步。7.4 留出真实环境验证集MBRL 的闭环里有多个环节可能出错模型训练、规划器搜索、真实环境交互。为了快速定位问题建议预留一条只有少量真实轨迹的验证轨迹集。每训练完一轮模型在前面预留的真实轨迹上测试多步预测误差。一旦发现模型更新之后验证误差反而变大说明模型可能已经过拟合到最近的数据分布上需要及时回滚或重新调整训练策略。7.5 日志与版本管理强化学习实验本身成绩方差就大MBRL 又多了一个模型训练环节整个实验链路更容易“看起来莫名其妙”。建议记录以下信息每轮迭代的真实交互数据量模型单步与多步验证误差MPC 在真实环境的累计回报模型正则化系数与训练 epoch随机种子。有了这些日志你才能判断一次性能提升到底来自更多的数据、更准的模型还是规划器参数调整。8. 总结与学习路线这一讲我们从基于模型的强化学习核心问题出发讲清楚了它和 Model-Free 方法的区别、模型学习的数学目标、四类关键技术模块并用一个完整的一维控制任务展示了“学习动力学模型 MPC 在线规划”的整套流程。如果你之前一直在用 DQN 或 PPO现在应该能感受到MBRL 的样本效率优势来自对环境规律的显式利用但同时也要承受模型误差带来的风险。下一步你可以从这几个方向继续深入在连续控制任务上替换确定性模型为概率模型并引入集成不确定性估计阅读并复现 MBPO 算法理解“短视界模型 rollout 无模型策略优化”的组合方式尝试在 MuJoCo 或其他仿真环境中实现 Dyna 风格的算法观察模型虚拟样本比例对训练稳定性的影响系统学习 CEM、iCEM 等更高效的规划器替代本文中的纯随机采样。实际项目中我建议先把“模型预测误差”作为第一优先级指标。只要模型足够可信MPC 和 MBPO 都能顺理成章地提升效果反过来如果模型长期预测不准任何上层规划器都很难救回来。最后分享一条工程经验MBRL 不是某种固定算法而是一套“学习环境、利用环境”的框架。理解它最好的方式不是只看概念而是亲手把一个小任务跑通再逐步增加不确定性估计、多模型集成、短视界 rollout 这些工程技巧。如果你正在做机器人控制、仿真策略迁移或者高成本采样场景这套框架很值得花时间研究。