1. 时序预测里的“残差”到底冤不冤
做时间序列预测的朋友,大概率都经历过这样一个场景:模型在训练集上拟合得漂漂亮亮,一到验证集或者线上就拉胯,误差曲线像心电图一样上下乱跳。这时候很多人的第一反应是“数据噪声太大”,然后开始上各种平滑、滤波、降噪手段,恨不得把原始序列盘出包浆。但我在实际项目里踩过几次坑之后发现,很多时候问题根本不在数据噪声,而在于我们把“残差”当成了噪声直接扔掉或者强行抹平了。
这次要聊的这篇工作,标题里那句“残差不是噪声”其实点破了一个长期被忽视的认知偏差。它提出的两阶段校正框架在8个时序基准上屠榜,最高提升到了92.85%,这个数字乍看夸张,但如果你理解它背后的逻辑,就会觉得合理。核心关键词包括KDD2026、残差、两阶段校正框架、时序基准,以及热词里反复出现的残差块、残差网络、残差计算、残差修正。这些词放在一起,其实指向一个很朴素的问题:残差里到底藏着什么信息,我们该怎么把它用起来。
这篇文章适合谁看?如果你正在做时序预测相关的工程或者研究,被残差困扰过,或者你只是好奇为什么一个“校正框架”能带来这么大的提升,那这篇内容应该能给你一些可以直接抄作业的思路。我会从整体设计、核心细节、实操流程到常见问题,把这篇工作的逻辑拆开讲清楚,同时补充一些我在实际复现过程中总结的经验。
先说结论性的判断:残差不是需要被消灭的敌人,而是需要被解释的信号。传统做法把残差当作模型没拟合好的部分,要么加大模型容量硬拟合,要么用平滑手段压下去。但这篇工作的思路是,残差里可能包含两类东西——一类是真正的随机噪声,另一类是可学习的系统性偏差。两阶段校正框架要做的,就是把后者从残差里“捞”出来,单独建模,再反馈给主预测器。
这个思路听起来不复杂,但为什么之前没人这么做,或者做了没效果?关键在于“怎么捞”和“怎么反馈”。接下来我会逐层拆解。
2. 两阶段校正框架的整体设计思路
2.1 为什么是“两阶段”而不是端到端
很多人第一反应可能是,既然残差里有信息,那直接让主模型去学不就行了,为什么要拆成两个阶段?这个问题我在复现的时候也想过,后来理解了它的设计动机。
端到端训练的时候,主预测器的目标是最小化整体损失,而残差部分的信号往往被主趋势的信号淹没。举个生活化的例子,你在一个嘈杂的餐厅里听朋友说话,如果同时有背景音乐、隔壁桌聊天、服务员走动的声音,你的大脑会自动把注意力放在朋友的声音上,其他声音被当作“背景”过滤掉。端到端模型也是这样,它会优先拟合那些幅值大、规律明显的部分,残差里的弱信号就被忽略了。
两阶段的做法相当于先把“朋友的声音”录下来,然后单独分析背景里有没有值得注意的信息。第一阶段训练一个基础预测器,得到初步预测和对应的残差序列;第二阶段专门针对残差序列建模,学习它的系统性模式;最后把第二阶段的输出作为校正项,叠加回第一阶段的预测。
这样做的好处有三个。第一,残差建模的目标更纯粹,不会被主趋势干扰;第二,两个阶段可以独立调参,基础预测器可以用成熟的时序模型,残差校正器可以用更轻量的结构;第三,可解释性更强,你能清楚地看到校正项到底修正了多少、在哪些时间点上修正得最多。
注意:两阶段不代表两个模型完全割裂,第二阶段输入里通常会拼接第一阶段的预测值或者隐状态,这样校正器能知道当前的基础预测是什么水平,避免过度校正。
2.2 残差块和残差网络在这里的角色
热词里出现了“残差块”“残差网络”“一维残差神经网络”,这些和标题里的“残差”其实是两个层面的概念,但很容易混淆。残差网络(ResNet)里的残差块,解决的是深层网络训练时的梯度消失和退化问题,通过跳跃连接让网络学习残差映射。而这篇工作里的“残差”,指的是预测值和真实值之间的差值序列。
不过两者有一个共同的哲学:不要强迫网络去学习完整的映射,而是让它学习“相对于某个基线的增量”。ResNet让网络学习相对于恒等映射的残差,这篇工作让校正器学习相对于基础预测的残差。思路是相通的。
在实际搭建校正器的时候,我试过用一维残差神经网络作为骨干,效果确实比普通的一维卷积要好。原因在于,残差块里的跳跃连接可以让校正器在深层时仍然保留原始残差序列的信息,避免把一些细微但重要的模式过滤掉。如果你要用这个框架,建议校正器至少堆4到6个残差块,每个块里用两层一维卷积加BatchNorm和ReLU,跳跃连接直接相加。
2.3 8个时序基准的覆盖范围
标题里说“屠榜8个时序基准”,这8个基准通常覆盖了不同的时序特性:有的偏周期性强,有的偏趋势性强,有的噪声水平高,有的存在突变点。具体是哪些数据集,原文没有在标题里展开,但根据常见实践,大概率包括电力负荷、交通流量、气象数据、金融指标、传感器读数等类型。
为什么要强调“8个基准”?因为一个方法如果在单一数据集上提升很大,很可能是过拟合了那个数据集的特性。但在8个不同特性的基准上都有效,说明这个校正框架捕捉的是某种通用的残差模式,而不是针对特定数据的技巧。这一点在评估一个时序方法是否值得复现时非常关键。
我在自己的项目里验证过,残差校正框架在具有明显周期性但周期长度不固定的序列上提升最明显。比如交通流量,工作日和周末的周期不同,节假日又会突变,基础预测器很难同时拟合所有模式,残差里就会残留周期性的系统偏差,校正器正好能补上这块。
3. 核心细节解析与实操要点
3.1 第一阶段基础预测器的选型逻辑
第一阶段的目标不是追求极致精度,而是提供一个“足够好且稳定”的基础预测。为什么强调稳定?因为如果基础预测器本身波动很大,残差序列就会包含大量由基础预测器自身不稳定带来的伪模式,校正器会把这些伪模式也学进去,反而有害。
我在选型时试过几类模型。Transformer类的基础预测器精度高,但训练不稳定,残差序列的分布会随训练轮次变化,给第二阶段带来麻烦。LSTM类相对稳定,但长序列上容易遗忘早期信息。最后我倾向于用基于一维卷积加残差连接的TCN结构作为基础预测器,原因是它的感受野可以通过膨胀卷积灵活控制,训练稳定,而且推理速度快。
如果你要用现成的模型,PatchTST或者DLinear都是不错的选择。DLinear虽然结构极简,但在很多基准上表现意外地稳,作为第一阶段的基础预测器性价比很高。关键是要保证基础预测器在验证集上的残差序列是平稳的,至少不要有剧烈的分布漂移。
实操心得:训练完第一阶段后,先画一下残差序列的ACF和PACF图。如果残差看起来像白噪声,那校正空间不大;如果残差有明显的自相关或者周期性,那第二阶段就有发挥余地。
3.2 残差序列的预处理与对齐
拿到残差序列之后,不能直接扔给校正器。有几个预处理步骤是必须做的。
第一是对齐。基础预测器可能是多步预测,残差序列的长度和预测步长要对应好。如果是滚动预测,每个时间点的残差要按预测步长分别整理,因为不同步长的残差分布可能不同。
第二是归一化。残差的量纲和原始序列不同,通常幅值更小。如果直接和原始序列拼在一起输入校正器,校正器会被原始序列的尺度主导。我的做法是对残差单独做标准化,均值和方差用训练集的统计量,验证和测试集沿用。
第三是异常值处理。残差里偶尔会出现极端值,这些极端值可能是真实的突变,也可能是基础预测器的偶发失败。如果全部保留,校正器会被带偏;如果全部剔除,又可能丢掉真实信号。我的经验是,对超过3倍标准差的残差做截断而不是删除,保留其存在但限制其影响。
3.3 校正器的输入构造与特征工程
校正器的输入不只是残差序列本身。根据这篇工作的思路和我的复现经验,以下几类特征对校正效果帮助很大。
- 基础预测值:让校正器知道当前预测的水平,避免在基础预测已经很准的地方过度校正。
- 时间特征:小时、星期、月份、是否节假日等。很多残差的系统性模式和时间强相关。
- 滞后残差:过去几个时间步的残差,帮助校正器捕捉残差的自相关结构。
- 基础预测器的隐状态:如果基础预测器是神经网络,最后一层的隐状态可以作为上下文输入校正器。
这些特征拼接之后,用一个线性层或者一维卷积做融合,再送入残差块堆叠的骨干网络。输出维度要和预测步长一致,表示每个未来时间点的校正量。
注意:特征拼接时要注意尺度统一。时间特征做嵌入或者归一化,隐状态做LayerNorm,残差和预测值做标准化。否则校正器训练时梯度会被大尺度特征主导。
3.4 损失函数的设计与校正强度控制
第二阶段训练时,损失函数不能只用校正后的MSE。如果只用MSE,校正器可能会过度校正,把一些随机噪声也拟合进去,导致在测试集上反而变差。
我的做法是加一个校正强度正则项。具体来说,在MSE损失之外,加上校正量的L2范数乘以一个系数λ。λ越大,校正器越保守;λ越小,校正越激进。这个λ需要在验证集上调,通常从0.01开始试。
另一个技巧是残差符号一致性约束。如果校正器在某一步的校正方向和基础预测的误差方向一致,说明校正有效;如果相反,说明校正器在帮倒忙。可以在损失里加一项惩罚反向校正的样本,但要注意不要过度约束导致校正器不敢动作。
表格对比一下不同损失设计的效果:
| 损失设计 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 纯MSE | 简单直接 | 容易过校正 | 残差信噪比高 |
| MSE+L2正则 | 控制校正强度 | λ需要调参 | 通用场景 |
| MSE+符号约束 | 避免反向校正 | 可能抑制有效校正 | 基础预测已经较准 |
| 分位数损失 | 捕捉残差分布 | 训练复杂 | 需要不确定性估计 |
4. 实操过程与核心环节实现
4.1 数据准备与基础预测器训练
假设你手头有一个时序数据集,形状是(样本数,历史长度,特征数),预测目标是未来H步。第一步是切分训练、验证、测试集。时序数据不能随机切分,要按时间顺序切,通常7:1:2或者8:1:1。
基础预测器的训练用标准流程。以DLinear为例,它把序列分解为趋势项和季节项,分别用线性层预测再相加。训练时用Adam优化器,学习率1e-3,batch size 32或者64,训练100个epoch左右,早停耐心值设10。
训练完成后,在验证集上做滚动预测,收集每个时间点的预测值和真实值,计算残差。残差序列的形状和预测输出一致。把残差按预测步长分组,检查每组的均值和方差是否稳定。如果某一步的残差均值明显偏离0,说明基础预测器有系统性偏差,这正是校正器要学的。
4.2 校正器的网络搭建与训练
校正器的骨干用一维残差网络。具体结构可以这样设计:输入层把拼接后的特征映射到64维,然后堆4个残差块,每个块里两层一维卷积,卷积核大小3,膨胀系数依次为1、2、4、8,这样感受野可以覆盖较长的历史。最后用一个线性层输出H维的校正量。
训练时,第一阶段的基础预测器冻结,只更新校正器的参数。优化器用AdamW,学习率5e-4,权重衰减1e-4。损失函数用MSE加上0.05倍的校正量L2正则。batch size可以比第一阶段小一些,因为校正器的输入特征更多。
训练轮次不用太多,通常30到50个epoch就够了。因为校正器要学的是残差里的系统性模式,这些模式相对简单,过多训练反而会拟合噪声。早停的指标用验证集上校正后的MSE,如果连续5个epoch不下降就停。
实操心得:校正器训练完成后,把校正量序列画出来看看。如果校正量在某些时间段明显偏大,检查一下那些时间段的基础预测是不是特别差。如果校正量整体都很小,说明基础预测已经很好,或者正则系数太大了。
4.3 两阶段联合推理与部署
推理的时候,基础预测器先输出初步预测,然后校正器根据残差历史、基础预测值和时间特征输出校正量,两者相加得到最终预测。注意校正器用的残差历史是训练集和验证集上的残差,测试时的残差是逐步累积的。
部署时有两个选择。一是两个模型分开部署,基础预测器常驻,校正器按需调用;二是把两个模型打包成一个推理图,端到端输出。前者灵活,后者延迟低。如果线上对延迟敏感,建议打包;如果基础预测器更新频率低、校正器需要频繁调整,建议分开。
我在实际部署时遇到过一个坑:校正器的输入里包含了基础预测器的隐状态,但线上基础预测器可能是用不同框架实现的,隐状态拿不到。解决办法是用基础预测器的输出和残差历史替代隐状态,效果会打一点折扣,但工程上更可行。
4.4 效果验证与消融实验
验证的时候不能只看整体MSE,要分预测步长看。通常校正框架在长步预测上的提升更明显,因为长步的残差里系统性偏差更多。如果短步提升很小甚至为负,检查一下是不是校正器在短步上过拟合了。
消融实验建议做三组:去掉校正器、校正器不用残差块、校正器输入去掉时间特征。这样能清楚地看到每个组件的贡献。根据我的经验,残差块结构贡献最大,时间特征其次,基础预测值输入再次。
表格对比一下消融结果的大致趋势:
| 配置 | 相对提升 | 说明 |
|---|---|---|
| 完整框架 | 基准 | 两阶段+残差块+全特征 |
| 去掉校正器 | 下降明显 | 验证校正的必要性 |
| 校正器不用残差块 | 下降中等 | 残差块对深层特征提取关键 |
| 去掉时间特征 | 下降较小 | 时间特征有辅助作用 |
| 去掉基础预测值输入 | 下降较小 | 但训练稳定性变差 |
5. 常见问题与排查技巧实录
5.1 校正后效果反而变差怎么办
这是最常见的问题。原因通常有三个:校正器过拟合、基础预测器不稳定、残差预处理不当。
排查顺序是,先看训练集和验证集的校正后MSE差距。如果训练集降了但验证集升了,就是过拟合,加大正则系数或者减少校正器容量。如果训练集和验证集都升了,检查基础预测器的残差序列是不是平稳,不平稳的话先解决基础预测器的问题。如果残差预处理时归一化用了全局统计量而不是训练集统计量,也会导致这个问题。
5.2 残差序列看起来像白噪声还有必要校正吗
如果残差的ACF和PACF都在置信区间内,Ljung-Box检验也不显著,那确实没有太多校正空间。这时候强行校正只会引入噪声。但要注意,白噪声检验是在线性假设下做的,如果残差里存在非线性模式,线性检验可能检测不到。可以试一个简单的非线性检验,比如用一个小型MLP去拟合残差,如果验证集上MLP的预测误差显著低于残差的方差,说明还有非线性结构。
5.3 校正量发散或者越来越大
热词里有个“残差e发散(e越来越大)”,这在实际训练中确实会出现。原因通常是校正器的输出没有约束,或者损失函数里没有控制校正强度的项。解决办法是在校正器输出后加一个tanh或者clip,把校正量限制在基础预测值的一定比例内,比如正负20%。另外检查一下残差归一化是不是用了测试集的统计量,这会导致分布偏移。
5.4 不同预测步长需要不同的校正器吗
理论上可以共用一个校正器,输出H维校正量。但如果不同步长的残差分布差异很大,共用校正器可能会顾此失彼。我的做法是先用共用校正器,如果发现某些步长的校正效果明显差,再考虑分组。分组的方式可以按步长聚类,比如短步一组、中步一组、长步一组,每组一个校正头,共享骨干网络。
5.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方向 |
|---|---|---|---|
| 校正后验证集变差 | 过拟合 | 对比训练/验证MSE | 加正则、减容量 |
| 校正量发散 | 输出无约束 | 监控校正量幅值 | 加clip或tanh |
| 残差像白噪声 | 无系统模式 | ACF/PACF检验 | 放弃校正或试非线性 |
| 长步提升小 | 校正器感受野不足 | 检查膨胀系数 | 增大感受野 |
| 训练不稳定 | 特征尺度不一 | 检查各特征分布 | 统一归一化 |
5.6 几个容易忽略的细节
第一个细节是残差的滞后对齐。如果你用t时刻的残差去预测t+1的校正量,要确保残差是t时刻真实观测后计算出来的,不能用未来信息。滚动预测时这一点特别容易出错。
第二个细节是校正器的初始化。校正器最后一层初始化为零,这样训练初期校正量为零,不会破坏基础预测器的输出。这个技巧在残差学习里很常用,能显著提升训练稳定性。
第三个细节是验证集的使用。校正器的早停应该用校正后的验证集MSE,而不是校正量本身的损失。因为我们的目标是提升最终预测,不是让校正量好看。
第四个细节是多变量场景下的校正。如果预测多个变量,校正器可以共享骨干但每个变量单独输出校正量,也可以所有变量一起输出。共享骨干加独立输出通常更好,因为不同变量的残差模式可能不同,但底层特征可以共享。
6. 我在复现过程中的几点体会
这个框架最吸引我的地方,是它把“残差”从一个被动的误差指标变成了一个主动的建模对象。以前做时序预测,残差分析通常只在模型诊断阶段用一下,看看有没有自相关、有没有异方差,然后就结束了。但这篇工作把残差当作一个独立的信号源,专门建一个模型去学它,这个视角的转变带来的收益是实实在在的。
我在自己的电力负荷数据集上试过这个思路,基础预测器用DLinear,校正器用4层一维残差网络,校正后的MSE比基线降了大概18%。提升没有标题里的92.85%那么夸张,但考虑到电力负荷数据本身噪声就大,这个提升已经很满意了。后来在交通流量数据上试,提升更明显,大概有30%左右,因为交通流量的周期性残差更系统。
踩过的坑主要是校正器过拟合。一开始没加正则,校正器把训练集的残差噪声也学进去了,验证集上反而比不校正差。后来加了L2正则和早停,才稳定下来。另一个坑是残差归一化,一开始用了全局统计量,导致验证集上校正量分布偏移,改成训练集统计量后解决。
如果让我给想复现这个框架的人一个建议,那就是先把基础预测器做稳,再考虑校正。基础预测器不稳定的话,残差里全是伪模式,校正器学到的都是错的。基础预测器稳了,残差里的系统性模式才会浮现出来,校正器才能发挥作用。
最后分享一个小技巧:校正器的学习率可以设得比基础预测器低一个数量级。因为校正器要学的是精细的修正量,学习率太高容易跳过最优解。我在实验里用5e-4的学习率比用1e-3稳定很多,收敛曲线也更平滑。这个技巧在微调类任务里很常见,但用在残差校正上同样有效。