1. 从确定性预测到概率性思维:为什么我们需要扩散模型?

如果你做过时间序列预测,不管是预测明天的股票价格、下周的用电负荷,还是未来一小时的交通流量,你一定遇到过这样的烦恼:模型给出的预测值,和真实情况总是差那么一点。更让人头疼的是,你很难说清楚这个“差一点”到底有多大风险。传统的模型,比如ARIMA、LSTM甚至Transformer,大多输出一个确定的数值(点预测)。它们告诉你:“明天销售额预计是100万。” 但现实世界充满了不确定性,供应链波动、突发天气、市场情绪,任何一个黑天鹅事件都可能让100万变成80万或120万。一个确定的数字,无法量化这种风险。

这就是概率时间序列预测要解决的核心问题。它不满足于只给一个“最可能”的值,而是致力于预测未来值的整个概率分布。它会告诉你:“明天销售额有90%的可能性落在95万到105万之间,其概率分布的形状是这样的……” 这种预测方式,对于风险管理、资源调度和决策支持来说,价值是颠覆性的。想象一下,电网调度员如果只知道“明天用电负荷大概是1亿千瓦”,他只能做粗略准备;但如果他知道“负荷有95%的概率在0.95亿到1.05亿千瓦之间,且出现极端高负荷的概率不足1%”,他就能做出更精细、更经济的调度方案。

那么,如何建模这种复杂的、可能非高斯的、多模态的概率分布呢?传统方法如DeepAR,通常假设未来数据服从一个参数化的分布(比如高斯分布),然后去学习这个分布的参数(均值和方差)。这个方法简单有效,但有个天花板:它假设的分布形状可能太“规矩”了,无法捕捉真实世界中那些奇奇怪怪的、不对称的、有多个峰值的分布形态。

自回归去噪扩散模型的出现,就像给我们送来了一把“万能钥匙”。它本质上是一个强大的生成模型。你不需要预先假设数据长什么样(是高斯还是拉普拉斯),扩散模型通过一个“加噪-去噪”的逆向学习过程,能够从零开始“学会”生成与训练数据一模一样复杂分布的数据。把它用在时间序列预测上,就等于说:我不去猜未来数据的分布公式是什么,我直接让模型学会“画出”所有可能的未来走势图。每一次预测,模型都能生成一大批(比如100条)可能的未来序列,这些样本集合起来,就自然构成了对未来概率分布最直观的估计。

我自己的体会是,这就像从“素描”升级到了“3D打印”。素描(传统点预测或简单概率预测)只能勾勒一个轮廓,而3D打印(扩散模型)能复现出物体所有的细节和材质。在预测任务中,这种对分布细节的捕捉能力,尤其是在面对不确定性极高、波动剧烈的序列时,优势非常明显。

2. TimeGrad模型拆解:当RNN遇见扩散模型

理解了“为什么”之后,我们来看“怎么做”。原始论文提出的TimeGrad模型,其核心思想非常巧妙,甚至可以说简洁。它把两个经典的东西粘在了一起:一个负责理解历史(RNN),一个负责生成未来(扩散模型)。

2.1 自回归的骨架:RNN编码历史信息

首先,模型是自回归的。这是什么意思呢?就是说,预测未来第t步的值时,模型会把之前预测出来的第1步到第t-1步的结果,也作为输入的一部分。这非常符合人的直觉:我们预测明天的天气,会参考今天的;预测后天的,会参考今天和明天的。自回归保证了预测在时间上的连贯性。

TimeGrad用一个RNN(比如GRU或LSTM)来充当这个“历史理解者”和“记忆单元”。在每一个时间步t,RNN会接收两个信息:

  1. 上一个时间步的观测值(或预测值)x_{t-1}
  2. 当前时间步的协变量 c_t(比如星期几、是否节假日、温度等外部特征)

RNN将它们融合,更新自己的内部隐藏状态 h_{t-1}。这个隐藏状态 h_{t-1} 是个精华,它压缩了从序列开始到t-1时刻的所有历史信息。你可以把它理解为模型对“到目前为止发生了什么”的一个总结。

2.2 扩散模型的核心:从噪声中雕刻出未来

拿到了浓缩历史的隐藏状态 h_{t-1},接下来要生成未来的 x_t。这里就是扩散模型大显身手的地方。

