基于HO-VMD-CNN的轴承故障诊断:从参数优化到分类实战
简介这份资源面向轴承故障诊断方向的研究生、算法工程师与深度学习入门者提供一套将高阶变分模态分解与卷积神经网络结合的完整Matlab实现方案用于解决西储大学驱动端振动信号中故障特征提取难、噪声干扰强、分类准确率低的问题。压缩包共15个文件约60.73MB以9个m脚本为核心配套4个xlsx数据集、1个pdf算法论文与1个txt环境说明覆盖信号分解、特征提取、网络搭建与训练全流程。资源内含HO-VMD分解脚本、五种适应度函数包络熵、排列熵、复合熵、信息熵、样本熵及spatialDropoutLayer等网络层实现并附多转速工况下的原始振动数据与特征提取后数据集便于直接复现与对比实验。目前已有203人学习下载适合希望快速搭建HO-VMD-CNN诊断基线、理解信号处理与深度学习融合思路的读者参考。1. 从一段振动信号说起HO-VMD-CNN 这套轴承故障诊断方案到底能干什么一台电机在实验室里跑得好好的拆下来装到现场振动频谱上却冒出一堆说不清的边频带——这是做旋转机械故障诊断的人最常遇到的场景。西储大学轴承数据集之所以被反复拿来练手就是因为它把正常、内圈、外圈、滚动体这几类状态在多个负载转速下都采全了信号干净、标签明确适合验证一套诊断流程到底能不能跑通。但真拿原始振动信号直接喂给 CNN十有八九效果不稳因为轴承故障的冲击成分往往被强背景噪声和工频干扰盖住网络学到的可能只是负载差异而不是故障特征。HO-VMD-CNN 这套组合的思路就是先用变分模态分解VMD把原始信号拆成若干本征模态分量再用优化算法HO即河马优化算法去自动搜 VMD 最关键的两个参数——模态数 K 和惩罚因子 α最后把优选出来的分量送进 CNN 做分类。它解决的不是“有没有故障”而是“在参数靠人拍脑袋调不准的情况下怎么让分解和分类串成一条能复现的流水线”。适合谁手里有振动数据、想跑通“信号分解深度学习分类”完整链路的人尤其是被 K 值选错、模态混叠、分类准确率忽高忽低折腾过的从业者。下面我按自己拆这套流程的顺序把参数、代码和坑一个个说清楚。2. VMD 分解与 HO 寻优为什么不能手动拍 K 和 α2.1 VMD 的两个命门参数K 和 αVMD 的本质是把一个实值信号分解成 K 个有限带宽的模态分量每个分量围绕自己的中心频率。它比 EMD 强的地方在于有数学约束、不容易模态混叠但代价是你要提前告诉它“拆成几个”。K 给小了故障冲击和转频可能被塞进同一个模态特征糊成一团K 给大了一个故障成分被拆到两个模态里反而制造出虚假分量。惩罚因子 α 控制每个模态的带宽α 太小带宽过宽、模态之间串扰α 太大带宽过窄、冲击成分被削平。我一般会先做一次网格观察K 从 3 试到 8α 从 1000 试到 5000看中心频率有没有出现两个模态挤在一起的情况。但网格搜太慢而且不同负载下的最优 K 未必一样所以才需要 HO 这类优化算法来替人做这件事。这里要强调一句HO 不是万能钥匙它只是把“试参数”这件事自动化目标函数设计得不对它照样给你搜出一组看着收敛、实际没用的参数。2.2 HO 优化 VMD 的目标函数怎么定HO 寻优需要一个能衡量“这组 K、α 好不好”的指标。常见做法是用包络熵对每个模态求包络再算熵值熵越小说明冲击成分越集中、周期性越明显故障特征越突出。把所有模态的包络熵取平均或取最小作为适应度。HO 的每个个体就是一个二维向量 [K, α]K 取整数、α 取连续值迭代过程中用边界约束把它们卡在合理范围。下面是我常用的适应度函数骨架直接可抄import numpy as np from vmdpy import VMD from scipy.signal import hilbert def envelope_entropy(modal): # 对单个模态求包络熵熵越小冲击特征越明显 env np.abs(hilbert(modal)) env env / (np.sum(env) 1e-12) ent -np.sum(env * np.log(env 1e-12)) return ent def fitness(params, signal): K int(round(params[0])) alpha params[1] # K 限制在 3~8alpha 限制在 500~5000防止搜出无意义解 if K 3 or K 8 or alpha 500 or alpha 5000: return 1e6 try: u, _, _ VMD(signal, alpha, 0, K, 0, 1, 1e-7) except Exception: return 1e6 ents [envelope_entropy(u[i]) for i in range(K)] return float(np.mean(ents))逻辑说明VMD的调用签名里第二个参数是 α第四个是 K中间几个是噪声容限、初始化方式等不同版本的 vmdpy 参数顺序略有差异抄之前先help(VMD)确认一遍。envelope_entropy里加1e-12是防止 log 出现负无穷。适应度返回均值意味着希望所有模态都尽量“干净”而不是只让某一个模态好看。参数边界那一段别省HO 的初始种群是随机撒的不卡边界很容易搜出 K2 或 α100 这种明显不合理的组合白白浪费迭代。2.3 HO 迭代与 VMD 分解的串联步骤把寻优和分解串起来实际执行就四步读入一段振动信号做归一化去掉直流分量。初始化 HO 种群维度设为 2上下界分别对应 K 和 α 的范围。每轮迭代用当前种群里的 [K, α] 调 VMD算包络熵均值作为适应度更新最优个体。迭代结束后用最优 [K, α] 对信号做一次最终 VMD输出 K 个模态。from HO import HO # 假设已有河马优化算法实现 signal signal - np.mean(signal) signal signal / (np.std(signal) 1e-12) dim 2 lb np.array([3, 500]) ub np.array([8, 5000]) pop 20 max_iter 30 best_params, best_fit HO(fitness, dim, lb, ub, pop, max_iter, signal) K_opt int(round(best_params[0])) alpha_opt best_params[1] u_opt, _, _ VMD(signal, alpha_opt, 0, K_opt, 0, 1, 1e-7)参数说明种群pop取 20、迭代max_iter取 30 是我在单段信号上试出来的折中值再大收敛曲线基本平了收益不明显。lb、ub要和适应度函数里的边界保持一致否则会出现“优化器以为在搜、适应度直接判死”的假收敛。最终分解得到的u_opt是一个 K×N 的矩阵每一行是一个模态后面送 CNN 之前要决定用哪几个模态——常见做法是挑包络熵最小的前 3 个或者把全部模态堆成多通道输入。3. 从模态分量到 CNN 输入数据组织与标签对齐3.1 模态选择与样本切分VMD 出来 K 个模态不是每个都含故障信息。低频模态往往是转频和趋势项高频模态可能是噪声。我一般按包络熵排序取熵最小的前 3 个模态把它们按通道叠起来形成一个 3×L 的输入。L 是样本长度西储数据在 12kHz 采样下取 1024 点或 2048 点都行取 1024 时样本数多、训练快取 2048 时频率分辨率高、但样本数减半。切分时有个容易翻车的地方不能先切分再 VMD也不能先 VMD 再随机切分后打乱。正确顺序是整段信号先 VMD再对每个模态做滑窗切分切分时保留标签。如果先切分再逐段 VMD每段的最优 K 可能不同模态物理意义对不上CNN 学到的就是一堆错位特征。def make_samples(modals, label, win1024, step512): # modals: 选中的模态形状 (C, N) C, N modals.shape X, y [], [] for start in range(0, N - win 1, step): seg modals[:, start:start win] X.append(seg) y.append(label) return np.array(X), np.array(y)逻辑说明win是窗口长度step是滑动步长取 512 表示 50% 重叠能在样本数有限时扩充数据。返回的X形状是 (样本数, C, win)正好是 CNN 的输入格式。标签y用整数编码后面接CrossEntropyLoss时不用再转 one-hot。3.2 训练集、验证集、测试集的划分边界西储数据按负载分 0、1、2、3 马力几组常见做法是拿一部分负载做训练、另一部分做测试模拟“变工况”场景。如果随机打乱所有负载的样本再划分准确率会虚高因为同一段信号切出来的相邻样本可能同时进训练和测试属于数据泄漏。我一般按负载划分0、1 马力训练2 马力验证3 马力测试。这样测出来的准确率才有参考价值虽然数字会比随机划分低一截但那才是真实泛化能力。提示如果发现测试准确率异常高比如 99.9%先检查是不是同一段信号的相邻窗口被分到了训练和测试两边这是最常见的“假高分”来源。3.3 CNN 结构选型为什么不用现成大模型轴承故障分类的输入是短时一维或多通道时序样本量通常几千到几万用 ResNet、Transformer 这类大模型容易过拟合训练也慢。我一般用 3 层一维卷积加池化再接全连接import torch.nn as nn class BearingCNN(nn.Module): def __init__(self, in_ch3, n_cls4): super().__init__() self.features nn.Sequential( nn.Conv1d(in_ch, 32, 7, padding3), nn.ReLU(), nn.MaxPool1d(2), nn.Conv1d(32, 64, 5, padding2), nn.ReLU(), nn.MaxPool1d(2), nn.Conv1d(64, 128, 3, padding1), nn.ReLU(), nn.AdaptiveAvgPool1d(8) ) self.classifier nn.Sequential( nn.Flatten(), nn.Linear(128 * 8, 64), nn.ReLU(), nn.Dropout(0.3), nn.Linear(64, n_cls) ) def forward(self, x): return self.classifier(self.features(x))参数说明in_ch3对应选出的 3 个模态n_cls4对应正常、内圈、外圈、滚动体四类。卷积核从 7 降到 3是为了先抓宽频冲击、再抓细节。AdaptiveAvgPool1d(8)把任意长度压到固定 8这样换窗口长度时全连接层不用改。Dropout(0.3)是防过拟合的常规手段样本少时可以加到 0.5。4. 训练、验证与结果判读别被一条准确率曲线骗了4.1 训练循环里的关键设置优化器用 Adam学习率 1e-3配合StepLR每 20 轮乘 0.5。批大小 64训练 60 轮左右。损失函数用交叉熵。这些不是玄学是这类中小规模时序分类任务里比较稳的起点。import torch from torch.utils.data import DataLoader, TensorDataset device torch.device(cuda if torch.cuda.is_available() else cpu) model BearingCNN(in_ch3, n_cls4).to(device) opt torch.optim.Adam(model.parameters(), lr1e-3) sched torch.optim.lr_scheduler.StepLR(opt, step_size20, gamma0.5) criterion torch.nn.CrossEntropyLoss() train_loader DataLoader(TensorDataset( torch.tensor(X_tr, dtypetorch.float32), torch.tensor(y_tr, dtypetorch.long)), batch_size64, shuffleTrue) for epoch in range(60): model.train() for xb, yb in train_loader: xb, yb xb.to(device), yb.to(device) opt.zero_grad() loss criterion(model(xb), yb) loss.backward() opt.step() sched.step()逻辑说明shuffleTrue只在训练集上开验证和测试集不能打乱否则没法按顺序对应标签。sched.step()放在 epoch 末尾不是 batch 末尾放错位置学习率会掉得过快。如果显存不够把批大小降到 32同时学习率降到 5e-4别只降批大小不调学习率那样收敛会变慢。4.2 混淆矩阵比准确率更能说明问题四分类任务里正常样本通常最好分内圈和外圈容易混滚动体故障因为冲击弱、样本少召回率往往最低。只看总体准确率会掩盖这个问题。我习惯每轮验证都算一次混淆矩阵重点看滚动体那一行的召回率。如果滚动体召回率长期低于 80%而其他类都在 95% 以上说明模型没学到滚动体的特征这时候回去检查 VMD 选出的模态里是不是把滚动体的高频冲击滤掉了。from sklearn.metrics import confusion_matrix, classification_report model.eval() with torch.no_grad(): logits model(torch.tensor(X_te, dtypetorch.float32).to(device)) pred logits.argmax(dim1).cpu().numpy() print(confusion_matrix(y_te, pred)) print(classification_report(y_te, pred, digits4))参数说明classification_report里的macro avg比weighted avg更能反映小类表现样本不均衡时优先看 macro。如果某一类召回率明显低先别急着加网络深度先回去看这一类在 VMD 分解后是不是被分到了被丢弃的模态里。4.3 变工况下的结果怎么读按负载划分训练测试时准确率通常会比随机划分低 5 到 15 个百分点这是正常的。如果低得离谱比如掉到 60% 以下常见原因是 VMD 的 K 和 α 是在训练负载上优化的直接套到测试负载上不匹配。解决办法有两个一是把 HO 的适应度改成在多个负载上取平均让参数更通用二是对测试负载单独做一次 VMD但只用训练阶段确定的 K 范围不重新寻优。前者更严谨后者更快看你的场景允不允许测试阶段做分解。5. 避坑与排查这套流程里最容易翻车的五个地方5.1 现象HO 收敛曲线一路下降但分类准确率没提升原因适应度用的是包络熵均值它衡量的是模态“干净程度”不等于“对分类有用”。有时候熵最小的模态恰好是转频故障冲击在另一个熵稍大的模态里。解决把适应度改成包络熵和模态与原始信号相关性的加权组合或者直接在下游用验证集准确率做反馈虽然慢但更直接。5.2 现象VMD 报错或返回的模态数不对原因vmdpy不同版本对参数顺序和噪声容限的处理不一致有的版本要求 α 是整数有的要求 K 必须小于信号长度的一半。解决先help(VMD)看签名再用一段已知信号跑通最小示例确认返回的u形状是 (K, N) 再接入主流程。别直接抄网上的调用版本对不上是常事。5.3 现象训练准确率 99%测试准确率 60%原因九成是数据泄漏。同一段信号滑窗切出来的相邻样本高度相似随机划分时它们被分到了训练和测试两边。解决按时间段或按负载划分确保训练集和测试集来自不同的信号段。如果一定要随机划分先在整段信号级别划分再各自切窗。5.4 现象换一组数据后 K 的最优值完全变了原因不同采样率、不同转速下故障特征频率和转频的比值变了最优 K 自然不同。解决把 K 的范围放宽到 3 到 10α 范围放宽到 500 到 8000同时把 HO 的种群和迭代适当加大。如果数据量允许针对每种工况单独寻优别指望一组参数打天下。5.5 现象CNN 训练 loss 震荡不收敛原因输入模态没有归一化或者不同模态的幅值差异太大网络被大幅值模态主导。解决每个模态单独做 z-score 归一化再叠成多通道。另外检查学习率1e-3 对某些数据偏大降到 3e-4 试试。批大小太小也会导致震荡64 以下时考虑调小学习率。6. 进阶技巧把 HO 寻优从“单段”扩展到“多段投票”前面说的 HO 都是对单段信号寻优实际用的时候你会发现同一工况下不同时间段的信号最优 K 可能差 1 到 2。如果每段都单独寻优计算量大而且 CNN 输入对应的模态数不固定网络结构没法固定。我后来改成一个更稳的做法从训练集里抽 10 到 20 段信号每段跑一次 HO把得到的 K 和 α 做统计取 K 的众数、α 的中位数作为整个训练集的统一参数。这样既保留了数据驱动的成分又保证了输入维度一致。from collections import Counter K_list, alpha_list [], [] for seg in sampled_segments: bp, _ HO(fitness, 2, lb, ub, 20, 30, seg) K_list.append(int(round(bp[0]))) alpha_list.append(bp[1]) K_final Counter(K_list).most_common(1)[0][0] alpha_final float(np.median(alpha_list)) print(统一参数 K%d, alpha%.1f % (K_final, alpha_final))逻辑说明Counter取众数是为了让 K 落在多数信号都认可的取值上np.median取中位数是为了避免某一段信号搜出极端 α 把整体带偏。抽样段数别太少10 段以下统计意义不够也别太多20 段以上收益递减。这个统一参数确定后整个训练集和测试集都用它做 VMDCNN 输入通道数就固定了。验证这套参数好不好我一般做两件事一是看统一参数下的包络熵均值和单段最优值的差距在 5% 以内就算合格二是看 CNN 在验证集上的混淆矩阵如果滚动体召回率比单段寻优时还高说明统一参数反而抑制了过拟合。最后说个我自己的习惯每次换数据集先拿 5 段信号跑一遍 HO把 K 和 α 的分布画出来分布太散就说明信号本身一致性差这时候与其硬调参数不如回去检查采集环节有没有问题。从那以后我每次接新数据都强制走一遍这个分布检查省下不少返工时间。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

