联合域适应:破解轴承剩余寿命预测跨工况失效难题
简介围绕预测性维护与轴承疲劳寿命估计的研究型docx文档面向智能制造、设备故障诊断及人工智能应用方向的科研人员和工程师。以联合域适应技术为核心聚焦轴承在变工况、复杂环境下的剩余寿命预测难题提供从理论到实验的系统性梳理。资源为1个docx文件压缩包整体仅77KB内容紧凑、目录完整便于快速查阅。目前已有31人学习浏览。文档主体涵盖预测性维护基本概念、轴承磨损与疲劳机理、域适应原理及数据域偏移分析并重点阐述联合域适应算法设计、特征提取与寿命预测模型集成实验部分涉及数据集描述、评价指标、域适应效果验证及鲁棒性测试可支撑论文写作提纲搭建、算法原理理解或课题入门参考。1. 预测性维护技术里轴承寿命模型为什么总在换线后翻车同样的轴承型号同样的振动采集器A产线标定好的剩余寿命模型搬到B产线后预测结果直接失真时好时坏。这是预测性维护技术最常见的落地挫折实验室指标高换条线就打折。原因是跨工况、跨机台、跨批次存在明显的分布差异而标题里的联合域适应正是为治好「换线失效」设计的算法方案——它同时对齐源域与目标域的特征分布和寿命条件分布让模型带着A线学到的退化规律继续在B线工作。全文按「分布偏移原理 → 数据划分与特征 → 模型实现 → 避坑清单 → 验证方法」展开适合做设备健康管理的算法工程师和故障诊断方向研究生读完能基于公开数据集复现一版跨工况轴承寿命估计方案并知道哪些坑必须绕开。2. 联合域适应解决什么问题轴承RUL估计里的分布偏移与「联合」的含义2.1 域偏移为什么让寿命模型翻车分类域适应处理的是「同一类物体长在不同背景下」而轴承寿命估计不一样。轴承从健康到失效是连续的退化过程转速、负载、装配预紧、润滑条件、环境温度一变振动信号的整体分布就漂移了。把这种漂移写成数学语言源域和目标域的输入分布 P(Xs) 与 P(Xt) 不同条件分布 P(Y|Xs) 与 P(Y|Xt) 也不同。一般域适应只强调输入分布寿命估计里更要命的是条件分布。如果目标域里「中等退化」对应的振动形态和源域「严重退化」对上了模型会把健康的轴承报成快到寿命维护计划全部被打乱。这正是纯分类式域适应方法在RUL估计上翻车的原因。磁悬浮轴承、加工产线工业机器人内部轴承遇到的也是同一类问题只是传感器信号来源和退化速度不一样。我把轴承RUL的域偏移来源归结为三类工况偏移不同转速、径向力组合改变退化轨迹的形态全寿命周期长度也会变动、本体偏移同型号轴承的批次内差异、装配间隙、预紧力偏差、监测偏移传感器安装位置、测点共振、采样参数变化导致同一退化状态采到不同波形。任何一类偏移单独出现模型性能都会明显下滑三者在实际产线里常常同时出现。2.2 「联合」到底联合了什么为什么单边对齐不够「联合」在RUL估计语境下有两层含义。第一层是 JDAJoint Distribution Adaptation的思路显式地把分布对齐拆成边缘部分和条件部分。边缘部分拉近两个域的整体特征形态条件部分负责「寿命阶段一样时特征分布应类似」。对RUL任务来说条件分布就是给定一个剩余寿命百分比振动特征服从的分布。第二层是目标函数的联合回归损失、边缘分布对齐损失、条件分布对齐损失放进同一个优化框架里互相制衡。可以写成一个直观的三段式目标函数L_total L_rul(f(z_s), y_s) λ_e * D_e(z_s, z_t) λ_c * D_c(z_s|c, z_t|c)L_rul 是源域的有监督回归损失常用 MSE 或 Huber LossD_e 是边缘分布距离比如 RBF-MMDD_c 是条件分布距离c 表示寿命阶段分箱或者由目标域伪标签算出的权重。只做边缘对齐的问题在于特征整体拉近了但退化阶段的先后次序被打乱了新轴承和临近失效的轴承可能被压缩到同一片区域。只做条件对齐的问题在于目标域没有RUL标签条件对齐要依赖伪标签伪标签质量差时误差会逐轮放大。联合方案的好处是边缘对齐提供全局约束条件对齐提供局部约束二者互相纠错。实践中我一般先做边缘对齐拿到一个不算差的基线再引入条件对齐这样伪标签的起点更可靠训练曲线也更稳。2.3 三条实现路线的选型对比具体实现常见有三条路线拿RUL回归场景对比着看更清楚。路线核心思想RUL适配性实现成本典型坑DANN对抗域适应域判别器迫使特征无法区分来源中低对抗训练不稳定寿命曲线被打碎MMD/CORAL距离度量最小化两域特征的分布距离中低只对齐整体不分退化阶段联合域适应JDA类边缘分布条件分布回归损失联合高中超参多需要两阶段训练做RUL项目我的选择顺序是先把MMD基线跑通再加条件对齐对抗判别头只作为辅助验证不放在主损失里。理由是回归任务的对抗训练梯度噪声太大寿命曲线本身是平滑的退化轨迹对抗容易破坏相邻时间步的连续性。缺陷检测回答「有没有病」故障诊断回答「什么病」寿命估计回答「还能跑多久」后者对分布对齐的要求远高于前两者联合对齐是成本与效果的平衡点。3. 数据划分与特征工程把公开轴承数据集切出源域和目标域3.1 公开数据集怎么选三份常见数据集的定位差别要做可复现的跨工况RUL实验第一步不是写模型而是选对数据集。西安交大轴承数据集XJTU-SY是目前做疲劳寿命估计最合适的一份公开数据包含3种工况、15套轴承每套轴承都从正常状态持续运行到完全失效信号中完整记录了自然退化过程并且每段数据都有对应的剩余寿命信息。这套数据的价值就在于「自然退化」不是人为在 healthy 轴承上加工缺陷符合疲劳寿命估计算法的研究前提。华中科技大学轴承数据集和江南大学轴承数据集也常被提到。华中科技大学的数据集中部分实验组合包含从故障产生到退化的过程适合做故障诊断与寿命估计的交叉验证江南大学轴承数据集的突出特点是对不同工况和不同安装位置的覆盖适合用来做「域差异敏感性」实验也就是验证模型到底怕不怕工况变化。我的划分习惯是西安交大数据集做主实验另外两套数据做跨数据集校验验证算法不只在单一数据分布上成立。CWRU数据集虽然在故障诊断里经典但它主要是人为加工故障缺乏完整退化轨迹不建议作为疲劳寿命估计的基准。源域和目标域的划分必须遵守三条纪律工况不能交叉源域全部来自工况一目标域来自另外工况轴承ID不能交叉同一套轴承既出现在源域又出现在目标域算泄漏时间不能交叉前一段作为训练、后一段作为验证的时序切分在域适应实验里不成立。三条纪律里最容易犯的是第三条很多人习惯把每套轴承前80%的数据划给源域、后20%划给目标域这不叫跨域泛化叫时序外推两类问题难度完全不同。3.2 振动特征提取与寿命标签构造模型输入选择原始振动波形还是特征取决于你对可解释性的要求。原始波形输入配合1D CNN是主流做法特征输入配合梯度提升或MLP更适合快速验证「对齐到底有没有用」。我一般先跑特征版本因为特征可以把采样率、轴承型号等干扰因素先隔离掉之后再切回波形做端到端训练。下面这套特征提取代码给出了时域与频域的基础组合窗口长度和滑动步长都可以按工况调整import numpy as np import pandas as pd def sliding_features(signal, fs25600, win_len2048, step1024): rows [] n len(signal) for start in range(0, n - win_len 1, step): seg signal[start:start win_len] t seg - seg.mean() mag np.abs(np.fft.rfft(t)) / win_len freq np.fft.rfftfreq(win_len, 1.0 / fs) rows.append({ rms: float(np.sqrt(np.mean(t ** 2))), peak: float(np.max(np.abs(t))), kurtosis: float(np.mean((t - t.mean()) ** 4) / (np.std(t) ** 4 1e-12)), crest_factor: float(np.max(np.abs(t)) / (np.sqrt(np.mean(t ** 2)) 1e-12)), fc: float(np.sum(freq * mag) / (np.sum(mag) 1e-12)), rmsf: float(np.sqrt(np.sum(freq ** 2 * mag) / (np.sum(mag) 1e-12))), }) return pd.DataFrame(rows)这段代码逻辑上做了三件事先用去均值避免直流偏置干扰然后在时域计算 RMS、峭度和峰值因子再对幅值谱计算重心频率和频率 RMS。RMS追踪全局退化幅度峭度对早期微弱冲击敏感重心频率捕获频带随磨损的转移。选择这些特征的根本原因是它们物理含义明确当域适应把两域特征拉近时你能判断对齐的到底是退化信息还是噪声。寿命标签有两种常用构造方式。第一种是剩余寿命百分比 η 1 - t/T其中T是该轴承从开始运行到失效的总时长适合做回归归一化第二种是分段阶段标签把η划分成若干区间适合做条件分布对齐里的分箱操作。公开数据集通常直接给出每段信号的剩余寿命你只需要把它按窗口起始时间映射到每个特征行。实际处理时我还会构造一个「run_id」字段标记每个特征行来自哪套轴承后面划分数据集时靠它来避免泄漏。3.3 按轴承ID划分训练与验证不是按滑窗划分这个错误我早期踩过一次后果是验证集RMSE极其好看换了工况直接崩溃。问题出在划分方式把滑窗切出的所有特征行合并后全局随机分成训练集和验证集。同一个轴承相邻窗口的振动形态高度相关训练集和验证集看似独立实际上包含了大量重叠信息模型相当于开卷考试。# 正确做法先按 run_id 切分再做滑窗特征 runs list(set(df[run_id])) np.random.shuffle(runs) train_runs runs[:12] val_runs runs[12:14] test_runs runs[14:] train_mask df[run_id].isin(train_runs) val_mask df[run_id].isin(val_runs) test_mask df[run_id].isin(test_runs) X_train, y_train df.loc[train_mask, feats].values, df.loc[train_mask, rul_pct].values这套划分逻辑的关键在于先随机打乱轴承ID再按ID归属划分数据集。这样源域和目标域内的数据都来自不同的轴承实体模型学到的才是跨轴承的退化规律而不是单套轴承的个体波形记忆。西安交大数据集里有工况标签跨工况实验应确保源域和目标域的 run_id 完全不相交同时目标域可以包含少量有标签样本做微调也可以完全不提供标签对应无监督域适应设定。4. 联合域适应寿命估计模型结构设计与最小复现4.1 网络结构特征提取器、回归头与域判别头的职责切分联合域适应模型在结构上可以拆成三个模块。特征提取器把原始振动特征映射成高维特征向量回归头在特征之上做RUL预测域判别头负责判别特征来自源域还是目标域。关键设计是梯度反转层正向传播时域判别头正常计算损失反向传播时梯度取反迫使特征提取器学习「让域判别器无法区分来源」的特征表达。与纯对抗方法相比我在RUL任务上会减少对抗损失权重同时加大边缘分布距离的权重因为对抗判别器在回归任务里梯度噪声大。更稳定也更容易解释的做法是用多核RBF-MMD做边缘对齐用分箱加权MMD做条件对齐对抗判别头只作为辅助约束。联合损失可以写成loss mse_loss(pred_rul, rul_label) \ lambda_e * mmd_rbf(z_src, z_tgt) \ lambda_c * conditional_mmd(z_src, z_tgt, pseudo_label)其中 conditional_mmd 需要先对目标域打伪标签也就是先跑一轮基线模型得到目标域每个样本的寿命预测值再按预测值分箱计算局部MMD。两阶段的好处是目标域伪标签的起点不是瞎猜而是来自一个已经做过边缘对齐的模型。4.2 核心模型定义与训练循环下面是可运行的最小实现骨架输入特征维度按上一章特征工程输出对齐。模型层数不多突出结构主干。import torch import torch.nn as nn class FeatureExtractor(nn.Module): def __init__(self, in_dim6, hidden64): super().__init__() self.net nn.Sequential( nn.Linear(in_dim, hidden), nn.BatchNorm1d(hidden), nn.ReLU(), nn.Linear(hidden, hidden), nn.ReLU(), ) def forward(self, x): return self.net(x) class RULHead(nn.Module): def __init__(self, hidden64): super().__init__() self.net nn.Sequential( nn.Linear(hidden, 32), nn.ReLU(), nn.Linear(32, 1), ) def forward(self, z): return self.net(z).squeeze(-1) class GradReverse(torch.autograd.Function): staticmethod def forward(ctx, x): return x.view_as(x) staticmethod def backward(ctx, grad_output): return -grad_output特征提取器用了两层带 BatchNorm 的 MLP。BatchNorm 在域适应里作用比较微妙它会把每个 batch 的均值方差拉到标准范围一定程度上削弱了域差异但也可能把退化趋势非线性变形。我的做法是先不加 BatchNorm 跑一遍效果不好再加而不是相反。RULHead 回归头的最后一层不加激活函数让输出直接落到 0~1 区间。class DomainHead(nn.Module): def __init__(self, hidden64): super().__init__() self.net nn.Sequential( nn.Linear(hidden, 16), nn.ReLU(), nn.Linear(16, 1), ) def forward(self, z): return self.net(z).squeeze(-1) def mmd_rbf(z_src, z_tgt, sigma1.0): def _kernel(a, b): sq torch.cdist(a, b) ** 2 return torch.exp(-sq / (2 * sigma ** 2)) return _kernel(z_src, z_src).mean() \ _kernel(z_tgt, z_tgt).mean() \ - 2 * _kernel(z_src, z_tgt).mean()RBF-MMD 的实现里核带宽 sigma 取值对结果影响很大。scikit-learn 风格的启发式做法是用两个域特征拼接后的中位数距离作为 sigma这样特征尺度变了 sigma 能跟着自适应。条件MMD可以复用同样的函数只是输入不再是全部特征而是按伪标签分箱后某个箱内的源域特征与目标域特征。箱数一般取 8~10太少分不清退化阶段差异太多每个箱内样本不足MMD估计方差过大。4.3 联合损失训练循环与关键参数训练循环采用一阶段联合优化伪标签每 N 个 epoch 更新一次。N 取 5既避免频繁更新带来的振荡也不至于整个训练过程都在用过时的伪标签。def train_one_epoch(model, src_loader, tgt_loader, opt, epoch, lambda_e, lambda_c): fe, rul_head, dom_head model fe.train(); rul_head.train(); dom_head.train() for (xs, ys), (xt, _) in zip(src_loader, tgt_loader): zs, zt fe(xs), fe(xt) pred rul_head(zs) loss_reg nn.functional.mse_loss(pred, ys) loss_domain nn.functional.binary_cross_entropy_with_logits( dom_head(GradReverse.apply(zs)), torch.ones_like(pred)) \ nn.functional.binary_cross_entropy_with_logits( dom_head(GradReverse.apply(zt)), torch.zeros_like(pred)) pseudo torch.clamp(rul_head(zt).detach(), 0.0, 1.0) bins torch.bucketize(pseudo, torch.linspace(0, 1, 9)) loss_cond 0.0 for b in range(8): ms, mt (bins[:len(zs)] b), (bins[len(zs):] b) if ms.sum() 0 and mt.sum() 0: loss_cond loss_cond mmd_rbf(zs[ms], zt[mt]) loss loss_reg 0.05 * loss_domain \ lambda_e * mmd_rbf(zs, zt) lambda_c * loss_cond opt.zero_grad(); loss.backward(); opt.step()训练循环中值得说明的参数有三个。对抗损失权重固定取 0.05只作为辅助防止梯度反转层太强打乱回归头的收敛。lambda_e 从 0.1 开始、每 20 个 epoch 乘以 1.5 退火到 1.0 封顶先让模型学到基本的退化规律再逐步加强域对齐类似课程学习的思路。lambda_c 直接固定为 0.5条件对齐发挥局部校正作用权重太高会强行把伪标签可能误差较大的目标域样本拉向错误区域。batch size 设为 64学习率 1e-3 配 Adam约 120 个 epoch 能稳定。如果训练曲线在 40 轮附近出现 loss 振荡第一件事不是调 lambda而是检查目标域伪标签分布是否在某一轮更新之后突然集中到同一个分箱。5. 落地避坑记录联合域适应从训练到部署最容易翻车的5个细节5.1 滑窗重叠导致验证集指标虚高现象模型在验证集上RMSE低得惊人换到另一工况立刻退化训练过程本身没有任何异常。原因滑窗特征切分后全局随机划分同一个轴承的邻近窗口同时进入训练和验证集模型间接看到了验证数据的退化趋势。解决按run_id划分数据集或者干脆把滑窗步长加大到与窗口长度相同让相邻样本不重叠。划分代码在第三章已给出这是所有基于振动信号的寿命估计项目里最容易翻车的点。5.2 MMD和对抗损失叠加后特征提取器输出崩塌现象训练 30 轮左右特征提取器输出向一个超球面收缩每个样本的特征方差趋近于零域对齐距离确实降了但RUL回归头也跟着失明。原因多核MMD和对抗损失共同迫使特征矩完全拉平等价于把退化阶段信息也一块儿抹掉了。解决给边缘对齐损失设置下界约束或者用特征方差正则项维持特征表达的离散度最简单的方式是把对抗权重降到0.01以下、lambda_e限制在0.5左右并监控特征空间的每维方差不能低于初始值的十分之一。5.3 目标域伪标签错误在条件对齐里被不断放大现象条件对齐后的RMSE反而比只做边缘对齐更差且越训练越差。原因目标域没有真实标签条件对齐依赖上一轮模型打出的伪标签早期伪标签整体偏低把很多中寿命样本错误归入临近失效的箱条件MMD把错误映射当成了对齐目标。解决伪标签只参与条件MMD的样本划分不参与梯度更新另一个技巧是每5个epoch才更新伪标签避免模型短期波动带偏分箱。如果这个坑仍然出现就先砍掉条件对齐项把边缘对齐和回归损失跑到收敛再用这个模型重新生成伪标签再开启联合训练。5.4 用全样本均值方差归一化抹掉了退化趋势现象两个域单独做Z-score归一化后模型几乎学不到退化趋势寿命预测集中在均值附近。原因不同工况下振动信号的均值和方差差异很大各自归一化等于把退化引起的幅值变化全部压缩到相同尺度模型只看到固定范围内的波动看不到原始退化幅度。解决统一使用源域训练集的均值和方差对目标域做变换或者改用中位数滤波后的相对振幅作为特征。后者对传感器灵敏度漂移更鲁棒。5.5 RMSE很高但维护决策完全不可用现象模型在测试集上平均RMSE看起来不错可实际部署时该提前报废的轴承没报警不该报警的反而误报。原因RMSE对预测误差的处理是线性的高估和低估RUL的代价一样而维护场景里低估寿命可能导致突发停机高估寿命可能导致备件浪费。解决改用指数型评分函数给「预测寿命大于真实寿命」的错误更高的惩罚权重具体公式在下一章给出。评估阶段还应按寿命阶段分段统计重点关注寿命后 20% 区间。6. 验证的进阶做法用维护决策的视角给寿命估计评分实验室里RMSE从0.15降到0.12不意味着产线会少一次停机。PHM领域常用的评分函数把预测误差映射成维护代价核心思想是低估值可以容忍高估值要重罚因为高估寿命意味着设备在预计报废时间之后继续运行一旦失效就是非计划停机。用分段评估看模型的失效预警能力我用下面这段代码快速得到各寿命阶段的误差画像def rul_score(y_true, y_pred): h y_pred - y_true # 预测值大于真实值 高估寿命 return np.where(h 0, np.exp(-h / 13.0) - 1.0, np.exp(h / 10.0) - 1.0) stage np.select([y_true 0.7, y_true 0.4, y_true 0.2], [early, mid, late], defaultcritical) for s in [early, mid, late, critical]: mask stage s print(s, np.mean(rul_score(y_true[mask], y_pred[mask])))除此之外我现在做RUL项目还固定会做三件事第一把目标域切出10%的「锚点数据」做实标签微调验证联合域适应在有少量目标域标签时的上限第二用多套公开数据集做一对多验证即一套工况做源域、多套其他工况做目标域模型在每组目标域上的性能衰减幅度比单点数值更有说服力第三记录特征空间在训练前后的分布变化用t-SNE做定性检查确认对齐没有把退化方向打乱。这三条已经成为我的项目验收底线前两板斧保指标第三板斧保可信。希望这篇偏实战的记录能帮你在联合域适应这条路上少走几步弯路把模型真正送进产线。本文还有配套的精品资源点击获取