哈里斯鹰优化VMD-CNN的轴承故障诊断全流程解析
简介面向轴承故障诊断与卷积神经网络结合的工程资源适合信号处理方向的研究生、工程师及机器学习初学者。方法采用高阶变分模态分解对西储大学不同转速下的驱动端振动信号进行多层次分解提取本征模式函数并削弱噪声再由CNN自动学习空间特征完成磨损、裂纹等故障模式的分类识别。压缩包共15个文件约60.73MB核心为9个.m脚本覆盖主程序、特征提取、网络正则化模块和五种适应度函数3个xlsx存放不同转速的原始振动数据1个xlsx为HO-VMD特征提取后的数据集便于对比验证另附1个txt安装说明和1个pdf河马优化算法论文辅助复现与理解参数寻优原理。目前已有203人学习下载可直接运行整个诊断流程也可基于不同转速数据和多种熵类适应度函数进一步调参适用于课题预研、入门实践及算法改进。1. 西储大学轴承故障诊断HO-VMD-CNN这条路解决什么问题一台风机轴承的振动信号里藏着故障的类型、位置和严重程度但原始波形根本不适合直接扔给神经网络。很多团队在西储大学CWRU轴承数据集上做实验CNN结构改了一轮又一轮准确率卡在八九成上不去问题往往出在前处理信号没分解干净故障冲击被噪声淹没。HO-VMD-CNN 是这类问题的标准解法——HO哈里斯鹰优化自动给 VMD 选最优的模态数和惩罚因子VMD 把原始振动信号拆成一簇有物理含义的 IMFCNN 再从分解后的多通道信号上学判别特征。这套流程适合手里有振动数据、想把故障类别自动分出来的人尤其适合被 VMD 两个参数折磨过的调参工。2. VMD为什么需要HO来救从模态混叠到参数黑洞VMD变分模态分解把一段振动信号同时拆成 K 个离散模态每个模态被约束在一个窄频带里。背后的优化目标是所有模态带宽之和最小同时要求 K 个模态加起来能完整还原原始信号。这个思路比 EMD经验模态分解干净EMD 靠极值插值递归剥皮对噪声和采样率敏感容易出现模态混叠VMD 转成一个带约束的变分问题用交替方向乘子法迭代求解分解结果稳定得多。轴承故障的典型特征是周期性冲击冲击在频域上会产生以故障特征频率为中心的一簇边带VMD 天然适合把这些频带分离开。VMD 的理论形式也不复杂对每个模态 u_k 做 Hilbert 变换得到解析信号再乘上指数项把频谱搬到基频附近最后求梯度范数。迭代过程中中心频率 ω_k 和模态 u_k 交替更新直到满足收敛容差。工程里不需要自己实现这么一整套流程直接用现成的 vmdpy 库就行但要理解两个关键参数K 是模态总数alpha 是带宽惩罚因子。这两个参数不经过寻优直接拍脑袋定后面的 CNN 做得再漂亮也白搭。2.1 VMD在轴承信号上到底做了什么以 CWRU 驱动端 12 kHz 采样加速度信号为例正常轴承能量分散在全频带看不到明显峰值内圈故障时冲击调制出的高频共振带和低频特征频率带同时出现。VMD 分解出的第一个模态往往捕获幅值优势频带后面几个模态捕获谐波和残余噪声。K 设小了故障冲击和噪声被塞进同一个模态CNN 学到的是混叠后的复合特征K 设大了一个真实频带会被拦腰切成两段出现没有物理意义的虚假模态。alpha 控制模态带宽的紧致程度alpha 太小模态带宽过宽相邻模态互相重叠alpha 太大模态被压得过窄迭代不易收敛还可能丢掉冲击的边带成分。这两个参数互相耦合单靠看包络谱人工判断眼睛根本不够用。参数影响对象典型表现K模态数模态数量K 过小导致模态混叠、能量交叉K 过大会出现无意义的虚假模态alpha惩罚因子模态带宽过小带宽宽、模态重叠过大带宽窄、迭代慢或发散tau噪声容忍重建保真度工程上一般设 0依靠保真项约束init初始化方式收敛路径用 1均匀初始化避免过度依赖首模态VMD 的输出是一组模态数组 ushape 是 (K, 信号长度)每个模态都是一条一维时域波形。后面做 CNN 输入时这 K 个模态就是 K 个通道和图像的 RGB 三通道类似。区别在于图像通道是像素矩阵这里每个通道是独立的时间序列长度可以人为截断。这意味着 CNN 的结构要选一维卷积而不是二维卷积输入张量是 (batch, K, length)。2.2 包络熵把分解质量变成一把刻度尺要让优化算法去搜 K 和 alpha先得有一个数值指标能评价“这组参数分解得好不好”。最常见的指标是包络熵。计算方式是对模态信号做 Hilbert 变换求出包络 a(t)归一化成概率分布 p_i a(i) / Σa然后算信息熵 E -Σ p_i · log p_i。正常轴承振动包络接近随机噪声概率分布平坦熵值高故障轴承的冲击在包络上呈现稀疏的尖峰概率分布集中在少数点上熵值低。VMD 参数选得好时故障模态的包络熵会比欠分解参数低一大截这就把“分解质量”变成了一个可以数值比较的标量。实际应用中每次寻优都要对整段训练信号跑一次 VMD算每个模态的包络熵。常见做法是取 K 个模态里的最小包络熵作为该组参数的适应度因为轴承故障冲击的能量往往集中在一个主导模态上最小包络熵能捕获这个主导故障模态。也有文献取平均包络熵或加权熵思路一样只是尺度不同。用包络熵做适应度有个隐含前提包络熵越低故障冲击越突出后续分类越容易。这个前提在大部分轴承数据上成立但不是绝对成立后面第 5 章会专门讲它的边界。2.3 人工试参和网格搜索为什么都不够用手工试参的流程是选一组 K 和 alpha跑 VMD看各 IMF 的包络谱比对特征频率换一组再跑。CWRU 每个类别采样时间约 10 秒按 2048 点滑窗能切出几百个样本一次 VMD 耗时几十到几百毫秒试 8 组参数乘 10 个类别半天就过去了。最麻烦的是 K 和 alpha 互相影响K5 配合 alpha2000 时看起来不错但 K6 时 alpha2000 反而过分解单独调一个参数没法收敛到好组合。网格搜索能系统覆盖参数空间但组合数膨胀K 取 3 到 10alpha 按对数间隔取 15 个值就是 8×15120 次 VMD。对一条 12 kHz、10 万点的信号120 次分解足够跑一个多小时而且网格是离散的最优 alpha 往往不在网格点上。更关键的是CWRU 有多种负载和多个故障直径不同数据段的最优 K 和 alpha 不一定相同网格搜索只能针对某一段信号换一段信号又要重来。把参数选择当成黑盒子优化问题用 HO 这类群体智能算法直接搜是目前最省事的做法。3. 用HO为VMD找最优参数优化映射与可复现代码3.1 哈里斯鹰优化怎么映射到VMD寻优哈里斯鹰优化Harris Hawks Optimization简称 HO是近年比较常用的群体智能算法模拟哈里斯鹰在沙漠中捕猎兔子的行为。兔子位置代表当前最优解鹰群在探索阶段随机栖息寻找兔子在开发阶段根据兔子逃跑能量做软包围、硬包围、渐进式俯冲。把它用到 VMD 参数寻优上一个鹰的位置就是一组候选参数 [K, alpha]适应度就是跑完 VMD 得到的包络熵。鹰群在 K-alpha 构成的二维平面上移动每一轮迭代更新所有鹰的位置然后比较每一处的适应度保留当前最优兔子位置。K 本身是整数但 HO 的位置更新是连续值。常见处理方式是把 K 当连续变量参与鹰的位置运算评价适应度时再 round 成整数。这样做的好处是算法不用做离散编码坏处是 K 的梯度几乎为零可能出现 K 在连续几次迭代里都不变。如果发现 K 一直卡在同一数值可以改用离散映射把 K 编码成 [0,1] 连续值解码时映射到 3 到 10 的整数区间。两种做法我都试过对 CWRU 数据来说连续取整通常够用因为 alpha 才是真正敏感的参数。3.2 边界设计K和alpha的范围为什么要这样定边界设得不对寻优结果是废的。CWRU 12 kHz 数据上K 取 3 到 10 比较稳妥小于 3 会把正常信号和故障冲击压在一起大于 10 噪声会被逐条拆成独立模态。alpha 取 500 到 5000alpha 太小带宽约束失效模态之间互相混叠alpha 太大迭代代价成倍上升还可能不收敛。另一个容易忽略的细节是采样方式alpha 在数千量级跨越很大初始化时要在指数空间采样即 np.logspace(np.log(500), np.log(5000), n)而不是线性空间的均匀分布。否则 alpha 大概率落到 500 到 2000 之间5000 附近几乎永远采样不到搜索空间被实际拉窄。种群规模和迭代次数也要克制。种群数量 10 到 20 个迭代 20 到 30 次一次完整寻优要跑 200 到 400 次 VMD。对一条 12 kHz、几万点的信号来说这个量级在几分钟到十几分钟可以接受。如果信号长度超过 20 万点建议把种群降到 6、迭代降到 15先对一小段代表性信号寻优再把最优参数应用到全部信号上不要试图一次寻优吃下整条长信号。3.3 HHO-VMD寻优代码与参数说明下面是基于 vmdpy 和 numpy 的完整寻优代码。vmdpy 是 VMD 的常见 Python 封装pip install vmdpy 就能装。如果环境装不上把 VMD 函数体换成自己实现的变分模态分解即可接口不变。import numpy as np from scipy.signal import hilbert from vmdpy import VMD def envelope_entropy(signal): # 对信号取希尔伯特包络归一化后计算信息熵 amp np.abs(hilbert(signal)) amp amp / (np.sum(amp) 1e-12) return -np.sum(amp * np.log(amp 1e-12)) def vmd_cost(pos, signal): # pos 就是一组 [K, alpha]K 转成整数再进入 VMD k int(round(pos[0])) alpha float(pos[1]) # 参数顺序signal, alpha, tau, K, DC, init, tol # tau0 表示不额外引入噪声控制DC0 不提取直流init1 均匀初始化 try: u, _, _ VMD(signal, alpha, 0, k, 0, 1, 1e-7) except Exception: # VMD 发散时返回一个大数作为惩罚 return 1e6 # 取 K 个模态里最小的包络熵作为适应度 entropy np.array([envelope_entropy(m) for m in u]) return np.min(entropy) def hho_vmd(signal, bounds, pop10, iterations20, seed1): rng np.random.default_rng(seed) dim len(bounds) # 指数空间初始化 alpha线性空间初始化 K lo np.array([b[0] for b in bounds]) hi np.array([b[1] for b in bounds]) pos np.zeros((pop, dim)) for d in range(dim): if d 1: # alpha 维度用对数均匀采样 log_lo, log_hi np.log(lo[d]), np.log(hi[d]) pos[:, d] np.exp(rng.uniform(log_lo, log_hi, pop)) else: pos[:, d] rng.uniform(lo[d], hi[d], pop) # 初始化兔子位置全局最优 best pos[0].copy() best_val vmd_cost(best, signal) for t in range(iterations): for i in range(pop): r rng.random() if r 0.5: # 探索阶段随机跳向种群里的其他位置或当前最优 if rng.random() 0.5: q rng.integers(0, pop) pos[i] pos[q] - rng.random() * np.abs(pos[q] - pos[i]) else: pos[i] best - rng.random() * np.abs(best - pos[i]) else: # 开发阶段这里简化成朝最优位置收缩完整的 HHO 有四种包围策略 pos[i] best - 0.2 * np.abs(best - pos[i]) * rng.random() # 越界处理直接裁剪到边界 pos[i] np.clip(pos[i], lo, hi) # 评估本轮每个鹰位置 for i in range(pop): val vmd_cost(pos[i], signal) if val best_val: best_val val best pos[i].copy() return best, best_val # 示例signal 是 CWRU 的一条整段振动信号12kHz长度至少几万点 # bounds 顺序是 [K_min, K_max], [alpha_min, alpha_max] # best_params, best_entropy hho_vmd(signal, bounds[[3, 10], [500, 5000]])这段代码有几个关键设计。vmd_cost 里把 K round 成整数alpha 保留浮点VMD 调用参数顺序不能错尤其是 tau 和 DC工程上固定为 0。适应度取最小包络熵而不是平均包络熵原因前面说过轴承故障能量集中在一个主导模态。HHO 的探索阶段用了两种随机跳跃开发阶段简化成收缩包围不是文献里的完整四策略但对二维参数寻优已经够用主要是收敛快、代码短。种群设 10迭代设 20总共 200 次 VMD 调用一条 5 万点信号大约 3 到 5 分钟跑完。如果想把 K 也处理得更细腻可以改成离散映射pos[:,0] 约束在 [0,1]解码时 k 3 int(round(pos[:,0] * 7))这样 K 的每一步变化都能被算法感知到。代价是搜索空间变成一深一浅两条腿收敛速度略降。建议先跑一次连续取整版如果发现 K 始终不变且包络熵不理想再换离散映射。4. 分解结果如何喂给CNN样本构造与训练配置4.1 从CWRU原始文件到训练样本先分解再滑窗CWRU 数据集按故障位置和故障直径组织文件。常见做法是取 12 kHz 驱动端加速度信号做十分类正常用 97.mat0 马力内圈故障用 105、106、107 对应 0.007/0.014/0.021 英寸滚动体故障用 118、119、120外圈故障用 130、131、132。外圈故障在数据里有 3 点钟、6 点钟、12 点钟三个方向通常只用其中一个方向比如 3 点钟避免类别数膨胀。每个文件信号长度约 12 万点对应 10 秒采样样本量完全够用。关键时序是先分解再滑窗不是先滑窗再分解。对整段信号做一次 VMD得到 (K, 整段长度) 的模态数组然后从模态数组上滑窗取 (K, 2048) 的样本。这样做的好处是 VMD 的边界效应只出现在整段信号的开头和结尾中间所有窗口的分解质量一致。如果先滑窗再逐窗口分解每个窗口两端都有边界效应等于每个样本都被污染。import numpy as np from vmdpy import VMD def make_samples(signal, label, opt_k, opt_alpha, window2048, overlap0.5): # 对整段信号做一次 VMD得到 opt_k 个模态 u, _, _ VMD(signal, opt_alpha, 0, opt_k, 0, 1, 1e-7) # u shape 是 (opt_k, len(signal)) # 丢弃开头和结尾各 256 点规避边界效应 u u[:, 256: -256] step int(window * (1 - overlap)) samples [] labels [] for start in range(0, u.shape[1] - window, step): samples.append(u[:, start:start window]) labels.append(label) return np.stack(samples), np.array(labels)样本标签是数字编码十类对应 0 到 9。滑窗重叠率用 0.5窗口 2048 点在 12 kHz 采样下约等于 0.17 秒包含足够多的冲击周期。这里 window 不用设太大2048 点对 CNN 来说既保留了局部冲击细节又不至于让特征图尺寸过大。样本量方面一条 12 万点信号去掉两端边界后按 1024 步长能切出约 110 个样本10 个类别合计 1000 个样本已经能支撑一个小型 CNN 训练。训练集和测试集的划分要格外小心。不能直接把全部样本随机打乱再切因为相邻窗口高度相关训练集和测试集会互相“抄答案”。正确做法是按文件来源切分每个类别的 10 秒信号前 60% 只进训练集后 40% 只进测试集再在训练集内部做 80/20 的验证集划分。这样测试样本和训练样本来自不同的时间片段才有评估意义。4.2 1D-CNN结构通道数、核大小与感受野CNN 的输入是 (batch, K, 2048)K 就是 VMD 寻优得到的模态数通常在 4 到 8 之间。因为输入是一维时间序列所以用一维卷积 Conv1d。第一层卷积核大小建议设大一点比如 kernel_size64、stride4。理由是一个冲击周期在 12 kHz 下大约持续 50 到 150 点64 点的卷积核能覆盖住半个到一个冲击周期相当于让第一层先做一次波形模板匹配。后续卷积核缩小到 3负责组合局部特征。全连接层不要堆太深。轴承故障分类任务的特征复杂度远低于图像识别两层全连接足够第一层 256第二层 10。全连接层多了训练集准确率能到 100%测试集反而掉 2 到 3 个百分点典型的过拟合。Dropout 放 0.5只在全连接前加一层即可。下面是模型的 PyTorch 定义。import torch import torch.nn as nn class VMDCNN(nn.Module): def __init__(self, n_channels, n_classes10): super().__init__() # 一维卷积分支K 个模态当作 K 个通道 self.branch nn.Sequential( nn.Conv1d(n_channels, 32, kernel_size64, stride4, padding32), nn.BatchNorm1d(32), nn.ReLU(), nn.MaxPool1d(2), nn.Conv1d(32, 64, kernel_size3, stride2, padding1), nn.BatchNorm1d(64), nn.ReLU(), nn.AdaptiveAvgPool1d(128) ) self.fc nn.Sequential( nn.Flatten(), nn.Linear(64 * 128, 256), nn.ReLU(), nn.Dropout(0.5), nn.Linear(256, n_classes) ) def forward(self, x): return self.fc(self.branch(x))这个结构很常规没有花哨模块。第一层 padding32 是为了补 kernel_size64 带来的长度损失配合 stride4 把 2048 点输入压到 512 左右。中间那层 Conv1d 的 stride2 继续压缩分辨率最后一层 AdaptiveAvgPool1d 把特征图统一到固定长度这样即使窗口长度变了全连接层的输入维度也不变。想用多尺度 CNN 做并行卷积也是可以的但对 CWRU 这个规模的数据集作用不大单分支结构已经足够很多实验结果都印证了这一点。4.3 PyTorch训练循环与超参配置训练超参按常见动作维护习惯来设Adam 优化器学习率 1e-3batch size 64epoch 50weight decay 1e-4遇到验证集连续 5 轮不升就把学习率乘 0.5。50 轮并不是固定值早停机制会在验证集不再提升时提前截断避免浪费时间。import torch def train_vmd_cnn(model, train_loader, val_loader, epochs50, lr1e-3, devicecuda): model.to(device) opt torch.optim.Adam(model.parameters(), lrlr, weight_decay1e-4) lr_scheduler torch.optim.lr_scheduler.ReduceLROnPlateau(opt, factor0.5, patience3) loss_fn nn.CrossEntropyLoss() for epoch in range(epochs): model.train() total_loss 0.0 for x, y in train_loader: x, y x.to(device), y.to(device) opt.zero_grad() pred model(x) loss loss_fn(pred, y) loss.backward() opt.step() total_loss loss.item() * x.size(0) model.eval() val_correct 0 val_total 0 with torch.no_grad(): for x, y in val_loader: x, y x.to(device), y.to(device) pred model(x) val_correct (pred.argmax(1) y).sum().item() val_total y.size(0) val_acc val_correct / val_total lr_scheduler.step(val_acc) # 实际项目里可以把 TQDM 进度条和模型保存加在这里训练循环本身没有特别之处重点在于配置。batch size 用 64因为样本本身只有一两千用 128 会减少梯度更新次数收敛变慢。学习率初始 1e-3 是 Conv1d 任务最稳的起点低于 5e-4 收敛太慢高于 2e-3 容易振荡。weight_decay 主要约束全连接层卷积层参数共享本身就带正则效果不用额外加太多。这里的 ReduceLROnPlateau 的 patience 是 3意思是验证集连续 3 轮不升就降学习率比固定 step 降学习率更稳。4.4 测试集评估混淆矩阵与准确率训练完在测试集上做最终评估输出准确率和混淆矩阵。评估时只跑前向不计算梯度预测结果和真实标签对比。常见的十类问题里最容易混的是内圈故障 0.007 英寸和滚动体故障 0.007 英寸两者都是轻微故障冲击幅值小、特征频率接近CNN 很难区分。如果有几个类互相混淆不要急着改网络结构先把对应类别的 VMD 模态画出来看看是不是分解不干净。import numpy as np from sklearn.metrics import confusion_matrix test_correct 0 test_total 0 all_pred [] all_true [] model.eval() with torch.no_grad(): for x, y in test_loader: x, y x.to(device), y.to(device) pred model(x) test_correct (pred.argmax(1) y).sum().item() test_total y.size(0) all_pred.extend(pred.argmax(1).cpu().numpy()) all_true.extend(y.cpu().numpy()) print(ftest accuracy: {test_correct / test_total:.4f}) cm confusion_matrix(all_true, all_pred) print(cm)测试准确率能到 95% 以上说明流程基本通了但别急着高兴。下一步要看跨负载表现这一步能筛掉很多只在特定转速下有效的假方案。测试集评估之后模型就不要再回头调参了否则测试集就变成了训练集的一部分后面的结果全是水分。5. HO-VMD-CNN最常翻车的5个环节现象与排查5.1 坑1K上限设大VMD直接发散现象K 上限设到 12 或 15寻优过程中 VMD 返回的模态数组里出现 NaN或者分解结果能量远大于原始信号包络熵突然跳到一个荒谬的大数。原因K 超过信号实际可分的频带数量后交替方向乘子法会把噪声一个点一个点地拆开迭代数值稳定性崩盘。解决把 K 的上限压到 10同时在 vmd_cost 里显式检查返回值是否包含 NaN一旦发现就返回一个很大的惩罚值让优化算法自动绕过这些区域。我见过有人把 K 上限设到 20跑了三个小时全部白费。5.2 坑2包络熵局部最优两次寻优结果对不上现象固定随机种子跑出 K6、alpha2800换一个种子变成 K8、alpha1200两者的包络熵差距不到 5%。原因包络熵曲面不是光滑的单峰函数很多参数组合的评价结果几乎一样HO 收敛到哪个峰取决于初始种群位置。解决同一信号跑三次寻优每次换随机种子取包络熵最小且出现次数最多的参数组合或者把寻优结果当作起点在邻域内再用几个固定组合排查。不要期待一次寻优就得到唯一最优解HO 的本质是给出一个很好的候选区间。5.3 坑3样本切分重叠测试准确率虚高现象全局随机切分样本时测试准确率 98%改成按时间片划分后掉到 91%模型结构一个字母没改。原因滑窗重叠率 0.5 时相邻样本有 50% 长度的波形完全一样随机划分会造成训练集和测试集里出现“孪生样本”测试准确率虚高。解决按原始文件的时间段划分每个文件前 60% 进训练集、后 40% 进测试集再做数据增强或交叉验证也要以文件为单位分组。很多人用 sklearn 的 train_test_split 直接切默认随机打乱这个坑踩得无声无息。5.4 坑4换个负载准确率掉一半现象0 马力数据训练验证 99%拿到 2 马力数据上直接掉到 70%。原因CWRU 的负载档位对应不同转速负载增大后转速下降故障特征频率跟着偏移振动幅值也变大模型在训练集里只见过 0 马力的统计特征。解决训练集里混合 0、1、2 马力数据测试集放 3 马力如果目标是单负载部署至少对每个样本做 z-score 归一化消除幅值差异。特征频率偏移靠归一化解决不了只能靠多负载数据覆盖转速范围。5.5 坑5包络熵最优的参数端到端反而变差现象HO 搜出来的 K 和 alpha 包络熵最低换到 CNN 上准确率比固定参数 K5、alpha2000 还低一个多点。原因适应度函数是单模态最小包络熵它评价的是“某个模态冲击是否突出”而 CNN 分类需要的是所有模态的判别信息两者不完全一致。解决不要把包络熵当作最终标准它只是搜索向导。寻优得到候选参数后用三组参数做对比固定经验值、HO 最优质、人为微调值各训一次 CNN看测试准确率决定最终采用哪个。这套流程看着笨但在很多数据集上固定参数并不输给寻优参数往往是人为微调后的组合拿到最好结果。6. 这套方案值不值得信混淆矩阵、t-SNE与跨负载验收6.1 混淆矩阵看模型在哪里犯糊涂测试集准确率只是一个平均值真正暴露问题的是混淆矩阵。拿 CWRU 十分类来说如果 0.007 英寸内圈故障那一列里混入了不少滚动体故障的预测说明这两种轻微故障的频带在 VMD 分解后仍然有重叠CNN 学到的特征不够清晰。这时候第一反应不是加卷积层而是看这两个类别的模态波形和包络谱差异在哪必要时把 K 整体加 1 或减 1 重新寻优。6.2 t-SNE看特征是否真正聚拢混淆矩阵之外t-SNE 是检查特征质量最直观的工具。用测试集跑一次前向把全连接层之前的特征抽出来做二维降维可视化后如果同一类聚成一团、不同类之间有明显间隔说明 VMD 分解把故障特征分好了如果各类混成一滩再调 CNN 结构也没有意义。from sklearn.manifold import TSNE import matplotlib.pyplot as plt features, labels [], [] model.eval() with torch.no_grad(): for x, y in test_loader: f model.branch(x.to(device)).cpu().numpy() features.append(f.reshape(f.shape[0], -1)) labels.append(y.numpy()) feat np.concatenate(features) lab np.concatenate(labels) tsne TSNE(n_components2, perplexity30, random_state1).fit_transform(feat) plt.scatter(tsne[:, 0], tsne[:, 1], clab, cmaptab10, s4) plt.show()perplexity 要和样本量匹配样本几百个时用 5 到 15样本上千时用 30 左右。t-SNE 只能定性判断看到重叠不一定是模型的问题也可能是可视化参数选得不合适要和混淆矩阵的数据互相印证。6.3 跨负载测试才是最终验收西储大学数据有 0、1、2、3 马力四档负载如果只用 0 马力训练、2 马力测试大多数方案准确率都会明显下滑这很正常。但一个值得投入的方案应该做到训练集包含 0 和 1 马力测试集用 2 和 3 马力准确率依然保持在 90% 以上。做到这一点需要 VMD 参数在多个工况下有适应性而不是针对某一段信号过拟合。我在实际工程里的习惯是把跨负载测试当作硬性门槛达不到就回头检查样本归一化和数据集划分而不是继续加网络深度。这套 HO-VMD-CNN 流程我最大的教训是不要为了“最优”去找最优包络熵是导航不是保险最终说了算的是测试集上的泛化表现尤其是在没见过的负载上。把每个环节都跑通之后这套流程能稳定帮我省掉一半调参时间也希望帮到你。本文还有配套的精品资源点击获取