LSTM汽车排放预测实战:从数据对齐到调参避坑

LSTM汽车排放预测实战:从数据对齐到调参避坑

简介:这份资源面向车辆工程、环境监测及数据科学方向的本科生与研究生,提供一套基于MATLAB实现的LSTM汽车排放量预测完整方案。汽车排放数据具有明显的时间序列特征,相比普通神经网络,长短期记忆网络更适合捕捉其前后依赖关系&…

2026/10/13 0:34:36 阅读更多 →
OpenCV DNN加载Faster R-CNN的三大核心陷阱与实战解析

OpenCV DNN加载Faster R-CNN的三大核心陷阱与实战解析

1. 这不是“调个API”那么简单:Faster R-CNN在OpenCV DNN模块里的真实定位与价值你搜“OpenCV DNN Faster R-CNN TensorFlow”,大概率会看到一堆“5分钟跑通”“一行代码检测”的标题。我试过,也写过类似教程——但后来删了。因为那根本不是在…

2026/10/13 0:34:30 阅读更多 →
Quartz定时任务调度中的MisFire机制:原理、策略与生产实践

Quartz定时任务调度中的MisFire机制:原理、策略与生产实践

做定时任务调度,Quartz 是绕不开的老牌框架。但很多人在生产环境跑了一阵子后,会发现一个诡异的现象:明明配置了每隔 5 分钟执行一次的任务,某次凌晨服务重启后,它要么疯狂补跑几十次,要么直接沉默一整天。…

