KDD 2025 上有一篇关于多变量时间序列无源域适配的工作,方法名叫 TERSE,标题写得很直白:破解多变量时间序列无源域适配难题,同时建模时间与空间依赖。如果你做过域适配,又恰好碰过传感器、能源、金融、医疗这类多变量时序数据,应该能立刻 get 到这句话的分量——源域数据在部署时往往已经拿不到了,只有预训练好的源模型,目标域数据又没有标签;与此同时,每个变量自己的历史轨迹很重要,变量之间的联动关系也很重要,但很多方法只顾一头,结果越适配越偏。
这篇文章我会从问题拆解开始,讲清楚无源域适配为什么遇到多变量时间序列会特别棘手,然后梳理 TERSE 这类方案的核心设计思路,再补充我在复现类似方法时踩过的坑以及排查经验。如果你正准备做时序数据的无源域适配,或者想参考一个能同时处理时间依赖和变量间依赖的框架,这篇笔记应该能帮你少走不少弯路。
1. 无源域适配为什么这么难?多变量时间序列的双重依赖拆解
1.1 无源域适配到底“无源”在哪
常规域适配里,我们假设源域数据是可见的,可以同时拿源样本和目标样本一起做对抗训练、MMD匹配或重建式对齐。但实际部署场景往往不是这样:源数据可能因为隐私、存储成本或者协议约束已经不可访问,能拿到的只有预训练好的源模型参数,甚至只有一个预测接口。这就是"无源域适配"(Source-Free Domain Adaptation)的基本设定——训练阶段只有目标域数据加一个从源域搬过来的模型,源域样本永远不出现。
这个设定带来的直接后果是,传统的域间分布对齐方法全部失效。你不能计算源域和目标域的MMD,因为你没有源样本;你不能做对抗域判别,因为判别器也需要两个域的样本来区分。能用的信息源只剩两个方向:一是目标域自身的结构,比如无标签数据上的统计分布;二是源模型内部残留的源域记忆,比如BN层的运行均值方差、权重参数、预测输出的置信度分布。所以大多数无源方法都依赖伪标签和自我训练,通过源模型在目标域上产出一批高置信度伪标签,再用这些伪标签微调模型。
但多变量时间序列有自己的特殊性。图像数据可以整体看,把一张图当作一个样本,而多变量时间序列里,每个样本本身是一个长度 L 的窗口,窗口内有 T 个时间步,每个时间步有 C 个变量通道。这意味着数据不仅有通道维度上的“空间”结构,还有时间维度上的动态演变。伪标签的鲁棒性、分布漂移的表现形式,都会比图像场景更复杂。
1.2 多变量时间序列里的“时间依赖”和“空间依赖”
我用一个简单的生产设备监控来举例。一个旋转机械上有温度、压力、振动、转速四个传感器,每秒钟记录一次,形成四个通道的时间序列。
时间依赖,是指同一个通道内部前后时刻的关联。比如温度今天升高,明天大概率还会继续升高,而不是随机跳变;振动信号有周期性的峰值。这种依赖可以通过循环神经网络、卷积神经网络或者Transformer来捕捉。但无源域适配里,时间依赖还会发生漂移,比如源域采集于夏季,设备温度整体偏高,目标域在冬季,整体水平变了,但局部波动的模式可能相似;也可能是传感器采样频率变了,导致相邻时间步的相关性密度发生改变。
空间依赖,在多变量时间序列里通常指变量通道之间的相互关系。比如温度升高时,压力往往也会上升,振动幅度受转速影响很大。这种跨变量依赖不是静态的,可能随着时间变化,比如启动阶段和稳定运行阶段,变量之间的耦合关系完全不同。如果模型没有显式建模变量间关系,它就只能依赖全局特征对齐,很难适应目标域中“变量间关系重排”的情况。
与此同时,时间依赖和空间依赖往往互相耦合。变频器启动时,转速先上升,随后温度和振动才跟着变化,这是一个时间滞后下的跨通道关系。如果只把整个窗口拉平成一个向量送入分类器,这种时间滞后的跨变量关系就完全丢失了;如果时间分支和空间分支完全割裂,也就是各做各的,信息又无法互通。
1.3 现有方法的三个盲区
让一个刚接触这个方向的人快速理解 TERSE 的价值,可以看看之前主流方法有三个盲区。
第一,很多无源域适配方法直接把图像领域的套路搬到时间序列上,比如用全局对抗对齐或全局BN统计量适配。这些方法把时间序列样本当成静态特征集合,忽视了时序的先后因果,适配完模型对变量顺序的扰动非常敏感。把传感器通道顺序打乱,性能就崩掉。
第二,有一些时序域适配方法考虑了时间建模,但空间依赖处理得很粗糙。要么假设所有变量独立,用共享的卷积核在通道间扫过去,要么直接用一个固定的相关矩阵(比如皮尔逊相关系数)定义通道关系。固定矩阵最大的问题在于它不随目标域变化,一旦目标域的变量关系发生变化,反而会引入错误先验,造成负迁移。
第三,缺乏对长周期的感知。多变量时间序列中的分布漂移经常体现在周期振幅、周期相位上,而常见的时间编码器窗口有限,感知不到完整周期。TERSE 在时间分支中强调局部与周期结合,很大程度上是在补这个洞。
2. TERSE 的核心设计:两个分支各司其职,再融合预测
TERSE 这类方法通常把问题拆成两条分支:一条处理时间依赖,一条处理空间依赖,最后把两个分支的特征融合起来做预测。这个解耦设计在工程上特别好落地,因为两个分支可以分开调试、分别替换,也方便在无源场景下做逐步适配。
2.1 时间分支:局部卷积 + 周期感知
时间分支的核心是让每个变量通道先独立地在时间维度上编码,捕捉通道自身的动态模式。为了不泄漏未来信息,一般用因果卷积或掩码注意力。因果卷积的意思是,输出 t 时刻的特征时,只使用 t 以及 t 之前时刻的输入,这和传感器实时采集的逻辑是一致的——你在 t 时刻能拿到的也就是过去的数据。
在实际实现里,我建议用一个两层或三层的膨胀因果卷积作为基础骨干,膨胀率按 1、2、4 递增,可以用很小的感受野覆盖比较长的历史窗口。膨胀因果卷积比标准TCN更强的地方在于,它不会改变序列长度,可以很方便地和后续的注意力拼接。在膨胀卷积之后,可以对时间维度做池化或注意力聚合,得到每个变量的时间特征向量。
但局部卷积只能覆盖有限的窗口长度。假设数据有24小时周期,你的窗口只有12小时,卷积再膨胀也看不到完整周期。所以时间分支还需要一个周期感知辅助模块。一个常见的做法是沿时间轴做快速傅里叶变换,把频域幅度谱或主要周期分量的能量作为额外特征;也可以把序列按估计周期切分成多个子段,计算子段间的均值和方差偏移,作为周期稳定性特征。这个周期感知模块在无源适配里还有一个额外作用:很多分布漂移表现为频率成分的变化,比如故障设备的振动信号中高频分量比例上升,如果源模型在频域特征上具有判别力,保留频域信息有助于更好地继承源模型的知识。
2.2 空间分支:从固定图到自适应图学习
空间分支的目标是捕捉变量通道之间的相互依赖。最朴素的做法是预定义一个静态图,比如用源域或通用先验计算通道间的相关系数矩阵,然后在这个固定的图上做图卷积。但这个做法在无源适配里风险很大:如果源域里通道A和通道B强相关,目标域里因为传感器布置或环境改变,通道A和B的相关性消失了,你还在用旧的图做消息传递,就是把错误信息扩散给每一个节点。
更稳健的思路是让图结构成为可学习的参数。具体来说,假设有 C 个变量通道,空间分支维护一个可学习的节点嵌入矩阵 E,维度是 C×d,然后通过节点嵌入的内积计算出通道间的相似度矩阵 S = E E^T,再对这个相似度矩阵做归一化和稀疏化,得到邻接矩阵 A。稀疏化可以用 top-k 截断:每个节点只保留与其最相似的 k 个节点作为邻居,k 是超参数。这样做的好处是,目标域的通道间关系可以通过梯度自动学到,不用依赖源域的先验。
有了邻接矩阵之后,可以用图卷积网络(GCN)或图注意力网络(GAT)在通道维度上做消息传递。每一层更新节点特征时,会把邻居节点的信息聚合到当前节点。如果变量间的关系存在时间滞后,也就是A在t−1时刻影响B在t时刻,纯静态图和纯空间分支是捕捉不到的。此时可以让空间分支的输入不只是当前时间步的特征,而是时间分支提取的分段特征集合,比如每个通道在一个时间窗口内的均值、趋势、能量。这样空间分支实际是在做“变量级语义关系”的学习,而不是逐时间步的瞬时依赖。
关于图结构的初始化,我有一个实操建议:不要完全随机初始化节点嵌入,最好先用目标域无标签数据计算皮尔逊相关矩阵或互信息矩阵,用这个矩阵的特征向量或直接作为邻接矩阵来初始化,会收敛得又快又稳。理由是自适应图学习本身参数自由度很高,如果没有一个还不错的起点,很容易陷入局部最优,甚至学出一个全连接或全断开的退化图。
2.3 双分支融合与目标函数设计
时间分支和空间分支分别得到特征之后,怎么融合也需要动点脑筋。简单地把两个特征向量拼接后接一个全连接层,是最容易想到的方案,但效果不一定最好。因为不同样本、不同目标域场景下,时间信息和空间信息的置信度可能完全不同。我更推荐用门控融合机制:为每个分支学习一个标量权重,或者一个二维权重向量,让模型根据当前输入自适应地调整两个分支的贡献。
例如,目标域里如果某个通道的某个传感器坏了,一直输出恒定值,那么空间分支的可信度会下降,模型应该倾向依赖时间分支;反过来,如果序列中有大量缺失值,时间分支的特征可能不稳定,模型应该多依赖空间分支。门控机制可以学习到这个偏好,而固定拼接学不到这种动态调节。
无源域适配的损失通常由三部分构成。第一部分是伪标签监督损失,用源模型在目标域数据上预测出的高置信度伪标签,对模型输出做交叉熵或均方误差约束。第二部分是对齐约束,常见的是让当前模型输出与源模型输出之间的KL散度尽量小,或者让当前模型提取的特征空间与源模型提取的特征空间保持一致,这一步是为了防止模型在无源微调时偏离源域的判别结构。第三部分是空间图正则,比如限制邻接矩阵的稀疏性,或者约束节点嵌入的均匀性,避免图结构学到退化形态。如果两个分支都输出预测,还可以加一个双分支一致性损失,让时间分支和空间分支对同一个样本的预测不要差别太大,这能帮助融合层更稳定地训练。
3. 复现 TERSE 的实操细节:预处理、训练与超参选择
这一节我会补充一些我在复现类似无源时序适配方法时的实际做法。如果你手头有自己的一套数据,可以对照这些细节逐项检查,很多跑不出来的问题都不是模型结构的问题,而是数据管道的问题。
3.1 数据预处理:别让时间泄漏毁了实验
时间序列实验最容易犯的错,就是在归一化时用到未来数据。假设你有整条长度为10000的序列,如果先计算整条序列的均值和方差,然后对整个序列做标准化,那么训练时t时刻的特征其实已经把t之后的信息算进去了,因为均值方差是全局统计量。这会让模型在验证时的表现虚高,但部署到线上后,你不可能知道未来数据才能计算归一化参数,性能会立刻打回原形。
正确做法是把数据集先按时间顺序划分成训练集、验证集、测试集,然后在训练集部分单独计算每个通道的均值和方差,用这个统计量去标准化训练集、验证集、测试集。如果数据本身是切片式的,比如每个样本是一个固定长度窗口,也要保证每个窗口内的归一化参数只来自窗口内过去部分,或者在窗口划分之前用训练集整体统计量。对于无源域适配来说,源数据不可见,但通常有一个预训练好的源模型,源模型内部自身带有BN统计量,这些统计量是源域数据上求得的,可以直接作为目标域数据的归一化参考之一。当然,更稳妥的是在目标域训练集上重新估计一个目标域的归一化统计量,因为模型最终要做的事就是适配目标域的分布。
另一个时间泄漏来自重采样和滚动窗口的构造。如果你用滑动窗口切样本,而且测试集紧跟在训练集之后,那么窗口之间会共享大量数据,评估结果会有偏差。正确的做法是在切分窗口之前,先预留一定间隔,比如训练集最后一个窗口的末尾和测试集第一个窗口的开始之间隔若干个时间步,确保没有数据重叠。
3.2 滑动窗口、批次组织与通道顺序
滑动窗口的长度是一个需要重点调的超参。窗口太短,模型看不到一个完整的周期,时间分支的周期感知模块基本没用;窗口太长,训练样本数变少,计算开销变大,而且可能包含多个周期,短期突变信息被淹没。我一般先用简单的周期检测工具(比如自相关函数或FFT)估计出主周期长度,再把窗口长度设置为主周期的1.5到2倍。比如数据有明显日周期,采样频率一小时一次,周期24,那窗口长度取36或48比较合适。如果数据没有明显周期,就做一个窗口长度的敏感性分析,比如取 {12, 24, 48, 96}。
批次组织上,如果直接把时序数据按顺序连续取batch,那么同一个batch内的样本都来自相近的时间段,模型看到的只是局部的小分布,收敛速度会很慢,而且更容易过拟合到某个短期模式。正确做法是把窗口打乱,随机采样组成batch。对于多变量时间序列,通道顺序本身是固定的,但模型里如果有空间分支,通道顺序会影响图结构的初始对应关系。我建议在训练时固定通道顺序,不要打乱通道,否则空间分支的节点嵌入初始映射没有意义。但可以做通道尺度的数据增强,例如对通道做随机缩放或噪声注入,帮助图结构更鲁棒。
3.3 伪标签生成与置信度筛选
无源域适配里,伪标签的质量直接决定上限。最理想的情况是源模型的预测准确率在目标域上仍然较高,这样伪标签大部分是对的。但现实往往不理想,所以必须引入筛选机制。
对于分类任务,常见做法是取softmax概率超过固定阈值(比如0.9或0.95)的样本作为“干净”样本,只拿这些样本计算监督损失。阈值不能太高,否则选出来的样本太少,训练信号不足;也不能太低,否则噪声大。一个更稳的做法是设置双阈值:高阈值样本作为强监督,低阈值样本作为弱监督,只参与一致性正则,不直接参与分类损失。对于回归任务,伪标签不存在概率,可以用模型预测的方差或集成多个随机Dropout掩码的结果来计算不确定性,只选择不确定性低的样本。
训练过程中可以使用课程学习策略:先只选最高置信度的20%样本训练几个epoch,让模型先学习到最可靠的特征,然后每过几个epoch把阈值降低一点,逐步纳入更多样本。这个过程很像人先做简单题,再做难题,可以显著降低早期噪声段对模型的影响。
3.4 优化器、学习率与模型选择
对于 TERSE 这种多分支模型,我建议用 AdamW 优化器,初始学习率设置在 1e-4 到 3e-4 之间,并配合余弦退火或线性 warmup。batch size 不宜过大,我常用的范围是 64 到 128,如果窗口长度很长,可以适当减小 batch size。自适应图学习模块的收敛比普通卷积慢,所以可以给图结构部分设置一个稍小的学习率,或者在图模块更新时加入梯度裁剪,防止邻接矩阵在早期剧烈波动。
无源域适配没有目标域标签,验证集也不好选。一个实用的监控指标是目标域上的预测熵:随着训练进行,模型对目标域样本的预测置信度会逐渐变高,熵下降说明适配有效。但这个指标不是万能的,模型也可能过度自信地给出错误预测。所以我更建议用源模型在目标域上的预测一致率:每训练一个epoch,固定当前模型参数,计算当前模型与源模型在目标域无标签样本上的预测一致率。如果这个一致率保持在较高水平,说明模型没有完全偏离源域知识;如果骤然下降,说明出现了灾难性遗忘,需要回调学习率或加强一致性约束。
4. 复现过程中我踩过的坑与排查思路
下面这些坑是我在类似框架上实际调试时遇到的,希望能帮你省掉几晚上折腾时间。
4.1 自适应图结构学成全连接了怎么办
自适应图学习如果没有约束,网络很容易把所有通道之间的边权重都学得很大,最终逼近全连接图。一旦图变成全连接,每个节点的特征就是所有变量特征的加权和,空间分支退化成一个普通的全连接层,同时计算量还暴涨。解决办法是在邻接矩阵生成时加一个稀疏约束,具体做法有两种:一是对相似度矩阵做 top-k 截断,每个节点只保留权重最大的 k 条边;二是在损失函数里加一个 L1 正则,惩罚邻接矩阵中非零元素的数量。
我自己的倾向是 top-k 截断更直接好用。选 k 时可以从变量总数的30%开始调,如果效果不好,上下浮动。另外,可以在每个训练批次里随机丢弃部分边,类似 Dropout,把稀疏化后的邻接矩阵中的边以一定概率置零,这样图结构不容易过拟合到某个固定的邻居集合。
4.2 伪标签噪声太大导致训练震荡
有一次我直接拿所有目标域样本的伪标签训练,前几个epoch损失下降,后面突然剧烈震荡。排查了一下,发现是伪标签中一批错误样本的置信度也偏高,模型被强行往错误方向上拉。解决办法是把伪标签筛选阈值从0.95提高到0.99,虽然可用的样本少了,但损失曲线明显稳定。如果可用样本太少,可以采用“伪标签+熵最小化”的配合策略:高置信度样本用交叉熵监督,低置信度样本不给他们硬标签,而是加入预测熵惩罚,让模型尽量以低置信度输出,避免过早承诺到错误类别。
另一个技巧是使用两个不同随机种子训练两个源模型的变体,分别生成伪标签,只有两个变体预测一致的样本才被选中。这个“双模型投票”的办法可以显著降低噪声,代价是训练时间翻倍,但在无源场景下非常有效。
4.3 显存爆炸怎么处理
多变量时间序列的通道数一旦达到几百甚至上千,空间分支的邻接矩阵就是 N×N 大小,显存占用很容易爆炸。我的建议有三个层面:第一,通道数很大时,不要直接用完整图,而是先对通道做聚类或分组,比如把 1000 个通道按相关性聚成 50 个簇,然后在这 50 个簇上做图卷积,簇内共享参数。第二,使用邻居采样技巧,每次只随机采样每个节点的一部分邻居参与聚合,类似 GraphSAGE,可以控制计算量。第三,在预处理阶段对序列做降采样或截断,虽然损失了一部分时间分辨率,但能换来更大的batch size,整体效果可能反而更好。
4.4 源模型遗忘太快,怎么办
无源域适配最怕微调几个epoch后,模型在目标域上表现还行,但原本学好的源域判别结构被冲掉了。由于源域数据不可见,一旦遗忘就无法恢复。我常用的办法是把源模型主干参数冻结,只微调时间分支、空间分支和融合层。如果必须全量微调,可以给主干网络设置极小的学习率,比如主干的 learning rate 是分支的0.1倍。
同时,在损失函数里加一个特征一致性正则,让当前模型在目标域样本上提取的中间特征和源模型提取的中间特征尽量接近,这个约束通常用均方误差或余弦距离。有了这个正则,当前模型不会偏离源模型太远,又能通过分支结构调整目标域的特定模式。
5. 一点个人体会和后续还能怎么玩
我自己在复现这类方法时,最大的体会是“端到端一次到位”往往不靠谱。无源域适配这种框架,适合分阶段搭建:先用固定图和时间分支跑通基线,确认时间依赖建模有效;再逐步加入自适应图、门控融合和伪标签课程学习;每加入一个模块就做一次消融,对比哪个部分真正起作用。很多论文里最终效果是三个模块叠加出来的,但中间每个模块的调试方式不一样,一次全塞进去出了问题根本定位不了。
从落地价值来看,无源域适配在工业场景里确实需求很大。制造现场、能源场站、医疗设备监控,到处都是多变量时间序列,但大多数场景根本不可能重新标注足够的目标域数据,而且旧数据往往因为版本迭代或合规要求不能长期保存。这种情况下,能用一份预训练模型,在目标域无标签数据上做自适配,是性价比非常高的路径。TERSE 这种时间分支加空间分支解耦的框架,也方便工程上替换对应模块——时间分支可以用最新的状态空间模型或分段卷积,空间分支也可以用注意力机制替代图卷积。
最后分享一个调参技巧:如果你发现最终适配后的模型效果反而不如源模型直接用在目标域,先别急着改网络结构,检查两件事。第一,归一化方式有没有引入时间泄漏;第二,伪标签筛选阈值和筛选方式是否合理。就我的经验看,七成的问题出在数据预处理,两成出在伪标签噪声,只剩一成才是模型结构本身的问题。把这些基础问题排查干净,再看模型能不能发挥出它该有的能力。