扩散模型的工作分两步走:前向过程和反向过程。

  • 前向过程(加噪):这是一个固定的过程,把一张清晰的图片(或者我们的时间序列数据)一步步地添加高斯噪声,最终变成一堆纯噪声。这个过程是不需要学习的。
  • 反向过程(去噪):这才是模型要学习的核心。它需要学会如何从一堆纯噪声中,一步步地“猜”出最初的清晰图片是什么。

在TimeGrad中,这个“去噪”过程是由一个神经网络 ϵ_θ 来完成的。这个网络的目标很明确:给定一个带噪声的数据 x_t^n(这里的n是噪声等级,相当于扩散模型原文中的时间步t),以及我们刚才得到的历史上下文 h_{t-1},去预测出添加到数据中的噪声 ϵ

训练时,我们会有很多这样的三元组 (干净数据 x_t^0, 噪声 ϵ, 噪声等级 n)。我们把加噪后的数据 x_t^n 和隐藏状态 h_{t-1}、噪声等级n一起喂给 ϵ_θ 网络,让它预测噪声。然后最小化预测噪声和真实噪声的差距(通常用MSE损失)。反复训练后,这个网络就变成了一个“噪声去除专家”。

2.3 如何串联起来进行预测?

训练好之后,预测(采样)过程就像一场魔术:

  1. 从你想开始预测的时刻 t0 开始,用RNN处理历史真实数据,得到隐藏状态 h_{t0-1}
  2. 要预测 t0 时刻的值,我们先随机画出一张“纯噪声画布” x_{t0}^N(N是最大的噪声步数)。
  3. 然后,请出我们的专家 ϵ_θ。它看着这张噪声画布 x_{t0}^N,结合“历史记忆” h_{t0-1},开始工作:“我觉得这里的噪声应该是这样的……” 它预测出噪声,我们从画布上减掉一部分预测的噪声,得到稍微清晰一点的 x_{t0}^{N-1}
  4. 重复步骤3,用 x_{t0}^{N-1}h_{t0-1} 去预测新的噪声,再减掉,得到 x_{t0}^{N-2}…… 如此迭代N次,噪声被一步步剥离,最终“雕刻”出来的 x_{t0}^0,就是我们模型生成的、t0时刻的一个可能值。
  5. 由于初始的噪声画布是随机绘制的,我们重复这个过程100次,就能得到100个略有不同的 x_{t0}^0。这100个样本,就构成了对 t0 时刻值的概率分布估计。
  6. 接下来预测 t0+1 时刻:我们将上一步生成的某个样本(或样本均值)x_{t0}^0 作为观测值,输入RNN,更新隐藏状态到 h_{t0}。然后,再重复步骤2-5,去生成 x_{t0+1}^0 的样本集合。

这个过程完全自回归,就像接力赛一样,一步步生成未来的整个序列。我第一次实现这个流程时,看着模型从纯粹的随机数中,一步步“幻想”出合理的时间序列走势,感觉非常奇妙。

3. 实战优化策略:让TimeGrad在你的数据上飞起来

论文给出了优雅的框架,但要把模型真正用得好,用到你自己的数据集上,免不了一番调优和折腾。下面分享几个我实践中觉得非常关键的优化点。

3.1 输入特征的工程化处理

扩散模型虽然强大,但它对输入数据的尺度非常敏感。时间序列数据常常包含趋势、季节性和不同量级的变量,直接扔给模型效果会很差。

  • 归一化是必须的:对于每个变量,我强烈建议进行实例归一化。也就是对每个预测样本的上下文窗口(context window)内的数据,单独计算均值和标准差,然后进行归一化。预测完成后,再用同样的参数反归一化回去。这样做的好处是,模型不需要去学习数据的绝对尺度,更专注于学习相对变化模式。我在一个包含销售额和客流量两个量级差百倍的数据集上试过,不做实例归一化,模型根本训不动;做了之后,两个变量的预测精度都大幅提升。
  • 协变量的巧妙设计:除了时间序列本身,协变量 c_t 是注入领域知识的关键。不要只局限于小时、星期几这样的基础时间特征。可以尝试:
    • 滞后特征:比如前24小时的平均值、前一周同期的值。
    • 事件标志:是否是节假日、促销日、极端天气日。
    • 滚动统计特征:过去窗口的均值、方差、斜率。这些特征能帮助RNN更好地捕捉近期动态。
    • 对于多变量序列,甚至可以加入其他变量的滞后值作为协变量,让模型捕捉变量间的领先滞后关系。