2026/10/13 0:33:29 阅读更多 →

最新新闻

计及需求侧响应的配电网供电能力综合评估Matlab实现

计及需求侧响应的配电网供电能力综合评估Matlab实现

供电能力评估这个方向,做配电网规划的人都不陌生。传统做法很简单:把负荷当成一个给定的“硬条件”,算主变、算线路、算N-1通过率,能带多少就是多少。但问题是,现在的负荷已经不再“硬”了——分时电价、可中断负荷、车…

2026/10/14 6:02:23 阅读更多 →
AI协作者实战指南:从提示词工程师到流程编排师

AI协作者实战指南:从提示词工程师到流程编排师

1. 这不是“自动印钞机”,而是AI时代的职业重构现场“自动赚钱时代来了?”——这个标题一出来,朋友圈就炸了。有人截图转发配文“终于等到这一天”,也有人冷笑评论“又一个割韭菜的标题党”。但真正让我坐下来认真拆解它的&#x…

2026/10/14 6:02:23 阅读更多 →
ZeroTermux 内置命令手册:tcpreplay 报文重放与双网卡网络测试实战

ZeroTermux 内置命令手册:tcpreplay 报文重放与双网卡网络测试实战

移动开发开发工具 【免费下载链接】ZeroTermux 项目地址: https://gitcode.com/GitHub_Trending/ze/ZeroTermux 点击查看 免费下载 导读 tcpreplay 是一款基于 PCAP 文件的报文重放工具,它能把用 Wireshark(及其前身 Ethereal)、…

