ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

TERSE:多变量时间序列无源域适配的时空联合建模

TERSE:多变量时间序列无源域适配的时空联合建模 多变量时间序列的无源域适配在 KDD 2025 上算是真正被摆到了台面上。TERSE 这个工作把时间依赖和空间依赖一起建模解决的是那种最现实也最头疼的问题源域数据已经拿不到了只剩源模型的权重目标域样本还得硬着头皮适配。先把这个场景说得直白一点。传感器网络、工业设备监控、金融行情、可穿戴设备几乎所有跑时间序列的地方都逃不过一个问题训练数据和部署数据不是同一批分布。设备校准换了一轮传感器型号变了甚至只是机房环境从夏天变成冬天模型效果就往下跌。这时候最尴尬的不是精度掉多快而是你手里只有当初训练好的模型文件原始数据集因为隐私、存储、导出权限等原因已经拿不到了。这就是无源域适配Source-Free Domain Adaptation, SFDA要解决的事情。而多变量时间序列Multivariate Time Series, MTS又给这任务加了一层难度每个样本内部同时存在随时间变化的规律和变量之间的相互影响这两个维度的依赖都必须建模少一个都不行。TERSE 的做法就是把这种两难拆成可以被单独设计、再统一收敛的部分。整篇文章读下来我的感受是它没有堆砌什么前所未见的新概念而是把该做的事情做对了并且真正把时间和空间两个维度同时建模而不是简单拼一个模块就说我们同时考虑了两者。适合看这篇文章的人有两类。一类是正在做时间序列域适配的研究者或学生想给自己的实验找一个新 baseline 或新的对比对象另一类是做工业落地、手里有部署模型但拿不到原训练数据的工程师想搞清楚这类方法能否解决实际问题。1. 先把问题说清楚为什么无源 多变量时间序列这么难1.1 多变量时间序列到底特殊在哪多变量时间序列简单说就是同一时刻观测到的多条相关序列。一个风力发电机组上有几十个传感器同时采集转速、温度、振动、风速等信号一个病人身上贴着心电、脑电、血氧多个导联一个交易系统里同时记录多只股票的分钟级量价数据。单变量序列只看自己过去怎么变化而多变量序列要额外回答另一个通道的变化对当前通道有没有影响。这个通道间影响就是空间依赖。它跟时间依赖一样是 MTS 数据里写死的信息结构。温度升高会影响振动幅度脑电的某个频段会跟着眼动信号联动风机的桨距角变化会直接影响发电功率。如果模型把每个通道独立看待等于把已经明摆着的因果关系扔掉了。反过来如果模型只顾着捕捉变量之间的关系又把序列本身的趋势、周期、突变全丢了。所以一个合格的 MTS 模型时间和空间是双主线不是二选一。这里有个很多人容易忽略的点空间依赖不是静态的。通道之间的相关性会随工况、随事件、随时间窗口变化。正常状态下两个传感器高度相关故障瞬间相关性可能瞬间归零甚至反向。所以空间建模不能学出一个固定的邻接矩阵就完事至少要能随输入样本动态调整。这也是很多初版方法效果差的原因——它们用一个全局共享的静态图把动态相关性压成了静态统计量。1.2 域偏移在多变量时间序列里长什么样域偏移在图像里可能是光照、风格、背景的变化比较好理解。在时间序列里偏移可以发生在好几个层面。第一是边际分布偏移源域传感器读数普遍偏低目标域普遍偏高均值方差都变了。第二是时间动态偏移源域采样频率是 100Hz目标域变成 50Hz或者源域里趋势平稳目标域出现明显漂移。第三是变量相关结构偏移源域两个通道强相关目标域换了布置位置相关性变弱甚至反向。第三种偏移最隐蔽也最致命。常规的统计对齐方法根本处理不了因为它不是单个变量自己变了而是变量之间的关系变了。你即使把每个通道的均值方差都对齐到目标域通道间的联合分布依然错着分类器照样判不准。图像域适配方法搬到时间序列上效果总是不尽如人意很大一部分原因就在这图像方法默认特征是独立同分布的像素而 MTS 里的像素之间有强结构且结构本身会偏移。1.3 无源约束意味着什么无源就是目标域适配阶段不再允许碰源域数据。听起来只是少了一个数据集实际影响非常大。没有源数据就不能重新计算源域特征分布不能做对抗学习去对齐两个域的判别边界也不能通过重采样平衡源域类别。你手里只有源模型的权重准确地说是一个编码器加一个分类器。你要在只有目标域样本的情况下让这个模型在目标域上重新变准。这不是锦上添花这是在没有标签的条件下重新校准一个已经过时的模型。但好在这种约束在实际部署里非常常见。医院不可能把病人的原始监测数据打包给你做二次训练金融机构的训练数据集过了有效期就要删除。所以近年来 SFDA 这个概念才会这么受关注KDD 2025 专门有人做多变量时间序列版本也说明工业界的真实需求已经传导到了学术界。2. TERSE 的核心思路时间与空间两手都要抓2.1 整体框架视角TERSE 这个名字和它的英文展开放在一起看核心特征就是两条Temporal Spatial。它把网络设计成两条互补的建模路径一条负责把序列的时间结构抽出来另一条负责把变量之间的空间关系抽出来最后通过融合层合并成统一表示再在这个表示上做适配任务。这里要强调一个容易被忽视的设计点它不是在网络末尾简单地把两个分支的特征向量拼接一下了事而是在中间层就开始让时间特征和空间特征互相调节。为什么因为真实 MTS 里时间和空间是纠缠的。空间相关性本身会随时间变化风机在正常工况下桨距和功率相关性很高故障瞬间这个相关性会突变时间模式又会随变量不同而不同有的通道变化快有的通道变化慢。如果两个维度在后端才融合前面的特征已经各自独走了后面再怎么拼接也补不回交互信息。用生活里的例子类比这就像两个人合作搬重物。如果全程各搬各的到最后一米才把东西对在一起多半早就偏了正确做法是走每一步都互相感知对方的位置和力度随时调整。2.2 时间依赖建模的要点时间维度的建模常见选择有 RNN 系列、TCN、Transformer 三种。RNN 对长序列有遗忘问题且顺序计算没法并行TCN 能并行感受野靠空洞卷积扩张但没有全局注意力Transformer 有全局注意力但复杂度随序列长度二次增长对周期性特征的归纳偏置也比较弱。TERSE 这类工作在时间分支上通常的做法是保留序列顺序以窗口或分块为单位做局部序列编码再叠加跨窗口的注意力层。这样做的优势是既能捕捉短期的局部模式一次脉冲、一个小幅波动也能捕捉长时间尺度上的趋势和周期而且窗口化设计让训练效率比纯全局注意力高不少。实操上有个细节时间戳对应的位置编码一定要加不加位置编码的自注意力会把序列当词袋处理周期相位信息全部丢失后面怎么适配都救不回来。时间分支的输出一般是一个每个时间步都有对应的特征的序列表示也可能是池化后的整体表示。这个选择取决于下游任务如果是序列级分类池化就够如果要做得更细比如事件检测或者局部异常定位那就保留逐时间步特征。TERSE 支持序列级任务的适配是足够的但读代码时要注意分支输出的形式别理解错了。2.3 空间依赖建模的要点空间依赖建模的本质是回答变量之间应该如何连边。最简单粗暴的连边方式是全连接每对变量都是邻居但参数量大还会把不相关通道强行关联。另一种极端是只按物理位置连边传感器按坐标构图但很多时候变量关系和物理距离并不一致。更合理的做法是让模型自己学图。具体来说给每对变量算一个可学习的相似度分数经过稀疏化或者 top-k 筛选决定保留哪些边然后在这张图上做图卷积或图注意力。这类可学习图结构的优势是能自适应地发现域间的变量关系但它对初始化比较敏感训练初期如果图结构乱跳整个模型都会不稳定。工程上一个常见补救措施是在图学习项上加正则化让邻接矩阵满足对称性、非负性并且把每个节点的度数限制在一定范围。我在复现类似结构时踩过一个大坑空间分支的输出和通道顺序强相关。如果源域和目标域的通道排列顺序不一致真实部署里太常见了传感器线序变了空间建模就全乱了。所以特征层面的空间建模最好在规范化之后的特征空间里做不要直接拿原始数值通道 ID 去构图。另一个坑是图卷积的深度不要贪多两层到三层通常就够再深反而会因为过平滑让所有节点特征趋同空间信息被抹平。3. 无源适配机制没有源数据怎么把模型拉回正轨3.1 从冻结到渐进式解冻无源域适配里源模型是唯一锚点不能一开始就把所有权重放开微调。常见做法是两阶段第一阶段锚定源模型只训练新加的适配模块比如规范化层、适配器或图学习参数第二阶段再轻微微调后端分类器。这样做的目的是防止模型在目标域上自说自话地漂移把源域学到的判别信息全忘了。这和直接在目标域上做无标签自训练有本质区别后者非常容易塌缩成只认识少数几个高频类别的退化模型。TERSE 从设计上也是类似的两阶段思路但多了一个可用的杠杆因为同时对时间和空间建模适配模块能利用的判别线索比普通 SFDA 方法多一个维度。时间上目标域的类别在时间结构上通常有明显一致性一段正常心电的节奏模式和一段异常心电完全不同空间上目标域的变量相关模式也能提供聚类信号。两个线索互为补充比单靠特征空间聚类要稳得多。有朋友会问为什么不直接开一个高学习率全量微调让模型更快适应目标域我踩过这个坑。目标域没有标签你怎么知道它学的是适应目标域分布还是记住目标域里的噪声全量微调在无源场景下基本等于赌博输的概率远大于赢。渐进式解冻虽然慢一点但每步都有约束塌缩风险小一个数量级。3.2 伪标签与置信度管理自训练是无源适配的核心引擎伪标签质量直接决定上限。这块有两个常见病。第一是确认偏差模型一旦把早期错误的高置信预测当成标签后面会不断强化错误越错越自信。第二是类别失衡目标域某些类样本少伪标签也少模型慢慢偏向高频类。处理办法不外乎几个设置置信度阈值低于阈值就丢弃对预测熵做校准用类原型而不是单样本标签做对比学习减少单点噪声影响。TERSE 这类方法在实现上通常会把伪标签和类原型结合起来先用源模型在目标域上提取特征按类别聚出原型向量然后每个样本的特征和各个原型的相似度作为软标签再结合硬伪标签一起构造损失。这样即使个别样本打错标签它对原型的更新影响也被平均掉了。我个人的经验是阈值不要定太死。0.9 太高早期会丢掉大量样本适配进度极慢0.7 太低混入的噪声会污染原型。比较实用的做法是从低阈值开始随着训练轮数增加逐步提到 0.95 左右让模型先学有把握的再慢慢扩大影响范围。这个调度策略我在公开数据集上试过普遍比固定阈值涨一到两个点而且更稳定。3.3 损失函数与训练过程一个标准的无源适配损失可以拆成三块。第一是熵最小化让目标域预测分布更尖锐直接减小分类不确定度。第二是伪标签监督用筛选过的伪标签做交叉熵或对比损失。第三是源模型约束让适配后的特征不要偏离源模型特征空间太远通常用特征层面的 L2 或余弦相似度约束。在 TERSE 的双分支结构里损失还要多加一层分支一致性正则。意思是时间分支和空间分支各自预测的结果应当一致如果分歧太大就惩罚。这是一种很自然的自集成相当于同一个样本的两个视角互相投票可以进一步压低伪标签噪声。我在自己的实验里试过类似的双视角一致性约束效果确实比只用一个分支更好尤其是在目标域和源域差异很大的时候。训练流程上建议用小学习率、大 batch 的配置。时间序列样本通常比较短GPU 上可以一次放很多batch 大一点原型估计会更稳定。下面给一个训练循环的伪代码框架实际写代码的时候可以直接照着搭# 伪代码TERSE 风格的无源适配训练循环 for epoch in range(total_epochs): for batch in target_dataloader: x_t batch[input] # [B, T, C] feat, logits_time, logits_space model(x_t, return_bothTrue) # 1) 熵最小化让预测更锐利 ent_time softmax_entropy(logits_time).mean() ent_space softmax_entropy(logits_space).mean() # 2) 伪标签监督阈值动态调整 prob softmax((logits_time logits_space) / 2) conf, pseudo prob.max(dim1) mask conf threshold_schedule(epoch) ce cross_entropy(logits_time, pseudo, mask) \ cross_entropy(logits_space, pseudo, mask) # 3) 分支一致性 kl kl_divergence(logits_time, logits_space).mean() # 4) 初始阶段锚定源模型特征 if epoch anchor_epochs: with torch.no_grad(): src_feat source_encoder(x_t) distill mse_loss(feat, src_feat).mean() else: distill 0.0 loss ent_time ent_space ce kl * alpha distill * beta loss.backward() optimizer.step()这段代码看着简单但有几个细节要注意。源模型锚定阶段不是越久越好锚太久会让适配模块学不到目标域特有的分布偏移一般建议前 10% 到 20% 的 epoch 做锚定。阈值调度也不是单调上升就一定好我在某些数据上试过低-高-低的循环调度反而效果更好可能是后期加入低置信样本做重新校准能避免过度自信但这一点论文里通常不会写只能自己调。代码里source_encoder要和model共享前面几层否则蒸馏就没有意义了。4. 实验怎么做数据集、评估协议与对比方法选型4.1 数据集与评估协议这类方法在公开实验里用的数据集相对固定主要围绕生理信号和活动识别两大类。比如睡眠分期数据、癫痫检测数据、人类活动识别数据再就是故障诊断数据。这些数据的共同特点是通道多、类别语义清楚、域偏移可以通过不同受试者或不同采集批次来构造。受试者之间的生理差异天然就是域偏移不需要人为合成非常接近真实场景。评估协议上标准做法是留出法加交叉验证一部分受试者作为源域训练另一部分作为目标域测试。关键是一定要在适配过程中不使用任何目标域标签连验证集的标签也不能用来调阈值否则就不是无源域适配了而是变相作弊。很多初学者在这里栽跟头用目标域验证集去选超参数结果论文里的数字很漂亮部署时完全失效。另一个容易忽略的协议细节是数据切分的窗口方式。多变量时间序列在做样本化的时候滑窗的窗口长度和步长会直接影响结果。窗口太短类别特征不完整窗口太长正负样本比例可能失衡。而且如果切窗时没有保证同一个片段不被切到训练集和测试集两边就会有数据泄漏指标虚高。复现这类实验时第一件事不是调模型而是确认对方的切窗协议到底是什么。4.2 对比方法怎么选实验对比通常是三个梯队。第一梯队是不做适配的基线直接把源模型丢到目标域上测试这是所有方法的下限参考。第二梯队是通用 SFDA 方法比如基于熵最小化的方法、基于聚类的无源适配方法、基于伪标签重加权的方法。这些方法不针对时间序列设计拿来对比正好可以说明为什么时间序列需要专用方法。第三梯队是时间序列专属的域适配方法包括一些带源数据的对抗方法以及少数无源版本。TERSE 的优势在这种对比里很容易体现通用 SFDA 方法通常会忽略变量间相关性在相关性结构发生偏移的数据上表现明显下滑而带源数据的方法虽然理论上界更宽松但真实场景里根本没有源数据可用只能作为如果还有源数据的上限参考。对比实验的核心结论一般落在差距上——不是精度差几个点而是哪些数据集上通用方法失效了而 TERSE 依然稳住这比总分高一点更有说服力。具体数值我就不在这里贴了不同实现、不同切窗方式下结果差异很大。我的建议是看论文时重点看三条一是对比方法有没有做公平调参二是消融实验是否拆分了时间和空间两个分支的贡献三是在相关性偏移明显的数据集上差距有多大。这三条比绝对值重要得多。5. 实操中踩过的坑和排查方法5.1 训练不稳定的排查方向无源适配训练最容易出现的一个现象是 loss 在下降但目标域准确率纹丝不动甚至下跌。这时候不要急着调学习率先检查伪标签的分布。把每个 epoch 的伪标签类别分布打出来如果某个类占了 70% 以上基本就是确认偏差已经把模型带偏了。处理方法提高阈值、加入类原型重建、或者给伪标签损失按类别频率做重新加权。另一个常见问题是空间分支训练初期剧烈震荡。图结构学习模块在第一批数据上通常没有稳定的梯度方向很容易把邻接矩阵学成一团噪声。排查方法很简单把邻接矩阵可视化出来看几条边是不是在乱跳如果是就给图学习加正则或者降低图分支的学习率让它比时间分支慢一拍。我在实践中的做法是给空间分支单独配一个优化器学习率设为主分支的十分之一训练稳定性明显改善。还有一个隐蔽的问题归一化层的统计量。源模型在源域上训练时BatchNorm 里累计的均值和方差到目标域上已经不适用了。如果目标域 batch 比较小重新估计的统计量方差会很大。无源适配任务里很多人会建议改用 LayerNorm 或者在适配初期冻结 BN 统计量等适配模块稳定后再放开更新。这个操作和模型结构强相关但值得作为排查方向记住。5.2 伪标签噪声与类别失衡的实战处理我之前在一次故障诊断任务上遇到过极端类别失衡目标域里正常样本占 85%三种故障一共只有 15%。直接用置信度阈值伪标签前几轮就把稀有故障类全部丢弃了后续原型更新里根本没有这几个类的位置模型最后直接退化成二分类。踩了这坑之后我总结了三层对策。第一层阈值按类自适应频次高的类阈值调高频次低的类阈值调低保证稀有类也有样本进入训练。第二层对原型做 EMA 更新给每个类维护一个指数移动平均的原型向量就算当前 batch 里没有某类样本历史原型信息也不会清零。第三层对伪标签的交叉熵做类别频率加权直接用1 / sqrt(cls_freq)这种重加权系数。三层一起上稀有类基本就能保住了。5.3 通道顺序与预处理一致性这个坑我在空间建模小节提过但值得单独再说一遍多变量时间序列的通道顺序一致性是所有复现工作里最容易翻车的点。源域数据集的通道顺序是风速、温度、振动、功率目标域数据集可能写成功率、风速、振动、温度如果代码里没有做通道映射空间branch学到的相关关系全错时间branch也因为特征空间偏移而跟着乱。现实中做跨部门或跨厂商数据时通道名往往还不是标准化的同样一个传感器有人叫temp1有人叫T_outlet_01。所以任何空间建模方法接入实际数据前第一步永远是建立规范化的通道 ID 映射表搞不定这个后面模型效果再好都是白搭。复现论文实验时也要先检查数据集描述里通道顺序是否一致别一上来就甩锅给模型。5.4 超参数速查表给一个我常用的配置参考不算金标准但作为起点够用超参数建议范围备注适配优化器Adam比 SGD 稳配合 warmup 更好适配初始学习率1e-4 ~ 5e-4主分支比源训练时低一个数量级空间分支学习率倍数0.1 ~ 0.5建议低于时间分支伪标签阈值0.7 起步逐步到 0.95按类别自适应更佳锚定阶段占比总 epoch 的 10% ~ 20%太长会影响适配速度分支一致性权重 alpha0.1 ~ 1.0分歧大时可适当加大蒸馏权重 beta0.5 ~ 2.0只在锚定阶段生效batch size64 ~ 256越大原型越稳定这套参数我在三个公开数据集上都能跑到不错的水平但你自己的数据分布偏移类型不同肯定还要再调。特别是如果目标域数据量很少比如就几百个样本建议把伪标签阈值整体调高牺牲召回换精度否则一点噪声都会被放大。6. 落地思考与扩展方向6.1 TERSE 适合什么场景从我自己的使用感受来看TERSE 这类方法最适合的场景有三个特征一是原始训练数据已经不可访问只有模型文件二是目标域数据量还比较可观至少是几百条以上的样本太少了适配不稳定三是变量之间的相关关系本身有信息量即类别的判别不仅靠单通道形态还靠通道间联动模式。反过来如果是单变量时间序列或者通道之间本来就接近独立那么额外做空间建模就是增加复杂度却不增加收益不如直接用轻量级的时间序列适配方法。这不算 TERSE 的缺点而是选型问题。任何方法都有它的适用边界搞清楚边界比硬套更重要。6.2 计算开销与工程化取舍双分支加上图学习训练开销确实比单分支方法高。我实测下来同样的数据量下TERSE 风格模型的适配时间大概是普通 SFDA 方法的两倍左右主要开销集中在图注意力层和分支一致性损失的反复前向计算。如果需要在边缘设备上做更新这个成本还是要掂量一下。工程化层面的一个折中思路是训练阶段用完整双分支部署或者推理阶段只保留效果更好的一个分支或者把两个分支蒸馏成一个单分支模型。我试过把双分支蒸馏成单分支精度大约掉一个点以内参数量和推理速度却能回归到普通模型的水平。对于有部署约束的团队这是一个非常实用的方案。6.3 后续可以怎么扩展顺着 TERSE 的思路我个人觉得有几个方向值得关注。第一个是开放集问题目标域里出现源域没有见过的新类别伪标签机制要怎么处理未知样本这比现有闭集设定更接近真实工业场景。第二个是测试时适配把适配过程压缩到推理阶段每个样本进来都做一次小步更新这对于流式数据场景很有意义。第三个是多源融合如果历史上曾经有过多个版本的源模型而不是单一模型怎么同时利用它们做更稳健的无源适配。这几个方向不算颠覆性创新但都是把 TERSE 这类框架从 Benchmark 推向真实现场必须补的短板。我自己的直觉是未来一两年时间序列无源适配会沿着更多约束 更少假设的方向发展一边引入更多自监督信号一边放宽对目标域数据量的要求。最后再分享一点个人体会。我在复现这个方法的过程中最花时间的反而不是模型结构本身而是把实验协议、通道顺序、伪标签调度这些看不见的细节逐个捋干净。无源域适配这个领域论文里写的差异是模型设计论文外决定成败的往往是这些脏活累活。如果你也在复现这类工作我建议先把自己的数据 pipeline 里所有泄漏和顺序隐患排查完再开始调模型——这个顺序反过来的话你省下的时间都会加倍还给 debug。
返回列表