1. 从最优控制到概率推断:一个视角的转换
第一次接触Control as Inference这个框架时,我的反应是:这不就是把控制问题硬套上概率的壳吗?但真正动手推了几遍公式、又在几个仿真环境里跑通之后,我才意识到这个视角转换的价值——它把最优控制和概率推断这两套原本各说各话的语言,用KL散度这个桥梁打通了。你如果做过MPC或者随机最优控制,大概率遇到过这样的困境:目标函数里的权重调起来全靠手感,约束一多求解器就崩,噪声一大整个系统就开始抖。Control as Inference给出的思路是,别把控制看成“找一个让代价最小的动作序列”,而是看成“在给定未来事件发生概率的条件下,推断最可能的后验动作分布”。这个视角一换,很多原本棘手的问题突然有了新的解法。
这篇文章适合谁看?如果你有最优控制或者强化学习的基础,想搞清楚Control as Inference到底在干什么、为什么变分推断会出现在控制问题里、KL散度又是怎么把这两件事绑在一起的,那这篇内容就是写给你的。我会从最基本的概率图模型开始,一步步推到变分下界,再讲清楚它和MPC、随机最优控制之间的对应关系。不堆公式,但关键的推导步骤一个不落,因为跳过推导你后面看代码实现时会完全懵。
先说清楚这个框架解决的核心问题:传统最优控制要求你显式定义一个代价函数,然后求解一个确定性或者随机的最优控制问题。但现实里,代价函数往往很难精确写出来,或者写出来之后参数调不准。Control as Inference的做法是,引入一个“最优性变量”,把控制问题重新表述为概率推断问题——给定系统动力学和最优性条件,推断动作的后验分布。这个后验分布既包含了控制目标,也包含了不确定性,天然适合处理噪声和模型误差。
我实测下来,这个框架最吸引人的地方在于三点:第一,它把控制问题统一到了概率框架下,和状态估计、系统辨识共享同一套数学工具;第二,变分推断的引入让高维连续控制问题可以用随机优化方法求解,避开了传统MPC里反复求解二次规划的计算瓶颈;第三,KL散度作为目标函数,天然具有信息几何的结构,对分布之间的差异度量比欧氏距离更合理。当然,代价是推导复杂了,实现起来也需要对变分推断有一定了解。但只要你跨过这个门槛,后面看到的东西会让你觉得之前的功夫没白花。
2. 概率图模型:把控制问题画成一张图
2.1 从确定性最优控制到随机动力学
传统最优控制的离散时间形式是这样的:系统状态x_t,动作u_t,动力学x_{t+1} = f(x_t, u_t),代价函数c(x_t, u_t),目标是找到动作序列u_{0:T-1}使得累积代价最小。这是确定性的表述,所有变量都是确定的,求解方法包括动态规划、LQR、MPC等等。
但现实系统几乎都有噪声。随机最优控制的表述是x_{t+1} ~ p(x_{t+1} | x_t, u_t),代价函数变成期望代价E[c(x_t, u_t)]。这时候问题就变成了在随机动力学下最小化期望累积代价。求解方法包括随机动态规划、随机MPC等。
Control as Inference在这个基础上又往前走了一步。它引入一个二值的“最优性变量”O_t,O_t = 1表示在时刻t系统处于“最优”状态,O_t = 0表示不是。然后定义p(O_t = 1 | x_t, u_t) ∝ exp(-c(x_t, u_t))。这个定义是整个框架的基石,它把代价函数转化成了概率——代价越小,最优性变量为1的概率越大。
我第一次看到这个定义的时候觉得有点强行,但仔细想想其实很自然。指数变换是单调的,所以最小化代价等价于最大化最优性概率。而且指数形式在后续推导中会带来很多便利,比如乘积变求和、对数变线性。这个选择不是随意的,它保证了推断问题和控制问题在最优解上是一致的。
2.2 概率图模型的构建与因子分解
有了最优性变量,整个控制问题就可以画成一张概率图模型。节点包括状态x_t、动作u_t、最优性变量O_t。边表示条件依赖关系:x_{t+1}依赖于x_t和u_t,O_t依赖于x_t和u_t。整张图的联合分布可以写成:
p(x_{0:T}, u_{0:T-1}, O_{0:T-1}) = p(x_0) ∏_{t=0}^{T-1} p(x_{t+1} | x_t, u_t) p(O_t | x_t, u_t)
这个分解是标准的概率图模型因子分解,它假设系统是一阶马尔可夫的,即下一时刻状态只依赖于当前状态和动作。这个假设在大多数控制问题中是合理的,也是传统最优控制的基础假设。
现在控制问题变成了推断问题:给定O_{0:T-1} = 1(即所有时刻都最优),推断后验分布p(x_{0:T}, u_{0:T-1} | O_{0:T-1} = 1)。这个后验分布就是我们要找的“最优”轨迹分布。注意这里推断的是整个轨迹的联合分布,而不是单个动作。这个区别很重要,因为控制问题本质上是一个序列决策问题,动作之间是有耦合的。
我第一次推导这个后验分布的时候,卡在了归一化常数上。因为p(O_{0:T-1} = 1)需要对所有可能的轨迹积分,这个积分在高维空间里是intractable的。这就是为什么需要变分推断——用一个简单的分布去近似这个复杂的后验分布,把积分问题转化成优化问题。
2.3 为什么需要变分推断而不是精确推断
精确推断在这个图模型上基本不可行。原因很简单:状态空间是连续的,而且维度可能很高;时间步长T可能很大;动力学p(x_{t+1} | x_t, u_t)通常是非线性的。这三个因素叠加起来,精确计算后验分布的计算量是指数级的。
我试过在小规模问题上用粒子滤波做精确推断,T=10、状态维度2的时候还能跑,但T=50、状态维度6的时候直接爆内存。所以变分推断不是可选项,是必选项。变分推断的核心思想是:找一个参数化的分布q(x_{0:T}, u_{0:T-1}),让它在KL散度意义下尽可能接近真实后验p(x_{0:T}, u_{0:T-1} | O_{0:T-1} = 1)。然后通过优化q的参数来逼近后验。
这个思路的好处是,优化问题可以用随机梯度下降求解,计算量随维度线性增长而不是指数增长。代价是q的表达式需要精心设计,太简单了近似不好,太复杂了优化困难。后面我会详细讲怎么设计q的结构。
3. 变分推断的核心推导:从KL散度到可优化下界
3.1 KL散度的定义与方向选择
KL散度衡量两个分布之间的差异,定义是KL(q || p) = ∫ q(x) log(q(x)/p(x)) dx。注意KL散度是不对称的,KL(q || p)和KL(p || q)不一样。在变分推断里,我们最小化KL(q || p),其中q是变分分布,p是真实后验。
为什么选这个方向?因为KL(q || p) = E_q[log q] - E_q[log p],第一项是q的熵,第二项是q在p下的期望对数概率。这个形式可以直接从样本估计,不需要知道p的归一化常数。而KL(p || q)需要计算p的归一化常数,也就是那个intractable的积分。所以方向选择不是随意的,是为了计算可行性。
我一开始没注意这个细节,直接写了KL(p || q)的表达式,结果推到一半发现需要算归一化常数,整个推导卡死。后来换成KL(q || p)才走通。这个坑很典型,新手很容易踩。
3.2 证据下界(ELBO)的推导
最小化KL(q || p)等价于最大化证据下界ELBO。推导过程如下:
KL(q || p) = E_q[log q(x)] - E_q[log p(x | O)]
其中p(x | O) = p(x, O) / p(O),所以:
KL(q || p) = E_q[log q(x)] - E_q[log p(x, O)] + log p(O)
整理得:
log p(O) = ELBO + KL(q || p)
其中ELBO = E_q[log p(x, O)] - E_q[log q(x)]。
因为KL(q || p) ≥ 0,所以log p(O) ≥ ELBO。最大化ELBO就是在最大化证据的下界,同时最小化KL散度。这个分解是变分推断的核心,也是Control as Inference里所有推导的起点。
我第一次推这个的时候,在p(x, O)的分解上卡了很久。后来才想明白,p(x, O) = p(x) p(O | x),而p(O | x) = ∏_t p(O_t | x_t, u_t)。这个分解利用了图模型的条件独立性,把联合概率拆成了先验和似然的乘积。先验p(x)就是动力学模型,似然p(O | x)就是最优性概率的乘积。
3.3 从ELBO到可优化的目标函数
ELBO的表达式里,E_q[log p(x, O)]可以进一步展开:
E_q[log p(x, O)] = E_q[log p(x_0) + ∑_t log p(x_{t+1} | x_t, u_t) + ∑_t log p(O_t | x_t, u_t)]
代入p(O_t | x_t, u_t) ∝ exp(-c(x_t, u_t)),得到:
E_q[log p(O_t | x_t, u_t)] = -E_q[c(x_t, u_t)] + const
所以ELBO可以写成:
ELBO = E_q[∑_t log p(x_{t+1} | x_t, u_t) - ∑_t c(x_t, u_t)] - E_q[log q(x, u)] + const
这个表达式很直观:第一项是动力学模型的似然,第二项是负代价,第三项是变分分布的熵。最大化ELBO就是在最大化动力学似然和负代价,同时最大化熵。熵项鼓励探索,防止q退化到确定性分布。
我实测下来,这个目标函数在优化时比直接最小化代价要稳定得多。因为熵项起到了正则化的作用,避免了传统最优控制里常见的过拟合和数值不稳定问题。当然,代价是收敛速度可能慢一些,因为多了熵这一项。
4. 变分分布的设计与结构化分解
4.1 均值场近似及其局限性
最简单的变分分布设计是均值场近似:q(x, u) = ∏_t q(x_t) q(u_t)。这个假设认为所有时刻的状态和动作都是独立的。优点是计算简单,每个q都可以用简单的分布(比如高斯)参数化。缺点是忽略了时间上的相关性,而控制问题里时间相关性恰恰是关键。
我试过在倒立摆问题上用均值场近似,结果控制效果很差,摆根本立不起来。原因是均值场假设下,q(u_t)不依赖于q(x_t),动作和状态解耦了,这显然不符合控制问题的本质。后来改成结构化变分分布,让q(u_t | x_t)依赖于状态,效果立刻好了很多。
4.2 结构化变分分布:让q(u_t | x_t)成为策略
Control as Inference里最常用的变分分布设计是:
q(x_{0:T}, u_{0:T-1}) = q(x_0) ∏_t q(x_{t+1} | x_t, u_t) q(u_t | x_t)
这个分解里,q(u_t | x_t)就是策略——给定状态,输出动作分布。q(x_{t+1} | x_t, u_t)是变分动力学模型,通常直接设为真实动力学p(x_{t+1} | x_t, u_t),因为动力学是已知的。q(x_0)是初始状态分布,通常也设为真实初始分布。
这个设计的好处是,策略q(u_t | x_t)是因果的——只依赖于当前状态,不依赖于未来。这符合控制的因果性要求。而且这个分解下的ELBO可以写成:
ELBO = E_q[∑_t log p(x_{t+1} | x_t, u_t) - ∑_t c(x_t, u_t) - ∑_t log q(u_t | x_t)] + const
最后一项是策略的熵,鼓励策略保持随机性。这个目标函数可以直接用策略梯度方法优化,和强化学习里的最大熵RL非常相似。
4.3 变分分布与MPC的对应关系
如果你做过MPC,会发现这个结构化变分分布和MPC的滚动时域优化很像。MPC在每个时刻求解一个有限时域的最优控制问题,只执行第一个动作,然后重新求解。Control as Inference里的变分推断也是类似的:优化q(u_t | x_t)在所有时刻上的参数,但实际执行时只取当前时刻的动作。
区别在于,MPC是确定性的,每次求解一个优化问题;Control as Inference是概率的,推断的是一个分布。这个区别带来的好处是,Control as Inference天然处理不确定性——策略输出的是动作分布而不是单个动作,可以采样也可以取均值。在噪声大的系统里,这个特性非常有用。
我实测下来,在模型误差较大的情况下,Control as Inference的鲁棒性明显优于传统MPC。因为变分推断的目标函数里包含了动力学似然项,模型误差会被自动降权。而MPC如果模型不准,约束就会失效,控制效果急剧下降。
5. 与随机最优控制和MPC的深层联系
5.1 随机最优控制的概率表述
随机最优控制的标准表述是:min E[∑_t c(x_t, u_t)],约束是x_{t+1} ~ p(x_{t+1} | x_t, u_t)。这个问题的解是随机最优控制律,通常用随机动态规划求解。
Control as Inference把这个问题的解重新表述为后验分布p(x, u | O = 1)。这个后验分布的均值就是随机最优控制律的均值,方差就是控制律的不确定性。所以Control as Inference不是替代随机最优控制,而是给出了一个新的求解视角。
我对比过两种方法在LQR问题上的解。传统LQR给出的是确定性控制律u_t = -K_t x_t,Control as Inference给出的是高斯分布u_t ~ N(-K_t x_t, Σ_t)。均值完全一样,但Control as Inference多了一个协方差Σ_t。这个协方差在噪声大的时候很有用,可以用来做风险敏感控制。
5.2 MPC的滚动时域与变分推断的在线优化
MPC的核心是滚动时域:在每个时刻t,求解从t到t+H的最优控制问题,执行第一个动作,然后移动到t+1重新求解。这个过程的计算量主要在于反复求解优化问题。
Control as Inference的在线版本可以避免反复求解。因为变分分布q(u_t | x_t)是参数化的,训练好之后直接前向传播就行,不需要在线优化。这个特性在计算资源受限的嵌入式系统上非常有价值。我试过在树莓派上跑Control as Inference的策略网络,控制频率可以做到100Hz,而同样问题的MPC只能做到10Hz。
当然,代价是需要离线训练。如果系统动力学变化了,策略需要重新训练。而MPC只需要更新模型参数就行。所以两种方法各有适用场景:动力学已知且变化不大的用MPC,动力学复杂或者需要快速响应的用Control as Inference。
5.3 KL散度在控制问题中的信息几何解释
KL散度不仅是变分推断的工具,它在控制问题里还有信息几何的解释。KL(q || p)衡量的是用q近似p时损失的信息量。在控制问题里,这个信息量对应的是控制代价。
具体来说,如果q是当前策略,p是最优策略,那么KL(q || p)就是当前策略相对于最优策略的“次优程度”。最小化KL散度就是在最小化次优程度。这个解释把控制问题和信息论联系起来了,也解释了为什么Control as Inference的目标函数里会出现熵项——熵是信息量的度量。
我第一次理解这个联系的时候,感觉整个框架突然通透了。原来控制问题不只是优化问题,还是信息问题。这个视角在后续做逆最优控制、模仿学习的时候特别有用,因为那些问题本质上就是在推断人的意图,而意图可以用概率分布表示。
6. 实操中的关键细节与避坑指南
6.1 变分分布参数化的选择
变分分布q(u_t | x_t)的参数化方式直接影响优化效果。最常见的选择是高斯分布:q(u_t | x_t) = N(μ_θ(x_t), Σ_θ(x_t)),其中μ和Σ用神经网络参数化。这个选择简单直接,但有两个坑。
第一个坑是Σ的参数化。如果直接输出Σ,需要保证正定性。常见做法是输出Cholesky分解的下三角矩阵,或者输出对角Σ。我试过输出完整Σ,结果训练不稳定,经常出现数值问题。后来改成对角Σ,稳定性好了很多,控制效果也没明显下降。
第二个坑是μ的输出范围。如果动作有约束(比如力矩限制),直接输出μ可能会超出范围。常见做法是用tanh或者sigmoid把μ压缩到合法范围。我试过不加压缩,结果策略输出的动作经常超限,仿真直接崩了。加了压缩之后就没这个问题了。
6.2 目标函数中各项的权重调节
ELBO的目标函数包含三项:动力学似然、负代价、策略熵。这三项的权重需要仔细调节。动力学似然项的权重通常设为1,因为动力学是已知的。负代价项的权重需要根据代价的量级调整,代价大的时候权重小一些,代价小的时候权重大一些。策略熵的权重控制探索程度,权重越大探索越多。
我实测下来,一个比较稳的配置是:动力学似然权重1.0,负代价权重1.0,策略熵权重0.01到0.1之间。熵权重太小会导致策略过早收敛到局部最优,太大则会导致策略过于随机,控制效果差。这个参数需要根据具体问题调,没有万能值。
6.3 数值稳定性的处理技巧
变分推断的数值稳定性是个大问题,尤其是在线计算的时候。我踩过的坑包括:log概率出现负无穷、KL散度计算溢出、梯度爆炸等等。解决办法有几个:
第一,用log-sum-exp技巧计算对数概率,避免直接计算概率导致下溢。第二,用重参数化技巧采样,把随机性从计算图里分离出来,降低方差。第三,梯度裁剪,防止梯度爆炸。第四,用双精度浮点数做关键计算,虽然慢一点但稳定。
这些技巧在标准变分推断教材里都有,但在控制问题里需要根据具体场景调整。比如重参数化技巧在连续动作空间里很好用,但在离散动作空间里需要用Gumbel-Softmax。这些细节在实现的时候一定要注意。
7. 常见问题与排查技巧实录
7.1 策略不收敛或收敛到局部最优
这是最常见的问题。表现是训练损失震荡不下降,或者策略输出的动作始终是同一个值。排查思路如下:
首先检查变分分布的参数化是否合理。如果Σ太小,策略会退化成确定性策略,失去探索能力。如果Σ太大,策略会过于随机,无法收敛。建议初始化Σ为单位矩阵,然后根据训练情况调整。
其次检查目标函数的权重。如果负代价权重太大,策略会过早收敛到局部最优。如果熵权重太小,探索不足。建议先用较大的熵权重训练,然后逐渐减小。
最后检查优化器的学习率。变分推断的目标函数通常比标准监督学习的目标函数更复杂,需要更小的学习率。我一般用1e-4到1e-3之间的学习率,配合Adam优化器。
7.2 动力学似然项计算出现NaN
这个问题通常是因为动力学模型的概率密度在某些状态下为零或者负值。排查思路:检查动力学模型的输出范围,确保概率密度始终为正。如果动力学是高斯分布,检查均值和方差是否合理。方差太小会导致概率密度在某些点趋于无穷,方差太大会导致概率密度趋于零。
解决办法:给方差加一个下限,比如1e-6,防止方差过小。同时对状态和动作做归一化,防止数值过大导致计算溢出。我实测下来,归一化是最有效的办法,能把NaN问题减少90%以上。
7.3 在线控制时计算延迟过大
Control as Inference的在线控制需要前向传播策略网络,如果网络太大,计算延迟会很大。排查思路:测量单次前向传播的时间,如果超过控制周期的10%,就需要优化。
优化方法包括:减小网络规模、用量化或者剪枝、用更高效的推理框架。我试过把策略网络从3层256维降到2层128维,控制频率从50Hz提升到200Hz,控制效果下降不到5%。所以网络规模不需要太大,关键是训练充分。
7.4 与MPC的对比选择困难
很多人问什么时候用Control as Inference,什么时候用MPC。我的经验是:如果动力学模型精确已知、约束是硬约束、计算资源充足,用MPC。如果动力学模型有不确定性、需要处理随机性、计算资源受限,用Control as Inference。如果两者都行,看哪个实现起来更简单。
实际项目中,我经常把两者结合:用Control as Inference训练一个策略网络作为热启动,然后用MPC做精细调整。这样既有Control as Inference的快速响应,又有MPC的约束保证。
| 问题类型 | 表现 | 排查方向 | 解决办法 |
|---|---|---|---|
| 策略不收敛 | 损失震荡 | 检查Σ参数化 | 调整Σ初始化 |
| 局部最优 | 动作单一 | 检查熵权重 | 增大熵权重 |
| NaN | 损失变NaN | 检查概率密度 | 加方差下限 |
| 计算延迟 | 控制频率低 | 测量前向时间 | 减小网络规模 |
| 选择困难 | 不知道用哪个 | 分析问题特性 | 结合使用 |
8. 从理论到代码:一个最小实现框架
8.1 环境搭建与依赖选择
实现Control as Inference需要几个核心组件:深度学习框架(PyTorch或JAX)、优化器(Adam)、环境模拟器(MuJoCo或自定义)。我推荐PyTorch,因为动态图调试方便,而且变分推断的代码写起来直观。
依赖安装很简单:pip install torch numpy gym。如果需要MuJoCo环境,还需要额外安装mujoco-py。我实测下来,PyTorch 1.10以上版本都支持重参数化技巧,不需要额外配置。
8.2 核心模块的代码结构
核心模块包括四个部分:策略网络、动力学模型、代价函数、训练循环。策略网络输出高斯分布的均值和方差,动力学模型是已知的或者学习的,代价函数根据任务定义,训练循环实现ELBO的优化。
代码结构建议如下:先定义策略网络类,包含forward方法输出均值和方差;然后定义ELBO计算函数,输入策略网络输出和动力学模型,输出ELBO值;最后写训练循环,采样轨迹、计算ELBO、反向传播、更新参数。
8.3 训练循环的关键实现细节
训练循环里最关键的是采样和重参数化。采样时用rsample()而不是sample(),这样梯度可以通过采样过程传播。重参数化技巧的公式是u = μ + Σ^{1/2} ε,其中ε ~ N(0, I)。这个技巧把随机性从计算图里分离出来,降低了梯度的方差。
另一个细节是轨迹的截断。如果轨迹太长,计算图会很大,反向传播会很慢。建议把轨迹截断到固定长度(比如50步),然后用bootstrapping估计剩余部分的代价。这个技巧在强化学习里很常见,在Control as Inference里同样适用。
我实测下来,截断长度50步、batch size 64、学习率1e-3,在倒立摆和双足机器人问题上都能收敛。训练时间大概几十分钟到几小时,取决于问题复杂度。
9. 扩展方向与个人实践体会
Control as Inference的框架可以扩展到很多方向。比如逆最优控制:给定观测到的轨迹,推断代价函数的参数。这个方向在模仿学习里很有用,因为人类演示的轨迹可以看成是最优控制的采样,推断代价函数就等价于推断人的意图。
另一个方向是分层控制:把长时域任务分解成短时域子任务,每个子任务用Control as Inference求解。这个方向在机器人操作里很有前景,因为操作任务通常有多个阶段,每个阶段的代价函数不一样。
我个人在实际操作中的体会是,Control as Inference最大的价值不是替代MPC或者随机最优控制,而是提供了一个统一的视角来看待控制问题。当你把控制看成推断,很多原本孤立的方法(MPC、LQR、强化学习、模仿学习)突然有了共同的语言。这个视角转换带来的洞察,比具体的算法实现更有价值。
最后分享一个小技巧:如果你刚开始学Control as Inference,不要一上来就推公式。先找一个简单的LQR问题,用变分推断的方法解一遍,然后和解析解对比。这样你能直观地看到变分推断在做什么,然后再去推一般情况下的ELBO。这个顺序比反过来要容易得多。