3.2 网络结构的选择与调整

原始的 ϵ_θ 网络是一个简单的多层MLP。对于复杂序列,这可能不够用。

  • 主干网络升级:一个有效的改进是将MLP替换为一维卷积网络(Temporal Convolutional Network, TCN) 或更轻量的线性注意力模块。TCN的感受野大,能更好地捕捉局部模式。我在一个高频传感器数据预测任务中,将MLP换成带有空洞卷积的TCN,CRPS指标提升了约8%。代码改动也不大,核心是把对 (x, h, n) 的拼接向量的处理,从全连接层换成卷积层。
  • 噪声等级嵌入:噪声等级 n 是一个关键输入。简单做法是像Transformer的位置编码一样,生成一个正弦嵌入向量。但你可以做得更精细。我试过一种可学习的、按噪声等级索引的嵌入表,效果比固定正弦嵌入略好。更重要的是,可以尝试自适应噪声调度。默认的噪声调度(如线性、余弦)是均匀的,但你的数据可能在某些噪声等级下更难学习。可以设计一个网络,根据训练损失动态调整不同噪声等级的权重,让模型更关注难学的去噪步骤。
  • RNN的替代方案:虽然RNN经典,但它存在梯度消失和并行化困难的问题。完全可以尝试用Transformer编码器TCN来替代RNN,用于编码历史序列。这些结构能更好地捕捉长期依赖,且训练更快。不过要注意,在自回归预测时,需要确保这些结构能以因果(Causal)方式运行,避免看到未来信息。

3.3 训练技巧与损失函数改进

扩散模型的训练相对稳定,但仍有技巧可循。

  • 损失函数的加权:原始的损失函数对所有噪声步 n 是平等看待的。但实践中发现,中间噪声等级的步骤往往对最终生成质量影响最大。因为初始步骤(噪声很大时)去噪任务太简单,最后几步(噪声很小时)又太精细。可以对损失函数按噪声等级进行加权,给中间步骤更高的权重。一个简单的策略是使用 sqrt(1/(1-α_n)) 作为权重,其中 α_n 是噪声调度参数。
  • 采样加速:扩散模型最大的痛点是采样慢(需要迭代N次,N通常为100或1000)。在预测阶段,这会导致延迟很高。我们可以采用知识蒸馏技术,训练一个更少的采样步数(比如10步)的学生模型,去模仿原始教师模型的行为。或者,使用更先进的采样器,如DDIM。DDIM是一种确定性采样器,它可以在20-50步内就达到原始模型1000步的采样质量,极大提升预测速度。在TimeGrad框架下,只需将采样循环中的更新规则从DDPM换成DDIM公式即可,代码改动很小,但效果立竿见影。
  • 多步预测的教师强制策略:在训练自回归模型时,一个经典难题是“曝光偏差”——训练时模型看到的是真实的历史值,但预测时用的是自己之前生成的、可能有误差的值。为了缓解这个问题,可以在训练中引入计划采样。即以一定概率p,在训练时用模型自己上一步的预测值(而不是真实值)作为RNN的输入,让模型提前适应预测时会出现的误差环境。

4. 评估与对比:如何科学地衡量概率预测的好坏?

模型调优了半天,怎么知道它是不是真的变好了?对于概率预测,像MAE、RMSE这样的点预测指标不再适用。我们需要能评估整个预测分布与真实数据分布之间差距的指标。

4.1 核心指标:连续分级概率评分(CRPS)

论文中使用的CRPS,是概率预测领域的黄金标准之一。我把它理解为“概率版本的MAE”。它的计算方式虽然涉及积分,但用样本近似时非常直观:

假设你对某个时间点预测了S个样本(比如100个),形成了一个经验分布。真实值是 x_true。CRPS衡量的是,你这个经验分布的累积分布函数(CDF)与一个在 x_true 处跳跃的真实CDF(是一个阶跃函数)之间的面积差。

用代码和语言来理解更简单:

# 假设 samples 是模型生成的100个预测样本,shape: (100,)
# true_value 是真实值
samples_sorted = np.sort(samples)
# 计算经验CDF在每一个排序样本点处的值
ecdf = np.arange(1, len(samples)+1) / len(samples)
# 计算真实CDF(阶跃函数)在同样点处的值:真实值左侧为0,右侧为1
step_func = (samples_sorted >= true_value).astype(float)
# CRPS近似为两者之差的平方的积分(求和)
crps = np.mean((ecdf - step_func)**2)

