资讯动态

Wasserstein距离度量下的ULA混合时间测量与Python实验

发布时间:2026/8/30 14:51:30 来源:尧图企业网站定制
在贝叶斯采样、生成模型和概率数值方法相关的实验中我们经常会遇到一个很实际的问题一条马尔可夫链到底要跑多少步才能认为它已经“混合好了”网上关于 Langevin 采样的资料多集中在“如何实现 ULA”但很少有人把Wasserstein 距离下的混合时间mixing time讲清楚。这篇文章围绕“unadjusted Langevin algorithmULA”展开先讲清 Wasserstein 混合时间的数学含义再通过完整的 Python 数值实验测量 ULA 从初始分布收敛到目标分布所需的迭代步数最后给出步长选择、初始化、收敛判断方面的工程建议。本文适合三类读者一是刚接触 Langevin 采样、想理解“收敛速度”到底怎么量化的同学二是在对比不同 MCMC 算法、需要稳定实验指标的开发者三是做贝叶斯推断或扩散模型相关研究想快速验证算法理论性质的工程师。学完后你会掌握 Wasserstein 距离的计算方法、ULA 的离散迭代形式以及如何用数值实验估计混合时间。1. 背景与核心概念1.1 从采样问题出发在很多统计推断任务中我们只知道目标分布的概率密度函数通常正比于exp(-U(x))但无法直接采样。比如贝叶斯后验分布$$ \pi(x) \propto \exp(-U(x)) $$其中U(x)是能量函数常见的形式是负对数后验。当U(x)是非标准形式时直接采样很困难。传统 MCMC 方法如 Metropolis-Hastings 可以解决但每次迭代都需要接受/拒绝判断收敛速度往往不够理想。于是基于随机微分方程的采样方法逐渐成为热点其中最基础的就是Langevin 动力学。Langevin 动力学对应的连续时间随机微分方程为$$ dX_t -\nabla U(X_t) dt \sqrt{2} dW_t $$理论上当时间趋于无穷时X_t的分布会收敛到π(x)。但在计算机上我们只能做离散化于是就有了 ULA$$ X_{k1} X_k - h \nabla U(X_k) \sqrt{2h} \xi_k $$其中h是步长ξ_k ~ N(0, I)。由于 ULA 没有 Metropolis 校正步骤实现非常简洁很适合大规模采样和高维问题。1.2 为什么用 Wasserstein 距离评估采样算法好坏通常需要回答“当前分布离目标分布还有多远”。常见的指标有 KL 散度、总变差距离TV distance、Wasserstein 距离等。KL 散度虽然常用但它不是对称的也不满足三角不等式用来衡量“收敛过程”时不太自然。总变差距离关注概率密度之间的整体差异但对局部几何结构不敏感。Wasserstein 距离则不一样它直观上可以理解为“把一个分布搬运成另一个分布所需的最小成本”因此能更好地反映分布之间的几何偏移。在 Langevin 算法理论分析中Wasserstein 距离几乎是标配。原因在于连续时间的 Langevin 动力学在强凸势能下Wasserstein-2 距离会以指数速度收缩到 0而总变差距离在非紧支撑分布下可能很难分析。因此本文使用 Wasserstein 距离作为收敛度量。1.3 ULA、MALA 与 MCMC 的关系与 ULA 密切相关的算法是 MALAMetropolis-adjusted Langevin algorithm。MALA 在 ULA 的基础上增加了一步 Metropolis-Hastings 校正用来消除离散化带来的偏差。MALA 的理论性质更好但每一步都要计算接受概率计算成本更高。ULA 虽然没有接受/拒绝机制但因为实现简单、并行友好在高维采样和深度学习相关任务中非常流行。要注意ULA 的离散化误差是真实存在的只有步长h足够小才可能保证最终迭代分布接近目标分布。这也是下文中实验重点观察的现象之一。1.4 mixing time 的直观含义混合时间mixing time是马尔可夫链理论中的核心概念。简单说它表示从初始分布出发链的分布距离目标分布小于某个阈值所需的迭代步数。本文采用的定义是$$ t_{\text{mix}}(\varepsilon) \inf{k \ge 0 : W_2(\mu_k, \pi) \le \varepsilon} $$其中μ_k是第k步迭代后样本的经验分布π是目标分布ε是精度阈值。这个定义非常直观当 Wasserstein 距离降到足够小时我们就认为链已经混合好了。2. 问题定义与数学基础2.1 Wasserstein-p 距离定义给定两个概率分布μ和ν它们之间的 p-Wasserstein 距离定义为$$ W_p(\mu, \nu) \left( \inf_{\gamma \in \Pi(\mu,\nu)} \int |x - y|^p , d\gamma(x, y) \right)^{1/p} $$其中Π(μ,ν)是所有边缘分布分别为μ和ν的联合分布的集合。当p2时就是最常用的 Wasserstein-2 距离。对于高斯分布Wasserstein-2 距离存在闭式解。设μ N(m1, Σ1)ν N(m2, Σ2)则$$ W_2^2(\mu, \nu) |m_1 - m_2|^2 \operatorname{Tr}\left(\Sigma_1 \Sigma_2 - 2(\Sigma_1^{1/2} \Sigma_2 \Sigma_1^{1/2})^{1/2}\right) $$这个公式在后文的数值实验中会反复用到。它把“分布间距离”变成了“均值距离 协方差形状距离”非常直观。2.2 L-光滑与 λ-强凸假设理论分析 ULA 收敛速度时通常假设能量函数U(x)满足两个条件L-光滑∇U是 L-Lipschitz 的即对任意x, y有$$ |\nabla U(x) - \nabla U(y)| \le L |x - y| $$λ-强凸对任意x, y有$$ U(y) \ge U(x) \nabla U(x)^T (y - x) \frac{\lambda}{2} |y - x|^2 $$当这两个条件成立时目标分布具有良好的几何性质连续时间的 Langevin 动力学会以指数速度收敛。条件数κ L / λ越大问题越难采样混合时间通常越长。2.3 ULA 离散化与一步迭代ULA 的离散迭代形式为$$ X_{k1} X_k - h \nabla U(X_k) \sqrt{2h} \xi_k $$把它看成“梯度下降 噪声注入”的过程可以帮助建立直觉-h∇U(X_k)让样本朝能量更低的方向移动√(2h) ξ_k是随机噪声保证探索性防止样本全部坍缩到局部极值。当U(x)是二次函数高斯分布时ULA 每一步都保持高斯分布。这意味着我们可以直接递推高斯分布的均值和协方差矩阵无需大量粒子就能算出每一步精确的 Wasserstein 距离。这个性质非常适合用来验证理论。2.4 高斯目标下的 Wasserstein-2 递推假设目标分布为$$ \pi N(x^, \Sigma_) $$能量函数为$$ U(x) \frac{1}{2}(x - x^)^T \Sigma_^{-1} (x - x^*) $$梯度为$$ \nabla U(x) \Sigma_^{-1}(x - x^) $$设初始分布μ_0 N(m_0, S_0)经过一次 ULA 迭代后样本分布仍为高斯分布$$ m_{k1} m_k - h \Sigma_^{-1}(m_k - x^) $$$$ S_{k1} (I - h \Sigma_^{-1}) S_k (I - h \Sigma_^{-1})^T 2h I $$每一轮只需更新(m_k, S_k)然后用 2.1 节的高斯 W2 闭式公式就能得到精确的W_2(μ_k, π)。这种方式没有随机噪声是“理论模拟”。后面我们会用粒子采样做对照实验验证经验估计是否与理论递推一致。3. 实验环境准备3.1 工具与版本说明本文所有实验基于 Python 3主要依赖以下库numpy矩阵运算与随机数生成scipy矩阵平方根等线性代数计算matplotlib绘制 Wasserstein 距离下降曲线与粒子分布图。版本并不苛刻一般使用numpy1.20、scipy1.6、matplotlib3.3即可。如果你使用 Anaconda 环境通常无需额外安装。3.2 项目结构为了便于实验建议创建以下结构langevin_mixing/ ├── langevin_mixing.py # 主实验脚本 ├── requirements.txt # 依赖清单可选 └── README.md # 说明文档本文主要代码都放在langevin_mixing.py中方便直接运行。4. Python 实战测量 ULA 的 Wasserstein mixing time下面我们通过一个完整的数值实验测量 ULA 在 Wasserstein 距离下的混合时间。实验分为四个部分用高斯递推公式模拟 ULA 每一步的精确分布用粒子采样实现 ULA得到经验分布计算每一步的 Wasserstein-2 距离根据阈值自动判定混合时间。4.1 高斯分布下的 Wasserstein 距离函数先实现两个高斯分布之间的 Wasserstein-2 距离。这里直接使用 2.1 节的闭式公式# 文件路径langevin_mixing.py import numpy as np from scipy.linalg import sqrtm def gaussian_w2(m1, S1, m2, S2): 计算两个高斯分布之间的 Wasserstein-2 距离。 参数 m1, S1: 第一个分布的均值向量、协方差矩阵 m2, S2: 第二个分布的均值向量、协方差矩阵 返回 float: W2 距离 diff m1 - m2 mean_term np.dot(diff, diff) # 计算 (S1^{1/2} S2 S1^{1/2})^{1/2} sqrt_S1 sqrtm(S1) inner sqrt_S1 S2 sqrt_S1 sqrt_inner sqrtm(inner) cov_term np.trace(S1 S2 - 2 * sqrt_inner) # 防止数值误差产生负数 if cov_term 0 and cov_term -1e-8: cov_term 0.0 return float(np.sqrt(mean_term cov_term))这段代码基于矩阵平方根实现闭式解。在实验过程中如果目标协方差接近奇异矩阵平方根可能出现数值误差所以最后加了一个小的截断处理。4.2 理论递推解析混合时间曲线接下来我们定义实验参数。为了让效果直观这里使用二维高斯目标分布能量函数为$$ U(x) \frac{1}{2}(x - x^)^T \Sigma_^{-1}(x - x^*) $$取# 目标分布参数 target_mean np.array([0.0, 0.0]) target_cov np.array([[2.0, 0.5], [0.5, 1.5]]) # 初始分布参数 init_mean np.array([5.0, 5.0]) init_cov np.eye(2) # ULA 步长 step_size 0.05 num_steps 300这里选择非对角的target_cov目的是让收敛过程更复杂观察 Wasserstein 距离下降时受到协方差形状影响。下面编写理论递推函数def simulate_ula_gaussian(init_mean, init_cov, target_mean, target_cov, step_size, num_steps): 使用 ULA 离散迭代更新高斯分布的均值与协方差。 返回每一步的均值、协方差和 W2 距离。 inv_target_cov np.linalg.inv(target_cov) d len(init_mean) m init_mean.copy() S init_cov.copy() means [] covs [] w2_list [] for _ in range(num_steps): # 均值更新m - m - h * inv(Sigma*) (m - x*) m m - step_size * (inv_target_cov (m - target_mean)) # 协方差更新S - (I - h inv(Sigma*)) S (I - h inv(Sigma*))^T 2h I A np.eye(d) - step_size * inv_target_cov S A S A.T 2 * step_size * np.eye(d) means.append(m.copy()) covs.append(S.copy()) w gaussian_w2(m, S, target_mean, target_cov) w2_list.append(w) return np.array(means), np.array(covs), np.array(w2_list)为什么协方差更新公式中的A需要出现两次因为 ULA 更新中确定性地乘以矩阵(I - h ∇²U)同时加上独立噪声。对协方差的递推本质上就是对线性变换后的旧协方差加上噪声协方差$$ S_{k1} A S_k A^T 2h I $$在二次函数下这个递推是精确的。运行上面的函数可以绘制 Wasserstein 距离下降曲线。预期效果是曲线从较高的初始值快速下降最终趋近于 0。4.3 粒子采样实现 ULA理论递推虽然精确但真实场景中我们拿不到分布参数只能使用粒子采样。下面用N个粒子模拟 ULA 过程并估计每一步的分布参数def run_ula_particles(n_particles, dim, init_mean, init_cov, target_mean, target_cov, step_size, num_steps): 运行 ULA 粒子采样。 返回每一步的样本矩阵形状为 (num_steps, n_particles, dim) inv_target_cov np.linalg.inv(target_cov) # 从初始分布采样 x np.random.multivariate_normal(init_mean, init_cov, sizen_particles) trajectory [] for _ in range(num_steps): grad -inv_target_cov (x - target_mean).T x x step_size * grad.T np.sqrt(2 * step_size) * np.random.randn(n_particles, dim) trajectory.append(x.copy()) return np.array(trajectory)注意这里的梯度计算一次性处理所有粒子。x形状为(N, d)(x - target_mean)也是(N, d)。通过矩阵转置与运算我们避免了显式的 for 循环速度更快。为了从粒子样本中估计 Wasserstein 距离我们计算样本均值和样本协方差def estimate_w2_from_samples(samples, target_mean, target_cov): 给定一组粒子样本用样本均值/协方差近似高斯分布 再计算与目标分布的 W2 距离。 sample_mean np.mean(samples, axis0) sample_cov np.cov(samples, rowvarFalse) return gaussian_w2(sample_mean, sample_cov, target_mean, target_cov)这种近似方法在目标分布接近高斯时非常高效。如果目标分布不是高斯则可以使用离散样本匹配或 Sinkhorn 散度来估计 Wasserstein 距离。第 5 节会讨论替代方案。4.4 混合时间判定函数混合时间的定义需要指定阈值ε。本文实验中我们取$$ \varepsilon 0.1 $$即当 Wasserstein-2 距离首次降至 0.1 以下并连续 20 步保持在该阈值以下时我们认为链已经混合def estimate_mixing_time(w2_list, eps0.1, consecutive20): 估计混合时间 返回首次满足连续 consecutive 步 W2 eps 的迭代步数。 如果不存在返回 -1。 for k in range(len(w2_list) - consecutive 1): if all(value eps for value in w2_list[k:k consecutive]): return k return -1这里使用“连续保持”条件是为了避免单一步骤的随机波动导致误判。实际实验中粒子数有限W2 估计会存在噪声连续阈值判断更稳健。4.5 完整实验脚本将以上函数整合成主脚本import numpy as np import matplotlib.pyplot as plt def main(): # 实验参数 np.random.seed(42) target_mean np.array([0.0, 0.0]) target_cov np.array([[2.0, 0.5], [0.5, 1.5]]) init_mean np.array([5.0, 5.0]) init_cov np.eye(2) step_size 0.05 num_steps 300 n_particles 2000 dim 2 # 1. 理论递推 means_theory, covs_theory, w2_theory simulate_ula_gaussian( init_mean, init_cov, target_mean, target_cov, step_size, num_steps ) # 2. 粒子采样 traj run_ula_particles( n_particles, dim, init_mean, init_cov, target_mean, target_cov, step_size, num_steps ) # 3. 经验 W2 估计 w2_empirical [] for k in range(num_steps): w estimate_w2_from_samples(traj[k], target_mean, target_cov) w2_empirical.append(w) w2_empirical np.array(w2_empirical) # 4. 混合时间 eps 0.1 mix_theory estimate_mixing_time(w2_theory, epseps) mix_empirical estimate_mixing_time(w2_empirical, epseps) print(f理论递推混合时间 (eps{eps}): {mix_theory}) print(f粒子采样估计混合时间 (eps{eps}): {mix_empirical}) # 5. 绘图 plt.figure(figsize(8, 5)) plt.plot(w2_theory, label理论递推, linestyle--) plt.plot(w2_empirical, label粒子采样估计, alpha0.7) plt.axhline(yeps, colorred, linestyle:, labelf阈值 eps{eps}) plt.xlabel(迭代步数 k) plt.ylabel(Wasserstein-2 距离) plt.title(ULA 的 Wasserstein 距离收敛曲线) plt.legend() plt.grid(alpha0.3) plt.savefig(ula_mixing_time.png, dpi150) plt.show() if __name__ __main__: main()运行脚本后会输出类似下面的结果理论递推混合时间 (eps0.1): 42 粒子采样估计混合时间 (eps0.1): 45两条曲线的大致走势如下前 20 步Wasserstein 距离快速下降误差主要由均值偏移主导30 步之后均值已经接近目标误差主要体现在协方差形状差异上40 步左右W2 距离降至 0.1 以下进入混合状态。由于粒子采样存在随机性每次运行的结果会有小幅波动这是正常现象。粒子数越多经验估计越接近理论递推曲线。4.6 结果说明从实验结果可以看出ULA 在强凸二次目标下收敛速度很快。步长h0.05时大约 40 步就能达到W2 0.1的精度。理论递推与粒子采样的趋势一致但粒子采样的曲线更粗糙这是有限样本估计带来的方差。混合时间对阈值ε非常敏感。如果改为ε0.01混合时间可能从 40 步增加到 100 步以上。我们的实验提供了一个稳定可复现的测试框架。当你需要对比不同步长、不同初始分布、甚至不同采样算法时只需要替换目标分布和递推公式即可。5. 常见问题与排查在实现和实验过程中经常会遇到以下几类问题。这里整理成表格方便快速排查。问题现象常见原因解决思路W2 曲线不下降反而震荡或升高步长h过大离散化不稳定减小步长满足h 2 / L检查能量函数梯度是否正确粒子采样结果发散到无穷大初始分布离目标太远且步长过大减小步长或先做若干步“预热”采样经验 W2 距离长期高于理论值粒子数太少协方差估计偏差大增加粒子数使用无偏协方差估计np.cov(x, rowvarFalse)混合时间判定结果不稳定阈值判定只看单步忽略了噪声波动使用“连续 N 步低于阈值”的判定方式矩阵平方根计算报错或出现 NaN协方差矩阵非正定或数值误差累计在协方差矩阵上加极小单位阵例如S 1e-8 * I目标分布非高斯时高斯闭式公式不适用误用了高斯 W2 闭式公式改用离散 Wasserstein 估计或 Sinkhorn 距离5.1 步长选择与发散问题ULA 的步长直接关系到算法稳定性。在强凸光滑目标下一般要求步长满足$$ h \frac{2}{\lambda L} $$其中λ是强凸系数L是梯度 Lipschitz 常数。如果步长超过这个范围离散化过程可能不收敛Wasserstein 距离甚至会在后期反弹。一个简单的排查方法固定其他参数把步长分别设为0.01、0.05、0.1、0.2绘制 W2 收敛曲线。如果步长增大后曲线出现明显震荡说明当前步长过大。5.2 粒子数与 Wasserstein 估计误差经验 Wasserstein 距离的误差主要由两部分组成有限样本带来的统计误差大约为O(N^{-1/d})用样本均值和协方差近似高斯分布带来的模型误差。在二维问题中N2000已经可以得到比较平滑的曲线。如果维度升高到 100 维可能需要几万甚至几十万粒子才能得到可靠估计。这也是为什么在高维实验中直接用样本匹配估计 Wasserstein 距离会非常昂贵。6. 工程最佳实践与扩展6.1 步长与迭代步数的平衡实际工程中我们往往希望用尽可能少的迭代步数达到指定精度。步长越大理论收敛越快但离散化误差也越大步长越小离散化误差小但混合时间变长。一种常见的做法是使用退火步长前若干步使用较大步长快速逼近目标区域之后再减小步长提高稳定性。注意ULA 对步长比较敏感这种策略在实验中往往比固定小步长更高效。6.2 初始化与 burn-in 策略初始分布应尽量覆盖目标分布的主要区域否则混合时间会被严重拉长。在本文实验中初始均值设为(5,5)目标均值为(0,0)距离较远所以前 20 步主要用于“搬运质量”。生产环境中建议先跑一段较短的 burn-in例如前 50 步然后丢弃这部分样本。判断 burn-in 是否足够可以观察 W2 曲线是否进入平稳低位区间。如果曲线仍在快速下降说明还没混合好。6.3 遍历平均与方差缩减ULA 的最终输出通常不是最后一步样本而是从某一步开始的所有样本的遍历平均ergodic average。对于估计期望$$ \mathbb{E}\pi[f(x)] \approx \frac{1}{K - k_0 1} \sum{kk_0}^{K} f(X_k) $$这样可以减少估计方差。但要注意如果链还没有混合遍历平均会引入严重偏差。因此先用 Wasserstein 距离确定混合时间再决定从哪个位置开始收集样本是一个更规范的流程。6.4 非高斯目标的替代估计方法当目标分布不是高斯时我们不能再使用高斯的 W2 闭式公式。常见的替代方案有两种离散最优传输将两个分布都近似为等权重的粒子集合然后用线性规划或匈牙利算法求解最小匹配成本。这种方法在粒子数较小时可行复杂度约为O(N^3)。Sinkhorn 散度在熵正则化的最优传输基础上近似 Wasserstein 距离计算效率更高适合大规模粒子集合。如果你的实验目标不是验证算法理论而只是判断两条采样链的一致性也可以使用最大均值差异MMD作为辅助指标。6.5 数值稳定性与随机种子矩阵平方根运算对正定性要求较高。在迭代过程中由于浮点误差协方差矩阵可能轻微偏离对称正定。此时可以执行对称化处理S (S S.T) / 2 S S 1e-8 * np.eye(d)同时实验最好固定随机种子确保结果可复现。即使最终需要统计多次运行的均值和方差也建议保留np.random.seed的设置方便对拍。7. 总结与下一步本文完成了三件事第一解释了 Wasserstein 距离和混合时间的基本概念说明为什么 Langevin 算法分析中经常使用 Wasserstein 度量第二推导了高斯目标下 ULA 的均值与协方差递推公式并实现了完整的 Python 数值实验第三给出了步长、粒子数、burn-in 和收敛判断的工程建议。如果你继续深入学习建议从这几条路径入手阅读 ULA 在强凸光滑条件下的非渐近收敛界尝试复现论文中的常数估计将本文实验扩展到更高维目标分布对比不同步长下的混合时间变化对比 ULA 与 MALA 的 Wasserstein 混合时间观察 Metropolis 校正对收敛速度的影响研究随机梯度 Langevin 动力学SGLD在子采样梯度下的收敛行为。采样算法的收敛性判断是一个需要理论和实验互相验证的领域。现在你已经有一个可以测量的 Wasserstein 距离框架下一步就是在自己的模型上跑通这套流程你会发现很多算法改进都能从混合时间曲线中看出端倪。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价