基于模型的强化学习连续动作实战:数据、CEM与MPC闭环

发布时间:2026/10/9 9:00:18

基于模型的强化学习连续动作实战:数据、CEM与MPC闭环 连续动作几乎是所有从分类任务转过来的强化学习新手的第一道坎。用 DQN 轻松解决 CartPole 之后我一度以为只要把网络输出换成连续值就行结果在 Pendulum 环境里转悠了两周都没把摆杆立起来。后来换到基于模型的强化学习这条路线用 Python 自建了一个小工具箱才把“从数据到连续动作”这条链路真正跑通。这是本系列的第三篇前面两篇分别聊了 MBRL 的基本思想和离散环境的快速 Demo。这一篇不准备堆理论公式而是把一整条实战链路拆开初始数据怎么采、环境模型怎么训练、CEM 规划器如何在连续动作空间里挑动作、MPC 闭环怎么稳住性能。如果你已经理解了基于模型强化学习的原理但没跑通过连续控制或者正在犹豫要不要自己造轮子这篇应该能帮你省下不少时间。动手前把环境准备好Python 3.10、PyTorch 2.x、Gymnasium、NumPy就够用了。1. 连续动作为什么难住了一批人问题定义与整套代码的边界1.1 从离散到连续不是换了个动作维度那么简单离散任务里决策等于“枚举比较”CartPole 这个时刻左转还是右转Q 值算一遍谁大选谁。连续任务里动作空间是稠密集合不存在一个天然的枚举表给你打分数。很多人卡在这里不是因为智能体学不会而是因为算法选错了路子。model-free 一派处理连续动作通常要靠策略梯度或演员-评论家这类偏“炼丹”的组件超参数稍微动一下训练曲线就给你看脸色。基于模型的强化学习在连续动作上天然友好先学一个环境响应模型也就是动力学模型再用这个模型做“离线试错”。奖励函数和环境步进都发生在模型里真实环境只负责收集新数据。这样“试错”的成本被压到极低——你可以在模拟器里模拟几百次尝试选出最像样的动作序列再真正执行一步。连续动作真正的难点有三个维数诅咒动作序列的长度乘以动作维度构成一个高维搜索空间。时序耦合当前动作好不好要看未来几步怎么走单步贪心往往原地打转。状态依赖同一个动作在不同状态下有完全不同的后果必须带着状态做条件化搜索。对应地这套工具箱的解决方案是“数据 模型 CEM 规划 MPC 闭环”。每个环节怎么设计下面逐个说。1.2 工具箱的边界宣言干什么、不干什么动手写代码前先把边界划清楚否则容易把自己绕进去。我自己维护的这个小工具箱名字就叫 mbrl_toolbox它只干一件事从环境里收数据训练环境动力学模型然后用模型做连续动作决策。它不负责深度策略网络的训练不负责把模型压缩成策略也不做环境仿真之外的任何可视化炫技。包含不包含随机策略数据收集DQN / PPO 等完整策略学习器集成动力学模型训练复杂的概率模型结构CEM / MPC 连续动作规划离散动作规划模型评估与数据回填环境建模的物理推导如果你以后想从“规划型”走到“策略型”即用训练好的模型蒸馏一个策略网络需要在这套工具箱外面再加一个策略头。但这一篇的重点就是“从数据到连续动作”这条最短闭环数据采集 → 模型拟合 → 规划器搜索连续动作 → 执行一步 → 数据回填 → 再训练模型。循环起来效果自己会长出来。2. 工具箱组件拆解从轨迹存储到动力学集成2.1 代码文件结构与每个模块的职责整个工具箱代码量在两千行上下全部按单一职责拆分。文件职责buffer.py轨迹存储、归一化参数统计dynamics.py集成动力学模型定义与训练cem.py交叉熵规划器mpc.pyMPC 闭环控制器evaluate.py模型评估与日志main.py端到端训练主循环buffer 和 dynamics 是整个管线的地基。这一节先把模型结构说清楚下一节再讲训练细节。这里先打一个预防针不要一上来就把工程做成大而全的框架先让“随机数据能训练出模型、模型加 CEM 能在 Pendulum 上动起来”这个最小闭环成立再去补文件结构。2.2 动力学模型为什么要预测“状态差分”而不是“下一状态”多数教材里的写法是 f(s_t, a_t) → s_{t1}直接回归下一状态。我在实际工程里从不这么干我让网络输出 delta s_{t1} - s_t。原因是连续控制系统的动力学大多是分段光滑的同一状态附近下一步的绝对位置可以差很远但“这一步带来的增量”往往是相对拟线性的小量。预测小增量比预测绝对量误差量级小得多训练也更好收敛。这就像你问一个司机“你下一秒在哪个坐标”他一脸懵但你问他“现在加速还是刹车”他能答得八九不离十。模型结构不复杂输入拼接 obs 和 act过两到三层 MLP输出一个均值和一个对数方差。均值是 delta 的预测方差用来表达模型对预测的不确定程度。import torch import torch.nn as nn class DynamicsModel(nn.Module): def __init__(self, obs_dim, act_dim, hidden256): super().__init__() self.net nn.Sequential( nn.Linear(obs_dim act_dim, hidden), nn.SiLU(), nn.Linear(hidden, hidden), nn.SiLU(), ) self.delta_head nn.Linear(hidden, obs_dim) self.logvar_head nn.Linear(hidden, obs_dim) def forward(self, obs, act): x torch.cat([obs, act], dim-1) h self.net(x) delta self.delta_head(h) logvar self.logvar_head(h) return delta, logvar2.3 归一化为什么用固定统计量不用 running stats模型输入是 obs 和 act输出是 delta 和 reward。obs 里角度、速度、加速度的量纲差距可能几十倍不归一化网络前几层会被大尺度特征绑架。归一化有两种做法running stats 和固定统计量。我在 MBRL 场景里用固定统计量。原因很直接数据缓冲区是逐步增长的running stats 会在每轮训练之间缓慢漂移模型学到的映射关系会跟着漂而 CEM 规划最怕模型本身不稳定。稳妥做法是每次重训模型前从当前 buffer 里重算一次 mean/std然后在整个训练过程中冻结。对 obs、act、delta 各统计一份reward 要不要归一化看范围Pendulum 的奖励固定在 -16 到 0 之间不做归一化也行。3. 训练一段可靠的环境模型数据准备、损失设计与常犯错误3.1 用“随机动作 噪声快照”采出第一桶数据MBRL 对初始数据的质量要求比你想的高。纯均匀随机采样会让动作停在边界区域的时间偏多分布不够均衡。我的做法是主体用均匀随机动作再叠加一个小的 OU 噪声快照让动作轨迹有时间相关性模拟真实控制中“平滑变化”的节奏。对 Pendulum 这种低维环境先采 10000 步就足够把状态空间覆盖得七七八八。不管怎么采数据都必须存成 (obs_t, act_t, obs_{t1}, reward_t, done_t) 的五元组。重训的时候从整个 buffer 里均匀抽样不要只抽最新的一段。我最开始犯的错就是直接按时间顺序滑窗抽结果模型把“最近的行为模式”背下来了换个状态完全不会泛化。3.2 训练集上的方差头与“一个 epoch 原则”集成模型的每个成员都单独训练损失函数用负对数似然让网络同时输出预测均值和方差方差会随着误差增大而调大误差减小而调小。规划器会把这种不确定性信息用起来而不是只拿一个冷冰冰的均值。训练轮次一定要克制。我的经验是每轮重训最多 1-3 个 epoch别按监督学习的思路跑几十个 epoch。MBRL 的数据是非平稳的模型的目标不是把历史 buffer 拟合到极致而是把当前规划区域拟合好。跑多了模型会对旧数据的局部细节过度自信一旦 CEM 顺着这条错的方向规划立刻穿帮。核心训练代码大致是import torch.optim as optim def train_model(model, buffer, epochs2, batch_size256): opt optim.Adam(model.parameters(), lr1e-3) model.train() for _ in range(epochs): for batch in buffer.sample(batch_size): obs, act, delta, rew batch delta_pred, logvar model(obs, act) inv_var torch.exp(-logvar) loss (0.5 * inv_var * (delta - delta_pred) ** 2 0.5 * logvar).mean() opt.zero_grad() loss.backward() opt.step()3.3 模型集成的作用不是锦上添花是保命集成动力学模型是 PETS 那套思路的核心遗产。具体做法是初始化 4 个结构相同、种子不同的网络各自独立训练。做规划时对某个候选动作序列随机挑 1 个成员做 rollout每个候选都这样做。为什么要随机挑而不是所有成员取平均因为取平均会把成员的认知不确定性抹掉规划器会以为模型非常自信。随机挑一个成员等于让每个候选序列暴露在“某个特定模型视角”下整体评估结果才能保留模型间的分歧。集成在数据稀缺阶段意义最大。数据量上来之后四个成员预测逐渐趋同分歧变小规划效果趋于稳定。到这个时候你才能真正感觉到“模型学会了”。4. 连续动作决策核心CEM规划器与MPC闭环的落地实现4.1 CEM的直观原理多做几次“抽样-筛选-集中”CEM交叉熵规划是个很有意思的思路把“找最优动作序列”当成“猜最优分布的参数”。开局先假设动作序列服从一个宽泛的正态分布均值为 0方差为 1然后反复做三件事从当前分布里抽一批候选序列、用动力学模型模拟并打分、把得分最高的那一批“精英”留下来重新计算均值和方差。迭代几轮后分布逐渐收敛到高分区域均值就是你要的动作序列。这个过程像组织一场选拔赛第一轮全国海选评委从几百人里挑出表现最好的三十个第二轮让这三十个人集中训练再按他们的特点微调“考核标准”几轮下来“什么样的动作序列能赢”这个画像就越来越清晰。4.2 参数设定与代码实现我给 Pendulum 的起点参数horizon25popsize300elites30iters5。这里的动作序列维度是 25×1300 份候选足够覆盖。动作空间归一化到 [-1, 1]所以初始 sigma1 是合理的。import numpy as np class CEMPlanner: def __init__(self, action_dim, horizon, popsize300, elites30, iters5, sigma_min0.1): self.action_dim action_dim self.horizon horizon self.popsize popsize self.elites elites self.iters iters self.sigma_min sigma_min def plan(self, obs, rollout_fn): mu np.zeros((self.horizon, self.action_dim)) sigma np.ones((self.horizon, self.action_dim)) for _ in range(self.iters): samples mu sigma * np.random.randn( self.popsize, self.horizon, self.action_dim) samples np.clip(samples, -1.0, 1.0) scores np.array([rollout_fn(obs, s) for s in samples]) elite_idx np.argsort(scores)[-self.elites:] elites samples[elite_idx] mu_new elites.mean(axis0) sigma elites.std(axis0) sigma np.clip(sigma, self.sigma_min, None) mu 0.7 * mu_new 0.3 * mu # 平滑更新防抖动 return mu[0]4.3 MPC闭环只取第一步动作然后不断重新规划如果直接把整个 25 步动作序列执行下去会死得很难看。原因有二模型误差会随 rollout 步数累积环境扰动会让真实轨迹偏离规划假设。所以要做 MPC每一控制周期只执行规划序列的第一个动作执行后用真实观测重新规划。这种“走一步看一步”的策略代价是需要每步都跑一遍 CEM但换来的是对模型误差的强鲁棒性。我建议把上一次规划得到的 mu 平移一位作为下一次规划的初值末位清零。这样 CEM 每一轮都从“上一轮的好解”附近出发而不是从零开始。sigma 初始值从 1 降到 0.5 更稳因为已经在好解附近没必要满太空撒网。4.4 评估候选序列时的细节rollout_fn 做的事是从当前 obs 出发把候选动作序列逐段送进动力学模型模拟出未来状态和累计奖励。这里有个容易被忽视的点——动力学模型输出的是 delta 和 logvar归一化是在特征空间做的rollout 时要把 delta 反归一化回原始状态空间再加到当前 obs 上。奖励如果也有预测头同样要反归一化。漏了这一步你会看到规划器给出各种离谱动作因为状态早已漂到模型没见过的区域。5. 端到端跑起来Pendulum 与 HalfCheetah 的实测对照5.1 Pendulum-v1一万步初始化几万步收敛Pendulum 是验证连续动作最合适的免费环境。目标很朴素从随机角度把摆杆立起来并稳住。动作是唯一扭矩范围 [-2, 2]。我的流程先随机采 10000 步训练 4 个集成模型然后进入主循环每个 episode 用 CEMMPC 控制整个 episode 长度 200 步执行数据追加进 buffer每新增 2000 步重训一次模型。实测在 6 到 8 万训练步左右得分稳定在 -220 到 -160 区间已经接近这个环境在常见强化学习算法下的中上水平。关键过程是前两万步数据开始包含“已经把摆杆顶起来的轨迹”模型才对高收益区域有了概念之后 CEM 才真正学会“先加速再刹车”的钟摆节奏。5.2 HalfCheetah动作维度一多CEM的性子全变了换到 HalfCheetah状态 17 维、动作 6 维规划序列长度取 30决策空间是 180 维。180 维的 CEM 还敢用吗敢但参数要认怂popsize 从 300 提到 800-1000iters 从 5 降到 3。维度一高每轮迭代用精英重估 sigma 的可靠性下降跑 5 次迭代很容易在低维假设下自嗨。另一个变化是重训频率要更敏感我按每 3000 步重训一次比 Pendulum 更频繁地“喂”新数据否则模型很快跟不上探索出的新行为。HalfCheetah 在不同发行版的奖励 scale 差别很大我不打算贴绝对值。更有意义的信息是曲线形态reward 从负值翻正的过程非常陡峭一旦模型在某个状态区域准确MPC 就能连续好几个 episode 复制出正向奖励轨迹于是缓冲区里正向数据迅速增多形成良性循环。反过来如果哪个环节归一化没做对这条陡峭曲线会直接消失变成一条死水。5.3 参数对照表与“先调哪个参数”的建议参数Pendulum-v1HalfCheetahhorizon2530popsize300800-1000elites30100-120iters53模型数量44重训间隔2000 步3000 步动作归一化[-1, 1][-1, 1]如果你刚上手我强烈建议先只调 popsize 和 iters。很多人一上来就改网络宽度、学习率、隐藏层数反而找不到方向。MBRL 这条管线里规划侧的参数通常比模型侧的参数更影响体验。6. 调试实录我在这套流程里栽过的五个坑6.1 动作没有归一化CEM采样出了“外星动作”现象模型 loss 不高但 MPC 执行时动作忽大忽小环境抖动得像帕金森。根因CEM 的初始 sigma1 是在 [-1,1] 假设下设计的如果直接把动作原始范围 [-2,2] 丢进 CEM采样出的序列大概率触边触边后动作被 env 内部 clip但模型输入看到的还是未 clip 的原始值。模型学的是被 clip 过的行为规划器用的是没 clip 的数值两边对不上。处理方式所有进模型的 action 一律先归一化到 [-1,1]CEM 也在这个空间跑最终执行时再映射回 [-2,2]。6.2 CEM方差坍塌规划器变成一个“一根筋”现象CEM 迭代到第三轮sigma 逼近 0.01所有候选序列几乎一模一样整个规划器退化成单点猜测。原因elite 比例过低或者 sigma 没设下限。当精英样本太少比如 300 个里只留 15 个分布更新对噪声极敏感很快收缩到局部。解决把 elite 数量控制在 popsize 的 10%-20%并且给 sigma 设一个下限我一般用 0.1。还有一个软化手段更新分布时做一次平滑mu 0.7 * mu_new 0.3 * mu_old减少每轮之间的剧烈跳变。6.3 数据漂移模型在“旧世界”很准“新世界”全靠编现象训练 loss 很低每个 candidate 打分都高但真到环境里执行前三步就崩了。这里的高分很可能是模型外推出来的幻觉奖励。根因是缓冲区几乎全是近期策略的行为模型对策略折腾出的新状态毫无概念它在没见过的地方给你一个乐观的“梦境分数”。处理办法有两个一是规划执行时加一点探索噪声我通常加 0.05 的均匀扰动让真实数据持续覆盖更宽状态空间二是在缓冲区里划定一块区域循环保留早期随机数据防止模型只见过一种行为模式。6.4 奖励模型学不动解析奖励有时是合法捷径Pendulum 的奖励可以通过状态直接算出来这类“奖励可解析”的环境完全没必要让模型学奖励。直接用真实解析奖励做 CEM 打分省掉一个容易出问题的头。但 HalfCheetah 这类奖励不可解析就得训练 reward head。这里有个反直觉的点reward head 的归一化比动力学 head 更容易出问题奖励分布往往非常不对称均值归一化后仍会偏。我的做法是对 reward 做 min-max 到 [0,1]保证 CEM 只在意相对排序不被绝对尺度干扰。6.5 重训频率不是越频繁越好慢变量才能稳住我最早用每 500 步重训模型结果训练曲线像心电图上蹿下跳。改成每 2000-3000 步后稳定了很多。原因是MBRL 是“慢变量”系统模型的进化节奏应该匹配数据分布的进化节奏。重训太频繁模型刚适应上一批数据数据又变了等于在移动靶上反复开枪每个靶都没练稳。把重训频率当成和 popsize 一样的超参数来对待效果立竿见影。如果你正准备动手把这条链路跑通我把这几轮实战浓缩成一句先跑通 Pendulum 的十行最小闭环再谈 HalfCheetah 上的花活。MBRL 的坑绝大多数藏在数据归一化、CEM 坍塌、重训节奏这三个地方工具本身不复杂复杂的是让每个环节的节奏对得上。我自己的 mbrl_toolbox 后来被朋友拿去试过 Walker 等环境改动最多的不是网络结构而是规划器的采样数和频率参数。希望这篇实战笔记能帮你少走几周弯路。
延伸阅读

更多相关文章

2026/10/9 9:00:18

C++编译器扩展如何影响跨平台代码兼容性

1. 编译器扩展到底是什么,为什么绕不开先说个我自己的真实经历。早年在 Linux 上用 GCC 写一个网络中间件,代码里用了一个 GNU 扩展语法__attribute__((packed))去定义网络协议头结构体,在 GCC 下编译、运行、压测都好好的。后来客户要求把模…

2026/10/9 9:00:18

综合均等化差异指数:从平均数陷阱到多维度资源均衡评估

年初的时候,我被领导塞了一个活儿:评估集团下属12家分公司在资源配置上到底“公不公平”。我一开始的想法很简单,把人均费用、人均培训时长、设备覆盖率这几个指标拉出来,算个平均数,排个名,谁低谁就是重点…

2026/10/9 9:00:18

Agent-Reach:智能体从能聊到能干的四层链路与工具调用实践

做 AI Agent 项目的人应该都有同感:模型智商早就不是瓶颈了,真正卡住我们的是 Agent-Reach——智能体到底能不能“够得着”真实的业务系统、数据库和外部工具。上个季度我接手了一个内部助手项目,模型选得再强,一到调考勤接口、写…

2026/10/9 10:01:00

开源项目“代码泥潭”生存指南:从选型到排查的实战避坑手册