CRPS值越小越好,0是完美预测。 它的美妙之处在于,它同时考虑了预测的校准度(预测的概率是否可靠)和锐度(预测的分布是否集中)。一个预测总是给出很宽、很模糊的分布(校准好但锐度差),或者一个预测总是给出很窄但偏离真实值的分布(锐度好但校准差),CRPS都会很大。

4.2 可视化诊断:分位数图与校准图

指标是冰冷的,图形是温暖的。要真正理解模型的行为,必须可视化。

  • 分位数图:这是我最常用的诊断工具。对于未来的每一个预测步长(例如,预测未来24小时),我们取出模型预测分布的某些关键分位数,比如5%, 50%(中位数), 95%。然后把这些分位数随时间变化的曲线画出来,同时把真实值曲线叠加上去。一个健康的预测,应该有大约90%的真实数据点落在5%和95%分位数线构成的区间内。通过这个图,你可以一目了然地看到:模型的不确定性估计是否合理?在波动剧烈的时段,预测区间是否随之变宽?中位数预测是否准确跟踪了真实趋势?
  • 校准图:这是一个更定量的诊断。我们检查模型声称的“X%置信区间”是否真的包含了X%的真实数据。例如,我们计算预测的50%置信区间(25%分位数到75%分位数),然后检查在所有预测中,真实值落在这个区间内的比例是否接近50%。如果比例远低于50%,说明模型过于自信;如果远高于50%,说明模型过于保守。我们可以对多个置信水平(10%, 20%, …, 90%)都做这个检查,然后画成一条曲线。理想情况下,这条曲线应该接近对角线。

在我优化TimeGrad模型时,我经常发现,单纯看CRPS下降,有时会掩盖问题。比如CRPS下降了,但校准图显示模型在高端分位数上变得过于自信。这时就需要回头检查损失函数或网络结构,看是否在某些区域过拟合了。

5. 超越TimeGrad:扩散模型在时序预测的新进展

TimeGrad为我们打开了一扇门,但社区的发展日新月异。了解这些进展,能帮助我们更好地把握方向,甚至启发自己的优化思路。

  • 非自回归扩散预测:TimeGrad是自回归的,一步接一步,这会导致误差累积和采样速度慢。最新的研究开始探索非自归扩散模型。这类模型一次性生成整个未来预测序列。它们通常使用一个强大的编码器(如Transformer)将整个历史序列编码为一个上下文向量,然后让扩散模型以这个上下文为条件,直接生成一个多步的未来序列“图像”。代表性的工作如CSDISSSD。它们的优势是采样快,且能更好地捕捉未来各步之间的联合分布。但缺点是需要更多的数据,且对长程预测的掌控力有时不如自回归模型。
  • 基于分数的扩散模型:TimeGrad基于DDPM,属于去噪扩散模型。另一大分支是基于分数的生成模型。它不直接预测噪声,而是学习数据分布的对数梯度(分数)。在时间序列预测中,ScoreGrad模型就是这一思想的体现。理论上,基于分数的方法在某些情况下更灵活。实践对比中,两者性能在伯仲之间,但ScoreGrad的实现可能需要对SDE(随机微分方程)有更深的理解。
  • 与Transformer的深度融合:这是目前最活跃的方向。既然Transformer在确定性预测上如此成功,何不将它作为扩散模型的条件骨干网络?最新的架构如Diffusion Transformer,用Transformer来参数化 ϵ_θ 网络,同时将历史序列、协变量、时间嵌入等信息通过交叉注意力机制注入。这种结构在处理超长历史序列和复杂协变量交互时,表现出更强的能力。我在一个包含数百个变量的宏观经济学指标预测项目里,将TimeGrad的RNN替换为这种Diffusion Transformer结构,在多变量联合预测的CRPS上取得了显著提升。

踩过几次坑之后,我的经验是:没有“银弹”。对于中短期预测、要求高解释性和稳定性的场景,TimeGrad这种自回归框架依然非常可靠和直观。对于需要快速生成大量未来情景、或变量间依赖关系极强的场景,非自回归或基于Transformer的扩散模型可能更合适。关键还是理解你的数据特性和业务需求,然后选择最适合的工具,并在此基础上进行细致的优化和打磨。概率预测的世界没有标准答案,只有不断逼近真实不确定性的探索。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