跳转至

第 4 章 CEM 家族与采样式 MPC 的统一视角——从一族算法到一个框架

📋 前置自测

答不出 ≥ 2 题,先回第 1 章(自由能–KL、重要性采样、零方差提议)、第 2 章(MPPI 主循环、ESS、样本效率主线)与第 3 章(六变体、提议分布的五个侧面),再读本章。

  1. 第 2 章 MPPI 的权重是 \(w_i \propto \exp(-J_i/\lambda)\)——这个指数加权是怎么从自由能–KL 推导里冒出来的?温度 \(\lambda\) 调大调小分别意味着什么?
  2. 第 3 章反复出现一条主线:"六变体各改提议分布的一个侧面"。其中"位置"和"协方差形状"分别由哪些变体改?vanilla MPPI 的协方差是什么形状(各向同性还是贴合地形)?
  3. 第 1 章的零方差理想说:最优提议分布就是目标分布 \(\mathbb{P}^\star \propto \mathbb{Q}\,e^{-S/\lambda}\)。如果能直接从它采样,需要撒很多样本吗?为什么现实中做不到?
  4. 第 2 章里 MPPI 是"一步闭式"(采样→加权平均,不迭代)。这个"不迭代"是它快的原因,但也放弃了什么?(提示:对比需要反复"采样—评估—更新"的方法)
  5. 交叉熵方法(Cross-Entropy Method, CEM)你可能在别处见过——它每轮保留一批"精英样本"、用精英拟合新分布。直觉上,它和 MPPI 的指数加权有什么相同、什么不同?

参考答案要点(自评用,不必逐字对照):(1) 指数加权来自最优分布 \(\mathbb{P}^\star \propto \mathbb{Q}e^{-S/\lambda}\) 对提议分布的重要性权重;\(\lambda\) 大→权重平、更多样本被纳入平均(偏探索)、\(\lambda\) 小→权重尖、集中到少数低代价样本(偏利用,极端时退化为贪婪)。

(2) 位置由 warm-start(第 2 章)改,协方差形状由 SVG-MPPI/U-MPPI 部分改;vanilla MPPI 用**各向同性**高斯(对地形一无所知)。

(3) 不需要——从目标分布直接采样是零方差的理想;做不到是因为 \(\mathbb{P}^\star\) 含归一化常数与 \(e^{-S/\lambda}\),无法直接采样,只能用提议分布近似。

(4) "不迭代"放弃了**逐轮精炼分布**的能力——一步到位意味着没有机会在同一周期内反复改进提议分布。

(5) 相同:都用"代价低的样本更重要"来更新分布;不同:MPPI 用**连续的指数权重**(所有样本都参与,按 \(e^{-J/\lambda}\) 加权),CEM 用**硬阈值**(只保留代价最低的前若干个精英、其余权重为零)。这道题的答案正是本章 §4.1 的核心。

符号说明:本章为与 CEM/优化文献记号对齐,用 \(J_i\) 记第 \(i\) 条 rollout 的总代价,等价于第 1–3 章的 \(S_k\)


本章目标

学完本章后,你应该能够:

  1. 说清 CEM(交叉熵方法)与 MPPI 的数学关系——"硬阈值精英"与"指数加权"如何是同一个分布更新问题的两种权重函数;
  2. 掌握 iCEM 的四大改进(有色噪声、elite memory、shift init、mean-as-sample),并理解每一项各自解决了 CEM 的什么低效;
  3. 理解 Tsallis VI-MPC 的统一框架——变形指数 \(\exp_r\) 的参数如何在 MPPI(\(r\to 1\))和 CEM(\(r\to\infty\))之间**连续插值**,从而把 MPPI/CEM/SV-MPC 收成一族的特例;
  4. 理解 Predictive Sampling(MJPC) 的极简设计为何意外地有竞争力,以及它在统一框架里对应什么;
  5. 掌握 Nav2 MPPI Controller 的 critic 插件架构,能读懂其主循环与 critic 分工、并动手写一个自定义 critic(含 C++ 示例、插件注册、YAML 配置);
  6. 理解 CoVO-MPC 的收敛性证明核心——为什么"采样分布的形状(协方差)比采样数目更重要",以及最优协方差为何由代价的 Hessian 决定。

本章知识导航

第 3 章把六个变体统一成"提议分布的五个侧面",但那仍是"一个侧面一处改进"的**局部增强**视角。本章换一个更高的视角:不再逐个打磨某个侧面,而是问一个更根本的问题——这一族采样式 MPC 算法(MPPI、CEM、SV-MPC……)背后,是不是同一个数学框架? 答案是肯定的,而看清这个框架,会让你对"该怎么设计一个采样式控制器"有全局性的理解。

本章的逻辑链是这样展开的:

主题 在全局框架里的位置
§4.1 CEM 与 MPPI 的关系 揭示两个看似不同的算法共享同一个"分布更新"骨架,只是**权重函数**不同
§4.2 iCEM 四大改进 CEM 为何慢、如何让它快到能实时——把 CEM 拉回采样式 MPC 的竞技场
§4.3 Tsallis 统一框架 用一个参数 \(r\) 把 MPPI、CEM、SV-MPC **连续地**统一为一族的特例
§4.4 Predictive Sampling 极简到只取 argmin 的采样器为何有效——统一框架的一个极端点
§4.5 Nav2 MPPI Controller 把统一视角落到生产级 ROS2 代码:critic 插件架构如何让"换代价"变成"换插件"
§4.6 CoVO-MPC 收敛性 十年来第一个 MPPI 收敛证明,以及它带来的洞察:形状比数目更重要

一条贯穿全章的主线:如果把采样式 MPC 看成"用提议分布近似目标分布 \(\mathbb{P}^\star\)",那么所有这些算法的差异,都可以归结为三个设计选择——用什么权重函数(§4.1、§4.3)、用什么噪声(§4.2)、用什么协方差(§4.6)。 第 3 章的"五侧面"是这个框架的局部体现;本章把框架本身讲清楚。

前置知识桥接

本章重度依赖前三章,先把要用到的关键点温习一遍(细节回各章):

  • 自由能–KL 与指数加权(第 1 章):MPPI 的 \(w_i\propto e^{-J_i/\lambda}\) 不是拍脑袋的,而是最优分布 \(\mathbb{P}^\star\propto\mathbb{Q}e^{-S/\lambda}\) 推导的必然结果。本章 §4.1、§4.3 会反复用到"权重函数从何而来"。
  • MPPI 主循环与一步闭式(第 2 章):采样 \(K\) 条 rollout → 算代价 → 指数加权平均 → 得到新均值。关键词"一步闭式、不迭代"——CEM 恰恰相反,它要迭代多轮,这是 §4.1/§4.2 的对比基础。
  • ESS 与样本效率主线(第 2 章):有效样本数衡量"撒出去的样本有多少真正有用"。iCEM(§4.2)和 CoVO-MPC(§4.6)本质都在提升样本效率,只是手段不同(一个改噪声、一个改协方差)。
  • 提议分布的五个侧面(第 3 章):位置、时间结构、尾部、模态、不确定性刻画。本章 §4.2 的有色噪声对应"时间结构",§4.6 的最优协方差对应"协方差形状"——它们都是第 3 章侧面观点的延续与深化。
  • 各向同性高斯的局限(第 3 章):vanilla MPPI 用一个对地形一无所知的圆形协方差。§4.6 的 CoVO-MPC 正是要回答"协方差到底该长什么样"——这是第 3 章留下的、当时未能深入的问题。

如果上面某一条想不起来了,对应章节会帮你补上;但建议至少把第 1 章的指数加权和第 2 章的 MPPI 主循环弄清楚再往下读,因为本章几乎每一节都建立在它们之上。

如果跳过本章会怎样

设想两个场景,它们会让你感到"少了一块拼图":

场景一:你在论文里读到"我们的方法可以看作 MPPI 在 \(q\to 1\) 时的特例",却不知道这句话什么意思。 近年大量采样式控制论文都在用"统一框架"的语言(Tsallis、VI-SOC、q-指数)来定位自己的工作。

不理解 §4.1/§4.3 的统一视角,你会把每篇论文都当成孤立的新算法,记不住、也看不出它们之间的关系;理解了,你能一句话归类任何新方法——"它不过是在这个框架里换了个权重函数 / 协方差 / 噪声"。

场景二:你的 MPPI 在某个任务上调了很久协方差都不理想,凭直觉乱试。 第 3 章告诉你 vanilla MPPI 的各向同性协方差是个短板,但没说"那到底该用什么协方差"。

§4.6 的 CoVO-MPC 给了答案——协方差应由代价的 Hessian 决定(凸方向小方差、平方向大方差),而且这是有**收敛性证明**支撑的。不知道这一点,你只能手调协方差、碰运气;知道了,你有了一个原则性的设计依据。

一句话:第 3 章教你"有哪些变体、各修什么缺陷",本章教你"这一族算法背后是什么、协方差到底该怎么设、新方法该怎么归类"。前者是工具箱,后者是把工具箱串起来的那张图。

预计阅读时间

  • 精读(推导 + 代码 + 自己跑 demo):约 4–6 小时。§4.1(CEM-MPPI 关系)和 §4.6(CoVO-MPC 收敛)是理论核心,值得慢读;§4.5(Nav2)是工程落地,可对着真实代码库读。
  • 速读(抓主线、跳过部分推导):约 2 小时。重点读 §4.1 的权重函数对比、§4.3 的统一表、§4.6 的"形状比数目更重要"。
  • 速查(按需查阅):iCEM 四大改进看 §4.2 的表;Nav2 critic 写法看 §4.5 的 C++ 示例;CoVO-MPC 协方差公式看 §4.6。

科研发展脉络

本章涉及的工作不像第 3 章那样集中由一个组推动,而是多个团队从不同角度逼近"统一"这件事——有人从交叉熵方法的工程优化切入(iCEM),有人从变分推断的理论统一切入(Tsallis),有人从极简主义切入(Predictive Sampling),有人从收敛性证明切入(CoVO-MPC):

年份 工作 Venue 修哪个问题 核心贡献
2020 Pinneri 等, Sample-efficient CEM for Real-time Planning(iCEM) CoRL CEM 太慢 iCEM:有色噪声 + elite memory 等四项改进,样本效率提升 2.7–22×
2020 Lambert 等, Stein Variational MPC(SV-MPC) CoRL 单模态 SV-MPC:用 SVGD 粒子集表示多模态后验(第 3 章 §3.4 已对比)
2021 Wang, So, Theodorou 等, VI-MPC using Tsallis Divergence RSS 缺统一框架 Tsallis VI-MPC:变形指数 \(\exp_r\) 把 MPPI/CEM/SV-MPC 统一为特例
2022 Howell 等, Predictive Sampling(MJPC) arXiv 过度复杂 Predictive Sampling:最简采样器(取 argmin)竟有强竞争力
2023 Macenski 等, Nav2 MPPI Controller ROSCon 缺生产级实现 Nav2 MPPI:ROS2 生产级、critic 插件架构、i5 上 50+ Hz
2024 Yi, Pan 等, CoVO-MPC L4DC 缺收敛理论 CoVO-MPC:MPPI 首个收敛性证明 + 最优协方差设计

这条脉络的内在逻辑可以这样读:2020 年前后,CEM 和 MPPI 是采样式 MPC 的两大主力,但 CEM 太慢(iCEM 来救)、MPPI 又被诟病缺乏理论。2021 年 Tsallis VI-MPC 第一次从理论上说清"它们其实是一族"。

2022 年 Predictive Sampling 反其道而行,证明"极简也能work",给这个框架补了一个极端点。2023 年 Nav2 把这套东西做成了生产级代码。

2024 年 CoVO-MPC 终于补上了最关键的一块——收敛性证明,并由此回答了"协方差该怎么设"这个十年悬而未决的问题。

一个值得留意的趋势:越往后,研究越关心"为什么 work"而非"又一个新 trick"。第 3 章的变体多是"针对某缺陷的工程改进",而本章的工作(尤其 Tsallis 和 CoVO-MPC)开始追问框架性、理论性的问题——这标志着采样式 MPC 从"经验驱动"走向"理论 + 经验并重"的成熟期。本章带你走完这一段。


§4.1 CEM 与 MPPI:同一个分布更新,两种权重函数 ⭐⭐⭐

动机:两个"看起来很不一样"的算法,真的不一样吗?

如果你分别学过 MPPI 和 CEM(交叉熵方法),第一印象多半是"两个不同的算法"。MPPI 来自路径积分控制和自由能(第 1、2 章),一身的物理与信息论味道;CEM 来自稀有事件估计与优化,讲的是"精英样本""分布拟合"。它们的更新规则**长得也不一样**:

  • MPPI:撒一批样本,每个样本按 \(w_i\propto e^{-J_i/\lambda}\) 加权,所有样本**都参与**加权平均得到新均值。
  • CEM:撒一批样本,只挑出代价最低的前若干个("精英",elite),用这些精英拟合一个新的高斯(求均值和方差),其余样本直接扔掉

一个用连续的指数权重、人人有份;一个用硬阈值、非精英即弃。看起来是两套不同的哲学。但本节要论证的是:它们其实是同一个"分布更新"问题的两种权重函数——把这件事看穿,你不仅能在两者之间自如切换,更重要的是,你拿到了理解本章后续所有统一框架(Tsallis、CoVO)的钥匙。

为什么这个"看穿"重要?因为采样式 MPC 的论文世界里,MPPI 和 CEM 常被当成两条独立的技术路线分别发展、各有一堆变体。

如果你把它们看成两个东西,就要记两套理论、两套调参经验;如果你看出它们同根,就只需理解"一个分布更新骨架 + 可替换的权重函数",所有变体都成了这个骨架上换权重的结果。这正是 §4.3 Tsallis 框架要正式完成的统一——而 §4.1 是它的直觉版预演。

如果不这样做会怎样:把它们当成两个孤立算法的代价

设想你不接受"它们同根",坚持把 MPPI 和 CEM 当成两个互不相干的算法。会发生什么?

第一,记忆负担翻倍。MPPI 有它的温度 \(\lambda\)、它的变体(第 3 章六个);CEM 有它的精英比例、它的变体(iCEM 等)。你得分别记两套"什么时候用、怎么调"。

而实际上,\(\lambda\) 和精英比例**控制的是同一件事**——分布更新有多"贪婪"(多聚焦于最优样本)。看不出这一点,你会把两个等价的旋钮当成两个不同的知识点。

第二,迁移经验失败。你在 MPPI 上积累的"\(\lambda\) 调小会过早收敛、ESS 会崩"的经验,本该能直接迁移到 CEM 的"精英比例取太小会过早收敛"——因为它们是同一个现象。但若你视二者为孤立算法,这份宝贵的经验就迁移不过去,每个算法都要重新踩一遍坑。

第三,看不懂统一框架的论文。当 Tsallis VI-MPC(§4.3)说"MPPI 和 CEM 都是我的特例",或 CoVO-MPC(§4.6)的收敛分析同时覆盖两者时,你会一头雾水——因为你脑子里它们是两个东西,凭什么被一个框架统一?反过来,先理解 §4.1 的"同根",后面这些统一框架就是水到渠成。

所以"看穿它们同根"不是一个 nice-to-have 的洞察,而是理解整章的地基。下面就来看这个地基怎么搭。

理论:分布更新的统一骨架

先把两个算法都**改写成同一个三步骨架**,你会发现它们只在第二步不同。

考虑用一个高斯提议分布 \(q(\cdot)=\mathcal{N}(\mu, \Sigma)\) 去逼近目标分布 \(\mathbb{P}^\star\)(回忆第 1 章:\(\mathbb{P}^\star\propto\mathbb{Q}e^{-S/\lambda}\),代价越低概率越高)。每一轮迭代做三步:

这里先回答一个你可能会有的疑问:为什么用**高斯**作提议分布?为什么不用别的分布?高斯之所以是采样式 MPC 的默认选择,有几个实在的理由。

其一,采样便宜——从高斯采样是计算机最擅长的操作之一(标准库一行代码、极快),而采样式方法每周期要撒几千个样本,提议分布必须能高效采样。

其二,参数少且直观——高斯由均值 \(\mu\) 和协方差 \(\Sigma\) 完全确定,"中心在哪、撒多开"两个直观的量就够了,更新时只需更新这两个量。

其三,最大熵性质——在给定均值和协方差的所有分布里,高斯是熵最大(最"无偏")的,所以在"只知道一阶二阶矩"时,高斯是最不引入额外假设的选择。

其四,矩匹配方便——用样本估计高斯参数(算加权均值和协方差)有简单的闭式公式,正是三步骨架的更新步要做的。

这四点让高斯成为采样式 MPC 的天然选择。但要记住——这也是本章结尾要点出的关键局限——高斯的表达能力有限:它是单峰的、对称的、形状受限。当真实的最优控制分布是多峰的(第 3 章 §3.4 的多条等优路径)、或有复杂结构时,高斯就力不从心了。

本章所有方法(MPPI/CEM/iCEM/Tsallis/CoVO)都用高斯(或高斯混合)作提议分布,所以它们都受这个表达能力天花板的限制——而这正是第 5 章用扩散模型突破的地方。

所以高斯是个"便宜好用但表达力有限"的选择:它让采样式 MPC 高效可行,但也设下了天花板。理解了"为什么用高斯"和"高斯的局限",你就同时理解了本章方法的基础和它们共同的边界。

考虑用上述高斯提议分布 \(q\) 去逼近目标分布 \(\mathbb{P}^\star\),每一轮迭代做三步:

  1. 采样:从当前 \(q\)\(K\) 个样本 \(U_1,\dots,U_K\),算各自代价 \(J_1,\dots,J_K\)
  2. 赋权:给每个样本一个权重 \(w_i = g(J_i)\),其中 \(g(\cdot)\) 是一个**单调不增**的"权重函数"(代价越低、权重越大)。
  3. 更新:用加权样本更新分布:\(\mu \leftarrow \sum_i w_i U_i \,/\, \sum_i w_i\)(方差同理用加权样本估计)。

这个"采样—赋权—更新"的迭代结构,和机器学习里的 **EM 算法(期望最大化)**有相通之处,点出来能帮你把它接入已有知识。EM 算法交替做两步:E 步根据当前参数估计隐变量的"责任"(软分配),M 步用这些加权的责任重新估计参数。

对照采样式 MPC 的骨架:赋权步(算 \(w_i\))像 E 步——根据当前分布和代价给每个样本一个"重要性";更新步(用加权样本重估 \(\mu,\Sigma\))像 M 步——用加权数据重新拟合分布参数。

尤其 CEM 用高斯拟合精英样本,几乎就是在做"用一批(硬选的)数据做最大似然估计高斯参数",这正是 M 步的典型形式。

这个相通不是表面的——它们背后都是"用当前模型给数据赋权、再用加权数据更新模型"的迭代逼近思想。标注边界:EM 是为最大化似然(拟合数据分布)设计的、有单调收敛保证;采样式 MPC 是为优化(找最优控制)设计的、且每轮重新采样(EM 通常用固定数据集)。

但"加权—重估"的交替结构是共享的。认出这个联系,你对采样式 MPC 的更新步就不陌生了——它是 EM 式"加权重估"思想在控制优化里的应用。

这也从另一个角度印证 MPPI/CEM 的同根:它们都是这个 EM 式迭代结构的实例,只是赋权(E 步)的方式不同(软 vs 硬)。

第 1 步和第 3 步,MPPI 和 CEM 完全一样。差别**只在第 2 步的权重函数 \(g\)**:

\[ \text{MPPI:}\quad g_{\text{MPPI}}(J) = e^{-J/\lambda}, \qquad\qquad \text{CEM:}\quad g_{\text{CEM}}(J) = \mathbb{1}\{J \le J_{\text{elite}}\}. \]

MPPI 的权重函数是一条**光滑衰减的指数曲线**——代价越高、权重越小,但永远不为零(人人有份,只是份额不同)。

CEM 的权重函数是一个**硬阶跃(Heaviside 阶跃函数)**——代价低于精英门槛 \(J_{\text{elite}}\) 的样本权重为 \(1\)(等权),高于门槛的权重为 \(0\)(直接扔掉)。

把这两条权重曲线画在同一张"代价 → 权重"图上,一切就清楚了:MPPI 是一条平滑下降的曲线,CEM 是一个方块台阶。

它们都满足"代价越低、权重越高"这个核心要求,只是一个用**软**的方式(连续过渡)、一个用**硬**的方式(非黑即白)实现这件事。

读到这里你可能会问:第 1 章不是说最优提议分布就是目标分布 \(\mathbb{P}^\star\propto\mathbb{Q}e^{-S/\lambda}\) 吗?那为什么还要这么费劲地用权重函数一步步逼近,不直接从 \(\mathbb{P}^\star\) 采样?这是个好问题,答案直指采样式 MPC 的根本困难。

\(\mathbb{P}^\star\) 虽然有解析表达式,但你**无法直接从它采样**——它含有一个归一化常数(配分函数)需要对整个控制空间积分才能算出,而这个积分在高维、非线性代价下根本算不出来。这正是第 1 章"零方差理想做不到"的原因。

于是采样式 MPC 退而求其次:用一个**能采样的**简单分布(高斯)当提议分布,撒样本后用权重函数去"模拟"从 \(\mathbb{P}^\star\) 采样的效果——权重 \(e^{-J/\lambda}\) 恰好是 \(\mathbb{P}^\star\) 相对提议分布的重要性权重(第 1 章重要性采样)。

所以 MPPI 和 CEM 的权重函数,本质都是在回答同一个问题:"既然不能直接从 \(\mathbb{P}^\star\) 采样,那怎么用能采样的高斯 + 权重去逼近它?"——MPPI 用指数权重逼近、CEM 用硬阈值逼近。

理解了这一点,你就明白权重函数不是任意设计的,而是"逼近不可直接采样的目标分布"这个根本任务的不同近似策略。所以:

本质洞察:MPPI 和 CEM 不是两个算法,而是同一个"采样—赋权—更新"分布迭代骨架上的两种**权重函数**——MPPI 用指数软加权,CEM 用阈值硬筛选。第 1 章的零方差理想说"最优提议就是目标分布本身",而这两个算法都是在用各自的权重函数、一步步把提议分布往目标分布上推。理解了这一点,"MPPI vs CEM 哪个好"就不再是一个二选一的问题,而变成"我的任务需要多硬的筛选"——这恰好是一个**连续**的选择(§4.3 的 Tsallis 框架会把这条连续谱明确画出来)。

这个统一还揭示了一个漂亮的对应:MPPI 的温度 \(\lambda\) 和 CEM 的精英比例,控制的是同一件事——筛选有多"贪婪"

  • MPPI 里 \(\lambda\) 越小,指数曲线越陡,权重越集中到极少数最低代价样本——越贪婪、越像 CEM 取很小的精英比例。极限 \(\lambda\to 0\) 时,只有全局最优样本权重非零,退化为"只取最好的一个"(贪婪)。
  • MPPI 里 \(\lambda\) 越大,指数曲线越平,所有样本权重趋于相等——越保守、越"民主"。极限 \(\lambda\to\infty\) 时所有样本等权,新均值就是样本均值(完全不利用代价信息)。
  • CEM 里精英比例**越小**(如只取前 5%),越像 \(\lambda\) 很小的 MPPI(聚焦最优);精英比例**越大**(如取前 80%),越像 \(\lambda\) 很大的 MPPI(接近均值)。

可以看到,\(\lambda\) 和精英比例是**同一个"探索-利用"旋钮**的两种刻度。把它跑出来看:

def cem(elite_frac):                              # 硬阈值: 取代价最低的前 elite_frac
    # ... 采样 → 取 elite → 用 elite 求均值方差 ...
    elite_idx = np.argsort(J)[:int(elite_frac*K)]
    mu = U[elite_idx].mean(0)
def mppi(lam):                                    # 指数加权: 所有样本按 exp(-J/λ)
    w = np.exp(-(J - J.min())/lam); w /= w.sum()
    mu = (w[:,None]*U).sum(0)

同一个到达任务(目标 \(=3.0\))跑 10 轮,最终代价:

CEM (elite_frac=0.1, 硬阈值聚焦): 38.76
CEM (elite_frac=0.5, 精英过半):  54.82   ← 精英太多 = 不够聚焦, 变差
MPPI(λ=1.0, 指数加权):           21.89
MPPI(λ=10,  权重更平):           47.82   ← λ大 = 不够聚焦, 变差
MPPI(λ=0.1, 权重更尖≈贪婪):      17.86   ← λ小 = 更聚焦, 更好(本任务单峰故贪婪有利)

数字印证了上面的对应:CEM 精英比例从 \(0.1\) 增到 \(0.5\)(更不聚焦)代价变差,正如 MPPI 温度从 \(1\) 增到 \(10\)(更不聚焦)代价变差——两个旋钮往"不聚焦"方向拧,效果一致地退化。

而 MPPI 温度拧到很小(\(0.1\),趋近贪婪)在这个**单峰**任务上反而最好,因为单峰问题没有"被一个坏峰吸住"的风险,越聚焦越快。

(注意:这只在单峰任务成立——多峰任务里过度聚焦会错失更优的峰,这正是第 3 章 §3.4 SVG-MPPI 处理的问题。)

顺带从这段代码里挑一个容易忽略却很重要的实现细节讲清——你注意到 MPPI 的权重写的是 exp(-(J - J.min())/lam) 而非直接 exp(-J/lam) 吗?那个减去 J.min() 不是可有可无的,它是**数值稳定**的关键。