2026/10/14 6:02:23 阅读更多 →
AnyPS5:一套对任意PS5都适用的折腾与优化方案

AnyPS5:一套对任意PS5都适用的折腾与优化方案

看到“AnyPS5”这个名字,估计不少人会误会:是破解方案?是某个新机型?其实都不是。我更愿意把它理解为一套“对任意一台PS5都适用的折腾与优化方案”。这些年帮朋友处理过不少台PS5主机,有的是刚拆封的新机,…

2026/10/14 6:02:23 阅读更多 →
轻资产酒店集团财报解读:现金流、分红与CFO变动背后的逻辑

轻资产酒店集团财报解读:现金流、分红与CFO变动背后的逻辑

最近酒店行业的头条,大概率是这家头部连锁酒店集团的年度成绩单:营收253亿,净利51亿,同时宣布派发约4亿美元股息,同一时间,任职多年的CFO卸任。几个消息堆在一起,很多人第一反应是"业绩不错…

2026/10/14 6:02:23 阅读更多 →
高校农业病虫害智能监测系统设计与实现

高校农业病虫害智能监测系统设计与实现

1. 项目概述农业病虫害监测与预测一直是农业生产中的关键环节。传统的人工巡查方式效率低下且容易遗漏,而基于大数据的智能监测系统正在改变这一现状。这个项目构建了一个面向高校场景的农业病虫害监测与趋势预测系统,整合了数据采集、存储、分析和可视化…

2026/10/14 6:01:22 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →