1. 项目概述:从零到一打造HVAC设备视觉检测器
最近在做一个工业视觉相关的项目,核心需求是让机器能自动识别和定位暖通空调系统中的各种设备部件,比如风机盘管、风阀、传感器、管道接口这些。HVAC(Heating, Ventilation, and Air Conditioning)系统的现场环境通常比较复杂,设备种类多、安装角度各异,还有管线遮挡,传统基于规则或简单模板匹配的方法效果很差,维护成本也高。所以,我们决定上深度学习,训练一个专用的目标检测模型。
在模型选型上,我们直接锁定了YOLO系列,毕竟它在速度和精度平衡上做得一直不错,社区生态也好。当时正好赶上Ultralytics发布了YOLOv11,看了一些评测,它在小目标检测和模型效率上又有了一些改进,就决定用它来试试水。这个“训练记录”其实就是我们整个从数据准备、模型训练、调优到最终部署测试的全过程复盘,里面踩了不少坑,也总结了一些在工业场景下用YOLO做特定目标检测的实用经验,特别是针对HVAC这种非标准、长尾分布的目标。
2. 核心需求解析与方案设计
2.1 业务场景与挑战拆解
我们的目标场景是建筑机房、管道井以及天花吊顶内部的HVAC设备巡检与资产盘点。人工巡检效率低、有安全隐患,而且对于大型建筑群,设备台账的更新维护是个大难题。我们希望通过部署在巡检机器人或固定摄像头上的视觉系统,实现自动化的设备识别、计数和状态初筛。
这个需求听起来像是典型的目标检测任务,但深入下去有几个独特的挑战:
- 类别长尾与定义模糊:HVAC设备细分种类极多,从大型冷水机组到小小的温湿度传感器,尺寸差异巨大。有些“设备”边界不清晰,比如一段包了保温棉的管道,该标整个管道还是标接口处?需要和业务方反复对齐标注规范。
- 环境复杂:现场光照不均(有的地方很暗,有的有强光反射)、背景杂乱(各种管线、墙体、其他设备)、存在大量遮挡(设备常常被管道或桥架挡住一部分)。
- 目标形态多变:同一类设备,比如风机盘管,有卧式、立式、吊顶式,安装角度千奇百怪,导致在图像中的表现形态非常多样。
- 数据获取成本高:清晰的、带标注的HVAC设备图像数据集几乎没有现成的。需要自己采集、清洗、标注,这个过程非常耗时耗力。
2.2 为什么选择YOLOv11?
面对这些挑战,我们需要一个快速、准确且易于开发和部署的检测框架。YOLO系列一直是实时检测的标杆。选择YOLOv11,主要是基于以下几点考量:
- 性能与效率的平衡:YOLOv11在YOLOv8的基础上,进一步优化了网络结构和训练策略。根据官方报告和一些社区测试,在相近的参数量下,v11在COCO等通用数据集上有着更高的mAP和更快的推理速度(FPS)。对于我们需要在边缘设备(如Jetson系列)或工控机上部署的场景,效率至关重要。
- 对小目标更友好:HVAC场景中有大量的小目标,如传感器、指示灯、小阀门。YOLOv11据说在neck部分和特征融合上做了改进,加强了对小目标的特征提取能力,这对我们是个利好。
- 完善的生态与工具链:Ultralytics提供的
ultralytics库,封装得非常好,从数据格式准备(支持YOLO格式、COCO格式等)、模型训练、验证、导出(到ONNX、TensorRT等)提供了一整套Pipeline。这对于快速迭代实验、减少工程化负担帮助巨大。像自动生成训练曲线、混淆矩阵、PR曲线这些可视化功能,对于分析模型短板非常直观。 - 社区活跃与可复现性:YOLO的社区非常庞大,遇到问题容易找到解决方案或参考案例。Ultralytics的代码和文档质量也比较高,复现官方结果相对容易。
当然,我们也评估过其他方案,比如两阶段的Faster R-CNN(精度可能更高但速度慢)、DETR系列(基于Transformer,训练慢且需要大量数据),最终从综合工程落地角度还是选择了YOLOv11。
3. 数据准备:工业视觉项目的基石
3.1 数据采集与清洗
“垃圾进,垃圾出”在深度学习里是铁律。我们花了项目近一半的时间在数据工程上。
采集来源:
- 现场拍摄:使用高分辨率工业相机和普通智能手机,在不同光照条件(白天、夜晚、补光灯下)、不同角度(平视、俯视、仰视)对目标设备进行拍摄。特别注意拍摄了被部分遮挡、有反光、处于复杂背景下的设备。
- 公开资料与模拟:收集了一些设备制造商的产品手册中的高清图片,以及利用3D建模软件(如Blender)渲染了一些标准设备的模拟图像,用于补充一些罕见角度或极端光照的数据。不过,模拟数据需要谨慎使用,要避免域差异(Domain Gap)过大。
清洗规则:
- 删除模糊、过暗、过曝严重无法辨认主体的图片。
- 统一图像尺寸。虽然YOLO可以训练不同尺寸,但为了批次处理效率,我们统一将长边缩放到640像素,短边按比例缩放,不足部分用灰边填充(LetterBox),这也是YOLO训练时的常见操作。
- 对图像进行初步去重,避免高度相似的图片在训练集和验证集同时出现,导致评估指标虚高。
3.2 标注规范与工具选择
我们使用LabelImg和Roboflow进行标注。对于团队协作和在线管理,Roboflow更优;对于单机快速标注,LabelImg足够。
标注关键规范(这是保证模型质量的核心):
- 类别定义:我们最终定义了12个核心类别,如
fan_coil_unit,air_handling_unit,damper,sensor,valve,pump,duct,filter,control_panel,compressor,condenser,pipe_joint。每个类别都有明确的文字描述和示例图,确保不同标注人员理解一致。 - 边界框(Bounding Box)原则:
- 紧贴目标:框体尽可能紧贴设备外缘,但不必像素级精确,适当留一点微小空隙是可以接受的。
- 部分遮挡处理:只要能看到目标的一部分且能明确判断其类别,就标注可见部分。并在标注系统中增加一个“遮挡”属性标签(后续可用于困难样本分析)。
- 密集小目标:对于成群的小传感器,确保每个目标都有独立的框,即使它们有部分重叠。
- 数据格式:采用YOLO格式。每张图片对应一个
.txt文件,每行内容为:<class_id> <x_center> <y_center> <width> <height>,坐标是归一化后的(0-1之间)。
注意:标注阶段一定要和最终的业务使用方(如运维工程师)一起Review标注结果,确保框选的部位是他们关心的“设备单元”。比如,一个大型空调机组,是标整个箱体,还是标出内部的压缩机、风机等子部件?这完全取决于业务需求。
3.3 数据集划分与增强策略
我们将清洗标注后的约4500张图像按8:1:1划分为训练集、验证集和测试集。划分时采用分层抽样,确保每个类别在三个集合中的比例大致相同。
数据增强(Data Augmentation): 这是提升模型泛化能力、防止过拟合的关键。我们直接在YOLO的训练配置文件中进行设置。Ultralytics支持丰富的增强选项,我们主要使用了以下组合:
# 在 data.yaml 或 train.py 参数中配置 augment: true augmentation: hsv_h: 0.015 # 随机色调变化 hsv_s: 0.7 # 随机饱和度变化 hsv_v: 0.4 # 随机明度变化 degrees: 10.0 # 随机旋转角度 translate: 0.1 # 随机平移 scale: 0.5 # 随机缩放 shear: 2.0 # 随机剪切 perspective: 0.0005 # 随机透视变换 flipud: 0.0 # 我们关闭了上下翻转,因为设备安装有方向性 fliplr: 0.5 # 水平翻转概率0.5,这是合理的 mosaic: 1.0 # Mosaic增强概率1.0,YOLO的利器,将四张图拼成一张 mixup: 0.1 # MixUp增强概率0.1,图像混合- Mosaic:极大地丰富了背景,让小目标有了更多的上下文信息,对于我们的场景非常有效。
- MixUp:相对温和的图像混合,有助于模型学习更鲁棒的特征。
- 色彩空间增强(HSV):模拟现场不同的光照和色温条件。
- 几何变换:旋转、平移、缩放、剪切,模拟不同的拍摄视角。特别注意,我们关闭了上下翻转(
flipud),因为HVAC设备在真实世界中很少会倒置出现,这种增强可能会引入噪声。
4. 模型训练实战与超参数调优
4.1 环境搭建与基础训练
我们选择在Ubuntu 22.04系统上,使用Python 3.9和PyTorch 2.0+进行训练。强烈建议使用Conda或Docker管理环境,避免依赖冲突。
# 创建环境 conda create -n yolo11_hvac python=3.9 conda activate yolo11_hvac # 安装PyTorch (根据CUDA版本选择) pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 安装Ultralytics pip install ultralytics # 验证安装 yolo checks数据准备完成后,目录结构如下:
datasets/hvac/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/同时需要一个data.yaml文件来指明路径和类别:
path: /path/to/datasets/hvac train: images/train val: images/val test: images/test nc: 12 # 类别数 names: ['fan_coil_unit', 'air_handling_unit', 'damper', 'sensor', 'valve', 'pump', 'duct', 'filter', 'control_panel', 'compressor', 'condenser', 'pipe_joint']启动第一次训练(Baseline): 我们选用预训练的yolo11m.pt(中等尺寸)模型作为起点,它提供了不错的精度和速度基础。
yolo train model=yolo11m.pt data=data.yaml epochs=100 imgsz=640 batch=16 workers=8epochs=100:对于我们的数据量,100个epoch通常足够收敛。imgsz=640:输入图像尺寸,与预处理时保持一致。batch=16:根据GPU显存(我们用的是RTX 4090)调整。更大的batch size有助于训练稳定,但可能降低泛化性。workers=8:数据加载的线程数,提高数据吞吐速度。
4.2 训练过程监控与指标分析
训练开始后,Ultralytics会在runs/detect/train目录下生成大量有用的文件和可视化图表。我们需要重点关注以下几个:
- 训练损失曲线(
results.png):观察train/box_loss,train/cls_loss,val/box_loss,val/cls_loss。理想情况是训练和验证损失都平稳下降,且两者差距不大。如果验证损失很早就开始上升,而训练损失持续下降,可能是过拟合。 - 性能指标曲线(
results.png):关注metrics/mAP50-95(B),即COCO标准的mAP(IoU从0.5到0.95的平均值)。这是衡量模型整体精度的核心指标。metrics/precision和metrics/recall也很有用,体现了模型的查准率和查全率。 - 混淆矩阵(
confusion_matrix.png):极其重要!它揭示了模型最容易混淆哪些类别。在我们的第一次训练中,发现valve(阀门)和pipe_joint(管道接口)混淆严重,sensor(传感器)容易被误检为背景。这直接指明了数据或模型需要改进的方向:要么增加这两类难分样本的数据,要么审视标注是否一致,或者调整分类头的权重。 - PR曲线(
PR_curve.png):针对每个类别的精确率-召回率曲线。曲线下的面积越大,该类别的检测性能越好。可以快速识别出哪些是“困难类别”。
4.3 超参数调优实战
Baseline模型训练完后,我们得到了一个mAP50-95约0.52的模型。这不够好。我们开始进行有针对性的调优。
1. 学习率与优化器: 默认使用SGD优化器。我们尝试了AdamW,并配合OneCycleLR学习率调度策略。发现对于我们的数据集,AdamW收敛更快,但最终mAP与SGD相差无几,而SGD的泛化性稍好,所以我们最终保持了SGD。但调整了学习率:
yolo train model=yolo11m.pt data=data.yaml epochs=100 lr0=0.01 lrf=0.01lr0=0.01:初始学习率。如果训练初期损失震荡大,可以降低到0.001。lrf=0.01:最终学习率是初始学习率的lrf倍(即0.01*0.01=0.0001)。这是一个余弦退火式的下降。
2. 针对小目标的改进: 观察到小目标(如sensor)的召回率很低。我们做了两件事:
- 修改Anchor Boxes(可选):YOLOv11默认使用自适应锚框计算,但我们可以先用全部训练数据聚类生成更适合我们目标尺寸的锚框,然后在配置中指定。使用Ultralytics提供的工具可以方便地完成。
- 增加小目标检测层:YOLOv11的模型结构可以通过修改配置文件调整。我们尝试了在更浅的特征层(具有更高分辨率)增加检测头,专门用于检测小目标。这需要修改模型定义文件(
.yaml),对于初学者有一定难度。一个更简单有效的方法是减小模型的下采样倍数,比如将imgsz从640提升到1280,同时按比例增加网络输入尺寸。但这会显著增加计算量和显存消耗,需要权衡。
3. 类别不平衡处理: 我们的数据中,duct(风管)和pipe_joint非常多,而compressor(压缩机)很少。我们采用了类别权重(Class Weight)。在YOLO中,可以通过在损失函数中设置cls_pw和obj_pw来调整分类损失和物体性损失的权重,但更直接的是使用Focal Loss。YOLOv11支持Focal Loss,可以通过参数fl_gamma来启用和调整。我们设置fl_gamma=1.5,给予难分类样本(通常是样本少的类别)更多的关注。
yolo train ... fl_gamma=1.54. 更激进的增强与模型尺寸: 在确认基础模型没有严重过拟合后,我们尝试了更强大的模型yolo11l.pt(大尺寸),并稍微增强了Mosaic和MixUp的概率。同时,引入了CutMix增强,它比MixUp更“硬核”,能更好地模拟遮挡。
augmentation: mosaic: 1.0 mixup: 0.15 cutmix: 0.1 # 新增CutMix经过几轮迭代调优,我们的最佳模型(基于yolo11l,使用Focal Loss和增强后的数据增强)在测试集上的mAP50-95达到了0.68,关键类别sensor和valve的AP也提升显著。
5. 模型评估、问题排查与优化
5.1 不仅仅是看mAP:深入分析模型短板
训练出一个高mAP的模型只是第一步,理解它为什么错、在哪里错,才能指导后续优化。
分析验证集上的错误样本:使用
yolo val命令在验证集上运行模型,并生成预测结果。然后,我们手动或借助工具(如Roboflow的Visualize API)查看那些置信度高但预测错误的、或者置信度低但确实是目标的样本。- 假阳性(False Positive):背景被误检为目标。例如,一个复杂的管道背景图案被误认为是
damper。这说明模型可能对某些纹理过拟合,需要增加类似的负样本(不包含目标的背景图)到训练集,或者在增强时增加更多的背景扰动。 - 假阴性(False Negative):目标没有被检测出来。主要集中在极端小目标、严重遮挡目标、或者与训练集差异极大的新形态目标。这就需要我们针对性补充这类“困难样本”的数据。
- 假阳性(False Positive):背景被误检为目标。例如,一个复杂的管道背景图案被误认为是
利用“标签平滑(Label Smoothing)”:为了防止模型对训练标签过于自信(导致过拟合),我们在最后一轮训练中加入了标签平滑(
label_smoothing=0.1),这通常能让模型在未知数据上表现更稳健。
5.2 常见训练问题与解决方案实录
以下是我们踩过的一些坑和解决办法:
| 问题现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
| 训练损失震荡大,不下降 | 学习率过高;批次大小太小;数据标注质量极差。 | 1. 将学习率lr0降低一个数量级(如从0.01到0.001)试试。2. 在硬件允许下增大 batch_size。3. 随机检查一批数据的标注,看是否存在大量错误框或类别标错。 |
| 验证损失远高于训练损失 | 典型的过拟合。模型记住了训练集噪声,而非一般规律。 | 1.加强数据增强:增加随机裁剪、色彩抖动、马赛克等。 2.使用正则化:增加权重衰减 weight_decay(如5e-4),或使用DropOut层(需修改模型结构)。3.减少模型复杂度:换用更小的模型(如 yolo11s)。4.早停(Early Stopping):监控验证损失,当其连续多个epoch不下降时停止训练。 |
| 某个特定类别AP始终很低 | 该类别样本数量太少;样本质量差(模糊、遮挡严重);与其他类别特征相似易混淆。 | 1.针对性数据收集与增强:专门采集和标注更多该类别样本。对该类别的图像做专属增强(如旋转、缩放)。 2.调整损失权重:在损失函数中增加该类别的权重(Focal Loss对此有帮助)。 3.重新审视标注:确认该类别的标注标准是否清晰一致,是否存在歧义。 |
训练时出现NaN损失 | 学习率爆炸;数据中存在异常值(如坐标超出范围)。 | 1. 大幅降低学习率。 2. 检查数据标注文件,确保归一化后的坐标值在[0,1]区间内。可以使用脚本进行批量检查。 |
| 模型推理速度慢 | 模型过大(如用了yolo11x);输入图像尺寸过大;后处理NMS参数不合理。 | 1. 换用更轻量模型(yolo11n,yolo11s)。2. 减小推理时的 imgsz(如从640降到320)。3. 调整NMS的 iou_thres和conf_thres,在精度可接受范围内提高阈值以过滤更多框,加速后处理。 |
5.3 模型导出与部署前优化
训练满意的模型需要部署到实际环境。我们通常导出为ONNX格式,以便在不同推理引擎(如OpenVINO, TensorRT)中使用。
# 导出为ONNX格式 yolo export model=runs/detect/train/weights/best.pt format=onnx imgsz=640 # 如果需要进一步优化,可以使用onnxruntime或者TensorRT的工具进行量化(INT8) # 这里以TensorRT为例(需要先安装TensorRT) yolo export model=best.pt format=engine device=0 imgsz=640部署优化要点:
- 动态尺寸 vs 固定尺寸:导出ONNX时,可以选择固定输入尺寸(
imgsz=640)以获得最佳性能,或者选择动态尺寸(dynamic=True)以支持可变分辨率输入,但后者可能在某些推理引擎上优化不佳。 - 量化:如果部署在资源受限的边缘设备,INT8量化能大幅提升速度并减少内存占用,但会带来轻微的精度损失。需要在测试集上仔细评估量化后的精度变化。
- 预处理与后处理集成:为了提升端到端效率,可以考虑将图像的预处理(归一化、LetterBox)和预测框的后处理(NMS)也集成到导出的模型图中。Ultralytics的导出功能已经支持这一点。
6. 项目总结与未来展望
经过这一轮完整的HVAC设备检测器训练,最大的体会是:在工业视觉项目中,数据和定义的重要性远大于模型本身的微调。花时间厘清业务边界、制定严谨的标注规范、收集覆盖各种 corner case 的数据,其回报远高于盲目尝试更复杂的网络结构。YOLOv11作为一个强大的工具,提供了极高的生产效率和不错的性能基线,让我们能把主要精力聚焦在解决业务和数据本身的问题上。
我们目前得到的模型在测试集和部分现场静态图片上表现良好,但真正的挑战在于动态视频流和极端现场环境。接下来的工作重点会放在:
- 在线难例挖掘:将模型部署到测试环境中,自动收集它预测置信度低或出错的帧,人工复核后加入训练集,进行迭代训练。
- 多模态融合:考虑结合红外热成像数据,因为某些设备故障(如电机过热)在可见光图像上不明显,但热成像下有显著特征。
- 部署工程优化:针对具体的边缘计算设备(如Jetson AGX Orin),进行深入的TensorRT优化,探索混合精度(FP16)甚至INT8量化的可行性,在保证精度的前提下追求极致的推理速度。
这个项目也再次证明,开源工具链(如Ultralytics YOLO)的成熟,极大地降低了计算机视觉应用的门槛。关键在于,我们要带着清晰的业务问题和扎实的数据工程思维去使用这些工具,而不是仅仅停留在跑通示例代码的层面。