原因在于 exp 函数对大的负指数极其敏感:如果代价 \(J\) 的数值很大(比如几千),exp(-3000/1.0) 会下溢成 \(0\)(浮点数表示不了这么小的数),结果所有样本权重都变成 \(0\)、归一化时除以零、整个计算崩溃为 NaN。

减去最小代价 J.min() 后,最小代价的样本指数变成 exp(0)=1、其余样本是 exp(负数),既避免了下溢、又不改变归一化后的相对权重(因为分子分母同乘了 exp(J.min()/lam),约掉了)。

这是 softmax 计算的标准技巧(深度学习里 softmax 也这么做,减去最大 logit),在 MPPI 里同样不可或缺。

为什么特意点它?因为这是 MPPI 实现里最常见的隐藏 bug 之一——新手直接写 exp(-J/lam),在代价尺度小的玩具任务上能跑,一到真实任务(代价数值大)就莫名其妙全是 NaN,还很难定位。记住:任何指数加权,都要先减去最小(或最大)值再取指数

这个细节也呼应 §4.1 陷阱里 CEM 的数值问题——采样式方法的实现里,数值稳定性是个反复出现、不能掉以轻心的主题。

CEM 与 MPPI 的取舍:硬筛选 vs 软加权各自的脾气

既然只是权重函数不同,那它们各自的"脾气"也就源于权重函数的形状。理解这些脾气,才能在实际中选对:

硬阈值(CEM)的脾气。优点是**直观、无需调温度**——你只需说"保留前 10%",不必像 MPPI 那样纠结 \(\lambda\) 取多少(\(\lambda\) 的合适值依赖代价的数值尺度,换个任务就要重调,是 MPPI 调参的一大痛点)。

缺点是**信息利用粗糙**:精英内部不分高下(都等权),精英门槛外的样本哪怕只差一点点也彻底扔掉——这在"次优样本其实也含有用方向信息"时是浪费。

另一个隐患是 CEM 对精英比例敏感:取太小,用极少数样本估计均值方差,方差估计噪声大、易过早坍缩(§4.1 陷阱里详述)。

指数软加权(MPPI)的脾气。优点是**信息利用充分**:所有样本按代价平滑赋权,次优样本也按比例贡献方向信息,不浪费。

缺点是 \(\lambda\) 难调且依赖代价尺度\(\lambda\) 必须与代价 \(J\) 的数值范围匹配,代价尺度一变(比如换个任务、改个权重)就要重调 \(\lambda\),否则要么权重全平(\(\lambda\) 相对太大)、要么权重集中在一个样本(\(\lambda\) 相对太小,ESS 崩)。第 2 章讲的 ESS 监控,本质就是在防后一种情况。

"硬阈值 vs 软加权"这对概念,在机器学习里有一个你可能熟悉的孪生兄弟值得一提——hard attention vs soft attention(或等价地 top-k vs softmax)。

深度学习里,当模型要从一组候选中"挑重点"时,也面临同样的选择:soft attention 用 softmax 给所有候选一个连续权重(人人有份,按相关性加权),hard attention 则只选最相关的若干个(其余丢弃)。

这和 MPPI 的指数软加权(softmax 本质就是指数加权归一化)、CEM 的硬阈值精英是**完全平行**的两种机制。

甚至连取舍都一样:soft attention 可微、信息利用充分但计算全量,hard attention 稀疏高效但不可微、丢信息——对应 MPPI 充分利用样本但要调 \(\lambda\)、CEM 硬筛选省心但丢次优样本。

这个平行绝非巧合,而是因为"如何从一组候选里按重要性聚合信息"是一个普适问题,无论在控制(聚合 rollout)还是在深度学习(聚合特征)里都会遇到,而"软(连续加权)vs 硬(离散选择)"是它的两种基本答案。

认出这个平行的价值在于:你在深度学习里积累的关于 soft/hard attention 的直觉(比如"soft 更稳定易训练、hard 更稀疏高效"),可以迁移过来理解 MPPI/CEM 的取舍;反之亦然。这也再次印证本章的统一精神——很多看似不同领域的技术,骨子里在解同一个问题。

一个实用的经验判断:代价尺度稳定、想充分利用样本 → 倾向 MPPI(指数加权);代价尺度多变、想要省心的鲁棒筛选 → 倾向 CEM(硬阈值,但配合 iCEM 的改进,见 §4.2)。

而 §4.3 的 Tsallis 框架会告诉你:你其实不必二选一——存在一个连续的中间地带,可以要"软硬之间"的任意筛选硬度。

顺带说清一个常被忽略的问题:CEM 为什么叫"交叉熵"方法?这个名字来自它的起源——CEM 最初不是为控制设计的,而是 Rubinstein 在 1990 年代为**稀有事件估计**(估计极小概率事件的发生率,如通信网络的丢包率、金融的极端风险)提出的。

在那个原始问题里,CEM 通过最小化"提议分布"与"理想分布"之间的**交叉熵(cross-entropy)**来迭代改进采样分布——交叉熵是信息论里衡量两个分布差异的一个量(和 KL 散度密切相关,KL = 交叉熵 − 熵)。所以"交叉熵方法"这个名字记录的是它的数学出身:用最小化交叉熵来逼近理想分布。

后来人们发现这套"采样—取精英—重拟合"的机制不仅能估计稀有事件,还能做**优化**(把"理想分布"设成集中在最优解附近的分布),于是 CEM 被引入轨迹优化和控制。

理解这个出身,你会发现 CEM 和 MPPI 的"同根"在历史层面也成立——MPPI 从 KL 散度推导、CEM 从交叉熵起源,而交叉熵和 KL 本就是信息论里一对孪生的量。

它们殊途同归地落到"用代价加权样本来逼近理想分布",绝非偶然,而是因为它们共享同一套信息论根基。这也预告了 §4.3:当 Tsallis 用更一般的散度统一它们时,统一的正是这套信息论根基。

⚠️ 常见陷阱

编程陷阱:CEM 精英比例取太小,方差估计坍缩到接近零,后续迭代彻底失去探索。 错误做法:为了"快速聚焦",把精英比例设得极小(如 \(K=100\) 只取前 2 个精英)。 现象/后果:头一两轮看似收敛飞快,但很快分布方差被估计成接近零(2 个样本估出的 std 极小甚至为 0),之后采样几乎全挤在一个点上,再也跳不出去——表现为"卡在一个次优解、代价不再下降"。 根本原因:用极少数样本估计高斯的方差,估计本身噪声极大且系统性偏小(样本方差是有偏的,样本越少偏得越厉害);一旦方差被低估,采样范围收缩,下一轮精英也都挤在小范围内,方差进一步低估——正反馈式坍缩。 正确做法:精英数不要太小(经验上至少 10 个以上);给方差设一个**下界**(floor)防止坍缩;或直接用 iCEM 的改进(§4.2 的 elite memory 与有色噪声能显著缓解)。 自检方法:每轮打印分布的平均 std,若它单调快速趋零且代价停止下降,就是坍缩了;可视化采样点是否越缩越紧。

概念误区:以为"CEM 不用调参,所以比 MPPI 简单/更好"。 错误认识:CEM 只需设精英比例、不用调温度 \(\lambda\),看起来参数更少更省心,于是认为它整体更优。 现象/后果:在代价尺度多变的任务上 CEM 确实省心,但在需要充分利用样本信息的任务上(尤其样本预算紧张时),CEM 的"扔掉非精英"会浪费信息、表现不如 MPPI;用错场景还以为是实现 bug。 根本原因:"参数少"不等于"更好"——CEM 用硬阈值换来了省心,但也牺牲了对次优样本信息的利用;这是**取舍**而非优劣。MPPI 的 \(\lambda\) 虽难调,但它换来的是对所有样本的平滑利用。 正确做法:按任务选——代价尺度多变选 CEM,样本珍贵且代价尺度稳定选 MPPI;或用 §4.3 的统一视角,在软硬之间选一个折中点。

思维陷阱:把"硬阈值 vs 指数加权"看成非此即彼的二元对立。 错误认识:认为一个采样式 MPC 要么是"CEM 派"(硬阈值),要么是"MPPI 派"(指数加权),二者泾渭分明。 现象/后果:遇到一个"既不完全是硬阈值、也不完全是指数"的方法(如 Tsallis VI-MPC、或某些 top-k 加权变体)时无法归类,觉得它"四不像"。 根本原因:硬阈值和指数加权其实是一条**连续谱**的两端,而非两个离散的点。Heaviside 阶跃可以看成某种极限下的特例,指数加权是另一端,中间存在无数种"软硬程度不同"的权重函数。 正确做法:把权重函数的"硬度"看成一个连续可调的量(这正是 §4.3 Tsallis 的 \(\exp_r\) 用一个参数 \(r\) 做的事);遇到任何采样式 MPC,先问"它的权重函数长什么样、有多硬",而非急着把它塞进 CEM 或 MPPI 的盒子。

练习

  1. (实现 + 验证,⭐⭐) 基于本节的三步骨架,用 NumPy 实现一个**可切换权重函数**的采样式优化器:传入一个 weight_fn(J) 参数,分别传入指数权重 exp(-J/λ) 和硬阈值 1{J≤J_elite} 两种实现,在同一个到达任务上对比它们的收敛曲线。

验证:MPPI 的 \(\lambda\) 调小、CEM 的精英比例调小,是否都让收敛更快但更易在多峰任务上陷入次优?(提示:把目标改成两个等距的峰来测多峰情形。)

  1. (参数对应关系,⭐⭐⭐) 本节说"\(\lambda\) 和精英比例控制同一个探索-利用旋钮"。设计一个实验定量验证这个对应:固定一个任务,扫描 MPPI 的 \(\lambda\) 和 CEM 的精英比例,画出各自的"最终代价 vs 参数"曲线。

能否找到一个 \(\lambda\) 和一个精英比例,使两者的行为(收敛速度、最终代价)近似一致?它们的对应关系是线性的吗?(开放:尝试从权重函数的形状解释你观察到的对应。)

  1. (设计思辨,⭐⭐⭐) Heaviside 硬阈值和指数加权之间,你能设计一个"半软半硬"的权重函数吗?例如"对前 50% 的样本用指数加权、后 50% 直接扔掉",或"用一个比指数更陡但仍连续的函数"。

实现你的设计并测试,思考:它在什么任务上可能优于纯 MPPI 或纯 CEM?这个练习会让你对 §4.3 Tsallis 用单一参数 \(r\) 连续调节软硬度的优雅之处有更深体会。

§4.2 iCEM:让 CEM 快到能实时的四大改进 ⭐⭐⭐

动机:CEM 又好用又致命地慢

§4.1 说清了 CEM 和 MPPI 同根。但在实践中,原始 CEM 有一个致命问题:。它需要每个控制周期内迭代很多轮(每轮采样—评估—取精英—重拟合),而每轮又要大量样本才能让高斯估计稳定。

在基于模型的强化学习里,CEM 因其简单和强经验性能而极受欢迎,但它的采样低效让它**无法用于实时规划与控制**——这是它长期以来的硬伤。

具体慢在哪?设想一个高维控制任务(如 24 自由度的灵巧手)。CEM 要在每个控制周期内:采几百上千条 rollout、跑动力学前向算代价、排序取精英、重新拟合高斯,且这套流程要重复多轮才收敛。

样本数 × 迭代轮数 × 每条 rollout 的前向开销——三者相乘,轻松超出实时控制的延迟预算(第 2 章讲过 MPPI 的实时性靠 GPU 并行,但 CEM 的多轮迭代是**串行**的,并行救不了迭代轮数)。

这个"串行迭代"的瓶颈值得展开,因为它是理解 CEM 为何慢、iCEM 为何重要的关键。MPPI 是**一步闭式**的(第 2 章)——它撒一批样本、加权平均一次就出结果,这"一批样本"可以完全并行(GPU 同时跑几千条 rollout),所以 MPPI 的延迟基本就是"一批 rollout 的并行时间",很短。

CEM 不同——它要迭代多轮,每轮的输入依赖上一轮的输出(这一轮的分布由上一轮的精英决定),所以**轮与轮之间无法并行,只能一轮接一轮串行执行**。

即便每一轮内部的样本可以并行,总延迟还是"轮数 × 每轮时间"。这就是问题所在:GPU 并行能压缩"每轮时间"(一轮内的样本并行),但压缩不了"轮数"(轮间的串行依赖)。

如果 CEM 需要 10 轮才收敛,那它的延迟至少是 MPPI 的约 10 倍——这在 50Hz(每周期 20 毫秒)的实时控制里往往就超预算了。

理解了这一点,你就明白 iCEM 的核心目标"砍样本数"其实是在**砍轮数 × 每轮样本数的总采样量**:通过让每一轮都更高效(有色噪声采得准、elite memory 不重复发现),iCEM 用更少的轮数、每轮更少的样本就能收敛,从而把总延迟压进实时预算。

所以 iCEM 不是简单地"减少样本",而是"让每个样本和每一轮都更值钱",最终减少串行轮数这个真正的瓶颈。

这也凸显了 CEM 和 MPPI 的一个根本差异:MPPI 用"一步 + 大批并行"换实时,CEM 用"多轮迭代"换精度——iCEM 的工作是让 CEM 的多轮迭代少到也能实时。

iCEM(improved CEM,Pinneri 等,CoRL 2020)的目标就是:在不牺牲 CEM 优点的前提下,把它需要的样本数砍下来,砍到能实时的程度

它的成果很惊人——在 DOOR、RELOCATE 这类高维操作任务上,用 13.7× 更少的样本达到 90% 成功率、平均性能反而提升 400%;综合各任务,样本效率提升 2.7–22×、性能提升 1.2–10×。换句话说,iCEM 让 CEM 从"理论上好用但太慢"变成"真能实时跑"。

它靠的是四个改进,每一个都针对 CEM 的一处具体低效。理解这四招,不只是学一个算法——它们体现了"如何让一个采样式优化器变得样本高效"的通用智慧,其中有色噪声直接呼应第 3 章的"时间结构"侧面、elite memory 呼应 warm-start 的"复用历史"思想。

如果不这样做会怎样:白噪声 + 无记忆的双重浪费

先看不做这些改进时,CEM 浪费在哪。

浪费一:白噪声采样,大量样本撞在"无效的高频抖动"上。 原始 CEM 对控制序列的每个时刻**独立**采高斯噪声(白噪声)——这正是第 3 章 §3.2 批评 vanilla MPPI 的同一个问题:相邻时刻噪声无关,采出的控制序列充满高频抖动。

但绝大多数控制任务的好解是**时间相关、平滑**的(一脚油门踩下去会持续一段,不会每个时刻乱跳)。于是白噪声采出的样本里,大量是"高频乱跳"的无效样本,根本不可能成为精英——采了等于白采。样本预算就这样被悄悄浪费掉一大半。

浪费二:每个控制周期从零开始,丢掉上一周期辛苦算出的精英。 原始 CEM 在每个新的控制周期把分布重置(均值归零、方差复位),完全不用上一周期的结果。

但 receding-horizon 控制里,相邻周期的最优解高度相似(第 2 章 warm-start 的核心洞察)——上一周期辛苦迭代出的精英样本,稍微平移一下就是这一周期的好起点。丢掉它们,等于每个周期都从头摸索,迭代轮数下不来。

把这两个浪费量化出来。先看白噪声 vs 有色噪声:

def colored_noise(N, T, beta, rng):       # 功率谱 S(f)∝1/f^β
    spectrum = 1.0/(freqs**(beta/2.0))    # β=0 白噪声, β=2 布朗噪声
    colored = np.fft.irfft(white_freq*spectrum, n=T, axis=1)
    return colored / colored.std(axis=1, keepdims=True)

同一个需要平滑控制的到达任务,CEM 用不同噪声、不同样本数的最终代价:

K= 30: 白噪声(β=0)=182.36   布朗噪声(β=2)=134.33   改善 26%
K=100: 白噪声(β=0)=132.87   布朗噪声(β=2)=109.83   改善 17%
K=300: 白噪声(β=0)=116.85   布朗噪声(β=2)=107.39   改善  8%

关键规律:样本越少,有色噪声的优势越大(K=30 时改善 26%,K=300 时只剩 8%)。这正是 iCEM 的精髓——它要解决的就是"样本少时怎么办",而有色噪声恰好在低样本预算下帮助最大。样本多到一定程度,白噪声靠数量也能凑出好解,有色噪声的优势就被稀释了;但实时控制恰恰是样本紧张的场景,所以有色噪声在这里价值最高。

再看 elite memory + shift init 的效果:

Receding-horizon 到达(每周期仅 2 次 CEM 迭代, K=40), 累积跟踪代价:
  无 memory/shift(每周期从零):  152.41
  有 elite memory + shift init: 101.60   改善 33%

在迭代预算被压到很低(每周期仅 2 轮)时,复用上一周期的精英带来 33% 的改善——因为低迭代预算下,"从一个好起点出发"比"从零摸索"重要得多。

这又一次印证 warm-start 的思想(第 2 章),只不过 iCEM 把它从"复用上一周期的均值"升级为"复用上一周期的一批精英样本"。

理论:四大改进逐一拆解

iCEM 的四个改进,每个对应上面分析出的一处低效。逐一来看:

改进一:有色噪声(colored noise / β-noise)。 不再对每个时刻独立采白噪声,而是采**功率谱按 \(S(f)\propto 1/f^\beta\) 衰减**的有色噪声。

\(\beta=0\) 是白噪声(各频率等能量),\(\beta\) 越大、低频成分越占主导、噪声越平滑(时间相关性越强)。iCEM 发现 \(\beta=2\)(布朗噪声 / 红噪声)对控制序列最友好——它生成的扰动平滑、时间相关,采出的样本天然贴近"好解应有的平滑形态",于是更可能成为精英。

这是四个改进里**影响最大**的一个(论文的消融实验显示去掉有色噪声性能下降最明显)。它和第 3 章 §3.2 Smooth-MPPI 的 input-lifting 殊途同归——都在"塑造控制序列的时间结构",只是 Smooth 用积分、iCEM 用频谱整形。

"有色噪声"这个概念值得做个跨领域类比来加深理解,因为它在多个领域都是核心工具。"颜色"这个说法本身来自**光学/信号处理**——白光含所有频率等能量,故"白噪声"指各频率等能量的噪声;而"红噪声/布朗噪声"低频占主导(像红光在可见光里偏低频),"蓝噪声"高频占主导。

这个术语被各领域借用:在**计算机图形学**里,蓝噪声(高频为主)用于抖动采样和纹理生成,因为它的样本分布均匀无聚团、视觉上更悦目;在**音频合成**里,粉红噪声(\(\beta=1\))听起来比白噪声更自然、更接近自然界的声音(雨声、海浪)。

iCEM 借用的是**布朗噪声(\(\beta=2\),红噪声的一种)**——它的低频主导特性让生成的序列平滑、缓慢变化,恰好匹配"好的控制序列应该平滑"这个先验。

标注一下这个类比的边界:图形学用蓝噪声是为了样本**空间分布**均匀,iCEM 用红噪声是为了控制**时间序列**平滑——一个关心空间、一个关心时间,且需求相反(蓝 vs 红)。

但共同的核心是"通过整形噪声的频谱来获得想要的结构"——这是一个跨越光学、图形学、音频、控制的通用思想。理解了它,你看到"有色噪声"就不会陌生,而能认出它是"频谱整形"这个大家族在控制领域的应用。

读到这里你可能会担心:有色噪声偏向低频、平滑,那它会不会**探索不充分**——比如某些任务需要突然的、高频的控制动作(急刹、急转),有色噪声采不到这些,岂不是漏掉了重要的解?这个担心点出了有色噪声的适用边界,值得讲清。

首先,有色噪声不是"不能产生快速变化",而是"降低了高频成分的比例"——它仍能产生需要的快速动作,只是不像白噪声那样把大量样本浪费在无意义的逐时刻乱跳上。

其次,关键在于**匹配任务的特性**:如果你的任务确实需要频繁的高频控制(如某些抖动镇定问题),那 \(\beta\) 应该调小(偏白);如果任务的好解主要是平滑的(大多数操作、导航、运动控制),\(\beta=2\) 的偏低频正好匹配,不会漏掉什么——因为本来就不需要那些高频成分。

换句话说,有色噪声不是无差别地压制探索,而是把探索的"预算"从无效的高频区**重新分配**到有效的低频区——在好解平滑的任务上,这是更聪明的探索,而非更少的探索。

这正呼应第 3 章 §3.3 Log-MPPI 的思想:探索不是"撒得越广越好",而是"撒在对的地方"。

如果你真的不确定任务需要多少高频,一个稳妥做法是混合——大部分样本用有色噪声(\(\beta=2\))保证平滑探索,少量样本用白噪声或更小的 \(\beta\) 保留高频探索能力,两全其美。

理解这个边界,你就不会因为"有色噪声偏低频"的担心而排斥它,而能根据任务的频率特性合理设置 \(\beta\)

改进二:elite memory(精英记忆)。 保留上一轮 CEM 迭代的一小部分精英样本,加进下一轮的采样池。

这让"上一轮辛苦找到的好样本"不至于因为下一轮的随机采样而丢失,相当于给迭代过程加了"记忆",避免每轮都重新发现同样的好方向。

读到这里你可能会担心:保留旧精英会不会**误导**当前优化?万一上一轮的精英在这一轮已经不好了(比如环境变了、或那是个局部最优),把它们留着岂不是拖后腿?这个担心合理,iCEM 用两个设计化解它。

其一,只保留一小部分精英(不是全部)——保留的旧精英只占采样池的一小份,即便它们过时了,也只是池中少数,新采的样本仍占主导,旧精英不会绑架整个分布。

其二,旧精英也要重新评估——带到新一轮的旧精英不是无条件信任,而是和新样本一起用当前代价重新打分、重新参与"取精英"的竞争。如果旧精英确实过时了(当前代价高),它们自然在重新排序中落选、被淘汰,不会进入新的精英集。

所以 elite memory 不是"盲目信任历史",而是"给历史一个被重新检验的机会"——好的历史精英会通过重新评估的考验继续贡献,过时的会被自然淘汰。这个设计的智慧在于:它既利用了历史信息(省去重新发现的成本),又通过重新评估避免了被陈旧信息误导。

这和强化学习里 replay buffer 的思想相通——保留历史经验复用,但用当前的价值估计重新加权,而非盲目相信旧经验。

理解这一点,你就不会因为"保留历史会不会误导"的担心而排斥 elite memory——关键是"保留 + 重新检验",而非"保留 + 盲信"。

改进三:shift init(移位初始化)。 在 receding-horizon 控制中,把上一个**控制周期**的解整体**左移一步**(因为时间前进了一步),作为新周期分布的初始均值。

这是 warm-start 在 CEM 上的直接应用——上周期解的第 2 到第 T 步,正是这周期第 1 到第 T-1 步的好猜测,末尾补一个新值即可。elite memory 也配合 shift:保存的精英同样左移一步带到下个周期。

这个"末尾补一个新值"的小细节,实际中有几种补法,值得知道,因为补得不好会引入抖动。左移一步后,序列末尾空出一个位置(原来的第 T+1 步,超出了上周期的时域),需要填一个值。

常见做法有三:(1) 补零——最简单,假设末尾控制为零(适合"减速停止"类任务,但对需要持续控制的任务会引入末尾的突变);(2) 重复最后一步——把原来的第 T 步复制到第 T+1,假设"继续保持上一个动作"(比补零平滑,适合控制连续变化的任务);(3) 补一个零均值的随机值——给末尾一点探索性(让新进入时域的那一步保持开放)。

选哪种取决于任务:减速停止类用补零、巡航类用重复末步、需要末端探索用随机。这个细节虽小,但和 §4.2 的整体精神一致——iCEM 的每一招都在精细地利用时序结构,连"左移后末尾补什么"这种边角都考虑到了。

一个常见的疏忽是补零却用在需要持续控制的任务上,导致每个周期的控制序列末尾都有一个"掉到零再恢复"的突变,表现为控制的周期性抖动——如果你的 receding-horizon 控制有莫名的末端抖动,检查一下 shift 的补值策略。

这也再次体现 warm-start 类技巧的一个普遍要点:复用历史的同时,要妥善处理"新进入的部分"(这里是末尾新步),否则历史复用的收益会被新部分的处理不当抵消。

改进四:mean-as-sample(均值作为额外样本)。 在最后一轮 CEM 迭代时,把当前分布的**均值**本身作为一个额外样本加入评估。为什么?两个原因。

其一,高维下很难采到接近均值的样本——维度越高,随机样本越倾向于落在远离均值的"薄壳"上(高维高斯的概率质量集中在远离中心的球壳,这是高维几何的反直觉现象),于是"均值"这个往往很优的点反而采不到,需要手动加进去。

这个"薄壳现象"反直觉到值得用具体数字说清,因为它是高维采样的一个核心陷阱。直觉上我们以为高斯分布的样本应该集中在均值附近(一维确实如此,钟形曲线峰在中间)。

但在 \(d\) 维高斯里,一个样本到均值的距离的平方期望是 \(d\sigma^2\)——也就是说,典型样本离均值的距离约为 \(\sigma\sqrt{d}\),且这个距离随维度增大而增大

在控制问题里 \(d\)(控制序列的总维度 = 时域 × 控制维数)轻松上百,于是 \(\sqrt{d}\) 有十几,典型样本离均值有十几个标准差远。

更精确地说,高维高斯的概率质量几乎全部集中在一个半径约 \(\sigma\sqrt{d}\)、厚度很薄的球壳上,而球心(均值)附近反而几乎没有样本——这就是"薄壳"或"肥皂泡"现象。

