简介:目标检测作为计算机视觉的核心任务,其原理是通过卷积神经网络提取图像特征,定位并分类目标对象。在工业智能化和安全生产需求推动下,人员检测成为车间管理的第一道基础能力,但真实场景中常面临样本量不足的困境。小样本数据集并不等于项目不可行,借助迁移学习、数据增强与合理的训练策略,即使只有百余张标注图片,也能训练出可用的YOLO模型。本文从目标检测基础原理出发,解析小样本场景下的技术价值与工程落地路径,重点介绍YOLO版本选型、预训练权重利用、在线增强参数调整以及过拟合规避方法,并延伸至推理部署与业务扩展,为产线监控、安全巡检等工业应用提供一套可复现的完整方案。 做工业视觉这几年,YOLO几乎是我处理车间视频流的默认起点。前两天整理素材时翻到一个“172张图片、标注类别为person”的车间人员目标检测数据集,正好有朋友问我这种小样本数据集到底能不能拿来训练YOLO,能不能落地。这算是目标检测项目里最典型的场景之一:数据少、场景杂、还要快速验证算法效果。这篇博文就基于这个项目标题,把工业车间人员检测这个任务从数据理解、算法选型到训练部署完整过一遍,特别是针对小数据集该怎么避坑、怎么把效果撑起来,都会给出可复现的实操方案。
如果你手里正攥着类似规模的数据集,或者打算在产线监控、安全巡检场景里做人员检测,这篇文章应该能帮你少走不少弯路。
1. 工业车间人员检测的任务拆解与数据集定位
1.1 车间场景下的检测难点与业务价值
在工业车间里做人员目标检测,和平时在街景、公开数据集里做人检测完全是两码事。车间环境有几个很棘手的特征:光照条件复杂,有的工位强光直射,有的区域光线昏暗;背景里全是设备、货架、传送带,纹理极其丰富,非常容易造成误检;工人着装通常统一,且颜色和安全帽、设备涂装容易相近;还有大量遮挡场景,人站在机器后面、弯腰操作时,身体只有一部分暴露在画面里。
但业务需求却非常明确。人员检测是车间安全管理的基础能力,往下走可以接安全帽佩戴识别、区域闯入告警、人员计数、在岗状态判断。不管是做合规巡检还是产线效率分析,第一步都是先把“人”的位置从视频帧里找出来。这也是为什么很多项目起步阶段都会先拿一个只有person类别的检测数据集来做算法验证——先把基础检测能力跑通,再逐步扩展业务类别。
这个数据集的定位其实很清晰:它不追求覆盖所有复杂场景,而是聚焦车间的真实拍摄画面,用172张标注好的图片提供一份可以直接喂给YOLO训练的干净数据。对于要做原型验证、算法选型测试、或者跑通整套训练流程的开发者来说,这个规模完全够用。
1.2 172张在深度学习项目中算什么量级
直说,172张图片在目标检测领域属于典型的极小样本。拿COCO数据集做参考,train2017有11.8万张图片、80个类别,相比之下172张连零头都不到。但这不代表这个数据集没有价值,关键在于你怎么用它。
小数据集真正的威胁是过拟合,模型很容易把训练集里的背景、光照、姿态“背”下来,而不是学到“人”的通用特征。如果直接从头训练一个YOLO模型,大概率会得到一份loss曲线很漂亮、验证集上却一塌糊涂的结果。
但实际工程里,我们很少会从零训练。工业项目通常都有预训练权重可以迁移,而YOLO在COCO上的预训练模型本身就见过大量person类别的样本,这相当于帮你把“什么是人”这件事已经学好了,你需要做的只是让它适配车间场景。在这个前提下,172张图片承载的任务不是让模型学会认人,而是让模型在车间场景里准确找到人。这个区别非常关键,决定了后续所有训练策略的走向。
数据划分上,我建议按8:1:1或9:1来切分训练集和验证集。172张的话,我不建议再单独切测试集,因为样本太少,测试集的评估结果方差会很大。把验证集留15张左右,用于观察训练过程中的mAP变化就够了。如果后面需要更严谨的评估,再用独立的车间视频抽帧来补。
2. YOLO算法选型:版本怎么挑、预训练权重怎么用
2.1 YOLO家族各版本核心差异与选择建议
YOLO发展到现在,v5、v6、v8、v9、v10、v11这么多版本,新手容易看花眼。但其实从工程落地角度,选型逻辑非常直接:看生态成熟度、预训练权重丰富度、部署难易度,而不是追新。
| 版本 | 核心特点 | 小样本场景适配性 | 部署友好度 |
|---|---|---|---|
| YOLOv5 | 生态最成熟,文档齐全,Ultralytics维护 | 高,v5s参数量小,容易收敛 | 极高,TensorRT/ONNX支持完善 |
| YOLOv6 | 美团开源,工业部署优化较多 | 中,需要自行适配训练流程 | 高 |
| YOLOv8 | 当前主流,anchor-free,API统一 | 高,ultralytics包一键训练 | 极高 |
| YOLOv10 | 无NMS设计,推理更快 | 中,新特性文档相对少 | 中高 |
| YOLOv11 | 最新版,分类/检测/分割统一框架 | 高,但部分功能仍在迭代 | 高 |
针对172张这种规模的数据集,我推荐用YOLOv5s或YOLOv8s。原因有三:第一,s版本参数量在7M到11M之间,在小数据上不容易过拟合,训练速度也快;第二,两个版本都有稳定的COCO预训练权重,person类在COCO里是第0类,迁移基础非常好;第三,在线增强策略成熟,mosaic、mixup这些增强手段在训练后期会自动关闭,减少过拟合风险。
我个人实测下来,YOLOv8s在工业场景的小样本任务上表现比较稳,ultralytics提供的训练接口也省心,适合把主要精力放在数据处理和调参上。
2.2 小数据集为什么必须用迁移学习
这个点值得展开讲。很多人拿小数据集训练,第一反应是“数据不够,那就改模型结构、加数据增强”,但最有效的手段其实是迁移学习。
我们看一下在COCO上预训练的YOLO模型到底学到了什么。COCO数据集里有大量person类别标注,模型的主干网络已经学会了提取人的边缘、轮廓、部件特征,检测头也学会了输出人的边界框。你把它拿到车间场景,要做的事情不是重新教它认人,而是做一次“领域适配”:让模型理解车间里的光照、背景、摄像头视角下的人是什么样子。
实际训练时有几个具体做法。第一个做法是直接加载预训练权重,比如yolov8s.pt,然后正常训练全部层。172张数据下,学习率要调低一些,建议初始学习率在0.001以下,避免在迁移基础上大幅破坏已学到的特征。第二个做法是冻结骨干网络,只训练检测头,等loss下降平稳后再解冻骨干网络微调。冻结骨干的好处是可以防止小数据训练时骨干特征被破坏,缺点是如果车间场景和COCO差异较大,最终精度可能不够。
我的建议是先用方案一,加载完整预训练权重,设一个较低的学习率跑50到100轮,观察验证集mAP。如果出现过拟合或特征漂移,再切换到冻结骨干的方案对比。
3. 数据集格式、标注细节与训练全流程实操
3.1 YOLO格式数据集的目录结构与标签含义
拿到数据集后,第一步是核对目录结构。标准YOLO检测数据集的格式如下:
dataset/ ├── images/ │ ├── train/ │ ├── val/ ├── labels/ │ ├── train/ │ ├── val/ ├── data.yamlimages里放原始图片,labels里放对应的txt标注文件,文件名字必须和图片名字完全一致(仅扩展名不同)。如果数据集本身把train和val分好了,直接用;如果没有分,那就自己按比例切分,注意切分时用random seed固定随机种子,保证可复现。
每一张图片对应的labels txt文件内容大致是:
0 0.5432 0.4156 0.3214 0.6542 0 0.1024 0.7834 0.1987 0.3521每行一个目标,共5个数,含义是:类别ID、目标中心点x坐标、目标中心点y坐标、目标宽度w、目标高度h。这里的x、y、w、h都是相对于图片宽度和高度的归一化值,范围在0到1之间。这行内容对应的就是YOLO标注格式的核心定义。
data.yaml配置文件长这样:
train: dataset/images/train val: dataset/images/val nc: 1 names: ['person']这个文件告诉训练脚本去哪里找训练数据和验证数据、类别数量是多少、每个类别叫什么名字。
3.2 训练实操:从环境准备到模型输出的完整步骤
这里我以YOLOv8为例,把完整训练流程走一遍,这些命令直接复制就能用。
先准备环境,建议用Python 3.9或3.10,GPU显存至少6G,如果只有CPU也能训练,但速度会慢很多:
pip install ultralytics # 如果要ONNX导出,需要额外安装 pip install onnxruntime验证一下环境是否正常:
yolo predict model=yolov8s.pt source='https://ultralytics.com/images/bus.jpg'能输出检测结果说明环境没问题。接下来把数据集放到项目目录下,确认好目录结构和data.yaml路径一致。启动训练:
yolo detect train data=dataset/data.yaml model=yolov8s.pt epochs=100 batch=8 imgsz=640 lr0=0.0005 patience=15几个关键参数的取舍我得重点说一下。
epochs设100是一个比较保守的起步值。172张图,batch=8的话,一个epoch大约21个step,100个epoch也就是2100个step,这个训练量配合预训练权重是合理的。如果想更快验证效果,可以先跑30个epoch看趋势。
batch-size在显存允许范围内尽量调大。batch=8对应大约8-10G显存,如果显存不够就调小到4。学习率lr0=0.0005是基于迁移学习场景的设置,比起默认的0.01要低很多,目的是在已有权重上做细调而不是大改。
patience=15是early stopping的容忍轮数,验证集mAP连续15个epoch没有提升就自动停止,能有效防止过拟合。
训练结束后,会在runs/detect/train目录下生成一堆文件:best.pt是验证集mAP最高的权重,last.pt是最后一轮的权重,results.png是训练曲线图,confusion_matrix.png是混淆矩阵,val_batch*.jpg是验证集上的预测可视化结果。
评估指标主要看三个:mAP@50(IoU阈值0.5下的平均精度)、mAP@50:95(从0.5到0.95取不同IoU阈值的平均,更严格)、precision和recall。在小数据集场景下,mAP@50是更有参考价值的指标,因为它不要求框特别精确,更关注能不能检出;而mAP@50:95对框的位置精度要求高,在样本少时波动会很大。
3.3 数据增强实测:172张怎么撑起一个能用的训练集
YOLO自带的在线数据增强在小样本任务中作用巨大,但很多人只是开着默认参数,并不知道每个增强选项对结果的影响有多大。我在实验里专门对比过几组增强策略。
默认开启的mosaic增强是把4张图片拼成一张再训练,这相当于强制模型在更丰富的上下文里学习目标特征,对场景多样性的提升很有帮助。但在训练的后期,如果一直开mosaic,反而可能影响模型对真实场景的适应能力,所以ultralytics默认在最后10个epoch自动关闭mosaic,这个设计已经帮你考虑到了。
另一个关键增强是HSV色彩空间扰动,包括色调、饱和度、亮度三个维度。车间不同区域的光照差异很大,这个增强能模拟不同曝光条件下的画面,让模型对光线变化更鲁棒。我通常会把hsv_s和hsv_v适当调高一点:
yolo detect train data=dataset/data.yaml model=yolov8s.pt epochs=100 batch=8 imgsz=640 lr0=0.0005 hsv_s=0.7 hsv_v=0.6除了在线增强,还可以从数据侧做离线增强。比如把图片做水平翻转、90度旋转、小幅缩放和裁剪,生成辅助训练样本。这样操作的前提是标注坐标会跟着变换,手动做容易出错,建议直接用ultralytics或Roboflow这类工具的增强功能,别自己写脚本改坐标。
数据增强的本质是给模型提供更多“看起来不同、但语义一致”的样本。在172张这个基数上,增强后相当于把有效训练数据扩大到5到10倍,配合预训练权重,效果提升会非常明显。
4. 车间场景下的常见问题与排查实录
4.1 小数据集过拟合的典型表现与对策
我拿小数据集训练YOLO时,最常遇到的问题就是过拟合。怎么判断过拟合?看训练曲线,如果train loss持续下降、val loss降到某个点后开始反弹,同时val mAP不再上升甚至下降,那基本就是过拟合了。
在172张数据上,过拟合几乎一定会出现,区别只是来得早还是晚。有几种手段可以缓解。
第一种是降低训练轮数并配合early stopping。我之前跑过一个实验,50轮时验证集mAP@50到0.91,继续跑到100轮反而跌到0.87,这就是典型的过拟合。所以训练时一定要盯着best.pt而不是last.pt,best.pt就是早停机制帮你选出来的最优权重。
第二种是增加数据增强强度。除了前面说的HSV扰动,还可以开启flipud(上下翻转)、scale(缩放)、translate(平移)。但注意,车间场景里人一般是直立站着的,上下翻转虽然能增加数据量,但会让模型学到“倒立的人”这种错误模式,所以flipud建议关闭,fliplr(水平翻转)可以开。
第三种是降低模型复杂度。如果yolov8s还是过拟合严重,可以换yolov8n,参数更少,虽然基准精度略低,但在小数据上可能反而效果更好。这个思路很多人想不到,但实测有效。
4.2 漏检与误检:工业车间的特有难点
用172张训练出来的模型放到车间真实视频流里跑,最容易出现两类问题:漏检和误检。
漏检主要集中在几个场景:工人背对摄像头且穿深色工作服时,人物和背景对比度太低;人在设备后面只露出半个身体时,检测框置信度偏低;光线强烈反光的地面上出现倒影时,模型有时会把倒影当成真实目标导致误检。
针对这些情况,我的处理顺序是:先在测试视频上跑一遍推理,把置信度阈值从默认的0.25调到0.1,看那些漏检的目标是否只是置信度低、但检测框位置其实是对的。如果确实是这样,说明模型是学到了特征的,只是不够自信,那可以通过补充类似难例的数据来提升。如果调到0.1仍然检不出来,说明模型完全没有学到这个模式的“人”,需要对这类场景单独抽帧补充标注。
误检则多半是模型把某些设备纹理、人形立牌、墙上的安全标识当成了人。查这个问题时,把推理结果可视化出来,逐张看误检目标的置信度分布。如果置信度普遍偏低,调高置信度阈值到0.35就能解决;如果置信度高,说明模型真的被某些视觉模式骗了,需要找一些这类负样本图片加入训练集,但注意负样本不需要标注,让模型看到这些图里没有人即可。
4.3 数据标注常见错误与清理方法
数据质量决定了模型上限,这是我在项目里反复验证的一句话。拿到数据集后,第一步不要急着训练,先做一个数据质量体检。
最常踩的坑有三个。
第一个坑是标注坐标越界。yolo格式要求坐标归一化到0到1之间,但有些标注工具导出时可能产生大于1或小于0的值,训练时会导致loss异常甚至报错。可以用下面这段代码快速检查:
import os label_dir = 'dataset/labels/train' for fname in os.listdir(label_dir): if not fname.endswith('.txt'): continue path = os.path.join(label_dir, fname) with open(path) as f: lines = f.readlines() for line in lines: parts = line.strip().split() if len(parts) != 5: print(f'{fname}: 字段数错误 -> {line}') continue cls, x, y, w, h = parts x, y, w, h = float(x), float(y), float(w), float(h) if not (0 <= x <= 1 and 0 <= y <= 1 and 0 <= w <= 1 and 0 <= h <= 1): print(f'{fname}: 坐标越界 -> {line}') print('检查完成')第二个坑是标注框不贴合目标。尤其是目标较小的工人,标注框经常偏大或者偏小。标签框偏大会给模型传递错误的目标范围信息,导致预测框总是或大或小。检查方法是把标注框画到图片上,肉眼扫一遍。用ultralytics提供的可视化脚本:
yolo detect val data=dataset/data.yaml model=dataset/runs/detect/train/best.pt会输出带预测框的可视化图片,但要看标注框本身,可以用opencv自己画一遍,我用下面这版脚本比较多:
import cv2 import os img_dir = 'dataset/images/train' label_dir = 'dataset/labels/train' for fname in os.listdir(img_dir): img_path = os.path.join(img_dir, fname) label_path = os.path.join(label_dir, fname.rsplit('.', 1)[0] + '.txt') img = cv2.imread(img_path) h, w = img.shape[:2] if not os.path.exists(label_path): continue with open(label_path) as f: for line in f: cls, x, y, bw, bh = line.strip().split() x, y, bw, bh = map(float, (x, y, bw, bh)) x1 = int((x - bw / 2) * w) y1 = int((y - bh / 2) * h) x2 = int((x + bw / 2) * w) y2 = int((y + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite('check_' + fname, img)第三个坑是类别命名不统一。有些数据集里同一类目标可能在不同图片里被标成person、people、worker、man,虽然语义一致,但YOLO会把它们当成不同类别。所以拿到数据后一定要检查labels目录下所有txt文件里的类别ID是否只有0,data.yaml中的nc是否为1。这个检查很简单,但往往决定训练是否顺利。
5. 模型部署与业务落地扩展
5.1 推理脚本:用训练好的权重做车间在线检测
训练的目标是落地。把这个训练好的best.pt接到实时视频流或者图片上,用ultralytics API非常直接:
from ultralytics import YOLO model = YOLO('runs/detect/train/best.pt') results = model.predict( source='车间视频.mp4', conf=0.25, iou=0.45, imgsz=640, save=True, classes=[0] # 只保留person类别 )如果接的是工业相机流,用cv2.VideoCapture读帧,然后逐帧推理:
import cv2 from ultralytics import YOLO model = YOLO('runs/detect/train/best.pt') cap = cv2.VideoCapture(0) # 换成实际相机ID或RTSP地址 while True: ret, frame = cap.read() if not ret: break results = model(frame, conf=0.25, iou=0.45, classes=[0])[0] annotated = results.plot() cv2.imshow('车间人员检测', annotated) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()这里要重点说一个参数配置思路:conf阈值要按实际场景调,固定摄像头场景下光照稳定,可以适当提高conf到0.3到0.4来减少误检;如果是移动巡检设备,画面变化快,conf可以降低到0.2左右,优先保证不漏检。iou在0.4到0.5之间,防止同一个人的多个框没有合并干净。
5.2 从人员检测到更多业务应用
训练好这个模型之后,它就是一个可持续扩展的基础能力。我在实际项目里常用的扩展方向有三个。
第一个是人员计数。在固定摄像头画面里划一条虚拟线或者一个虚拟区域,当检测到的人的中心点越过线或进入区域时计数加一。这可以统计产线某个工位的人员在岗时长,或者防止人员在危险区域逗留。
第二个是安全帽识别。工业安全场景里,人员检测通常和安全帽检测是配套的。常见做法是先用这个模型检测出人,再对人的头部区域做一次裁剪,用独立的分类模型判断是否戴了安全帽。这种级联方案比一次性训练多类别检测要稳定得多,因为安全帽是小目标,单独做分类更容易提高精度。
第三个是扩展为多类别检测。如果业务需要识别“人+安全帽+反光衣”,可以在现有标注基础上,补充这些类别的数据,把nc改成对应类别数,然后加载best.pt继续训练。这样可以保留已经在车间场景上学到的人员特征,不需要从头再来。
实际项目中,我发现用这种方式扩展类别,即使新类别数据只有几十张,结合迁移学习也能得到一个能用的模型。核心思路就是:不要每次都从零开始,让模型在已有积累上持续迭代。
最后再分享一个落地层面的小建议。如果模型要部署到边缘设备上,比如Jetson Nano或者RK3588这类板子上,建议把权重导出为TensorRT或ONNX格式,推理速度能提升不少。导出命令如下:
yolo export model=runs/detect/train/best.pt format=tensorrt imgsz=640导出后需要跑一遍验证集,确认导出前后mAP没有明显下降,一般fp16精度下差距在1%以内都属于正常。这一步很多人会忘记,但部署到实际设备前,精度对比验证是必须做的。
本文还有配套的精品资源,点击获取