开源项目这事儿,真得是“没进去之前是围城,进去之后是泥潭”。我在技术圈摸爬滚打了十几年,从最初只会在 GitHub 上点 Star、看热闹,到后来正儿八经把开源项目集成到生产环境,再到自己也维护过几个不上不下的小项目&am…

2026/10/9 10:01:00

三级医院信息化智能化弱电方案深度解析:从综合布线到三网隔离

简介:面向新三级医院信息化与智能化建设,这份PPT解决方案系统梳理了门诊、医技、病房楼等核心场景的弱电智能化设计要点,适合医院信息科、弱电总包、智能化咨询人员及新院区建设管理者参考使用。内容以基础设施建设为主线,逐项展开…

2026/10/9 9:56:00

k-means-LSTM组合预测:多输入多输出时序建模实战

简介:本资源是一份面向具备Python编程与机器学习基础的研发人员、数据科学家及进阶学习者的时间序列预测实战项目,聚焦k均值聚类与LSTM深度结合的多输入多输出组合建模方法,有效提升能源管理、气象预测、金融分析等场景下的预测精度与鲁棒性。…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/8 10:03:20

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 0:04:27

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略当数万字的学位论文初稿经历开题、实验、问卷与多轮文献梳理最终成形时,绝大多数研究生都会面临一道全新的形式审查关卡:AIGC 疑似度排查。在高校毕业审核流程中,盲审前的文本检测通…

2026/10/9 0:04:27

食堂节能改造源头工厂,商用厨房设备焕新方案广受好评

商用厨房作为餐饮经营、单位供餐的核心后勤阵地,其设备配置、动线规划与运维体系直接决定后厨作业效率、运营成本与合规性。从基础的灶具、制冷存储设备,到油烟净化、水处理等配套系统,每一个环节的合理性都与食品安全、能耗管控、消防安全挂…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