后果是:均值这个点,在高维下你**几乎永远采不到它附近的样本**,纯靠随机采样去"碰"到均值是指望不上的。而均值恰恰常常是个很优的点(它是当前分布认为最可能好的中心)。

所以 iCEM 的 mean-as-sample 显式地把均值加进去评估,是对高维几何这个"反直觉陷阱"的直接补救——不靠运气采到它,而是手动确保它被考虑。

这个现象不只影响 iCEM:任何高维采样式方法(包括 MPPI)都受其困扰,理解它能帮你解释很多"高维下采样效率莫名变差"的现象。

其二,对许多需要"干净"控制序列的任务(操作、够取、任何状态空间里的线性轨迹),执行均值往往是有益的——而 CEM 默认执行的是精英的均值、均值本身从未被评估过,手动加入可保证它被考虑。

把四招合起来,iCEM 的执行流程是:每个控制周期,用 shift init 设好初始均值、注入上周期的 elite memory,然后做几轮迭代(每轮用有色噪声采样、取精英、重拟合),最后一轮加入 mean-as-sample,执行最优序列的第一个动作,进入下一周期。

如果你不想一次实现全部四招,而想按性价比逐个上,这里给个**优先级建议**(基于论文消融和实际经验)。第一优先是**有色噪声**——它是论文消融里影响最大的一招,且实现独立(只改采样噪声的生成、不动其他逻辑),性价比最高,应该首先上。

第二优先是 shift init——它就是 warm-start,几乎是免费的(左移一步、补个末值),且对 receding-horizon 控制的连续性帮助明显,实现也简单。

第三是 elite memory——它需要额外维护一个精英缓冲区、处理跨周期的存取,实现稍复杂,收益在低迭代预算下明显(前面 demo 的 33%),可在前两招之后上。

最后是 mean-as-sample——它最简单(就多评估一个样本),但收益相对小(主要在高维任务防漏均值),可最后补上或在高维任务才上。

所以一个务实的实现路径是:先有色噪声(拿大头)→ 加 shift init(免费的连续性)→ 加 elite memory(低预算下的提升)→ 补 mean-as-sample(高维保险)。每加一招测一次,看在你的任务上收益如何——这也呼应累积项目"逐个加、逐个验"的方法论。

这个优先级不是绝对的(依任务而变,比如不需平滑控制的任务有色噪声收益就小),但给了你一个合理的起点,避免一上来就实现全部四招的复杂度。理解每招的独立性和收益大小,你就能按自己的需求和精力,灵活地组合这四招,而非要么全上要么不用。

本质洞察:iCEM 的四大改进看似零散,实则都在回答同一个问题——"样本这么少,怎么把每一个都用在刀刃上"。有色噪声让样本不浪费在无效高频上(采得准);elite memory 和 shift init 让历史信息不浪费(不重复发现);mean-as-sample 让最优的均值点不被高维几何漏掉(不遗漏)。这与第 2 章的样本效率主线、第 3 章的"提议分布五侧面"是同一种思维的延续:采样式方法的核心竞争力,从来不是"采得多",而是"采得巧"。iCEM 把"采得巧"做到了极致,于是用 1/10 的样本达到甚至超过原始 CEM 的性能。理解这一点,你看任何采样式方法的改进,都会本能地问:"它让样本更有效了吗?怎么做到的?"

iCEM 与 MPPI 变体的对照:同一智慧的不同实现

有趣的是,iCEM 的四招在第 2、3 章的 MPPI 世界里都能找到对应——这再次印证 §4.1 的"同根":

  • 有色噪声 ↔ Smooth-MPPI 的 input-lifting(§3.2):都塑造控制的时间结构、压制无效高频。手段不同(频谱整形 vs 导数空间积分),目标一致。
  • shift init ↔ warm-start(§2.1):都把上周期解平移复用。几乎是同一个技巧。
  • elite memory ↔ Biased-MPPI 的采样先验(§3 前沿):都把"已知的好样本/好方向"注入采样。
  • mean-as-sample ↔ MPPI 本就评估均值附近的样本:MPPI 的指数加权天然让均值附近样本高权重,但高维下同样面临"采不到均值"的问题,iCEM 的显式加入是更直接的解法。

这个对照说明:CEM 阵营和 MPPI 阵营在各自发展中,独立地发现了相同的样本效率智慧。这从侧面强烈暗示——它们背后有一个共同的框架在起作用。这个框架,就是 §4.3 的 Tsallis 统一视角。

最后值得点一下 iCEM 在更大图景里的位置,为第 6 章埋个伏笔。iCEM 的论文标题是"为实时规划的样本高效 CEM",它的核心动机——让 CEM 快到能实时——其实服务于一个更大的方向:基于模型的强化学习(model-based RL, MBRL)

在 MBRL 里,智能体先学一个动力学模型,然后用这个模型做规划(在"想象"中 rollout)来选动作——而这个"用模型规划"的环节,常常就是用 CEM 或 MPPI 这类采样式优化器。

所以 CEM 的样本效率直接决定了 MBRL 能否实时:CEM 太慢,整个 MBRL 智能体就快不起来。iCEM 把 CEM 的样本效率提升一个数量级,正是为了让 MBRL 中的"规划"环节能实时运行。

这条线索会在第 6 章展开——那里讲的 TD-MPC 等方法,正是把采样式规划(CEM/MPPI)与学习的世界模型、价值函数结合,而 iCEM 的样本效率智慧是这类方法能实时的前提。

所以本章学的 iCEM 不只是"一个更快的 CEM",它是连接经典采样式 MPC 与现代 MBRL 的一块关键拼图。

带着这个认识,你在第 6 章会看到采样式优化器如何嵌进一个学习系统里——iCEM 的四招在那里依然适用,因为"样本高效"是任何实时规划器的永恒追求。

⚠️ 常见陷阱

编程陷阱:有色噪声生成后忘记归一化,导致不同 β 下的实际采样尺度不一致。 错误做法:直接用 irfft(white * spectrum) 的输出作噪声,不做标准化。 现象/后果:不同 \(\beta\) 值生成的噪声标准差差异很大(\(\beta\) 越大、低频能量越集中、整体幅度越不可控),于是"换 \(\beta\)"实际上同时改变了"采样步长",你以为在比较噪声颜色,其实混入了步长变化,实验结论失真。 根本原因:\(1/f^\beta\) 谱整形会改变信号的总能量;不归一化时,\(\beta\) 同时影响了"颜色"和"幅度"两个量。 正确做法:生成有色噪声后按行(每条序列)标准化到单位标准差,再乘以 CEM 的 \(\sigma\)——让 \(\beta\) 只控制"颜色"、\(\sigma\) 只控制"幅度",两者解耦。 自检方法:对不同 \(\beta\) 生成的噪声打印其标准差,应都接近 1(归一化后);若随 \(\beta\) 大幅变化,说明没归一化。

概念误区:以为有色噪声里 β 越大越好(越平滑越好)。 错误认识:既然 \(\beta=2\) 比白噪声好,那 \(\beta=3\)\(\beta=4\) 岂不更平滑更好? 现象/后果:\(\beta\) 取得过大时,噪声几乎只剩极低频成分(接近一条缓慢漂移的直线),失去了在时域上"局部调整"的能力——采出的样本都是"整体平移"型的,无法表达需要快速响应的控制段,性能反而下降。 根本原因:平滑是把双刃剑(第 3 章 §3.2 的平滑↔敏捷权衡在这里重现)。\(\beta\) 太大 = 过度平滑 = 失去敏捷性。\(\beta=2\) 是经验上的甜点,平衡了平滑性与时域调整能力,并非越大越好。 正确做法:默认从 \(\beta=2\) 起步;若任务需要更敏捷的控制可适当减小 \(\beta\),需要更平滑可略增,但很少超过 \(\beta=3\)。把 \(\beta\) 当作一个需要按任务权衡的旋钮,而非"越大越好"。

思维陷阱:把 iCEM 的四招当成"CEM 专属技巧",不知道它们可迁移到任何采样式 MPC。 错误认识:认为有色噪声、elite memory 等是为 CEM 量身定做的,和 MPPI 无关。 现象/后果:在用 MPPI 时遇到样本效率问题,不会想到"借 iCEM 的招"——明明有色噪声可以直接用到 MPPI 的采样上(事实上"有色噪声 MPPI"正是一个真实的变体,见第 3 章前沿),却因为思维定式而错过。 根本原因:把改进绑定到具体算法名上,而非理解改进背后的通用原理。如前面对照表所示,iCEM 的四招在 MPPI 世界都有对应——它们是"采样式优化"的通用智慧,不是 CEM 的私有财产。 正确做法:把每个改进理解为"针对采样式方法某处低效的通用补丁"——有色噪声治时间结构、memory/shift 治历史浪费。遇到任何采样式 MPC 的样本效率问题,都可以问"这四招里哪个能用上"。

练习

  1. (实现,⭐⭐) 实现一个有色噪声生成器(用 FFT 方法:白噪声频谱 × \(1/f^{\beta/2}\) 整形 → 逆 FFT → 归一化)。

在一个需要平滑控制的到达任务上,把它接入一个简单 CEM,扫描 \(\beta\in\{0, 1, 2, 3\}\),画出"最终代价 vs \(\beta\)"曲线,验证 \(\beta=2\) 附近是否是甜点。再扫描样本数 \(K\),验证"样本越少、有色噪声优势越大"这一规律。

  1. (消融实验,⭐⭐⭐) 实现完整 iCEM(四招齐全),然后逐个**关掉**每一招做消融:去掉有色噪声(用白噪声)、去掉 elite memory、去掉 shift init、去掉 mean-as-sample。

在一个 receding-horizon 到达任务上测每种配置的累积代价,复现论文的结论"有色噪声影响最大"。思考:在你的任务上,哪一招影响最大?为什么可能和论文不同?(提示:影响大小依赖任务特性——任务越需要平滑控制,有色噪声越重要。)

  1. (跨算法迁移,⭐⭐⭐) 把 iCEM 的有色噪声**迁移到 MPPI**:在第 2 章的 MPPI 主循环里,把白噪声采样换成有色噪声采样(其余不变),得到一个"有色噪声 MPPI"。

在同一任务上对比它与原始 MPPI(白噪声)的控制平滑度与样本效率。这个练习会让你亲手验证 §4.2 的思维陷阱里说的"四招可迁移",也呼应第 3 章 §3.2 的平滑主题——你会发现有色噪声 MPPI 和 Smooth-MPPI 在效果上颇为相似,尽管原理不同。

§4.3 Tsallis 统一框架:一个参数把一族算法连起来 ⭐⭐⭐

动机:从"它们同根"到"用一个公式写出全家"

§4.1 用直觉论证了 MPPI 和 CEM 同根(同一骨架、不同权重函数),§4.2 又发现 CEM 和 MPPI 阵营独立发现了相同的样本效率智慧。

这些都强烈暗示:背后有一个统一的数学框架。本节就把这个框架正式建立起来——它来自 Tsallis VI-MPC(Wang、So、Theodorou 等,RSS 2021)。

这个框架的威力在于:它用**一个参数 \(r\)** 和**一个变形指数函数 \(\exp_r\),把 MPPI、CEM、SV-MPC(第 3 章 §3.4 的 Stein 变分 MPC)统一写成**同一个算法的不同特例——\(r\to 1\) 是 MPPI,\(r\to\infty\) 是 CEM,中间是连续的过渡。这不是"它们很像"的模糊类比,而是"它们是同一个公式在不同参数下的实例"的严格陈述。

为什么要追求这种统一?三个理由。其一,认知经济:与其记一族零散的算法,不如记"一个框架 + 一个旋钮 \(r\)"。

其二,设计自由:一旦知道 MPPI 和 CEM 是一条连续谱的两端,你就能取中间任意一点——要"比 MPPI 硬一点、比 CEM 软一点"的筛选,不再需要二选一。

其三,理论锐度:统一框架让"为什么这些方法 work、它们的方差/风险特性如何"可以在一个框架里统一分析(Tsallis 论文正是这么做的,给出了各方法的风险敏感度分析)。

如果不这样做会怎样:没有连续谱,只能在离散的点之间跳

不接受统一框架、坚持把 MPPI 和 CEM 当两个离散选项,会怎样?

最大的损失是**失去了中间地带**。现实任务的"最优筛选硬度"未必恰好落在 MPPI 或 CEM 上——可能"比 MPPI 略硬"最好,可能"介于两者之间偏 CEM"最好。

如果你只有 MPPI 和 CEM 两个离散选项,就只能在这两点上二选一,错过中间可能更优的设置。这就像只有"全开"和"全关"两档的开关,而你需要的是一个无级调光的旋钮。

第二个损失是**调参直觉的割裂**。MPPI 调 \(\lambda\)、CEM 调精英比例,看起来是两套独立的调参。

但若理解它们是同一条连续谱(由 \(r\) 参数化),你就明白"调 \(\lambda\)"和"调精英比例"和"调 \(r\)"本质都在调同一个量——筛选硬度。统一框架把三套调参直觉合成一套。

第三个损失是**无法理解和定位新方法**。前面说过,近年大量论文用"我们是 MPPI 在某参数下的特例""我们用 q-指数/Tsallis 散度"这类语言。

没有 §4.3 的框架,这些论文你只能死记;有了它,你能立刻把任何新方法定位到这条连续谱上的某一点,或者识别出它在框架的哪个维度(权重函数 / 散度 / 协方差)做了文章。

理论:变形指数与连续插值

统一框架的数学核心是**变形指数函数(deformed exponential,也叫 q-指数)**。先给定义,再解释它怎么实现统一。

标准指数 \(\exp(x)\) 有一个推广,叫变形指数 \(\exp_r(x)\)

\[ \exp_r(x) = \big[\,1 + (1-r)\,x\,\big]_+^{\frac{1}{1-r}}, \]

其中 \([\,\cdot\,]_+ = \max(\cdot, 0)\) 表示截断负数(保证底数非负)。这个函数有一个关键性质:\(r\to 1\) 时,它退化为标准指数 \(\exp(x)\)

(可以验证:令 \(r\to 1\),用 \(\lim_{r\to1}[1+(1-r)x]^{1/(1-r)} = e^x\),这是 \(e\) 的经典极限定义的变形。)而当 \(r\) 取其他值时,它是一个"变了形的"指数——衰减的快慢和形状随 \(r\) 改变。

这个变形指数不是数学家凭空造出来的,它有真实的物理来源,了解一下能加深对它的理解。它来自**非广延统计力学(non-extensive statistical mechanics)**,由物理学家 Tsallis 在 1988 年提出。

标准统计力学建立在玻尔兹曼-吉布斯熵之上,而玻尔兹曼分布里的指数 \(e^{-E/kT}\) 正是我们熟悉的标准指数——这也是 MPPI 的 \(e^{-J/\lambda}\) 在形式上像玻尔兹曼分布的原因(第 1 章讲过这个物理类比,\(\lambda\) 像温度)。

但标准统计力学有个隐含假设:系统是"广延的"(extensive),即整体的熵等于各部分熵之和。Tsallis 注意到,许多真实系统(长程相互作用、分形结构、某些复杂系统)**不满足**这个可加性——它们是"非广延的"。

为描述这些系统,他推广了熵的定义(Tsallis 熵),相应地,玻尔兹曼分布的标准指数就被推广成了变形指数 \(\exp_r\),参数 \(r\)(物理里常记作 \(q\),这就是"q-指数"名字的由来,也解释了 §4.3 后面要澄清的 \(q\)/\(r\) 记号问题)刻画了系统偏离广延性的程度,\(r=1\)\(q=1\))恢复标准的广延情形。所以变形指数 \(\exp_r\) 是"推广的玻尔兹曼因子"。

理解这个物理出身有两个好处:其一,它解释了为什么 \(r=1\) 是个特殊点(恢复标准统计力学)、为什么 \(\exp_r\)\(r=1\) 退化为标准 \(\exp\)——这不是数学巧合,而是"非广延推广在广延极限下回到标准情形"的必然。

其二,它让你明白 Tsallis VI-MPC 把 MPPI 推广到变形指数,本质是把控制问题从"玻尔兹曼式的标准统计"推广到"Tsallis 式的非广延统计"——一个有深厚物理根基的推广,而非随意的数学游戏。

当然,对工程应用而言,你不需要深究非广延统计的物理细节,只需知道 \(\exp_r\) 是标准指数的一个有理论根基的单参数推广,\(r\) 调节它的形状即可。

把这个变形指数用作**权重函数**:\(w_i = \exp_r(-J_i/\lambda)\)。现在看 \(r\) 怎么在 MPPI 和 CEM 之间插值。把一组代价喂进去,看不同 \(r\) 下的归一化权重:

def exp_r(x, r):
    if abs(r-1.0) < 1e-6: return np.exp(x)        # r→1 退化为标准 exp
    base = np.maximum(1.0 + (1.0-r)*x, 0.0)       # [·]_+ 截断
    return base**(1.0/(1.0-r))
w = exp_r(-J/lam, r); w /= w.sum()                # 用作权重函数

输出(代价 \(J=[0, 0.5, 1, 1.5, 2, 3, 5]\),已减最小值):

r→1 (MPPI/指数加权)    : 0.419 0.254 0.154 0.093 0.057 0.021 0.003
r=2                    : 0.302 0.201 0.151 0.121 0.101 0.075 0.050
r=5                    : 0.217 0.165 0.145 0.133 0.125 0.114 0.101
r=20 (趋向 CEM/硬阈值)  : 0.167 0.147 0.143 0.140 0.138 0.135 0.131

看这组数字的变化趋势:

  • \(r\to 1\)(MPPI):权重是标准指数衰减——最低代价样本权重 \(0.419\),随代价升高平滑地降到 \(0.003\)。差异悬殊、平滑过渡,正是 MPPI 的指数加权。
  • \(r\) 增大:权重分布越来越"平"——\(r=20\) 时从 \(0.167\)\(0.131\),各样本权重趋于接近。这意味着高代价样本不再被指数式地极度压低,而是和低代价样本拿到相对接近的权重。
  • \(r\to\infty\)(趋向 CEM):在极限和配合截断支撑集下,权重函数趋向"被纳入的样本近似等权、被排除的样本权重为零"——这正是 CEM 硬阈值的"精英内等权、非精英为零"。

并验证 \(r\to 1\) 的退化:exp_r(x, r=1.0001) 算出 \([0.368, 0.607, 1.0]\),与标准 \(\exp(x)\)\([0.368, 0.607, 1.0]\) 一致。

所以 \(r\) 是一个连续的"筛选硬度"旋钮\(r=1\) 时是 MPPI 的软指数加权,\(r\) 增大时筛选逐渐变硬,\(r\to\infty\) 时趋向 CEM 的硬阈值。

读到这里你可能会问:上面的统一表里提到 MPPI 对应"KL 散度"、Tsallis 对应"Tsallis 散度"——这个"散度"是什么,它和权重函数有什么关系?这值得用几句话讲清,因为它揭示了统一框架更深的一层。

回忆第 1 章:MPPI 可以从"最小化提议分布 \(q\) 与目标分布 \(\mathbb{P}^\star\) 之间的 KL 散度"推导出来——KL 散度衡量两个分布有多"不一样",最小化它就是让 \(q\) 尽量贴近 \(\mathbb{P}^\star\)

而指数权重 \(e^{-J/\lambda}\) 正是这个 KL 最小化问题的解的形式。Tsallis 框架做的事是:把"KL 散度"换成更一般的"Tsallis 散度"(KL 散度的一个推广,\(r=1\) 时退化为 KL)。

换了散度,对应的最优权重函数就从标准指数变成了变形指数 \(\exp_r\)。所以**权重函数的形状,根源于你用什么散度来衡量"分布的接近程度"**——用 KL 得到指数权重(MPPI)、用 Tsallis 散度得到变形指数权重(Tsallis VI-MPC)。这就是为什么统一表里"散度"和"权重函数"两行是对应的:散度是因、权重函数是果。

理解这一层,你会看到统一框架不只是"换个权重函数"的表面操作,而是"换个衡量分布距离的尺子"的深层选择——而 Tsallis 散度这把尺子比 KL 更一般,所以它的框架能涵盖 MPPI 和 CEM。这也呼应了 §4.1 那个本质洞察的升级:从"两种权重函数"深化为"两种散度度量"。

MPPI 和 CEM 不再是两个孤立的算法,而是这条由 \(r\) 参数化的连续谱的**两个端点**。把这个统一画成一张表:

维度 MPPI CEM Tsallis VI-MPC
散度正则 KL 散度 (隐式 Heaviside 筛选) Tsallis 散度(KL 的推广)
权重函数 \(e^{-J/\lambda}\)(标准指数) \(\mathbb{1}\{J\le J_{\text{elite}}\}\)(硬阶跃) \(\exp_r(-J/\lambda)\)(变形指数)
参数 \(r\) \(r\to 1\) \(r\to\infty\) 可调 \(1 < r < \infty\)
筛选硬度 最软(人人有份) 最硬(非精英即弃) 连续可调
特性 全局搜索、方差较大 精英聚焦、易陷局部 软硬之间任意平衡

本质洞察:Tsallis 框架完成了一件深刻的事——它把"MPPI vs CEM"这个**离散的二选一**,变成了"\(r\) 取多少"这个**连续的旋钮**。这背后是一个更一般的数学结构:标准指数 \(\exp\) 和它对应的 KL 散度,只是 Tsallis 变形指数 \(\exp_r\) 和 Tsallis 散度这个**更大家族**里的一个点(\(r=1\) 那个点)。换句话说,MPPI 的全部信息论根基(第 1 章的自由能–KL)本身就是一个更大框架的特例。这解释了为什么第 3 章那么多变体能被"五侧面"统一、为什么 CEM 和 MPPI 阵营独立发现相同智慧——因为它们从一开始就活在同一个数学框架里,只是用了不同的参数。理解了这一点,你对采样式 MPC 的认识就从"一堆算法"升级为"一个框架 + 几个旋钮",这是质的飞跃。

值得停下来想一想"统一"在科学中为什么这么有价值,因为它不只是 Tsallis 框架的局部好处,而是科学进步的一种普遍模式。

科学史上最重要的进展往往是统一:牛顿用万有引力统一了"天上的行星运动"和"地上的苹果下落"——在他之前这是两类看似无关的现象;麦克斯韦用电磁理论统一了电、磁、光——之前它们是三个独立的研究领域。

这些统一的价值不只是"少记几个理论",更在于:统一揭示了现象背后的共同结构,从而带来新的预测能力和设计自由(麦克斯韦统一后预言了电磁波,催生了无线电)。

Tsallis 框架对采样式 MPC 做的是同一类事——它揭示 MPPI、CEM、SV-MPC 背后的共同结构(用散度度量逼近目标分布),从而:其一,让你能预测和归类新方法(任何新方法都能定位到这个框架的某个点或维度);其二,给你设计自由(可以取框架里任意一点,而非局限于已知的几个特例);其三,让理论分析可以一次覆盖整族(如风险敏感度分析对所有 \(r\) 成立)。

这就是为什么本章花这么大力气讲统一视角——它不是炫技的理论游戏,而是把你对采样式 MPC 的理解从"博物学式地记录一个个物种"提升到"掌握支配整个族群的规律"。

当你拿到任何一个采样式控制方法,能立刻说出"它是这个框架里换了 X 的特例"时,你就达到了这种理解层次——这比记住一百个算法的细节更有力量。

这里还要厘清论文的一个记号细节,免得你读原文时困惑。Tsallis VI-MPC 论文里用的参数符号是 \(r\)(reparameterized 变形指数),\(r\to 1\) 对应 MPPI、\(r\to\infty\) 对应 CEM。

有些资料(包括本章大纲的早期版本)用 \(q\) 来记 Tsallis 的变形参数,方向可能相反(\(q\to 1\) 对应 MPPI、\(q\to\infty\) 对应 CEM,或某些约定下 \(q\)\(r\) 互为某种变换)。

\(q\)\(r\) 是同一套 Tsallis 数学的两种参数化,本质一样,但具体公式里的符号方向要以你所读的那篇论文为准。本章统一采用论文 RSS 2021 的 \(r\) 记号。

Tsallis 框架统一了谁:四个特例

Tsallis VI-MPC 论文明确指出,它把以下方法都收为特例(通过选择不同的"形状函数"和参数):

  • VI-MPC(变分推断 MPC):用 KL 散度的变分推断框架,是 Tsallis 在标准 KL(\(r=1\))下的情形。
  • MPPI:路径积分控制,对应 \(r\to 1\) 的指数加权。
  • CEM:交叉熵方法,对应 \(r\to\infty\) 的硬阈值精英。
  • SV-MPC(Stein 变分 MPC):第 3 章 §3.4 提到的用 SVGD 粒子集表示多模态后验的方法,在 Tsallis 框架里对应用 Stein 类的策略参数化。

论文在 5 种机器人系统、3 种策略参数化(单峰高斯 UG、高斯混合 GM、Stein)上做了实验,验证这个统一框架不仅理论优美、而且实践有效(通过调 \(r\) 控制代价/奖励变换,能在均值和方差上同时优于 MPPI 和 CEM)。

一个有意思的理论结论:对同样的精英门槛和合适的 \(r\),Tsallis 可以做到比 CEM 更低的平均代价——因为 CEM "无限硬地"惩罚方差、且给所有精英等权,而 Tsallis 的软硬可调让它能更灵活地平衡均值与方差。

这里值得展开一下"风险敏感度"这个概念,因为它是理解"为什么 \(r\) 这个旋钮有用"的关键,也是 Tsallis 论文分析的核心。所谓风险敏感,指的是控制器在"平均表现好"和"最坏情况不太糟"之间如何权衡。

一个风险中性的控制器只看平均代价;一个风险厌恶的控制器会额外惩罚高方差(宁可平均差一点,也要避免偶尔的灾难性结果);风险偏好则相反。

关键洞察是:权重函数的"硬度"直接对应风险敏感度。直观地想:CEM 的硬阈值只保留最好的一批、对其等权——它极度关注"挑出最好的",相当于对方差有很强的态度(要么入选要么出局,没有中间)。

MPPI 的软指数加权让所有样本按代价平滑贡献——它对"次优但不差"的样本更宽容,风险态度更温和。Tsallis 的 \(r\) 在两者之间连续调节,于是 \(r\) 实际上是一个"风险敏感度旋钮":调 \(r\) 就是在调控制器对"平均 vs 方差"的权衡。

这解释了为什么前面说 Tsallis 能比 CEM 拿到更低平均代价——因为对某些任务,CEM 那种"无限硬"的风险态度过于极端(把方差惩罚得太狠,牺牲了平均),而 Tsallis 调一个合适的 \(r\) 能找到更优的风险平衡点。

从泰勒展开的角度,不同 \(r\) 对应代价变换在均值附近不同的二阶项系数,这个系数正是风险敏感度的数学度量(论文有详细推导)。

理解了"\(r\) = 风险敏感度旋钮",你就明白 Tsallis 框架的实用价值不只是"统一了 MPPI 和 CEM"这个理论优美,更在于它给了你一个**显式调节风险态度**的工具——这在安全攸关的任务(要避免灾难性失败)里尤其有用。

这里要诚实地说一下 Tsallis 框架的实践采用现状,免得你产生"它既然这么好为什么大家还在用 MPPI"的困惑。事实是:MPPI(\(r=1\))在实践中仍是绝对主流,Tsallis 的中间 \(r\) 用得相对少。这不矛盾,原因有几个。

其一,多一个参数就多一份调参负担:用 Tsallis 中间 \(r\) 意味着除了 \(\lambda\) 还要调 \(r\),对很多任务这份额外复杂度换来的收益不足以抵消调参成本——MPPI 加好的协方差和 warm-start 往往已经够用。

其二,MPPI 有更成熟的生态:开源实现、调参经验、社区支持都围绕 MPPI,用 Tsallis 要自己实现变形指数、自己摸索 \(r\) 的整定。

其三,收益的任务依赖性强:Tsallis 的优势在需要精细风险权衡的任务上明显,但很多任务(尤其代价设计得当时)对风险态度不敏感,\(r=1\) 就挺好。

所以 Tsallis 框架的主要价值,目前更多在**理论层面**(统一理解、指导分析、定位新方法)而非"日常首选算法"——这和很多统一框架的命运类似:它们的贡献是提供视角和工具,而非取代所有特例。

这对你的实践启示是:把 Tsallis 当成理解采样式 MPC 的认知工具、和需要精细风险控制时的备选,而非日常默认。

日常你大概率还是用 MPPI(\(r=1\))配好协方差——而理解了 Tsallis,你知道 MPPI 只是连续谱上的一个点,需要时可以往硬的方向调。这种"理论上掌握全谱、实践中按需取点"的态度,正是统一框架的正确用法。

⚠️ 常见陷阱

编程陷阱:实现变形指数时忘记 \([\,\cdot\,]_+\) 截断,底数为负时产生 NaN 或复数。 错误做法:直接写 (1 + (1-r)*x)**(1/(1-r)),不做 max(·, 0) 截断。 现象/后果:当 \(1+(1-r)x < 0\) 时(\(r>1\)\(x\) 足够负,即代价足够高时会发生),底数为负、分数次幂在实数域无定义,得到 NaN 或复数,权重计算崩溃或产生乱码。 根本原因:变形指数的定义本身含截断 \([\,\cdot\,]_+\)——它表示"超出支撑集的样本权重为零",这恰是 \(r>1\) 时"硬筛选"的数学体现(高代价样本被直接置零,正像 CEM 扔掉非精英)。漏掉截断就破坏了定义。 正确做法:严格按定义写 base = np.maximum(1 + (1-r)*x, 0.0),再取幂。\(r\to 1\) 的情形单独用 np.exp 处理(避免 \(1/(1-r)\) 除零)。 自检方法:用一组含很高代价的样本测试 \(r=5\),确认权重里高代价项是 \(0\) 而非 NaN;打印 base 的最小值,应被截断在 \(0\)

概念误区:以为 Tsallis 框架"发明了一个新算法"。 错误认识:把 Tsallis VI-MPC 当成又一个和 MPPI、CEM 并列的新方法。 现象/后果:试图比较"Tsallis vs MPPI vs CEM 哪个好",却发现 Tsallis 在 \(r=1\) 时就是 MPPI、\(r\to\infty\) 时就是 CEM——它怎么能和自己的特例比较?陷入逻辑混乱。 根本原因:Tsallis 不是一个并列的新算法,而是一个**包含 MPPI 和 CEM 的框架**。它的贡献是统一与推广,不是"再加一个"。"Tsallis vs MPPI"是范畴错误,正如"动物 vs 狗"。 正确做法:把 Tsallis 理解为"参数化的一族算法",MPPI/CEM 是其特例。有意义的问题不是"Tsallis vs MPPI",而是"在我的任务上,\(r\) 取多少最好"——可能恰好是 \(r=1\)(MPPI),也可能是中间某值。

思维陷阱:以为有了统一框架,就该永远用中间的 \(r\)、不再用纯 MPPI 或纯 CEM。 错误认识:既然中间地带可达,那"纯 MPPI(\(r=1\))"和"纯 CEM(\(r\to\infty\))"就都过时了,应该总是调一个中间 \(r\)。 现象/后果:在本该用纯 MPPI 的任务上非要调 \(r\),多引入一个难调的参数、收益甚微;或在代价尺度多变、本该用 CEM 硬阈值省心的场景,强行用中间 \(r\) 反而要操心 \(r\)\(\lambda\) 两个旋钮。 根本原因:统一框架提供了"可以取中间值"的自由,但不意味着"必须取中间值"。端点(MPPI、CEM)本身就是框架里的合法选择,且各有其适用场景(§4.1 已分析)。框架的价值是给你**选择的自由**,而非强制你用中间值。 正确做法:先从端点起步(任务简单单峰用偏硬的、需充分利用样本用 MPPI),只有当端点都不理想、且你愿意多调一个参数时,才探索中间 \(r\)。统一框架是工具箱,不是非用不可的紧身衣。

最后给一个"实践中如果真要调 \(r\) 该怎么调"的操作建议,把 §4.3 从理论落到可操作。第一步,默认从 \(r=1\)(MPPI)起步——它有最成熟的生态和调参经验,先把 \(\lambda\) 和协方差调好,看是否够用。

第二步,如果观察到特定问题再考虑调 \(r\):如果发现控制器"太冒进、偶尔出灾难性结果"(风险态度太松),往**大 \(r\)**方向调(更硬、更保守、更厌恶方差);如果发现"太保守、错失了平均更优的解",那 \(r=1\) 或更小可能更好(但 \(r<1\) 较少用,因为它比指数还软)。

第三步,用粗网格扫描——\(r\) 不必精调,在 \(\{1, 2, 5\}\) 这样的粗网格上试几个值,看哪个区间好,通常不需要更细。

第四步,注意 \(r\)\(\lambda\) 的耦合——调 \(r\) 改变了权重函数的形状,可能需要相应微调 \(\lambda\)(它们都影响实际的筛选效果)。

一个常见的实用区间是 \(r\in[1, 5]\)\(r=1\) 是 MPPI,\(r\) 到 5 左右已相当硬(接近精英筛选的行为),更大的 \(r\) 收益边际递减且数值上更需小心截断。

所以调 \(r\) 的实践不复杂:默认 \(r=1\),遇到风险态度问题时在 \([1,5]\) 粗扫,注意和 \(\lambda\) 一起调。记住前面的诚实提醒——大多数任务 \(r=1\) 就够了,调 \(r\) 是少数需要精细风险控制时的手段,不是日常必做。这个操作建议让你在确实需要时知道怎么动手,而不被"还有个 \(r\) 可调"搞得无所适从。

练习

  1. (实现 + 插值验证,⭐⭐⭐) 实现变形指数 \(\exp_r\)(注意截断和 \(r\to1\) 的特判),把它作为权重函数接入 §4.1 的统一采样优化器。

扫描 \(r\in\{1, 1.5, 2, 5, 20\}\),在同一任务上:(a) 验证 \(r=1\) 的行为与标准 MPPI 一致;(b) 观察 \(r\) 增大时权重分布如何从"指数衰减"变到"趋于平等再到硬截断";(c) 找出在你的任务上代价最低的 \(r\),它是端点还是中间值?

  1. (风险敏感度,⭐⭐⭐⭐) Tsallis 论文指出不同 \(r\) 对应不同的"风险敏感度"。设计一个含随机扰动的任务(代价带噪声),对比不同 \(r\) 下最终解的**均值代价**和**代价方差**。

\(r\) 越大(越硬),方差控制如何变化?能否观察到"\(r\) 提供了在均值和方差之间权衡的旋钮"?(提示:这道题较难,需要仔细设计随机代价;可参考论文的风险敏感度分析。)

  1. (统一视角综合,⭐⭐⭐) 回顾第 3 章的某个变体(如 Log-MPPI 或 SVG-MPPI),尝试用 Tsallis 框架的语言描述它:它改的是框架的哪个维度(权重函数的 \(r\)?协方差?提议分布的参数化?)?哪些变体能被 Tsallis 框架自然涵盖、哪些不能(提示:改"协方差形状"的变体如 CoVO-MPC 涉及的是另一个维度,§4.6 会讲)?这个练习帮你把第 3、4 章的所有方法挂到同一张框架图上。

§4.4 Predictive Sampling:极简采样器为何意外地有效 ⭐⭐

动机:当一个"教学玩具"打败了精心设计的算法

前三节我们见识了越来越精巧的设计:MPPI 的指数加权、CEM 的精英筛选、Tsallis 的连续插值。

一个自然的预期是——越精巧的权重方案,性能越好。Predictive Sampling(Howell 等,DeepMind + Stanford,2022)却给了一个反直觉的发现:最简单的采样器,竟然意外地有竞争力

Predictive Sampling 简单到什么程度?它把"赋权"这一步彻底砍掉了——不做指数加权、不做精英筛选,就一句话:采一批样本,取代价最低的那一个,作为新的均值(即取 argmin)。没有温度 \(\lambda\),没有精英比例,没有变形参数 \(r\)

它最初被设计为 MuJoCo MPC(MJPC)里的一个**基础 baseline,主要为教学价值**——作者本意只是放一个"最朴素的采样方法"当参照系。结果出人意料:它和更成熟的算法(iLQG、梯度下降)竞争力相当。

为什么会"意外"有效?把背后的原因想透,比单纯记住这个事实更有价值。第一个原因是**模型可用且 rollout 便宜**——在 MuJoCo 这样的快速仿真器里,前向 rollout 极快,所以即便 PS 每轮只用一个样本(argmin)、需要靠 receding-horizon 多周期慢慢改进,总的计算预算也足够它收敛到好解。

换个 rollout 昂贵的场景,PS 的"只用一个样本"就吃亏了。第二个原因是**样条参数化降维**——MJPC 用少数样条控制点参数化整条控制序列,把高维的逐时刻控制压缩成低维的控制点,于是 argmin 在低维空间里"碰运气碰到好样本"的概率大大提高(回忆 §4.2 的薄壳现象:维度越低,采到好样本越容易)。

第三个原因是**任务特性**——MJPC 演示的多是确定性仿真任务(噪声小,§4.4 后面讲的"优胜者诅咒"不严重)、且很多任务的最优控制相对平滑简单,这些都是 argmin 的友好条件。

把这三个原因合起来:PS 的"意外有效"不是魔法,而是"快 rollout + 低维参数化 + 友好任务"三个条件凑齐时的自然结果。

这个分析也告诉你 PS 何时**不**会有效——rollout 昂贵、控制高维难参数化、代价噪声大、任务需要精巧权衡时,PS 就会输给 MPPI。

所以"意外"二字其实是相对于"精巧方案必胜"的错误预期而言的;一旦理解了背后的条件,PS 的有效就毫不意外了。这也呼应本节的核心——采样式方法的威力来自"采样+评估真实代价"的核心机制,当这个核心机制在友好条件下运转时,连最简的 argmin 都够用。

这件事的意味深长之处在于:它逼我们重新审视"精巧的权重方案到底贡献了多少"。如果一个连权重都不要、只取 argmin 的方法都能 work,那 MPPI 的指数加权、CEM 的精英筛选,它们额外的复杂度换来的收益,是否被我们高估了?这正是 §4.4 要探讨的——以及,Predictive Sampling 在 §4.3 的统一框架里对应哪个位置。

如果不这样做会怎样:被"必须精巧"的预设困住

如果你抱着"采样式 MPC 必须有精巧的权重方案才能 work"的预设,会错过什么?

你会错过**极简方案在很多场景下足够好**这个事实,从而过度工程化。设想你要快速验证一个新任务能否用采样式 MPC 解决——上来就实现完整 MPPI(调 \(\lambda\)、加 warm-start、调协方差)需要不少功夫。

而 Predictive Sampling 几行代码就能跑(采样 + argmin),让你**几分钟内**就知道"这个任务采样式方法有没有戏"。把它当成最快的可行性探针,能省下大量前期试错。

你还会错过一个重要的认知——采样式 MPC 的威力,很大程度来自"采样 + 评估真实代价"本身,而非具体的权重方案

只要你能采样、能用模型前向算出真实代价、能取出好的样本,就已经抓住了采样式方法的核心。权重方案(指数 vs 硬阈值 vs argmin)是锦上添花的优化,不是 work 与否的关键。理解这一点,你面对采样式方法时心态会更从容:先用最简单的跑起来,再按需精化。

Predictive Sampling 还体现了一种值得推崇的**工程哲学——把强基线当一等公民**。在算法研究里有个常见的陷阱:人们热衷于提出复杂的新方法,却用一个被故意削弱的、调参不充分的简单方法当"基线"来对比,从而让新方法显得很强。

Predictive Sampling 的作者反其道而行——他们明确说这个方法"主要为教学价值"、不声称算法创新,却把它实现得足够好、调得足够充分,结果它打平了更复杂的方法。

这件事的深意是:一个被认真对待的简单基线,往往比想象中强得多;很多"复杂方法的优势",在和强基线对比时会缩水。这呼应了机器学习社区近年的一个反思——"先把简单基线做强"(如经典的"神经网络不如调好的线性模型"案例)。

对你的实践有两个启示。其一,做研究/选型时,永远先实现一个认真调过的简单基线(如 Predictive Sampling),用它当真实的参照系,而非随便搭个弱基线自欺欺人。其二,警惕"复杂=更好"的直觉——复杂方法要证明自己的价值,得打赢强基线,而非弱基线。

这也和奥卡姆剃刀(如无必要勿增实体)一脉相承:在简单方法够用时,复杂方法的额外复杂度是需要被质疑的成本,而非理所当然的进步。

Predictive Sampling 用一个"教学玩具竟然打平大人"的故事,把这个工程哲学讲得格外生动——它的价值不只在算法本身,更在它示范的这种诚实、务实的研究态度。

把它跑出来对比:

if mode == 'ps':                          # Predictive Sampling: 直接取最优样本
    mu = U[np.argmin(J)]
elif mode == 'mppi':                      # 指数加权
    w = np.exp(-(J-J.min())/1.0); w /= w.sum(); mu = (w[:,None]*U).sum(0)
elif mode == 'cem':                       # 硬阈值精英
    mu = U[np.argsort(J)[:K//10]].mean(0)

同一到达任务,三种聚合方式的最终代价:

Predictive Sampling(取argmin): 42.84
MPPI(指数加权):                42.19
CEM(硬阈值精英):               42.22

三者**几乎相同**。极简的"取最优样本"和精心设计的指数加权、精英筛选打成平手。当然这是个简单的单峰任务(PS 在复杂任务上未必总能追平更精巧的方法),但它确凿地说明:在不少场景下,权重方案的精巧程度贡献有限,采样 + 取好样本这个核心才是主力

理论:极简的代价与它在统一框架里的位置

Predictive Sampling 的极简带来什么取舍?

它放弃了什么。取 argmin 意味着**只用了一个样本的信息**——其余 \(K-1\) 个样本算了代价却没贡献到更新里(除了用于比较"谁最低")。

相比之下,MPPI 用所有样本的加权信息、CEM 用一批精英的信息。在样本含丰富方向信息、且需要平均掉单个样本噪声时,argmin 会浪费这些信息、且容易被单个"幸运但高方差"的样本带偏。

"被幸运样本带偏"这个风险值得展开,因为它是 argmin 最微妙的弱点。设想代价评估带噪声(真实系统几乎总有噪声:传感器噪声、随机扰动、模型的随机性)。

这时一个样本的"观测代价"= 真实代价 + 噪声。argmin 取的是观测代价最低的那个——但它可能不是真实代价最低的,而是**真实代价不错、且恰好噪声为负(运气好)**的那个。

换句话说,argmin 有系统性地选中"被噪声低估"的样本的倾向,这在统计上叫"优胜者的诅咒"(winner's curse)——你选出的"最好"往往高估了它的真实质量,因为选择过程偏好了那些运气好的。

MPPI 的加权平均则天然抵抗这个问题:它对所有样本加权,单个样本的噪声在平均中被抵消(大数定律),所以更新方向反映的是"代价低的区域的平均趋势",而非"某个幸运样本的位置"。

这就是为什么前面说 argmin 在高噪声下不如加权平均——噪声越大,优胜者的诅咒越严重,argmin 被带偏得越厉害。

理解这个机制,你就知道 Predictive Sampling 的适用前提之一是"代价评估噪声不大"——在确定性仿真里(MJPC 的主场)噪声小,argmin 没问题;在高噪声的真实系统或随机环境里,加权平均的抗噪性就显出价值了。

这也是本节练习要你验证的(增大代价噪声看 PS 是否落后)。所以选 argmin 还是加权,一个关键判据就是"你的代价评估有多少噪声"。

它换来了什么。极致的简单:无参数(不用调 \(\lambda\) 或精英比例)、代码最短、行为最可预测。

在样本噪声不大、或迭代次数足够多时,"每轮取当前最优"也能稳步逼近好解。加上 MJPC 用样条参数化控制(少数控制点决定整条序列,降低了有效采样维度),argmin 的"只用一个样本"在低维参数空间里没那么吃亏。

样条参数化这个细节值得单独说说,因为它是一个能用到任何采样式 MPC 的通用技巧。常规做法是对控制序列的**每个时间步**独立采样——若时域有 56 步、控制 3 维,那采样空间就是 \(56\times3=168\) 维。

样条参数化则反过来:只在少数**控制点**(比如 5 个)上采样,中间的控制值由样条插值(zero/linear/cubic)算出——采样空间降到 \(5\times3=15\) 维。

这带来三个好处。其一,降维提升样本效率——采样空间小了一个数量级,同样的样本数在低维空间覆盖得更密(直接呼应 §4.2 薄壳现象:低维下采样更有效),这正是 argmin 在 MJPC 里够用的关键原因之一。

其二,天然平滑——样条插值出的控制序列本身就是平滑的(尤其 cubic),无需额外的平滑处理(呼应第 3 章 §3.2 的平滑主题,但用插值而非导数空间采样实现)。其三,减少计算——少数控制点意味着采样和存储的量都小。

当然也有代价:样条限制了控制序列的表达能力(只能表达样条能插出的形状),对需要高频精细控制的任务可能不够灵活——这是"降维换效率"的典型权衡(呼应第 3 章 SCP-MPPI 的样条思想)。

所以样条参数化不是 PS 专属,而是一个通用的"降低采样维度"手段,可以用到 MPPI、CEM 等任何采样式方法上——当你的控制序列较长、且好解相对平滑时,它能显著提升样本效率。

理解这一点,你就看到 PS 的"意外有效"里,样条参数化贡献了重要一份——它把高维控制压成低维样条,让简单的 argmin 也能在低维空间里有效工作。

读到这里你可能会问:既然 Predictive Sampling 每次取最优样本就行,为什么还要 receding-horizon 地每个控制周期反复优化?取一次最优、执行整条序列不就完了吗?这个问题触及了所有 MPC(不只采样式)的核心——为什么要 receding-horizon(滚动时域)。原因有二。

其一,模型不完美:你用模型前向 rollout 算出的"最优序列",是基于模型预测的;真实系统执行后会偏离预测(扰动、模型失配,第 3 章 §3.1 反复讲的)。

如果一次算好就盲目执行整条,偏差会累积到不可收拾。滚动时域的精髓是"只执行第一步,然后用真实的新状态重新规划"——不断用最新的真实反馈纠正模型预测的偏差。

其二,环境在变:障碍物在动、目标在变,一次规划无法预见未来所有变化,必须持续重规划。所以 Predictive Sampling 的"每周期取最优"不是冗余,而是和所有 MPC 一样的滚动时域机制——它只是把"每周期怎么优化"这一步用最简的 argmin 实现了。

区分两个层次:滚动时域(每周期重规划)是 MPC 的框架层面、与用什么优化器无关;取 argmin(怎么优化)是 Predictive Sampling 在优化器层面的极简选择。Predictive Sampling 简化的是后者,保留了前者。

理解这个区分,你就不会把"极简优化器"误解为"可以不要滚动时域"——前者是省了优化的复杂度,后者是 MPC 应对不完美模型和动态环境的根本机制,不能省。

它在 Tsallis 框架里的位置。这是个有启发的问题(也是本节练习的思考题)。回忆 §4.3:\(r\to 1\) 是 MPPI(软指数)、\(r\to\infty\) 是 CEM(硬阈值,精英内等权)。Predictive Sampling 取 argmin,相当于"精英比例小到只剩一个样本"的极端 CEM——或者说,是筛选硬到极致的情形。

从权重函数看,argmin 对应一个"只有全局最优样本权重为 1、其余全为 0"的权重函数,这正是 CEM 硬阈值在"精英数 = 1"时的极限,也可以理解为 MPPI 在 \(\lambda\to 0\)(温度趋零、权重无限尖)时的极限。

所以 Predictive Sampling 不是统一框架之外的"另类",而是框架的一个**极端端点**——把"筛选硬度"推到最硬的那一头。

把 Predictive Sampling 放进更广的优化方法谱系,还能看到它和**进化策略(Evolution Strategies, ES)**的亲缘。

ES 是一类无导数优化方法,基本套路也是"采一批候选、评估、用好的候选更新分布"——和采样式 MPC 的骨架几乎一样。

ES 里有一个谱:从 \((\mu,\lambda)\)-ES(只保留最好的若干个,类似 CEM 硬阈值)到用所有样本加权的 NES(Natural Evolution Strategies,类似 MPPI 软加权),中间还有各种选择策略。

Predictive Sampling 的"取最优一个",对应 ES 里最朴素的 \((1,\lambda)\) 选择(只保留最好的一个)。

这个联系说明:采样式 MPC 和进化优化本质上是同一类"基于种群的无导数优化"在不同领域的实例——MPC 把它用于时序控制(每个周期重新优化)、ES 把它用于一般参数优化。

标注边界:ES 通常用于**离线**优化一个固定目标(如优化神经网络权重),采样式 MPC 是**在线**地每个控制周期重新优化、且利用 receding-horizon 的时序结构(warm-start)。

但"采样—选择—更新"的核心循环是共享的。理解这个亲缘,你会发现 Predictive Sampling 的"极简"其实站在进化计算几十年的传统上——它不是凭空的简化,而是一个有深厚渊源的经典选择策略在控制问题上的应用。

本质洞察:Predictive Sampling 的存在,给整章的统一视角补上了关键一笔——它证明"筛选硬度"这条连续谱的**最硬端点(只取一个最优样本)依然可用**。结合 §4.1 的另一端(\(\lambda\) 很大、权重几乎均等),我们看到一条完整的谱:从"几乎不筛选"(所有样本近等权)到"筛选到极致"(只取一个)。MPPI、CEM、Tsallis、Predictive Sampling 全都是这条谱上的点。这条谱最深刻的启示是:采样式 MPC 的有效性,主要来自"采样 + 用模型评估真实代价"这个核心机制,而权重方案只是在这个核心之上调节探索-利用的平衡。这解释了为什么连最极端的 argmin 都能 work——因为核心机制已经在那里了。也提醒我们:面对一个新任务,不必一上来就追求精巧的权重,先用最简单的跑通,往往就能解决大半问题。

把 Predictive Sampling 放进"采样式规划"的更大版图,能看清它代表的流派。在序贯决策里,用采样来规划大致有两大流派。

一是**轨迹优化流派**(本章和第 2、3 章讲的 MPPI/CEM/PS 都属此):在连续控制空间里采样整条控制序列、评估、更新分布——适合连续控制、有模型可前向 rollout 的场景。

二是**树搜索流派**(如蒙特卡洛树搜索 MCTS、AlphaZero 的核心):在离散动作空间里构建搜索树、用采样(rollout 或值网络)评估树节点、反向传播更新——适合离散动作、博弈、需要深度前瞻的场景。Predictive Sampling 是轨迹优化流派里最极简的代表。

把它和 MCTS 对照很有启发:MCTS 也"采样—评估—选择",但它在树结构上做、用 UCB 这类策略平衡探索利用、保留整棵搜索树的信息;PS 在连续序列上做、用最朴素的 argmin、只保留一条最优序列。

两者都成功,说明"采样—评估—选择"这个元模式在离散和连续、简单和复杂的形态下都 work——这呼应本章的统一精神,只是统一的范围更大了(跨越轨迹优化和树搜索两大流派)。

标注边界:MCTS 擅长离散、需深度前瞻、有明确博弈结构的问题(围棋、棋类);轨迹优化擅长连续控制、高频实时的问题(机器人控制)。它们各有主场,但共享"用采样探索决策空间、用评估筛选、用结果更新"的内核。

理解这个版图,你就知道 Predictive Sampling 不是孤立的奇招,而是"采样式规划"这个大家族里轨迹优化流派的极简端点——而这个大家族还包括 AlphaZero 那样改变了 AI 历史的方法。

⚠️ 常见陷阱

编程陷阱:用 Predictive Sampling 时不做 warm-start / shift,每周期从零采样,导致 argmin 抖动剧烈。 错误做法:每个控制周期把均值重置为零,重新采样取 argmin。 现象/后果:因为 argmin 只取一个样本、不做平均,相邻周期取到的"最优样本"可能差异很大(各自是不同的随机样本),导致控制序列在周期间剧烈跳变、不连贯。 根本原因:argmin 没有"平均掉噪声"的作用(不像 MPPI 加权平均能平滑掉单样本噪声),所以它对"起点"和"采样随机性"更敏感;不做 warm-start 时,每周期独立采样的随机性直接体现为控制抖动。 正确做法:即便用极简的 PS,也要保留 warm-start(用上周期解 shift 一步作为新均值)、并配合 §4.2 的有色噪声让采样平滑;MJPC 正是用样条参数化 + warm-start 来稳定 PS 的输出。 自检方法:观察相邻周期输出控制的差异,若跳变剧烈,加上 warm-start 和有色噪声后应明显改善。

概念误区:以为 Predictive Sampling 的"简单有效"意味着 MPPI/CEM 的复杂是多余的。 错误认识:既然 argmin 都能打平,那 MPPI 的指数加权、CEM 的精英筛选岂不是白费功夫? 现象/后果:在真正需要精巧权重的任务(高噪声代价、需要充分利用样本信息、多峰)上,盲目用 PS 会显著不如 MPPI,却以为"PS 既然简单有效就该一直用"而排查不出问题。 根本原因:PS 的"简单有效"是有条件的——它在样本噪声不大、单峰、低维参数(样条)的场景下能打平,但这些条件不总满足。复杂的权重方案在条件变苛刻时(高噪声、需平均、多峰)会显出价值。"简单够用"不等于"复杂多余"。 正确做法:把 PS 当成基线和快速探针,先用它探路;当它不够好时(高噪声、多峰、需充分利用样本),再升级到 MPPI 或 Tsallis 的软加权。简单与复杂各有适用区间。

练习

  1. (实现 + 对比,⭐⭐) 实现 Predictive Sampling(采样 + argmin + warm-start),在一个简单到达任务上对比它与 MPPI、CEM 的最终代价与收敛速度,复现"三者打平"的现象。

然后增大代价的随机噪声(每次评估加噪),观察 PS 是否开始落后于 MPPI——验证"高噪声下 argmin 不如加权平均"。

  1. (统一框架定位,⭐⭐⭐,思考题) 本节说 Predictive Sampling 取 argmin,对应统一框架的"最硬端点"。

请论证:argmin 等价于 MPPI 在 \(\lambda\to ?\) 时的极限、也等价于 CEM 在精英数 \(= ?\) 时的情形。

从 §4.3 的变形指数 \(\exp_r\) 看,argmin 对应 \(r\to ?\)?把 Predictive Sampling 准确地标到 §4.3 那张统一表上。(这道题是大纲点名的思考题,答案揭示 PS 不是"另类"而是框架的极端端点。)

  1. (样条参数化,⭐⭐⭐) MJPC 用样条(zero/linear/cubic 插值)参数化控制——少数控制点决定整条序列。

实现一个用样条参数化的 Predictive Sampling(在控制点上采样、插值出完整序列),对比它与"逐时刻采样"的 PS 在样本效率上的差异。

思考:样条参数化为什么能缓解 argmin"只用一个样本"的劣势?(提示:样条降低了有效采样维度,呼应第 3 章 SCP-MPPI 的样条思想。)

§4.5 Nav2 MPPI Controller:把采样式 MPC 做成生产级插件 ⭐⭐⭐

动机:从"能跑的算法"到"能用的产品"

前四节都在讲算法与理论。但一个采样式控制器要真正用在机器人产品上,还隔着一道工程鸿沟——它得跟整个导航栈对接(接收全局路径、查询代价地图、输出速度指令)、得在嵌入式 CPU 上实时跑、得让不同任务方便地定制行为(这个机器人要避行人、那个要贴边走)。

Nav2 MPPI Controller(Aleksei Budyakov 创建,Steve Macenski 适配到 Nav2,ROSCon 2023)就是把 MPPI 做成生产级 ROS2 组件的范例。

它最值得学习的设计是 critic 插件架构:把"代价函数"拆成一组可插拔的 critic(评判器)——避障是一个 critic、跟随路径是一个 critic、对齐朝向是一个 critic……每个 critic 独立地给所有 rollout 轨迹打分(累加代价),最终所有 critic 的代价之和构成总代价,喂给 MPPI 的指数加权。

要改变控制器行为,不必改算法核心,只需增删或调整 critic——这正是把第 2、3 章讲的"代价函数设计"工程化、模块化的优雅方案。

为什么这个架构值得专门学?因为它回答了一个实际问题:真实任务的代价函数往往很复杂(要同时考虑避障、跟随、朝向、前进偏好、速度限制……),如果把这些全塞进一个庞大的代价函数,既难写又难调难维护。

critic 架构把这个复杂代价**分解**成一组职责单一、可独立开发测试、可按需组合的插件——这是软件工程的"单一职责 + 组合优于继承"原则在采样式控制里的体现。学会它,你不仅会用 Nav2,更掌握了"如何把复杂代价工程化"的通用模式。它也呼应了 §4.5 全章的工程落点:把前面统一框架的"算法",真正变成"能部署的代码"。

如果不这样做会怎样:单体代价函数的维护噩梦

设想不用 critic 架构,而是把所有代价逻辑写进一个巨大的 computeCost() 函数。会怎样?

改一处牵全身。避障、跟随、朝向的逻辑全耦合在一个函数里,改避障逻辑时容易不小心影响跟随;加一个新的代价项(如"避行人")要在这个庞大函数里插入代码、小心不破坏现有逻辑。代码越长越脆,每次修改都提心吊胆。

无法按任务裁剪。机器人 A 要避行人、机器人 B 在仓库里不需要避行人但要严格贴边——单体函数里这些逻辑混在一起,无法干净地"为 A 开启避行人、为 B 关闭"。你只能维护多个版本的代价函数,或者用一堆 if-else 开关把函数搅得更乱。

难以独立测试。想单独测"避障代价算得对不对",但它和其他代价缠在一起,没法隔离出来测。bug 定位变成大海捞针。

调参困难。各代价项的权重全在一个函数里,调一个权重要在长代码里找到对应位置;各项之间的相对重要性关系不清晰,调参全靠试。

critic 架构把这些问题一次性解决:每个 critic 是独立的类、独立的文件、独立的参数、独立的开关。

改避障只动 ObstaclesCritic,加避行人就新写一个 PedestrianAvoidanceCritic 插件挂上去,不碰任何现有代码。

每个 critic 可单独测试,权重在各自的参数里清晰可调。这就是工程化的力量——把第 2 章"代价函数"这个单一概念,发展成一套可维护、可扩展、可组合的工程架构。

理论:critic 架构与 MPPI 主循环

先看 Nav2 MPPI 的整体结构,再看 critic 如何嵌入。

整体定位。Nav2 MPPI Controller 实现 nav2_core::Controller 接口,作为局部轨迹规划器跑在 controller_server 里。

它的输入是全局规划器给出的路径 + 代价地图,输出是机器人的速度指令(线速度、角速度)。它在第 4 代 i5 这样的普通处理器上能跑 50+ Hz,支持差速(Differential)、全向(Omnidirectional)、阿克曼(Ackermann)三种底盘运动模型。

为了让你理解 Nav2 MPPI 的定位,值得说一下它在导航软件栈里处于什么位置——这决定了它要解决什么、不解决什么。

机器人导航通常分**全局规划**和**局部规划**两层:全局规划器(如 A*、Dijkstra、或采样式的 RRT*)在地图上算一条从起点到终点的粗略路径,不考虑动力学和实时障碍;局部规划器(也叫局部轨迹规划器或控制器)则负责"沿着全局路径走、同时实时避开动态障碍、并输出符合机器人动力学的速度指令"。

Nav2 MPPI Controller 是一个**局部规划器/控制器**——它接收全局路径作为参考(PathFollow/PathAlign 这些 critic 就是让它贴着全局路径走),在局部实时地用 MPPI 算出避障且可行的速度指令。

这解释了它的几个设计:它不做全局路径搜索(那是全局规划器的活),所以它的 critic 里有"跟随给定路径"而非"找到路径";它的预测时域较短(如 2.8 秒),因为它只管局部、不管全局;它高频运行(50+ Hz),因为局部避障要快速响应。

和传统的局部规划器(如 DWA 动态窗口法、TEB 时间弹性带)相比,Nav2 MPPI 的优势正是采样式方法的优势——能处理非光滑代价、能灵活组合多种目标(靠 critic 架构)、对各种底盘通用。

理解这个"局部规划器"定位,你就明白为什么本章把它当作"采样式 MPC 的工程落地范例"——它是 MPPI 这个算法在一个真实、成熟、广泛部署的机器人软件栈里的具体化身,而非一个孤立的研究原型。这也是为什么学它有实战价值:它就在你装 ROS2 导航栈时触手可及。

MPPI 主循环(在 optimizer.cpp 里)。每个控制周期做的事,和第 2 章的 MPPI 主循环一致,只是工程化了:

  1. 从当前最优控制序列出发,采样 batch_size 条候选控制序列(加噪声,默认有 warm-start)。
  2. 用运动模型把每条控制序列前向,得到 batch_size 条轨迹(每条是一串 \((x, y, \theta)\))。
  3. 调用所有 critic 给这些轨迹打分——这是 critic 架构的核心,下面详述。
  4. 把所有 critic 累加出的总代价,按 MPPI 的指数加权 \(w_i\propto e^{-J_i/\lambda}\)(这里温度参数叫 temperature,默认 0.3)计算权重。
  5. 加权平均得到新的最优控制序列,输出其第一个控制(速度指令)给机器人。

第 3 步是把前四节的"算法"和真实导航"任务"对接的关键。来看 critic 怎么工作。

在深入 critic 之前,先说一下第 2 步的**运动模型(motion model)**,因为它体现了 Nav2 MPPI 对不同机器人的适配。

运动模型回答"给定一串控制(速度指令),机器人的位姿 \((x,y,\theta)\) 会怎么演化"——这正是第 2 章 MPPI rollout 里的"动力学模型"在导航场景的具体化。

不同底盘的运动学不同:**差速(DiffDrive)**底盘只能前进/后退和原地转(不能横移),其运动模型把 \((v, \omega)\)(线速度、角速度)映射为位姿变化;**全向(Omni)**底盘能任意方向平移,多一个横向速度 \(v_y\);**阿克曼(Ackermann)**底盘像汽车,转向受最小转弯半径约束,不能原地转。

Nav2 把运动模型做成可配置的插件(mppi::DiffDriveMotionModel 等),换底盘只需换运动模型配置——这又是一处插件化设计(和 critic 插件一个思路)。

为什么这个设计重要?因为它让同一套 MPPI 算法能服务于差速轮式机器人、全向移动平台、汽车式机器人,而不必为每种底盘重写控制器。

运动模型的正确性直接关系到 rollout 预测的准确——如果运动模型和真实底盘不符(比如把阿克曼当差速处理),预测的轨迹就是错的,MPPI 会基于错误的预测做决策(呼应第 3 章 §3.1 的模型失配主题)。

所以用 Nav2 MPPI 时,选对运动模型是第一步——它定义了"机器人会怎么动",是整个 rollout 的基础。

理解了运动模型这一层,你就看到 Nav2 MPPI 的可配置性是全方位的:运动模型适配底盘、critic 适配任务目标,两者都用插件化实现——这是它能成为通用导航控制器的工程基础。

第 3 步是把前四节算法对接真实导航任务的关键。来看 critic 怎么工作。

critic 架构。所有 critic 都继承自基类 mppi::critics::CriticFunction,由 CriticManager 统一加载和调用。每个 critic 实现一个核心方法:

void score(CriticData & data);   // 给所有 rollout 轨迹打分, 原地累加到 data.costs

关键点:score 接收一个 CriticData(里面有所有 rollout 的轨迹 data.trajectories、当前路径、代价地图等),它的职责是**遍历所有轨迹、计算本 critic 关心的那部分代价、原地累加到 data.costs**。

注意是"累加"(+=)而非"覆盖"——这样多个 critic 的代价自然叠加成总代价。所有 critic 跑完后,data.costs 就是每条轨迹的总代价,喂给上面第 4 步的指数加权。

读到这里你可能会问:为什么 critic 之间用**累加**(加权和)来组合,而不是取**最大值**(取最严格的那个约束)或别的方式?这是个有深度的设计问题。

取 max 的思路是"哪个 critic 觉得这条轨迹最差,就听谁的"——这在纯硬约束场景(任何一个约束违反就完全不可接受)有道理。

但导航的多数目标是**软的、可权衡的**:离障碍稍近一点、离路径稍偏一点、朝向稍差一点,这些都不是"绝对不可接受",而是"各扣一些分、综合考量"。

加权和恰好表达这种"综合权衡"——每个 critic 按其重要性(权重)贡献一份代价,总分反映了轨迹在所有目标上的综合表现。

取 max 则会丢失这种综合性:它只看最差的一项,忽略其余项的好坏,导致"一票否决"式的僵化(一条在其他方面都很好、只在某项略差的轨迹会被那一项的 max 否决)。

还有一个数学原因(呼应 §4.5 本质洞察):加权和让总代价对各 critic 是**线性可分解**的,这正是 critic 能独立计算再累加、插件架构能成立的前提;取 max 是非线性的,会破坏这种可分解性。

当然,对真正的硬约束(碰撞、超出运动学极限),Nav2 的做法是给那个 critic 一个**极大的权重或专门的硬惩罚**,让违反硬约束的轨迹代价大到实际上不可能被选中——用"很大的加权代价"来近似"硬约束",既保持了加权和的可分解性,又实现了硬约束的效果。

理解这个设计,你就明白"累加"不是随意的选择,而是"软目标可权衡 + 架构可分解"的必然,也明白硬约束在这个框架里是怎么用大权重来表达的。

这个设计的精妙在于:每个 critic 只管自己那摊事,彼此通过"累加到同一个 costs 数组"来组合。避障 critic 只算避障代价、跟随 critic 只算跟随代价,它们互不知道对方存在,却能通过累加机制协同工作。

这就是"组合"的威力——加一个新 critic,只是多一个往 costs 里累加的来源,不影响任何现有 critic。

读到这里你可能会担心效率:每个 critic 都要遍历全部 batch_size 条轨迹(默认 2000 条)、每条又有 time_steps 个点(默认 56),十来个 critic 各遍历一遍,这么大的计算量怎么做到 50+ Hz?这是个实际的工程问题,Nav2 用几个手段化解。

其一,向量化:critic 的打分不是朴素的三重 for 循环,而是用向量化操作(Nav2 用 xtensor 库,类似 NumPy 的批量运算)一次性处理整个 batch,充分利用 CPU 的 SIMD 并行——这比逐条循环快几个数量级。

其二,共享预计算:多个 critic 会用到一些共同的中间量(如轨迹上每点到路径的最近距离、代价地图查询结果),Nav2 把这些**惰性计算一次、所有 critic 共享**(如 setPathCostsIfNotSet 这类工具函数),避免每个 critic 重复算。

其三,提前返回:critic 在不适用时(如没有行人、或被 disable)直接 return,不做无用功。

其四,参数规模适配batch_sizetime_steps 是可调的——算力紧张时减小它们(如 1000 条 @ 50Hz),用样本数换实时性(这又回到 §4.6 的"形状比数目"——与其堆样本数,不如把协方差形状调好)。

理解这些手段,你就明白 critic 架构的"每个 critic 遍历全部轨迹"在工程上是可行的——靠的是向量化、共享预计算和参数适配,而非朴素循环。

这也提示你写自定义 critic 时(§4.5 实战)要注意:用向量化操作、复用共享的预计算量、不适用时提前返回——否则一个写得低效的 critic 会拖垮整个控制器的实时性(这正是后面陷阱要讲的"score 里做重活")。

Nav2 的内置 critic 一览(都在 nav2_mppi_controller/src/critics/ 下,各司其职):

Critic 职责
ConstraintCritic 惩罚违反运动学约束(如超速)的轨迹
CostCritic 直接查询代价地图的栅格代价(较新版本引入)
ObstaclesCritic 根据到障碍物的距离施加避障代价(用膨胀层公式把代价转成距离估计)
GoalCritic 惩罚离目标点远的轨迹
GoalAngleCritic 惩罚到达目标时朝向不对的轨迹
PathAlignCritic 惩罚偏离全局路径的轨迹(对齐路径)
PathFollowCritic 推动机器人沿路径前进(跟随路径)
PathAngleCritic 惩罚朝向与路径方向不一致的轨迹
PreferForwardCritic 偏好前进(惩罚倒车,对差速机器人有用)
TwirlingCritic 惩罚原地打转(抑制无意义旋转)
VelocityDeadbandCritic 惩罚落入速度死区的指令(避免发出执行器无法响应的微小速度)

(注:CostCriticObstaclesCritic 职责相似,通常只用其一——前者直接用代价地图的原始代价,后者通过膨胀层公式把代价转成距离估计。)

本质洞察:Nav2 的 critic 架构,本质是把第 2 章那个抽象的"代价函数 \(J\)"做了**软件工程意义上的分解**——从一个单体函数,变成"一组可插拔、可组合、职责单一的插件 + 一个累加机制"。这个分解的深刻之处在于:它让"设计代价函数"从一件需要通盘考虑的整体工作,变成了"开发一组独立 critic 再组合"的模块化工作。这正是好的软件架构的标志——把复杂性分解到可独立理解、独立修改、独立测试的单元里。而它能成立,依赖一个数学事实:MPPI 的总代价是各项代价之和(线性叠加),所以各 critic 可以独立计算再累加。如果代价项之间是非线性耦合的(不能简单相加),这个干净的插件架构就不成立。理解这一点,你不仅会用 Nav2,更懂得了"可分解性"是工程化的前提——以及为什么采样式 MPC 的"代价加和"结构特别适合做成插件架构。

如果你熟悉软件设计模式,critic 架构能精准地对应到几个经典模式,这有助于把它纳入你已有的工程知识体系。

最贴切的是**策略模式(Strategy Pattern)**——每个 critic 是一个可互换的"评分策略",共享同一个接口(score),调用方(CriticManager)不关心具体是哪个 critic、只管依次调用。

这正是策略模式的精髓:"定义一族算法、各自封装、可互换"。其次它也有**责任链(Chain of Responsibility)**的影子——所有 critic 依次对同一份数据(轨迹)做处理(累加代价),像一条处理链。

还有**组合优于继承**的原则:要新增行为,不是去继承修改 MPPI 核心类,而是组合一个新的 critic 插件进去。把这些模式认出来,你会发现 Nav2 的设计不是凭空的巧思,而是软件工程几十年沉淀的经典模式在控制系统里的自然应用。

标注一下边界:纯粹的策略模式里各策略通常是"选一个用",而 critic 是"全部用、结果累加"——所以它更准确地说是"策略模式 + 累加聚合"的组合。

但核心的"可互换的封装单元 + 统一接口"完全是策略模式的思想。这个对应的价值在于:当你在别的项目里需要"一组可配置、可组合的行为"时,会本能地想到这套模式——无论是不是控制系统。

实战:写一个自定义 critic(完整 C++ 示例)

光理解架构不够,要会写。下面以"避行人 critic"为例,走一遍**自定义 critic 的完整四步**:为什么这么写 → 正确写法 → 常见错误 → 注册与配置。这是把前面架构知识落到可运行代码的关键。

第一步:为什么 critic 要这样写。 一个 critic 的本质是"给每条候选轨迹,按某个准则算一份代价、累加进总代价"。对避行人来说,准则是"轨迹上任何一点离任何行人太近,就罚"。

所以这个 critic 要做的事是:遍历每条 rollout 轨迹的每个时间步、对每个行人算距离、距离小于安全半径就按"侵入深度"累加代价。

理解了这个意图,代码就是它的直接翻译。关键约束有三:(1) 必须**累加**到 data.costs(用 +=),不能覆盖,否则会抹掉其他 critic 的贡献;(2) 要处理好"轨迹的批量维度"(一次性给所有 rollout 打分,而非循环单条——为了效率);(3) 参数(安全半径、权重)要可配置,从 ROS 参数读取。

第二步:正确写法。

#include "nav2_mppi_controller/critic_function.hpp"
#include "nav2_mppi_controller/tools/utils.hpp"

namespace my_critics
{
// 自定义 critic: 惩罚靠近行人预测轨迹的候选轨迹
class PedestrianAvoidanceCritic : public mppi::critics::CriticFunction
{
public:
  void initialize() override
  {
    auto node = parent_.lock();
    // 从 ROS 参数读取可配置项(带默认值)
    getParam(safety_radius_, "safety_radius", 1.5);   // 安全半径(米)
    getParam(cost_weight_,   "cost_weight",  10.0);   // 代价权重
    getParam(cost_power_,    "cost_power",   1);      // 代价幂次
  }

  // 核心: 给所有 rollout 轨迹打分, 原地累加到 data.costs
  void score(mppi::CriticData & data) override
  {
    using namespace xt::placeholders;
    if (!enabled_) {                       // 尊重 enabled 开关
      return;
    }
    // 取得行人当前预测(从感知模块更新, 这里假设已填入 pedestrians_)
    if (pedestrians_.empty()) {
      return;                              // 没有行人, 无需打分
    }

    const auto & traj_x = data.trajectories.x;   // 形状: [batch_size, time_steps]
    const auto & traj_y = data.trajectories.y;
    const size_t batch_size = traj_x.shape(0);
    const size_t time_steps = traj_x.shape(1);

    // 对每条轨迹累加避行人代价
    for (size_t k = 0; k < batch_size; ++k) {
      float traj_cost = 0.0f;
      for (size_t t = 0; t < time_steps; ++t) {
        const float px = traj_x(k, t);
        const float py = traj_y(k, t);
        for (const auto & ped : pedestrians_) {
          // 行人在时刻 t 的预测位置
          const float dx = px - ped.predicted_x(t);
          const float dy = py - ped.predicted_y(t);
          const float dist = std::hypot(dx, dy);
          if (dist < safety_radius_) {
            traj_cost += (safety_radius_ - dist);   // 侵入越深, 罚越重
          }
        }
      }
      // 关键: 累加(+=)到总代价, 按权重与幂次
      data.costs(k) += cost_weight_ * std::pow(traj_cost, cost_power_);
    }
  }

private:
  float safety_radius_{1.5f};
  float cost_weight_{10.0f};
  int   cost_power_{1};
  std::vector<PedestrianPrediction> pedestrians_;   // 由感知模块更新
};

}  // namespace my_critics

这段代码就是第一步意图的直接翻译:双重循环遍历"轨迹 × 时间步",对每个行人算距离、侵入安全半径就按深度累加,最后乘权重 +=data.costs(k)

它继承 CriticFunction、实现 initialize(读参数)和 score(打分),这是每个 critic 的标准骨架。

代码里的两个参数 cost_weightcost_power 值得解释,它们是 Nav2 critic 调节行为的两个通用旋钮。

cost_weight(权重)好理解——它是这个 critic 在总代价里的相对重要性,大权重让这个 critic 的关切更受重视(前面 §4.5 多目标优化讲过)。

cost_power(幂次)则微妙些——它是给代价取的幂(如 pow(traj_cost, cost_power)),控制代价随"违反程度"增长的**陡峭度**。cost_power=1(线性)时代价正比于违反程度;cost_power=2(平方)时代价随违反程度平方增长——这意味着"轻微违反"被相对宽容、"严重违反"被急剧惩罚。

为什么要这个旋钮?因为不同目标对"违反程度"的态度不同:对避障这类安全相关的,你可能想要平方幂次(轻微靠近还好、太近就急剧加罚,强烈推开危险轨迹);对跟随路径这类偏好性的,线性幂次就够(偏离多少罚多少,温和)。

所以 cost_power 让你调节每个 critic 的"惩罚曲线形状"——是温和线性还是急剧非线性。

这两个参数配合,给了 critic 相当的表达力:cost_weight 调"这个目标多重要"、cost_power 调"惩罚随违反多快增长"。理解它们,你写自定义 critic 时就知道怎么暴露合适的可调参数(暴露 weight 和 power 是 Nav2 的惯例),也知道调一个 critic 行为时除了权重还有幂次这个旋钮可用。这也再次体现 critic 架构的精细可调——不只是"开关某个 critic",还能精细地塑造每个 critic 的代价曲线。

第三步:常见错误写法及为何错。

// ❌ 错误 1: 用 = 覆盖而非 += 累加
data.costs(k) = cost_weight_ * traj_cost;
// 问题: 抹掉了之前所有 critic(避障/跟随/朝向)累加的代价!
//      结果总代价里只剩避行人这一项, 机器人不再避障、不再跟随路径。
//      这是 critic 新手最常犯的致命错误。

// ❌ 错误 2: 忽略 enabled_ 开关
void score(CriticData & data) override {
  // 直接开始打分, 不检查 enabled_
  // 问题: 用户在 YAML 里设了 enabled: false 想关掉这个 critic,
  //      但代码不检查, critic 照常运行——开关失效, 行为不符合配置。
}

// ❌ 错误 3: 在 score 里做重活(如每次重新查询/分配大内存)
void score(CriticData & data) override {
  auto big_buffer = std::vector<float>(batch_size * time_steps * 100);  // 每周期都分配!
  // 问题: score 每个控制周期(50+ Hz)都被调用, 在这里分配大内存/做重计算
  //      会拖垮实时性。重活应放到 initialize(只调一次)或缓存复用。
}

// ❌ 错误 4: 忘记处理批量维度, 只给第一条轨迹打分
data.costs(0) += ...;   // 只更新了 k=0
// 问题: 其余 batch_size-1 条轨迹没被这个 critic 打分,
//      避行人约束形同虚设(大部分轨迹没算这项代价)。

这四个错误对应四个关键约束:累加而非覆盖、尊重开关、不在热路径做重活、覆盖整个批量。每一个都是真实工程里会踩的坑——尤其错误 1(覆盖 vs 累加)会让整个控制器行为崩坏,且因为"机器人还能动、只是不避障了"而难以立刻定位。

第四步:与内置 critic 的写法对比。 看一个内置 critic(如 ObstaclesCritic)的实现,你会发现它和上面的避行人 critic 结构一致——都是"遍历轨迹批量 → 算本 critic 的代价 → +=data.costs",只是 ObstaclesCritic 算的是到静态障碍的距离(查代价地图的膨胀层)、避行人 critic 算的是到动态行人的距离。

这印证了架构的一致性:所有 critic 共享同一个接口和模式,差别只在"算什么代价"。这正像 §4.1 揭示的 MPPI/CEM 共享骨架、只在权重函数不同——同一种"统一骨架 + 可替换部件"的设计哲学,在算法层面是权重函数、在工程层面是 critic 插件。

既然 critic 是独立的单元,它就**可以独立测试**——这是插件架构的一大工程红利,值得讲讲怎么用。

对一个自定义 critic(如避行人 critic),你可以脱离整个 MPPI 系统单独写单元测试:构造几条已知的测试轨迹(一条明显撞向行人、一条明显远离、一条擦边),手动调用 critic 的 score,检查它给这些轨迹的代价是否符合预期(撞向的代价最高、远离的最低、擦边的居中)。

这种测试不需要启动 ROS、不需要真实机器人、不需要跑完整的 MPPI——因为 critic 的职责单一且接口清晰(输入轨迹、输出代价),它的正确性可以孤立地验证。这正是单体代价函数做不到的(§4.5 动机讲过):单体函数里避行人逻辑和其他逻辑缠在一起,没法单独测。

具体的测试要点:(1) 边界情况——没有行人时是否正确返回零代价(不崩溃)、enabled: false 时是否跳过;(2) 代价方向——更危险的轨迹代价是否确实更高(符号和单调性对不对);(3) 累加正确性——确认它是 += 而非覆盖(可以先在 costs 里放一个已知值,调用后检查是否在原值基础上增加);(4) 数值健康——极端输入下不产生 NaN/Inf。

把这些测试写成自动化的单元测试,纳入 CI(持续集成),你每次改 critic 都能立刻知道有没有破坏它的行为——这是生产级软件的标准实践。

理解了"critic 可独立测试",你就看到插件架构的好处不止于"易扩展",还在于"易验证"——而易验证对安全攸关的机器人控制尤其重要(你得能证明你的避障/避行人逻辑是对的)。这又一次说明:好的架构(可分解、职责单一)不只让代码好写,更让代码好测、好信赖。

实战:注册插件并在 YAML 中激活

写完 critic 类还不能用,要把它**注册为插件**让 Nav2 能动态加载。三个文件:

(1) 在 CMakeLists.txt 里编译并导出插件:

# 编译自定义 critic 为共享库
add_library(my_critics SHARED src/pedestrian_avoidance_critic.cpp)
ament_target_dependencies(my_critics nav2_mppi_controller pluginlib)

# 导出 pluginlib 插件描述
pluginlib_export_plugin_description_file(nav2_mppi_controller critics.xml)

install(TARGETS my_critics
  LIBRARY DESTINATION lib)
install(FILES critics.xml
  DESTINATION share/${PROJECT_NAME})

(2) 在 critics.xml 里声明插件(让 pluginlib 能找到它):

<library path="my_critics">
  <class type="my_critics::PedestrianAvoidanceCritic"
         base_class_type="mppi::critics::CriticFunction">
    <description>
      Critic that penalizes trajectories approaching predicted pedestrian paths.
    </description>
  </class>
</library>

注意 base_class_type 必须是 mppi::critics::CriticFunction——这告诉 pluginlib"这个插件是一个 critic",从而能被 Nav2 的 CriticManager 加载。

(3) 在 Nav2 参数 YAML 里激活并配置:

controller_server:
  ros__parameters:
    controller_frequency: 30.0
    FollowPath:
      plugin: "nav2_mppi_controller::MPPIController"
      time_steps: 56
      model_dt: 0.05            # time_steps * model_dt = 预测时域
      batch_size: 2000          # 候选轨迹数(30Hz 下 2000 较合适)
      temperature: 0.3          # MPPI 温度 λ(§4.1 的探索-利用旋钮)
      gamma: 0.015
      motion_model: "DiffDrive"
      # critic 列表: 把自定义的 PedestrianAvoidanceCritic 加进去
      critics: ["ConstraintCritic", "GoalCritic", "PathFollowCritic",
                "ObstaclesCritic", "PedestrianAvoidanceCritic"]
      # 各 critic 的参数
      ObstaclesCritic:
        enabled: true
        cost_weight: 20.0
      PedestrianAvoidanceCritic:    # 自定义 critic 的参数
        enabled: true
        cost_weight: 10.0
        safety_radius: 1.5
        cost_power: 1

激活就这么简单——在 critics 列表里加上 "PedestrianAvoidanceCritic",再给它一组参数。不需要改 MPPI 核心代码、不需要改任何内置 critic。这就是插件架构的终极好处:扩展功能 = 写一个新插件 + 在配置里加一行

注意 YAML 里的 temperature: 0.3 正是 §4.1 反复讲的 MPPI 温度 \(\lambda\)——理论里的 \(\lambda\) 在生产代码里就是这个参数,调它就是在调探索-利用的平衡。

把整个流程串起来看:你理解了 §4.1–§4.4 的算法本质(MPPI 的指数加权、代价函数的作用),然后在 §4.5 看到它如何落地成一个有 critic 插件架构、能 50+ Hz 实时跑、能通过加插件扩展的生产级系统。从理论到产品,这一节是桥梁。

关于 critic 权重的整定,还有一个值得点破的本质——它其实是一个**多目标优化(multi-objective optimization)**问题。

每个 critic 代表一个目标(到达目标、避障、跟随路径、舒适……),它们往往相互冲突(贴路径 vs 大幅绕障、快速 vs 平稳)。

给各 critic 设权重 cost_weight,本质就是在做多目标优化里的**标量化(scalarization)**——把多个目标用加权和合成一个标量目标。

这立刻带来两个多目标优化的经典认识。其一,权重决定了你在 Pareto 前沿上的位置:不同的权重组合对应"在各目标间的不同折中",没有唯一正确的权重,只有"符合你偏好的折中"。

其二,加权和标量化有其局限:它只能找到 Pareto 前沿上凸的部分,且权重与最终行为的关系往往非线性、不直观(调一个权重可能引起行为的突变)。

理解了"调 critic 权重 = 多目标标量化",你对调参就有了更清醒的预期:不要指望存在一组"客观最优"的权重(那取决于你要什么折中);调参时一次只动一个权重、观察行为变化(因为各权重耦合);如果发现怎么调都无法同时满足两个目标,可能是它们在 Pareto 前沿上本就不可兼得,需要重新审视任务需求而非死磕权重。

MJPC 的 GUI 甚至能可视化这个 Pareto 前沿,让你直观看到各目标的权衡。这个视角把 critic 调参从"玄学试错"提升为"有理论框架的多目标决策"——你调的不是一堆魔法数字,而是在表达"你想要什么样的折中"。

⚠️ 常见陷阱

编程陷阱:在自定义 critic 的 score 里用 = 覆盖 data.costs 而非 += 累加。 错误做法:data.costs(k) = my_cost; 现象/后果:本 critic 的代价覆盖了之前所有 critic 累加的代价,总代价里只剩这一项。机器人会丢失其他所有行为(不避障、不跟随路径、不顾朝向),只对本 critic 关心的事有反应——比如只会避行人但会直接撞墙、不沿路径走。最坑的是机器人"还能动",不会崩溃报错,所以容易误以为是别的问题。 根本原因:critic 架构靠"所有 critic 累加到同一个 costs 数组"来组合多项代价(§4.5 理论)。用 = 覆盖破坏了这个累加机制,相当于把其他 critic 的工作全抹掉。 正确做法:critic 的 score 里**永远用 +=** 把本 critic 的代价加到 data.costs。这是 critic 编写的铁律。 自检方法:临时只启用你的 critic(其余在 YAML 里 enabled: false),确认机器人有预期行为;再启用全部 critic,若加上你的 critic 后机器人丢失了其他行为(如不避障了),多半是覆盖了 costs。

概念误区:以为 critic 越多越好、应该把所有能想到的 critic 都加上。 错误认识:既然 critic 可自由组合,那多加几个总没坏处,把避障、跟随、朝向、前进、避行人、防打转……全加上最保险。 现象/后果:critic 过多会带来两个问题。其一,权重调参爆炸——每个 critic 一个权重,N 个 critic 就有 N 个相互影响的权重要平衡,调参难度随 N 急剧上升。

其二,目标冲突——某些 critic 的目标可能矛盾(如"严格贴路径"和"大幅绕障避行人"会拉扯),堆太多会让控制器无所适从、行为犹豫。 根本原因:critic 之间通过代价累加竞争,过多的竞争项会稀释主要目标、放大调参复杂度。代价函数设计的智慧是"用最少的项表达任务",而非"项越多越全面"。 正确做法:只加任务**真正需要**的 critic;从一组最小 critic 起步(如 Goal + PathFollow + Obstacles),确认行为正常后再按需增加;每加一个 critic 都重新平衡权重并验证。少而精胜过多而乱。

思维陷阱:把 critic 架构看成 Nav2 特有的东西,不知道它是"可分解代价"的通用模式。 错误认识:认为 critic 插件是 Nav2 的特定实现细节,换个框架就用不上。 现象/后果:在别的采样式控制项目里重新陷入"单体代价函数"的维护噩梦,不知道可以借鉴 critic 架构把代价模块化。 根本原因:把一个通用的设计模式("可分解的代价拆成独立可组合的评分插件")误当成特定框架的实现。事实上,只要你的代价是"多项之和"(线性可分解),就能用这个模式,与框架无关。 正确做法:把 critic 架构理解为"代价可分解时的通用工程模式"。在任何采样式控制项目里,当代价由多个独立项相加构成时,都可以借鉴:把每项做成独立的评分单元、通过累加组合。这个模式的适用条件是"代价线性可加",与是不是 Nav2 无关。

练习

  1. (读源码,⭐⭐) 找到 Nav2 的 nav2_mppi_controller/src/critics/obstacles_critic.cpp(或 goal_critic.cpp),读它的 score 方法,确认它的结构是"遍历轨迹批量 → 算代价 → += 到 data.costs"。

对照本节的避行人 critic,列出它们的相同点(接口、累加模式)和不同点(算什么代价、用什么数据)。这道题帮你把"架构一致性"从文字变成对真实代码的认识。

  1. (写 critic,⭐⭐⭐) 实现一个自定义 critic(不必真编译进 Nav2,可写成结构完整的 C++ 代码 + 逻辑说明)。

可选题目:(a) SpeedComfortCritic——惩罚加速度过大的轨迹(让乘客舒适);(b) SocialDistanceCritic——比避行人更进一步,惩罚"从行人正前方穿过"的轨迹(社交礼貌)。

写出 initialize(读参数)和 score(打分,注意 +=),并写出对应的 plugin.xml 声明和 YAML 配置片段。

  1. (调参思辨,⭐⭐⭐) 假设你的机器人配了 Goal、PathFollow、Obstacles、PedestrianAvoidance 四个 critic,发现它"宁可大幅绕开行人也不沿路径走"(避行人太激进)。

从 critic 权重的角度分析:该调哪个 critic 的 cost_weight、往哪个方向调?如果调权重还不够,safety_radiuscost_power 又分别如何影响行为?写出你的调参方案,并说明为什么这体现了"critic 架构让行为可通过权重精细调节"的优势。

§4.6 CoVO-MPC:MPPI 的收敛性证明与最优协方差 ⭐⭐⭐

动机:用了十年的 MPPI,竟然没有收敛性证明?

MPPI 从 2016 年前后开始广泛使用,到处都在用它做控制和基于模型的强化学习。但有一个尴尬的事实长期存在:没有人严格证明过它会收敛

大家凭经验知道它 work,凭直觉调它的协方差(第 3 章反复说 vanilla MPPI 用各向同性高斯,但"为什么是各向同性、该不该是各向同性"始终没有理论答案),但"它到底会不会收敛到最优、收敛多快、协方差怎么设最好"这些根本问题,十年里一直悬而未决。

这种"用得很好但说不清为什么"的状态,在工程领域其实很常见,但它有真实的代价,值得点明。一方面,缺乏理论让调参变成纯试错——不知道协方差该是什么形状,工程师只能各向同性地用、然后手调标量方差碰运气,遇到不理想的情况没有原则性的改进方向。

另一方面,缺乏收敛保证让人对方法的可靠性心里没底——MPPI 会不会在某些情况下发散?会不会卡在很差的解?没有证明时,这些只能靠"经验上没见过"来安慰,在安全攸关的应用里这种安慰是不够的。

还有一层,缺乏理论阻碍了方法的进一步改进——如果不知道"什么决定了收敛速度",就无法有针对性地优化它(你不知道该调什么)。

所以 CoVO-MPC 补上收敛理论这件事,价值远超"发表一篇理论论文":它把 MPPI 从"经验上好用的黑箱"变成"理论上理解的工具",让调参有了方向(协方差贴合 Hessian)、让可靠性有了保证(二次代价下收敛)、让改进有了抓手(优化收缩率)。

这也体现了理论工作在工程领域的真正价值——不是为了数学上的优美,而是为了让实践从"碰运气"走向"有依据"。这个从"经验"到"理论"的跨越,正是一个领域走向成熟的标志,本章把采样式 MPC 在这个跨越上的关键一步(CoVO-MPC)讲给你听。

CoVO-MPC(Yi、Pan 等,CMU LeCAR Lab,L4DC 2024)补上了这一块。它做了两件事,环环相扣:

  1. 第一次证明了 MPPI 的收敛性:在二次代价(涵盖时变 LQR 系统)下,MPPI **至少线性收敛**到最优控制序列。它还把收敛速率与采样协方差 \(\Sigma\)、温度 \(\lambda\)、系统特性的关系精确刻画出来。
  2. 由收敛分析直接导出最优协方差设计:既然收敛速率由 \(\Sigma\) 决定,那就能求出**让收敛最快的最优 \(\Sigma\)——而它由代价的**局部 Hessian 决定(凸方向小方差、平方向大方差)。据此提出的 CoVO-MPC 算法,比 vanilla MPPI 提升 43–54%

为什么这件事重要?因为它把采样式 MPC 从"经验调参"推向了"理论指导设计"。在 CoVO-MPC 之前,"协方差怎么设"是个玄学问题,大家用各向同性纯粹因为"不知道还能怎么设、各向同性最省事"。CoVO-MPC 之后,你有了原则性的答案:协方差应该贴合代价地形的形状。

这个洞察可以一句话概括——也是本节、乃至本章最重要的一句话:"采样分布的形状比采样数目更重要"。它是十年来第一个支撑这句话的严格理论证据。

读到这里你可能会好奇:MPPI 用了十年,收敛证明为什么这么难、拖了这么久?理解这个难点,能帮你体会 CoVO-MPC 工作的分量。难有三处。

其一,采样的随机性:MPPI 每步的更新依赖随机采样的样本,是一个随机过程,不像确定性优化(梯度下降)那样有干净的递推式可分析——你得处理"期望意义下的收敛"和样本带来的方差,数学上复杂得多。

其二,指数加权的非线性:MPPI 的更新是 \(e^{-J/\lambda}\) 加权平均,这个 softmax 式的非线性映射让"当前解→下一步解"的关系高度非线性,难以建立收缩不等式。

其三,代价的一般性:MPPI 被用于各种非凸、非光滑代价,对完全一般的代价根本无法证明收敛(可能根本不收敛到全局最优)。

CoVO-MPC 的突破口,是**先退一步、限定到二次代价**——在这个受限但重要(涵盖时变 LQR)的情形下,指数加权的分析变得可处理,从而能严格建立线性收敛。这是理论工作常见的智慧:不贪一般性,先在一个可证明的子类上把事情做透、获得洞察,再向外推广。

所以 CoVO-MPC 不是凭空证明了"MPPI 总收敛"(那太难、也不真),而是精准地在二次代价这个甜点上证明了收敛、并由此导出最优协方差——既诚实(不夸大适用范围)又有用(二次/LQR 是一大类实际系统)。

理解了这三个难点,你会更欣赏为什么这个"迟到十年"的证明是重要贡献,也会更准确地理解它的边界(§4.6 陷阱里会强调:证明限于二次代价)。

如果不这样做会怎样:各向同性协方差的隐性浪费

不理解 CoVO-MPC 的洞察、继续用各向同性协方差,会有什么隐性损失?

各向同性协方差(\(\Sigma = \sigma^2 I\))意味着**在控制空间的所有方向上,用同样的力度探索**。

但真实代价地形几乎总是**各向异性**的——有些方向代价变化剧烈(陡,曲率大),有些方向代价变化平缓(平,曲率小)。在这种地形上各向同性地撒样本,会造成双向浪费:

  • 陡方向撒太多:陡方向上代价对控制变化极敏感,稍微偏一点代价就涨很多。在这个方向上大范围撒样本,大部分样本都落到高代价区、被指数权重压成接近零权重——采了等于白采,还可能因为偶尔的大步"越过"最优点造成震荡。
  • 平方向撒太少:平方向上代价变化平缓,本该大胆地多探索(步子迈大些快速接近最优),但各向同性给它的方差和陡方向一样小,导致这个方向上挪动太慢、收敛拖沓。

把这个"双向浪费"量化出来。在一个病态的二次代价上(各方向曲率从 40 到 1,差异巨大),固定样本数和总方差预算,只改协方差的**形状**:

# 三种协方差形状, 总方差(迹)归一化到相同, 只比"形状"
iso  = run([1, 1, 1, 1])        # 各向同性
bad  = run([10, 3, 1.5, 1])     # 陡方向(曲率大)给大方差 —— 坏
good = run([1, 1.5, 3, 10])     # 平方向(曲率小)给大方差 —— 好

到最优距离 \(\|u-u^\star\|\) 随迭代(30 个随机种子平均):

迭代 5: 各向同性=1.664   陡向大方差(坏)=2.313   平向大方差(好)=1.520
迭代10: 各向同性=1.089   陡向大方差(坏)=1.921   平向大方差(好)=0.646
迭代20: 各向同性=0.582   陡向大方差(坏)=1.512   平向大方差(好)=0.211

差异触目惊心:样本数和总方差完全相同,仅仅协方差的形状不同,迭代 20 后到最优的距离从 \(0.21\)(好形状)到 \(1.51\)(坏形状)差了 7 倍

"平方向多撒、陡方向少撒"的形状(good)收敛最快,各向同性(iso)居中,"陡方向多撒"(bad)最慢。

这就是"形状比数目更重要"的直接证据——你给再多样本,如果形状不对(各向同性或更糟),都不如形状对了高效。各向同性不是"中性安全"的默认,而是"放弃了形状这个免费的巨大收益"的次优选择。

(说明:这个 demo 用"平方向大方差"演示形状的影响方向,与 CoVO 的核心直觉一致;CoVO 论文给出的**最优**协方差有精确的解析形式,由 Hessian 严格推导,不止"平方向大方差"这么简单,但方向性的直觉正是如此。)

讲到这里,有个实践问题值得提前回答:完整的最优协方差是一个**稠密矩阵**(各控制维度之间有相关性),算它、存它、用它(每次采样要做矩阵分解)在高维下都不便宜——这会不会让 CoVO 在实践中难以落地?答案是有几个层次的简化可用,按精度与开销权衡。

最完整的是用**稠密协方差**(捕获所有方向相关性,最准但最贵)。退一步用**对角协方差**——只给每个维度一个独立方差("陡维度小方差、平维度大方差"),放弃维度间的相关性,但实现简单(采样只需逐维缩放、无需矩阵分解)、且往往已能拿到大部分收益(因为主要的各向异性常体现在各维度的方差差异上)。

再退一步是**分块对角**——把强相关的维度分组、组内稠密、组间独立,在精度和开销间折中。实践中常从对角近似起步,它把 CoVO 的核心思想(各方向方差不同、贴合曲率)用最低的实现成本实现了,正呼应前面"离线近似已能拿大部分收益"的发现——形状的大方向对了最重要,精确到每个非对角元反而是次要的。

这给你一个务实的落地路径:不必一上来就实现完整的稠密 Hessian 协方差,先用对角近似(每维方差正比于该维曲率的倒数)验证收益,需要时再上稠密版。

这也降低了 CoVO 思想的采用门槛——你不需要重写整个 MPPI 的协方差机制,只需把各向同性的标量方差换成逐维的方差向量,就迈出了关键一步。

理论:收敛定理与最优协方差

把 CoVO-MPC 的两个核心结果讲清楚。

结果一:MPPI 的线性收敛定理。 考虑代价是二次型的情形(\(J(U)\) 关于控制序列 \(U\) 是二次函数,这涵盖了时变 LQR 这一大类重要系统)。CoVO-MPC 证明:MPPI 的迭代满足

\[ \|U_{k+1} - U^\star\| \le \rho(\Sigma)\,\|U_k - U^\star\|, \]

其中 \(U^\star\) 是最优控制序列,\(\rho(\Sigma)\) 是一个**收缩率(contraction rate)**,\(0 \le \rho < 1\)

这个不等式说:每次迭代后,当前解到最优解的距离至少按比例 \(\rho\) 缩小——这正是**线性收敛(几何收敛)**的定义。距离呈几何级数衰减,MPPI 稳定地逼近最优。

为什么二次代价是个好的突破口、而非一个无关紧要的特例?这值得说清,因为它关系到这个收敛定理的实际分量。表面看"二次代价"像个很强的限制——真实任务的代价大多不是二次的。但二次代价涵盖的**时变 LQR**(线性时变系统 + 二次代价)是控制理论里极其重要的一大类,原因有二。其一,LQR 本身就覆盖大量实际系统——许多机器人在工作点附近可以线性化、用二次代价描述(这正是经典控制的主力工具),所以"二次代价下的收敛"直接适用于这些系统。其二,更重要的是,二次近似是一切非线性问题的局部基础——任何光滑代价在最优解附近都可以用二次型近似(泰勒展开到二阶),所以"二次代价下的收敛行为"刻画了 MPPI 在接近最优时的局部收敛性质,这对一般非线性问题也有指导意义(至少在解的邻域内)。

这和优化理论里"先分析二次型、再推广到一般凸/非凸"的研究范式一致——二次型是分析的起点和基石,不是无关的特例。所以 CoVO-MPC 选二次代价,是抓住了"既实际重要、又分析可行、还能指导一般情形"的甜点,而非回避难点。理解这一点,你就不会因为"只证明了二次代价"而低估这个定理——它覆盖的 LQR 类系统本身重要,且它揭示的局部收敛机制对更广的问题有启发。当然,严格的全局收敛(任意非线性代价)仍是开放问题(§4.6 陷阱会强调),但"从二次代价这个坚实的基石出发"是完全正当且有价值的第一步。

"线性收敛"这个理论结论对实践有什么具体意义?值得说清,因为它不只是数学上的安心,还有操作上的指导。其一,它保证了 MPPI 在二次代价下是可靠的——不会发散、不会卡住,每个控制周期的迭代都在稳步接近最优。这给了你信心:在 LQR 类系统上用 MPPI,它的行为是有理论背书的,不是碰运气。

其二,几何收敛意味着收敛很快——几何级数衰减是很快的(每次乘以 \(\rho<1\),误差指数下降),所以 MPPI 通常不需要很多次迭代就能接近最优,这解释了为什么实践中 MPPI 每个控制周期只迭代很少几次(甚至 Nav2 默认 iteration_count: 1,即每周期只迭代一次)就够用——因为收敛快,配合 warm-start(每周期从上次的好解出发),一次迭代就能跟上。

其三,收缩率 \(\rho\) 给了"收敛快慢"的定量刻画——\(\rho\) 越小收敛越快,而 \(\rho\) 依赖协方差 \(\Sigma\),这就引出了"调 \(\Sigma\)\(\rho\) 最小"的优化(结果二)。

所以这个收敛定理不是纯理论——它解释了 MPPI 的一个重要实践现象(为什么每周期迭代很少次就行)、给了用 MPPI 的信心(二次代价下可靠)、并直接通向"如何设计协方差加速收敛"的实用结论。

把"线性收敛"从一个数学名词理解成这些实践含义,你就明白 CoVO-MPC 的理论贡献是如何落到工程上的——理论和实践在这里是连通的,而非两张皮。

关键在于 \(\rho\) 依赖什么。CoVO-MPC 精确刻画了收缩率 \(\rho(\Sigma)\) 由**采样协方差 \(\Sigma\)、温度 \(\lambda\)、以及系统特性(代价的 Hessian)**共同决定。\(\rho\) 越小,收敛越快。

于是优化收敛速度,就变成了"选 \(\Sigma\)\(\rho(\Sigma)\) 最小"——这直接通向结果二。

读到这里你可能会问:既然 CoVO-MPC 要算代价的 Hessian,那为什么不干脆用**牛顿法**这类二阶优化方法直接求解?牛顿法不正是用 Hessian 来加速收敛的吗?这是个切中要害的问题,答案揭示了采样式方法的定位。

牛顿法要求代价**可微、能解析地算梯度和 Hessian**——但采样式 MPC 的整个存在理由,正是为了处理那些**不可微、黑箱**的代价和动力学(第 2、3 章反复强调的杀手级场景:稀疏奖励、学到的神经网络模型、含接触的动力学)。

在这些场景里,牛顿法根本用不了,因为你算不出解析的梯度和 Hessian。CoVO-MPC 的巧妙之处在于:它**不要求代价可微**——它用采样和 rollout 来**数值估计** Hessian(对当前均值序列做有限差分式的二阶估计),把"用 Hessian 加速"这个二阶方法的好处,移植到了无导数的采样框架里。

所以 CoVO-MPC 不是"退化成牛顿法",而是"在无导数的约束下,尽可能地利用二阶信息"——它站在采样式方法(能处理黑箱)和二阶方法(收敛快)的交叉点上,取两者之长。

标注边界:如果你的代价真的光滑可微,那直接用牛顿法或梯度 MPC(acados)确实更高效(第 3 章横向定位讲过);CoVO-MPC 的价值在代价不可微、但你仍想利用曲率信息的场景。理解这个定位,你就明白 CoVO-MPC 不是要取代二阶方法,而是把二阶智慧带进采样式方法的领地。

结果二:最优协方差由 Hessian 决定。 既然收缩率 \(\rho(\Sigma)\)\(\Sigma\) 的函数,求让 \(\rho\) 最小的 \(\Sigma\),就得到**最优采样协方差** \(\Sigma^\star\)

CoVO-MPC 证明:\(\Sigma^\star\) 由**代价的局部 Hessian** 决定,其形状遵循"凸方向(曲率大)小方差、平方向(曲率小)大方差"的原则。

直觉上这完全合理(和上面 demo 的"good 形状"一致)——曲率大的方向敏感、该谨慎小步探索,曲率小的方向平缓、该大胆大步探索。CoVO-MPC 让采样协方差**贴合代价地形的曲率**,而非各向同性地无视地形。

值得提一下协方差 \(\Sigma\) 和温度 \(\lambda\) 这两个旋钮的相互作用,因为它们都出现在收缩率 \(\rho\) 里、不是完全独立的。

直观上,\(\lambda\) 控制权重的"软硬"(§4.1:小 \(\lambda\) 更聚焦),\(\Sigma\) 控制采样的"形状和范围"——但它们共同决定了"实际探索的有效区域"。

举个例子:如果 \(\Sigma\) 在某方向很大(撒得宽)、但 \(\lambda\) 很小(权重很尖),那实际只有少数靠近最优的样本起作用,宽撒的大部分被压成零权重——这时大 \(\Sigma\) 的探索意图被小 \(\lambda\) 抵消了。反过来 \(\Sigma\) 小而 \(\lambda\) 大,则探索范围窄但每个样本都算数。

所以调这两个旋钮不能完全分开看——CoVO-MPC 的收敛分析把它们一起纳入 \(\rho(\Sigma)\)(其中也含 \(\lambda\)),求最优 \(\Sigma\) 时是在给定 \(\lambda\) 下求的。

实践启示有二:其一,改了 \(\Sigma\) 可能需要重新审视 \(\lambda\)(反之亦然),因为它们耦合;其二,CoVO-MPC 主要优化 \(\Sigma\) 的**形状**(各方向的相对大小),而整体的"软硬"仍由 \(\lambda\) 主管——可以理解为 \(\lambda\) 管"全局探索强度"、\(\Sigma\) 的形状管"探索强度在各方向如何分配"。

理解这个分工与耦合,你调参时会更有章法:先用 \(\lambda\) 定全局探索强度,再用 \(\Sigma\) 的形状把这份强度合理分配到各方向(贴合 Hessian),而非孤立地调某一个。

这也补全了本章三维框架里"权重函数(\(\lambda\))"和"协方差(\(\Sigma\))"两个维度的关系——它们虽是不同维度,但在决定实际探索行为时是协同作用的。

怎么算这个 Hessian。 CoVO-MPC 给了两种方案:

  • 实时计算:在线对当前的均值控制序列 \(U_{\text{in}}\) 做 rollout、计算代价的二阶导(Hessian),据此设当前周期的 \(\Sigma\)。最准,但每周期算 Hessian 有计算开销。
  • 离线近似:为降低在线开销,预先用一个简单的标称控制器(如 PID)算出 Hessian 并**缓存**,在线直接查用。这牺牲一点精度换实时性。

读到这里你可能会问:既然协方差形状这么重要,为什么不干脆**用数据学一个协方差**(比如用强化学习或监督学习训练一个网络,输出每个状态下该用的协方差),而要费劲算 Hessian?这是个有前瞻性的问题,触及了 CoVO-MPC 的方法选择和它的潜在替代路线。

先说为什么 CoVO-MPC 选 Hessian 而非学习:其一,有理论保证——Hessian 导出的最优协方差是从收敛证明里严格推出来的,有"为什么这样最优"的理论支撑;而学一个协方差是经验的,没有同等的理论保证。

其二,无需训练数据——算 Hessian 只需当前的代价函数(在线或用标称控制器离线算),不需要收集训练数据、不需要训练过程;学协方差则要数据和训练,成本高、且可能过拟合到训练分布。

其三,可解释——Hessian 协方差的"凸方向小、平方向大"有清晰的几何意义,出问题好排查;学出来的协方差是黑箱。

但你的直觉也指向一个真实的前沿方向:确实有工作尝试**用学习来设计或加速采样分布**(如学一个提议分布、学协方差调度),这在动力学复杂到 Hessian 难算、或想端到端优化时有价值。

所以这不是"Hessian vs 学习"谁绝对好,而是取舍:CoVO-MPC 的 Hessian 路线理论扎实、无需训练、可解释,适合有明确代价模型的场景;学习路线更灵活、能处理 Hessian 难算的复杂情形,但要数据和训练、牺牲可解释性和理论保证。

理解这个取舍,你既懂了 CoVO-MPC 为什么选 Hessian,也看到了一条可能的研究方向——这正是第 5、6 章"用学习增强采样式 MPC"主题的一个切入点。

一个意味深长的实验发现:离线近似版本在仿真里几乎和实时版一样好——这说明 CoVO-MPC 的效果主要来自"\(\Sigma_t\) 有了非平凡的、贴合地形的模式",而非 Hessian 的精确数值。

换句话说,"形状大致对了"就能拿到大部分收益,不必追求 Hessian 算得分毫不差。即便迁移到真实四旋翼(有 sim-to-real 差距,离线近似的 Hessian 不那么准了),CoVO-MPC 仍比 MPPI 高 22%

这个"离线近似几乎和实时版一样好"的发现,有一个超出 CoVO-MPC 本身的深刻启示——它揭示了一种**鲁棒性**:方法的收益对其关键参数(这里是 Hessian)的精确度**不敏感**。这种鲁棒性在工程上极有价值,因为它意味着"你不必把事情做到完美,做到大致对就能拿大部分收益"。

对照一下:如果 CoVO-MPC 的收益高度依赖 Hessian 算得分毫不差,那它在实践中会很脆弱——任何 Hessian 估计误差(数值误差、模型失配、sim-to-real 差距)都会让收益大打折扣,落地会很难。

但实验显示收益对 Hessian 精度不敏感,于是你可以用便宜的离线近似、可以容忍 sim-to-real 误差,方法依然有效。

为什么会有这种鲁棒性?因为收益来自协方差形状的**定性模式**(哪些方向该大、哪些该小),而非精确数值——只要大方向对了(陡方向相对小、平方向相对大),具体差一点不影响大局。

这呼应了一个普遍的工程智慧:好的方法应该对其假设的不精确具有鲁棒性——一个只在理想条件下才 work、稍有偏差就崩的方法,再优美也难以落地;而一个"大致对就够用"的方法才经得起真实世界的不完美。CoVO-MPC 的这个性质(连同它的理论保证)正是它从"理论漂亮"走向"实践可用"的关键。

理解这一点,你评估任何方法时会多问一句:它的效果对参数/假设的精度有多敏感?敏感的要警惕(落地脆弱),不敏感的更可靠(容错性好)。这是从 CoVO-MPC 学到的、可迁移到一切方法评估的一条判据。

这里有一个值得点透的联系,能把 CoVO-MPC 接入你可能已熟悉的优化理论——收敛速度与代价的**条件数(condition number)**密切相关。

条件数是 Hessian 最大特征值与最小特征值之比,衡量代价地形有多"病态"(各方向曲率差异有多大)。

优化理论里有个经典结论:梯度下降在病态问题(条件数大)上收敛很慢,因为它在陡方向震荡、在平方向蜗行——这正是上面 demo 里各向同性协方差遇到病态二次代价时的窘境。

各种加速方法(动量、预条件、牛顿法)本质都在"改善有效条件数"。CoVO-MPC 的最优协方差做的也是同一件事:通过让协方差贴合 Hessian(平方向大方差、陡方向小方差),它实际上把病态地形"预条件"成了各向同性的好地形——在变换后的空间里,各方向曲率被均衡了,收敛自然变快。

所以 CoVO-MPC 的最优协方差,可以理解为采样式 MPC 版本的**预条件(preconditioning)**。

如果你学过数值优化里的预条件共轭梯度(用 \(M^{-1}\) 预条件改善条件数),会立刻认出这是同一个思想:用一个贴合 Hessian 的变换把病态问题"掰正"。

这个联系不仅加深理解,还提示了改进方向——数值优化里成熟的各种预条件技巧,或许都能借鉴到采样式 MPC 的协方差设计上。理解"协方差 ≈ 预条件子",你就把 CoVO-MPC 接到了优化理论几十年的积累上。

本质洞察:CoVO-MPC 最深刻的贡献,是把"采样分布的形状"从一个被忽视的细节,提升为决定性能的核心因素,并用收敛证明给了它理论地位。"形状比数目更重要"这句话颠覆了一个常见的直觉——很多人以为采样式方法的性能主要靠"撒更多样本"(数目),CoVO-MPC 证明:在样本数固定时,把协方差的形状调对(贴合 Hessian),收益远大于盲目增加样本。这呼应并深化了贯穿第 2-4 章的样本效率主线:第 2 章讲 ESS(有多少样本有用)、第 3 章讲提议分布的五侧面(含协方差形状)、iCEM 讲有色噪声(采得巧),而 CoVO-MPC 给出了"协方差形状该怎么定"的**最优答案**和**理论保证**。至此,"采得巧胜过采得多"这条主线有了最坚实的理论支点。对工程师的实际启示是:下次 MPPI 调不好,先别急着加样本数或调温度,想想你的协方差形状是否贴合了任务的代价地形——这往往是更高杠杆的改进点。

CoVO-MPC 在统一视角里的位置

回到本章的统一主线。§4.1/§4.3 讲的是**权重函数**这个设计维度(MPPI 的指数、CEM 的硬阈值、Tsallis 的连续插值),§4.2 讲的是**噪声**维度(有色噪声)。CoVO-MPC 讲的是第三个维度——协方差

这三个维度(权重函数、噪声、协方差)正是本章开篇知识导航里说的"三个设计选择"。任何一个采样式 MPC,都是在这三个维度上做了选择:

  • 权重函数:怎么根据代价给样本赋权?(§4.1、§4.3)
  • 噪声:采样噪声的时间结构如何?(§4.2 的有色噪声)
  • 协方差:采样分布的形状如何?(§4.6 的最优协方差)

第 3 章的"五侧面"是这个框架在变体层面的展开,本章把框架的三个核心维度讲透。当你拿到任何一个采样式控制方法(无论本书内外),都可以问这三个问题来定位它。

而 CoVO-MPC 的特殊地位在于:它是唯一一个为"协方差"这个维度提供了**最优解 + 收敛证明**的工作——其他维度大多还停留在"有多种选择、各有取舍",协方差维度则被 CoVO-MPC 给出了原则性的最优答案。

如果你接触过强化学习或优化里的**自然梯度(natural gradient)**,这里有个值得点出的深层联系。

自然梯度的核心思想是:参数更新不该在"朴素的欧氏空间"里走,而该在考虑了"分布的内在几何"的空间里走——具体是用 Fisher 信息矩阵作为度量,对梯度做预条件。

这和 CoVO-MPC"用 Hessian 塑造协方差"在精神上高度一致:两者都认识到"各个方向不是平等的,更新/采样应该考虑问题的内在曲率/几何"。

自然梯度用 Fisher 矩阵、CoVO-MPC 用代价 Hessian,但共同的洞察是"用二阶几何信息来引导一阶的探索/更新方向"。

在 TRPO、PPO 等强化学习算法里,自然梯度(或其近似)正是让策略更新更稳定高效的关键;在 CoVO-MPC 里,Hessian 塑造的协方差让采样更新更快收敛。

把这个联系记住,你会看到一条贯穿优化、强化学习、采样式控制的共同主线——利用问题的二阶几何(曲率)来超越朴素的各向同性方法,无论这个"朴素方法"是普通梯度下降、各向同性策略探索,还是各向同性协方差的 MPPI。

这也呼应了前面"协方差≈预条件子"的洞察:预条件、自然梯度、CoVO 最优协方差,是同一个"用曲率信息掰正病态问题"思想在不同领域的化身。理解这一点,你就把 CoVO-MPC 接到了一个跨越多个领域的深刻思想脉络上,而非孤立地记一个控制算法。

⚠️ 常见陷阱

编程陷阱:实时计算 Hessian 时不加正则/不检查正定性,得到病态或非正定的协方差。 错误做法:直接对代价做二阶差分得到 Hessian、求逆当协方差,不做任何数值保护。 现象/后果:实际代价的 Hessian 可能接近奇异(某方向曲率近零)或因数值误差非正定,求逆/分解时得到巨大的、甚至非法(非正定)的协方差矩阵,导致采样发散或崩溃(协方差必须正定才能做高斯采样)。 根本原因:Hessian 在平坦方向曲率接近零,求逆会放大成巨大方差;数值误差也可能让本应正定的矩阵失去正定性。直接用未保护的 Hessian 是不稳健的。 正确做法:给 Hessian 加正则(如加 \(\epsilon I\) 保证正定)、对特征值设上下界(防止某方向方差爆炸或塌缩)、做正定性检查与修复(如特征值截断)。CoVO-MPC 的实现里有这类数值保护。 自检方法:每周期检查协方差是否正定(Cholesky 分解成功)、其条件数是否在合理范围;若采样突然发散,多半是协方差出了数值问题。

概念误区:以为 CoVO-MPC 的收敛证明适用于任意非线性系统。 错误认识:CoVO-MPC 证明了 MPPI 收敛,那 MPPI 对任何系统都有收敛保证了。 现象/后果:在强非线性系统上期待 CoVO-MPC 的收敛保证成立,遇到不收敛时困惑——明明有"收敛证明"为何不收敛? 根本原因:CoVO-MPC 的严格收敛证明是针对**二次代价(涵盖时变 LQR)**的;对一般非线性系统,论文做了推广讨论,但严格的收敛保证仍限于二次/LQR 情形。非线性系统的收敛性是公开的开放问题(本章前沿会提)。 正确做法:把收敛保证理解为"二次代价/LQR 下严格成立、一般非线性下是有依据的启发"。CoVO-MPC 的最优协方差设计在非线性系统上经验有效(实验验证),但这是经验有效、非理论保证。区分"证明覆盖的范围"和"经验有效的范围"。

思维陷阱:把"形状比数目更重要"误解为"样本数无所谓、越少越好"。 错误认识:既然形状比数目重要,那就尽量减少样本数、只在形状上下功夫。 现象/后果:把样本数砍得过少(如几个、十几个),即便协方差形状对了,也因为样本太少导致加权估计的方差极大、更新噪声大、不稳定甚至坍缩(§4.1 CEM 精英太少的坍缩同理)。 根本原因:"形状比数目更重要"说的是"在合理样本数下,优化形状的收益大于增加数目",不是"数目可以无限少"。样本数有一个下限保证统计估计的稳定性,低于这个下限,形状再对也救不了。形状和数目都重要,只是边际收益不同。 正确做法:先保证样本数在一个能让估计稳定的合理范围(按任务和维度定,通常几百到几千),在此基础上优化协方差形状。不要为了"形状重要"这个洞察就把样本数砍到危险的低位。形状是高杠杆,但数目是地基。

练习

  1. (形状对比,⭐⭐⭐) 复现本节的 demo:在一个病态二次代价上,固定样本数和总方差,对比不同协方差形状(各向同性、陡方向大方差、平方向大方差)的收敛速度,验证"平方向大方差"最快、"形状比数目更重要"。

再做一个对照实验:固定各向同性协方差,增大样本数,看要增加多少样本才能追上"好形状 + 少样本"的性能——量化"形状的收益相当于多少倍样本"。

  1. (最优协方差推导,⭐⭐⭐⭐) 对一个简单的二次代价 \(J(U)=\frac{1}{2}U^\top H U\),尝试从 MPPI 的更新公式出发,分析采样协方差 \(\Sigma\) 如何影响单步更新后到最优的距离,定性地论证"为什么 \(\Sigma\) 应该和 \(H^{-1}\) 相关(平方向大方差)"。

(这是 CoVO-MPC 收敛分析的简化版,较难;不必严格推导出最优形式,能定性说清方向即可。提示:考虑各方向解耦后,每个方向的收敛速率如何依赖该方向的方差与曲率。)

  1. (跨章综合,⭐⭐⭐) 把 CoVO-MPC 和第 3 章的 U-MPPI(§3.5,用 Unscented Transform 传播协方差)、SVG-MPPI(§3.4,自适应估计协方差)对比:它们都涉及"协方差",但目的和方法有何本质不同?(提示:CoVO-MPC 优化的是"采样协方差的形状以加快收敛",U-MPPI 传播的是"状态不确定性的协方差以评估风险",SVG-MPPI 估计的是"目标 mode 的协方差"——同一个词"协方差"在三处指的是不同的东西、服务不同的目的。)这道题帮你厘清"协方差"在采样式 MPC 里的多重含义,避免混淆。

三维框架全景:把六节收进一张图

走完六节,是时候把它们收进本章开篇承诺的那个统一框架了。本章反复强调:采样式 MPC = 用提议分布近似目标分布 \(\mathbb{P}^\star\),而所有算法的差异归结为三个设计选择——权重函数、噪声、协方差。现在每个维度都讲过了,把它们并排放在一起,你能看到整族算法如何被这三个旋钮组织起来。

设计维度 它控制什么 本章的讨论 典型选择
权重函数 如何根据代价给样本赋权(筛选有多硬) §4.1(MPPI 指数 vs CEM 硬阈值)、§4.3(Tsallis 连续插值)、§4.4(PS 的 argmin 极端) 指数 / 硬阈值 / 变形指数 / argmin
噪声 采样噪声的时间结构(频谱) §4.2(iCEM 有色噪声 \(\beta=2\) 白噪声 / 有色噪声(红/布朗)
协方差 采样分布的形状(各方向方差如何分配) §4.6(CoVO-MPC 最优协方差由 Hessian 定) 各向同性 / 贴合 Hessian(对角或稠密)

这张表是本章的核心地图。任何一个采样式 MPC 方法——无论本章内外、无论多新——你都可以问这三个问题来定位它:它的权重函数是什么形状(多硬)?它的采样噪声有什么时间结构?它的协方差是什么形状?答出这三个,你就抓住了这个方法的本质,剩下的都是细节。

举几个例子练习这个定位法。Vanilla MPPI:权重=指数、噪声=白、协方差=各向同性——三个维度都取最朴素的选择,所以它是基线。iCEM:权重=硬阈值(CEM)、噪声=有色(核心改进)、协方差=对角自适应——它主要在噪声维度发力。

CoVO-MPC:权重=指数(仍是 MPPI)、噪声=白或有色、协方差=贴合 Hessian(核心改进)——它主要在协方差维度发力。

有色噪声 MPPI(第 3 章前沿):权重=指数、噪声=有色、协方差=各向同性——它把 iCEM 的噪声改进借给了 MPPI。

看出规律了吗?大多数方法是在**某一个维度**上做改进、其余维度保持朴素——这正是第 3 章"每个变体只改一个侧面"的观点在三维框架下的精确表述(第 3 章的"五侧面"是这三维的更细分解)。

本质洞察:这个三维框架是本章送给你的最重要的认知工具——它把采样式 MPC 从"一份越来越长的算法清单"压缩成"三个正交的设计维度"。正交是关键词:权重函数、噪声、协方差三者**大致独立**,可以自由组合(累积项目正是验证这一点——任意搭配权重 × 噪声 × 协方差)。这种正交分解的威力在于:它把一个看似无穷无尽的算法空间,组织成了一个有结构的、可探索的三维空间——每个已知算法是其中一点,而维度之间的空白处是潜在的新方法(比如"硬阈值 + 有色噪声 + Hessian 协方差"也许还没人系统研究过)。当你内化了这个框架,你看采样式 MPC 的眼光就根本改变了:不再是"记住几十个算法名字和它们的 trick",而是"理解三个维度、知道每个算法在三维空间的坐标、能预测维度组合的效果"。这是从"博物学"到"坐标系"的飞跃——也是本章标题"统一视角"的全部含义。带着这张三维地图进 Part 3,你会看到扩散模型如何在"提议分布"这个更根本的维度上突破高斯的限制——那是这个框架的又一次升维。


跨章综合应用:为一个仿真灵巧手任务选型

把本章和前三章的知识合起来,走一遍真实的选型推演。任务:用基于模型的方法(已有一个学到的动力学模型)控制一只仿真灵巧手完成抓取,要求实时(控制频率不能太低)、样本预算有限(GPU 不算顶级)。

第一步,定范式(呼应第 3 章横向定位)。 代价非光滑(抓取成功是稀疏奖励)、动力学是学到的黑箱——梯度 MPC 用不了,采样式 MPC 是主力。范式确定。

第二步,选基础算法(§4.1)。 MPPI 还是 CEM?灵巧手是高维系统(关节多),代价尺度可能随抓取阶段变化。CEM 的硬阈值省心、不用调温度,适合代价尺度多变;但样本预算有限时,CEM"扔掉非精英"浪费信息。

权衡后可以先用 MPPI(充分利用样本),或用 §4.3 的 Tsallis 取一个偏硬的中间 \(r\)(兼顾省心和信息利用)。

第三步,解决样本效率(§4.2)。 高维 + 样本有限,这正是 iCEM 的主场。上有色噪声(\(\beta=2\),让采样的控制序列平滑、贴合抓取动作的时间结构)、elite memory + shift init(复用上周期精英,receding-horizon 里省迭代)、mean-as-sample(高维下别漏掉均值这个好点)。这几招直接把样本效率拉上来——iCEM 的招牌实验正是 24 自由度的 ShadowHand。

第四步,优化协方差(§4.6)。 抓取代价地形各向异性强(某些关节方向敏感、某些平缓),各向同性协方差浪费严重。

用 CoVO-MPC 的思想让协方差贴合代价 Hessian(平方向大方差、陡方向小方差);若实时算 Hessian 太贵,用离线近似(预算 Hessian 缓存)——实验表明离线近似已能拿大部分收益。

第五步,工程落地(§4.5)。 如果这是要上真实产品的导航类任务,借鉴 Nav2 的 critic 架构把复杂代价(抓取成功 + 避免自碰撞 + 关节限位 + 动作平滑)拆成独立 critic,可维护、可组合、可单独调权重。

串起来看:第 3 章告诉你"用采样式、哪些变体修哪些缺陷",本章告诉你"这些方法背后的统一框架(§4.1/§4.3)、怎么让它样本高效(§4.2)、协方差怎么设最优(§4.6)、怎么工程化(§4.5)"。

一个真实任务的解法,是把这些知识按"范式 → 基础算法 → 样本效率 → 协方差 → 工程化"的顺序组合起来——这正是本章给你的全局视角的价值:不是孤立地用某个算法,而是在统一框架下系统地设计一个采样式控制器。

跨章综合思考题:接上面的灵巧手任务。(a) 如果把基础算法从 MPPI 换成 Tsallis(取中间 \(r\)),§4.2 的 iCEM 四招还能不能用?哪些需要改动?(提示:有色噪声改的是采样噪声、与权重函数正交,可直接用;elite memory 涉及"精英"概念,在软加权下要重新定义。)(b) §4.6 的 CoVO-MPC 最优协方差是为二次代价推导的,但灵巧手的代价高度非线性、非二次——CoVO 的协方差设计还适用吗?你会怎么用它(直接用 / 局部二次近似 / 只借"平方向大方差"的定性直觉)?(c) 把第 3 章的 Smooth-MPPI(§3.2 input-lifting)和本章 §4.2 的有色噪声对比:它们都让控制平滑,在这个灵巧手任务上你选哪个、为什么?如果同时用会怎样(提示:可能冗余,因为都在塑造时间结构)?


本章常见误解汇总

误解 正确理解
MPPI 和 CEM 是两个不同的算法 它们是同一个"采样—赋权—更新"骨架的两种权重函数(指数 vs 硬阈值);\(\lambda\) 与精英比例是同一个探索-利用旋钮(§4.1)
CEM 不用调温度,所以比 MPPI 简单/更好 是取舍而非优劣——CEM 省心但硬阈值浪费次优样本信息,MPPI 难调 \(\lambda\) 但充分利用样本;按任务(代价尺度是否稳定)选(§4.1)
有色噪声里 \(\beta\) 越大越好 \(\beta=2\) 是甜点;\(\beta\) 太大过度平滑、失去时域调整能力(平滑↔敏捷权衡的重现)(§4.2)
iCEM 的四招是 CEM 专属技巧 它们是采样式方法的通用样本效率智慧,可迁移到 MPPI(有色噪声 MPPI 就是真实变体)(§4.2)
Tsallis VI-MPC 是又一个和 MPPI 并列的新算法 它是包含 MPPI/CEM 的框架,MPPI/CEM 是其特例(\(r\to1\)\(r\to\infty\));"Tsallis vs MPPI"是范畴错误(§4.3)
有了 Tsallis 框架就该永远用中间 \(r\) 框架给的是"可取中间值"的自由,不是"必须取";端点(MPPI/CEM)本身是合法且常更优的选择(§4.3)
Predictive Sampling 简单有效,说明 MPPI/CEM 的复杂多余 PS 的简单有效有条件(单峰、低噪声、样条参数化);高噪声/多峰下复杂权重显出价值(§4.4)
Predictive Sampling 是统一框架之外的另类 它是框架的极端端点——筛选硬到极致(只取一个样本),对应 \(\lambda\to0\) / \(r\to\infty\) / 精英数=1(§4.4)
critic 越多越全面越好 critic 过多导致权重调参爆炸和目标冲突;用最少的、任务真正需要的 critic(§4.5)
critic 的 score 用 = 赋值就行 必须用 += 累加——critic 架构靠"累加到同一 costs 数组"组合,用 = 会抹掉其他 critic 的贡献(§4.5)
采样式方法靠撒更多样本提升性能 "形状比数目更重要"——固定样本数下,协方差形状贴合 Hessian 的收益远大于盲目加样本(§4.6)
CoVO-MPC 的收敛证明适用于任意非线性系统 严格证明限于二次代价/时变 LQR;非线性系统的收敛是开放问题,CoVO 在其上是经验有效(§4.6)
"形状比数目更重要"意味着样本数越少越好 样本数有保证估计稳定的下限;形状是高杠杆,但数目是地基,不能砍到危险低位(§4.6)

本章小结

本章从"一族算法"走到"一个框架",主线是:采样式 MPC 可以统一看成"用提议分布近似目标分布 \(\mathbb{P}^\star\)",而各算法的差异归结为三个设计选择——权重函数、噪声、协方差。

  • §4.1 揭示 CEM 与 MPPI 同根:同一个"采样—赋权—更新"骨架,MPPI 用指数软加权、CEM 用硬阈值筛选,\(\lambda\) 与精英比例是同一探索-利用旋钮。这是理解后续统一框架的钥匙。
  • §4.2 讲 iCEM 用四招(有色噪声、elite memory、shift init、mean-as-sample)把 CEM 的样本效率提升 2.7–22×,让它能实时。四招都在回答"样本少时怎么用在刀刃上",且都能迁移到 MPPI。
  • §4.3 用 Tsallis 变形指数 \(\exp_r\) 把 MPPI(\(r\to1\))、CEM(\(r\to\infty\))、SV-MPC 统一为一族特例,把"软硬筛选"从离散二选一变成连续旋钮。
  • §4.4 用 Predictive Sampling 证明"筛选硬度"谱的最硬端点(取 argmin)依然可用,揭示采样式 MPC 的威力主要来自"采样+评估真实代价"的核心机制。
  • §4.5 把统一视角落到生产级代码:Nav2 的 critic 插件架构把复杂代价分解成可组合的评分插件,是"代价可分解"的通用工程模式。
  • §4.6 CoVO-MPC 给出 MPPI 首个收敛证明(二次代价下线性收敛)和最优协方差设计(由 Hessian 决定),证明"形状比数目更重要"。

术语速查表

术语 一句话定义
CEM(交叉熵方法) 采样—取精英—用精英重拟合分布的迭代优化器;权重函数是硬阈值
精英(elite) CEM 每轮保留的代价最低的一批样本
精英比例(elite fraction) 保留为精英的样本占比;与 MPPI 的温度 \(\lambda\) 是同一探索-利用旋钮
权重函数 把样本代价映射为更新权重的函数;MPPI 用 \(e^{-J/\lambda}\)、CEM 用 \(\mathbb{1}\{J\le J_{\text{elite}}\}\)
iCEM 改进的 CEM,四招提升样本效率 2.7–22×
有色噪声(colored noise) 功率谱 \(S(f)\propto1/f^\beta\) 的时间相关噪声;\(\beta=2\)(布朗)对控制最友好
elite memory iCEM 保留上轮精英加入下轮采样池的机制
shift init iCEM 把上周期解左移一步作为新周期初始均值(warm-start 的 CEM 版)
mean-as-sample iCEM 把分布均值作为额外样本加入评估(防高维下采不到均值)
变形指数 \(\exp_r\) \([1+(1-r)x]_+^{1/(1-r)}\)\(r\to1\) 退化为标准 \(\exp\);Tsallis 框架的核心
Tsallis 散度 KL 散度的推广;\(r=1\) 时退化为 KL
Predictive Sampling 最简采样器:采样后取 argmin(不加权);统一框架的最硬端点
critic(评判器) Nav2 MPPI 里负责计算某一项代价并累加到总代价的可插拔插件
CriticFunction Nav2 所有 critic 的基类;核心方法 score 给所有轨迹打分累加
收缩率 \(\rho(\Sigma)\) CoVO-MPC 收敛定理里的几何收敛比例;由 \(\Sigma\)\(\lambda\)、系统特性决定
最优协方差 \(\Sigma^\star\) 让收缩率最小的采样协方差;由代价 Hessian 决定(凸方向小、平方向大)

知识点总表

编号 知识点 核心要点 对应节 难度
4-1 CEM-MPPI 统一骨架 采样—赋权—更新;差别只在权重函数 §4.1 ⭐⭐⭐
4-2 \(\lambda\) 与精英比例的对应 同一探索-利用旋钮的两种刻度 §4.1 ⭐⭐⭐
4-3 iCEM 有色噪声 \(\beta=2\) 布朗噪声,影响最大;样本越少优势越大 §4.2 ⭐⭐⭐
4-4 iCEM 其余三招 elite memory / shift init / mean-as-sample §4.2 ⭐⭐
4-5 Tsallis 变形指数统一 \(\exp_r\) 用一个 \(r\) 连续插值 MPPI(\(r\to1\))–CEM(\(r\to\infty\)) §4.3 ⭐⭐⭐
4-6 Tsallis 统一四特例 VI-MPC/MPPI/CEM/SV-MPC 都是特例 §4.3 ⭐⭐⭐
4-7 Predictive Sampling 极简 取 argmin 也有竞争力;框架的最硬端点 §4.4 ⭐⭐
4-8 Nav2 critic 架构 代价拆成可插拔插件,靠累加组合 §4.5 ⭐⭐⭐
4-9 自定义 critic 写法 继承 CriticFunction、score 里 +=、注册+YAML §4.5 ⭐⭐⭐
4-10 MPPI 收敛定理 二次代价下线性收敛,收缩率由 \(\Sigma\) §4.6 ⭐⭐⭐
4-11 最优协方差 由 Hessian 决定,凸方向小方差、平方向大方差 §4.6 ⭐⭐⭐
4-12 形状比数目更重要 固定样本数下,调对协方差形状收益远超加样本 §4.6 ⭐⭐⭐

承上启下

本章完成了对采样式 MPC "经典家族"的统一理解——从 MPPI/CEM 的同根(§4.1)、到样本效率的工程优化(§4.2)、到 Tsallis 的理论统一(§4.3)、到极简主义的启示(§4.4)、到生产级工程化(§4.5)、到收敛理论与最优协方差(§4.6)。

至此,你手里有了一张完整的图:采样式 MPC 是"用提议分布近似目标分布",三个设计维度(权重函数、噪声、协方差)刻画了这一族的所有差异,CoVO-MPC 还为协方差维度给出了理论最优。

但这一族算法有一个共同的前提:提议分布是简单的参数化分布(主要是高斯)。无论怎么调权重函数、噪声、协方差,提议分布的"表达能力"始终受限于高斯(或高斯混合)这个家族——它能表达的形状有限,面对真正复杂、多模、高维的最优控制分布时力不从心。

这正是 Part 3 要突破的:用**扩散模型**这种强大的生成模型作提议分布(第 5 章),用**学习的世界模型**让采样式 MPC 摆脱对精确动力学模型的依赖(第 6 章)。

如果说本章是把经典采样式 MPC 的框架讲到了头,那么 Part 3 就是这个框架与现代生成模型、学习方法融合的前沿——采样式 MPC 故事的下一章。


累积项目:本章新增模块

第 3 章的累积项目交付了一个"可切换变体的 MPPI"——同一个主循环、几个钩子,不同变体替换对应钩子(采样钩子挂 Smooth/Log、rollout 钩子挂 RMPPI/U-MPPI 等)。那个骨架的核心洞察是"变体只改某个钩子、骨架不变"。

本章的模块是把这个骨架**升级为一个真正统一的采样优化器**——把本章的三个设计维度(权重函数、噪声、协方差)都做成可配置项,从而能用同一份代码实例化出 MPPI、CEM、Tsallis、iCEM 乃至 CoVO 风格的优化器。这是本章"采样式 MPC = 三设计选择"主线的代码兑现:

def unified_optimizer(weight='mppi', noise='white', cov='iso', ...):
    for _ in range(iters):
        # 维度2(§4.2): 噪声 —— 白噪声 or 有色噪声
        eps = colored(K, T, beta, rng) if noise == 'colored' else randn(K, T)
        # 维度3(§4.6): 协方差形状 —— 各向同性 or 贴合 Hessian(此处简化为对角缩放)
        U = mu + (sigma_shape * eps)
        J = cost(U)
        # 维度1(§4.1/§4.3): 权重函数 —— MPPI指数 / CEM硬阈值 / Tsallis变形
        if   weight == 'mppi':    w = np.exp(-(J-J.min())/lam)
        elif weight == 'cem':     w = (J <= np.quantile(J, elite_frac)).astype(float)
        else:                     w = exp_r(-(J-J.min())/lam, r)      # Tsallis
        w /= w.sum(); mu = (w[:,None]*U).sum(0)
    return mu

同一到达任务,自由组合权重函数 × 噪声,最终代价:

权重=mppi     噪声=white   : 41.59
权重=mppi     噪声=colored : 41.61
权重=cem      噪声=white   : 44.27
权重=cem      噪声=colored : 43.33
权重=tsallis  噪声=white   : 118.59
权重=tsallis  噪声=colored : 72.05

这个模块让"换算法"变成"换配置"——想要 MPPI 就 weight='mppi'、想要 iCEM 风格就 weight='cem', noise='colored'、想要 Tsallis 中间硬度就 weight='tsallis' 配一个 \(r\)

它把本章六节讲的方法收进了**一份可运行、可配置的统一代码**里,正是本章"从一族算法到一个框架"主线的最佳注脚。

本章新增模块清单:(1) 可配置权重函数(MPPI/CEM/Tsallis 三选,§4.1/§4.3);(2) 可配置噪声(白/有色,§4.2);(3) 可配置协方差形状(各向同性/贴合代价地形,§4.6);(4) 与第 3 章骨架兼容(warm-start、约束钳位等照常)。

后续第 5、6 章会在此基础上把"提议分布"这一维从高斯换成扩散模型、把"动力学模型"换成学习的世界模型——这个统一骨架将继续延展。

给读者的实践建议:动手把上面的骨架补全(加入协方差形状开关、shift init、mean-as-sample),在一个你熟悉的任务上跑通三种权重 × 两种噪声的全部组合,画出收敛曲线对比。

这个练习会让本章的"统一框架"从概念变成你指尖的代码——当你能用一份代码切换出整个算法家族时,你就真正理解了"它们是一族"这件事。


延伸阅读

核心论文(按本章顺序,标注难度):

  • iCEM:Pinneri 等, Sample-efficient Cross-Entropy Method for Real-time Planning, CoRL 2020, arXiv:2008.06389。⭐⭐⭐ 读四大改进与消融实验(哪招影响最大)。开源 martius-lab/iCEM
  • Tsallis VI-MPC:Wang, So, Theodorou 等, Variational Inference MPC using Tsallis Divergence, RSS 2021, arXiv:2104.00241。⭐⭐⭐⭐ 本章理论核心,读变形指数如何统一 MPPI/CEM/SV-MPC;风险敏感度分析较难。
  • Predictive Sampling:Howell 等, Predictive Sampling: Real-time Behaviour Synthesis with MuJoCo, arXiv:2212.00541, 2022。⭐⭐ 读极简采样器为何竞争力强;配套 google-deepmind/mujoco_mpc
  • CoVO-MPC:Yi, Pan, He, Qu, Shi, CoVO-MPC: Theoretical Analysis of Sampling-based MPC and Optimal Covariance Design, L4DC 2024(PMLR 242:1122-1135), arXiv:2401.07369。⭐⭐⭐⭐ 收敛证明与最优协方差,理论压轴;开源 LeCAR-Lab/CoVO-MPC(JAX)。
  • SV-MPC:Lambert 等, Stein Variational Model Predictive Control, CoRL 2020。⭐⭐⭐ 多模态后验的粒子表示(与第 3 章 §3.4 SVG-MPPI 对照)。

工程实现

  • martius-lab/iCEM:有色噪声生成与 elite memory 管理的参考实现,看 colored_noise 与精英存储逻辑。
  • google-deepmind/mujoco_mpc(MJPC):mjpc/planners/sampling/planner.cc(Predictive Sampling)vs mjpc/planners/cross_entropy/planner.cc(CEM)——两个文件对比,最能体会"权重函数不同、骨架相同"。还有 ilqg/ 可对比导数法。MJPC 的 GUI 可实时切换 planner、看 Pareto 前沿。
  • ros-navigation/navigation2nav2_mppi_controllersrc/optimizer.cpp(主循环)、src/critics/(所有 critic)、include/.../critic_function.hpp(critic 基类)。生产级 C++ 的最佳学习材料。
  • LeCAR-Lab/CoVO-MPC:JAX 实现,看协方差调度(实时 Hessian 与离线近似)的核心代码。

背景补充

  • Tsallis 统计与 q-指数的数学背景(非 ML 文献,了解变形指数的物理来源即可,不必深究)。⭐⭐⭐⭐
  • 交叉熵方法的原始文献(De Boer 等的 CEM tutorial),了解 CEM 在稀有事件估计中的起源。⭐⭐⭐

本章与后续章节的关系

后续章节 关系 本章铺垫的知识点
第 5 章 扩散启发采样 MPC 用扩散模型替代高斯提议分布,突破本章"提议分布受限于高斯"的根本局限 三设计维度(尤其"提议分布"这一维)、采样式 MPC 的统一视角
第 6 章 学习世界模型 TD-MPC 让采样式 MPC 摆脱对精确动力学模型的依赖,用学习的世界模型 + 值函数 iCEM/CEM 作为 MBRL 的规划器、采样—评估真实代价的核心机制
(回看)第 3 章 六大变体 第 3 章的"五侧面"是本章"三设计维度"在变体层面的展开 提议分布的五侧面、各向同性协方差的局限

给读者的衔接提示:本章反复强调"提议分布是高斯(或高斯混合)"这个共同前提,并指出它是表达能力的天花板。

带着这个"高斯天花板"的认识进第 5 章,你会立刻明白扩散模型为什么是个突破——它是一个表达能力强得多的提议分布生成器,能表达高斯远不能及的复杂多模分布。本章把经典框架讲到头、并明确点出其局限,正是为了让你看清第 5 章突破的是什么。


🔧 故障排查手册

症状 可能原因 排查步骤 相关节
CEM 头几轮飞快收敛后卡死、代价不再下降 精英比例太小,方差估计坍缩 打印每轮分布平均 std,若快速趋零即坍缩;增大精英数、给方差设下界 §4.1
换了任务后 MPPI 突然不工作(权重全平或全集中在一个样本) 温度 \(\lambda\) 没随代价尺度重调 检查代价数值范围,\(\lambda\) 应与之匹配;用 ESS 监控(第 2 章)判断权重是否健康 §4.1
有色噪声实验里"换 \(\beta\)"的效果很乱、无规律 生成后忘记归一化,\(\beta\) 同时改了颜色和幅度 打印不同 \(\beta\) 噪声的 std,应都≈1;归一化到单位 std 再乘 \(\sigma\) §4.2
实现的变形指数 \(\exp_r\) 在高代价样本处出现 NaN/复数 忘记 \([\cdot]_+\) 截断,底数为负取分数次幂 检查 1+(1-r)x 是否被 max(·,0) 截断;\(r\to1\) 是否单独用 exp §4.3
Predictive Sampling 的控制在相邻周期剧烈跳变 没做 warm-start,argmin 不平均噪声、对采样随机性敏感 加 shift/warm-start 复用上周期解;配有色噪声让采样平滑 §4.4
加了自定义 critic 后机器人不避障/不跟随路径了 critic 的 score 用 = 覆盖而非 += 累加 检查 score 里是否 data.costs(k) +=;单独启用各 critic 验证 §4.5
自定义 critic 在 YAML 里设了 enabled: false 却仍生效 score 里没检查 enabled_ 开关 在 score 开头加 if (!enabled_) return; §4.5
控制器实时性突然变差、帧率掉 critic 的 score 里做了重活(每周期分配大内存/重复查询) 把重活移到 initialize 或缓存;检查 score 是否在热路径分配内存 §4.5
CoVO 的协方差导致采样发散或崩溃 Hessian 求逆未保护,得到病态/非正定协方差 给 Hessian 加正则 \(\epsilon I\)、对特征值设界、检查正定性(Cholesky) §4.6
critic 太多导致行为犹豫、调参困难 critic 过多、目标冲突、权重难平衡 砍到最小必要 critic 集;从少数起步逐个加并重新平衡权重 §4.5

API / 参数速查表

统一采样优化器(概念骨架,§4.1)

# 采样—赋权—更新三步骨架; 换 weight_fn 即得不同算法
def sampling_optimizer(weight_fn, mu, sigma, K, iters):
    for _ in range(iters):
        U = mu + sigma * randn(K, T)          # 1.采样
        J = cost(U)                            # 算代价
        w = weight_fn(J)                       # 2.赋权(MPPI/CEM/Tsallis 的差别在此)
        mu = (w[:,None]*U).sum(0) / w.sum()    # 3.更新
    return mu
# weight_fn 三选: exp(-J/λ) [MPPI] | 1{J≤J_elite} [CEM] | exp_r(-J/λ) [Tsallis]

关键参数对照

参数 算法 含义 典型值/取向
\(\lambda\) (temperature) MPPI 探索-利用旋钮;小→聚焦、大→均等 Nav2 默认 0.3;依代价尺度调
精英比例 CEM 探索-利用旋钮;小→聚焦、大→均等 常 5%–20%;别太小防坍缩
\(\beta\) iCEM 有色噪声 噪声颜色;大→更平滑 \(\beta=2\)(布朗)甜点
\(r\) Tsallis 筛选硬度;\(\to1\) MPPI、\(\to\infty\) CEM 端点或中间,按任务
batch_size Nav2 MPPI 候选轨迹数 1000@50Hz / 2000@30Hz
time_steps×model_dt Nav2 MPPI 预测时域 如 56×0.05=2.8s
cost_weight Nav2 critic 该 critic 的权重 按 critic 相对重要性
cost_power Nav2 critic 代价幂次 常 1

变形指数实现要点(§4.3)

def exp_r(x, r):
    if abs(r-1.0) < 1e-6: return np.exp(x)         # r→1 特判, 避免 1/(1-r) 除零
    return np.maximum(1.0 + (1.0-r)*x, 0.0)**(1.0/(1.0-r))   # 务必 max(·,0) 截断

Nav2 自定义 critic 骨架(§4.5)

class MyCritic : public mppi::critics::CriticFunction {
  void initialize() override { getParam(weight_, "cost_weight", 10.0); }
  void score(CriticData & data) override {
    if (!enabled_) return;                          // 尊重开关
    for (size_t k=0; k<data.trajectories.x.shape(0); ++k)
      data.costs(k) += weight_ * my_cost(data, k);  // 务必 += 累加
  }
};

研究实践建议

如果你要落地某个方法。 先按本章顺序问自己:范式对吗(采样式还是梯度式,§4.1 横向定位)→ 基础算法选 MPPI 还是 CEM 还是中间的 Tsallis(§4.1/§4.3,按代价尺度是否稳定、样本是否珍贵)→ 样本效率够吗(不够就上 iCEM 四招,§4.2)→ 协方差形状对吗(各向同性往往次优,借 CoVO 思想贴合 Hessian,§4.6)→ 工程化(代价复杂就用 critic 架构,§4.5)。

从开源实现起步:iCEM 用 martius-lab/iCEM、想要生产级 ROS2 用 Nav2、想理解收敛与协方差读 LeCAR-Lab/CoVO-MPC

最省力的探针是 Predictive Sampling(§4.4)——几行代码先确认采样式方法在你的任务上有没有戏,再精化。

如果你要做研究、找选题。 本章的开放问题就是选题地图:CoVO-MPC 的收敛证明只覆盖二次代价/LQR,非线性系统的收敛性完全开放(§4.6 前沿)——这是个硬核理论方向。

Tsallis 框架统一了权重函数维度,但"噪声"和"协方差"维度的统一理论还不完整——能否有一个同时涵盖三个维度的更大框架?另外,本章所有方法的提议分布都是高斯,第 5 章的扩散模型提议分布是新的前沿——把 CoVO 的"最优协方差"思想推广到扩散提议分布,是个有意思的交叉方向。务实建议:先复现 iCEM 或 CoVO-MPC(有开源、结论清晰),在复现中发现可改进的细节。

如果你只是想建立理解、为后续打基础。 抓住三条主线就够了:(1) MPPI/CEM 同根、由权重函数区分(§4.1);(2) 三设计维度(权重函数/噪声/协方差)刻画整个家族(贯穿全章);(3) "形状比数目更重要"(§4.6)。

带着这三条进第 5、6 章,你会看到它们如何与扩散模型、学习世界模型融合。不必记住每个方法的全部实现细节,但要能把任何新方法定位到三个设计维度上。

给所有人的一条共识。 本章最反直觉、也最有价值的洞察是"形状比数目更重要"(§4.6)——它提醒你,采样式方法的性能瓶颈往往不在"样本不够多",而在"采样分布的形状/结构没设计好"。

下次 MPPI 调不好,先检查协方差形状、噪声结构、权重函数,而非第一反应加样本数。这个思维习惯会让你的调参事半功倍。


版本信息速查

工作 / 工具 年份 发表 开源实现
iCEM 2020 CoRL martius-lab/iCEM
SV-MPC 2020 CoRL (见论文)
Tsallis VI-MPC 2021 RSS(arXiv:2104.00241) (见论文)
Predictive Sampling / MJPC 2022 arXiv:2212.00541 google-deepmind/mujoco_mpc
Nav2 MPPI Controller 2023 ROSCon ros-navigation/navigation2
CoVO-MPC 2024 L4DC(PMLR 242:1122-1135) LeCAR-Lab/CoVO-MPC

环境提示:本章 CPU 演示(CEM/MPPI 对比、有色噪声、变形指数、协方差形状)仅需 NumPy,可在任意环境复现其定性结论。

iCEM 官方实现基于 PyTorch/NumPy;MJPC 是 C++(含 GUI);Nav2 MPPI 是 C++/ROS2;CoVO-MPC 是 JAX。

各论文报告的性能数字(如 iCEM 的 2.7–22×、CoVO-MPC 的 43–54%)引自原文实验。

本章正文与全部章末组件已完成:CEM-MPPI 关系(§4.1)+ iCEM 四大改进(§4.2)+ Tsallis 统一框架(§4.3)+ Predictive Sampling(§4.4)+ Nav2 critic 架构(§4.5)+ CoVO-MPC 收敛与最优协方差(§4.6)+ 跨章综合应用 + 误解汇总 + 本章小结 + 延伸阅读 + 后续关系 + 故障排查 + API 速查 + 研究实践建议 + 版本信息速查。本章紧扣"采样式 MPC = 用提议分布近似目标分布,差异归结为权重函数/噪声/协方差三个设计选择"这条主线,把一族看似零散的算法统一为一个框架,并指出其共同局限(提议分布受限于高斯)——这正是第 5 章用扩散模型突破的起点。