简介这是一份面向YOLO系列目标检测学习者的仓库工人数据集聚焦仓储场景下的人员识别与安全监控需求适合正在做课程设计、毕业项目或算法验证的初学者与工程人员使用。压缩包共1870个文件包含623张jpg图像、623个txt标签、623个xml标签以及1个yaml配置文件整体约30.25MB图像与标注一一对应开箱即可投入训练与验证。数据集已按YOLO训练规范完成划分同时提供YOLO格式与VOC格式两套标注txt文件采用归一化的中心点与宽高比例坐标xml文件则保留传统VOC结构便于在不同框架间灵活切换。标签覆盖仓库工人这一单一类别可直接适配yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流版本省去自行标注与格式转换的繁琐环节。目前已有43人学习关注适合希望快速搭建仓储安全检测基线、验证模型效果或补充实战数据的读者参考使用。1. 仓库工人检测数据集到底能训出什么623 张图像背后的真实门槛623 张带标签的仓库工人图像听起来像是一个周末就能跑完的小数据集。但我第一次拿到类似规模的数据集时花了整整三天才让模型在验证集上不再把货架阴影识别成人。仓库场景的特殊性在于光照极端不均、人员被货架和纸箱大面积遮挡、工服颜色和背景高度接近这些因素叠加起来让一个在 COCO 上 mAP 能到 50 的预训练模型直接迁移过来可能连 20 都保不住。这个数据集的核心价值不在于量大而在于场景聚焦。623 张图像全部来自仓库环境标注目标明确指向工人这一类别这意味着你不需要在通用数据集上做漫长的类别筛选和场景过滤。它适合三类人一是做仓储安全监控、需要快速验证检测方案可行性的工程师二是想在有限数据条件下练习 YOLO 微调流程的开发者三是需要评估小数据集 预训练权重这套组合到底能撑到什么程度的项目负责人。但我要先把预期说清楚623 张图像训练出来的模型不是一个可以直接部署到生产环境的成品。它的合理定位是原型验证和流程打通。你要验证的是这个技术路线在我的场景里能不能跑通而不是这个模型能不能直接上线。理解这一点后面的参数设置和训练策略才不会跑偏。2. 从压缩包到可训练格式YOLO 数据管线的搭建与校验2.1 先搞清楚压缩包里的目录结构再动手拿到warehouse-skj9z.zip这类数据集压缩包第一件事不是急着解压完就开训而是先看清楚它的组织方式。常见的仓库工人数据集有两种布局一种是已经整理成 YOLO 格式的images/labels/平行目录另一种是 VOC 风格的JPEGImages/Annotations/ImageSets/。这两种的处理路径完全不同搞错了后面全是白费功夫。我一般会先用一条命令把目录树打出来确认结构再决定下一步# 查看压缩包内容结构不急着全解压 unzip -l warehouse-skj9z.zip | head -50 # 如果确认是标准结构再解压到工作目录 mkdir -p ~/workspace/warehouse_dataset unzip warehouse-skj9z.zip -d ~/workspace/warehouse_dataset # 统计图像数量和标签数量是否匹配 find ~/workspace/warehouse_dataset -name *.jpg -o -name *.png | wc -l find ~/workspace/warehouse_dataset -name *.txt | wc -l这里的关键判断点是图像数和标签文件数是否一致。如果图像 623 张、标签只有 600 个说明有 23 张图没标注或者标注文件丢失这批图要么补标要么剔除不能直接混进去训。另一个要看的点是标签文件里的类别索引是从 0 开始还是从 1 开始YOLO 格式要求从 0 开始如果是 1 开头训练时会出现类别越界但不报错的玄学问题。2.2 用脚本做一次全量标签校验别靠肉眼抽查623 张图靠人眼看标注质量是不现实的但写个校验脚本十分钟就能跑完。校验的核心目标有三个坐标是否越界、类别索引是否合法、标注框面积是否过小。import os import glob def validate_yolo_labels(label_dir, num_classes1, min_area_ratio0.001): 校验 YOLO 格式标签文件的合法性 label_dir: 标签文件所在目录 num_classes: 类别总数仓库工人数据集通常为 1 min_area_ratio: 最小标注框面积占比过滤掉误标的小框 issues [] label_files glob.glob(os.path.join(label_dir, *.txt)) for lf in label_files: with open(lf, r) as f: lines f.readlines() if len(lines) 0: issues.append(f{lf}: 空标签文件) continue for i, line in enumerate(lines): parts line.strip().split() if len(parts) ! 5: issues.append(f{lf} 第{i1}行: 字段数不对期望5个实际{len(parts)}个) continue cls_id int(parts[0]) x, y, w, h map(float, parts[1:]) # 类别索引校验 if cls_id 0 or cls_id num_classes: issues.append(f{lf} 第{i1}行: 类别索引{cls_id}越界) # 坐标范围校验 if not all(0 v 1 for v in [x, y, w, h]): issues.append(f{lf} 第{i1}行: 坐标超出[0,1]范围) # 面积校验 if w * h min_area_ratio: issues.append(f{lf} 第{i1}行: 标注框面积过小 w{w:.4f} h{h:.4f}) return issues # 执行校验 problems validate_yolo_labels(~/workspace/warehouse_dataset/labels) print(f共发现 {len(problems)} 个问题) for p in problems[:20]: # 只打印前20条避免刷屏 print(p)这个脚本的逻辑很直白逐文件逐行读取检查字段数、类别索引、坐标范围和框面积。参数min_area_ratio设成 0.001 是一个经验值对应大约 32×32 像素的框以 640 分辨率计比这更小的框大概率是误标。跑完之后如果问题数量在个位数手动修一修就行如果超过 50 个说明标注质量本身有问题需要考虑是否重新清洗。2.3 划分训练集和验证集时别踩分布不均的坑623 张图按 8:2 划分训练集约 498 张验证集约 125 张。听起来简单但如果直接按文件名排序取前 80%很可能出现一种情况前 498 张全是白天光照的图后 125 张全是夜间或暗光图。这样训出来的模型在验证集上表现极差但你以为是模型不行实际上是划分方式有问题。我一般会先按图像亮度做一个粗略分层再在每层内随机抽样import os import random import shutil from PIL import Image import numpy as np def stratified_split(image_dir, label_dir, output_dir, val_ratio0.2): 按图像亮度分层划分训练集和验证集 避免光照分布不均导致的验证集偏差 images sorted([f for f in os.listdir(image_dir) if f.endswith((.jpg, .png))]) # 计算每张图的平均亮度 brightness_list [] for img_name in images: img_path os.path.join(image_dir, img_name) img Image.open(img_path).convert(L) arr np.array(img) brightness_list.append((img_name, arr.mean())) # 按亮度排序后分成5层每层内随机抽取验证集 brightness_list.sort(keylambda x: x[1]) n_layers 5 layer_size len(brightness_list) // n_layers val_images [] for i in range(n_layers): start i * layer_size end start layer_size if i n_layers - 1 else len(brightness_list) layer brightness_list[start:end] n_val max(1, int(len(layer) * val_ratio)) val_images.extend([x[0] for x in random.sample(layer, n_val)]) # 创建输出目录并复制文件 for split in [train, val]: os.makedirs(os.path.join(output_dir, images, split), exist_okTrue) os.makedirs(os.path.join(output_dir, labels, split), exist_okTrue) for img_name in images: split val if img_name in val_images else train shutil.copy(os.path.join(image_dir, img_name), os.path.join(output_dir, images, split, img_name)) label_name os.path.splitext(img_name)[0] .txt label_src os.path.join(label_dir, label_name) if os.path.exists(label_src): shutil.copy(label_src, os.path.join(output_dir, labels, split, label_name)) print(f训练集: {len(images) - len(val_images)} 张, 验证集: {len(val_images)} 张) stratified_split(~/workspace/warehouse_dataset/images, ~/workspace/warehouse_dataset/labels, ~/workspace/warehouse_split)这段代码的核心思路是先算每张图的平均灰度值作为亮度代理指标排序后分五层每层按比例抽验证集。这样保证验证集里既有亮图也有暗图评估结果才有参考意义。参数val_ratio在数据量小于 1000 时建议不低于 0.15否则验证集太小mAP 波动会很大。3. YOLO 微调参数怎么设623 张图不是把 epochs 拉满就行3.1 预训练权重选哪个版本直接决定收敛速度小数据集训练最忌讳从随机初始化开始。623 张图如果从零训模型根本学不到有效的底层特征大概率欠拟合。正确做法是加载在 COCO 上预训练的权重让模型带着通用的边缘、纹理、形状特征过来只需要微调高层语义部分。选权重时要注意两点一是模型规模要和数据量匹配623 张图用 YOLOv8n 或 YOLOv8s 就够了上到 YOLOv8x 参数量太大过拟合风险极高二是确认预训练权重的输入分辨率和你计划训练的分辨率不要差太多否则底层特征也要重新适应。# 以 YOLOv8s 为例加载 COCO 预训练权重进行微调 # 数据配置文件 data.yaml 需要提前准备好 yolo detect train \ modelyolov8s.pt \ data~/workspace/warehouse_split/data.yaml \ epochs150 \ imgsz640 \ batch16 \ lr00.001 \ lrf0.01 \ patience30 \ warmup_epochs5 \ cos_lrTrue \ mosaic0.5 \ mixup0.1 \ degrees10.0 \ translate0.1 \ scale0.5 \ fliplr0.5 \ project~/workspace/runs \ namewarehouse_yolov8s逐参数说明lr00.001是初始学习率小数据集微调时不要用默认的 0.01太大容易把预训练权重带偏lrf0.01是最终学习率因子配合余弦退火让学习率从 0.001 平滑降到 0.00001patience30表示 30 轮验证指标不提升就早停623 张图通常 80 到 120 轮就收敛了设 150 轮上限是留余量mosaic0.5是马赛克增强概率小数据集需要增强但不要拉满0.5 比默认的 1.0 更稳mixup0.1轻微混合增强再高会让小数据集欠拟合。3.2 数据增强参数要针对仓库场景做减法通用增强策略在仓库场景里有些是帮倒忙的。比如上下翻转flipud仓库工人永远是站立的上下翻转后变成倒立的人这种样本只会干扰模型学习。再比如大角度旋转degrees超过 15仓库监控摄像头角度固定训练时见过大角度旋转的样本推理时反而对正常角度不敏感。我一般会这样调整fliplr0.5保留左右翻转因为工人朝向左右都有flipud0.0关掉上下翻转degrees10.0限制旋转角度在正负 10 度以内hsv_h0.015、hsv_s0.7、hsv_v0.4这三个颜色增强参数保持默认或略微调低因为工服颜色是重要特征颜色抖动太剧烈会让模型忽略颜色线索。注意如果你不确定某个增强参数该不该开最稳妥的办法是先用默认参数训一版作为基线然后每次只改一个参数再训一版对比验证集 mAP。同时改多个参数出了问题根本不知道是哪个引起的。3.3 用验证集曲线判断是过拟合还是欠拟合训练跑起来之后看results.csv里的三条曲线就能判断状态训练损失持续下降但验证损失开始上升是过拟合训练损失和验证损失都居高不下是欠拟合两条损失同步下降且验证 mAP 稳步提升是正常收敛。623 张图最常见的问题是过拟合表现为训练 mAP 到 0.9 以上但验证 mAP 卡在 0.5 左右。这时候的应对手段按优先级排先加数据增强提高 mosaic 和 scale再降模型规模从 s 换到 n最后才是加 dropout 或 weight decay。不要一上来就加正则化小数据集本身信息量就少正则化太强会让模型什么都学不到。import pandas as pd import matplotlib.pyplot as plt # 读取训练日志绘制损失和mAP曲线 df pd.read_csv(~/workspace/runs/warehouse_yolov8s/results.csv) df.columns df.columns.str.strip() # 列名可能有空格 fig, axes plt.subplots(1, 2, figsize(14, 5)) # 损失曲线 axes[0].plot(df[epoch], df[train/box_loss], labeltrain_box_loss) axes[0].plot(df[epoch], df[val/box_loss], labelval_box_loss) axes[0].set_xlabel(Epoch) axes[0].set_ylabel(Loss) axes[0].legend() axes[0].set_title(Box Loss Curve) # mAP曲线 axes[1].plot(df[epoch], df[metrics/mAP50(B)], labelmAP0.5) axes[1].plot(df[epoch], df[metrics/mAP50-95(B)], labelmAP0.5:0.95) axes[1].set_xlabel(Epoch) axes[1].set_ylabel(mAP) axes[1].legend() axes[1].set_title(mAP Curve) plt.tight_layout() plt.savefig(training_curves.png, dpi150)这段代码把训练日志里的关键指标画出来比盯着终端输出滚动数字直观得多。重点看验证 mAP 是否还在提升如果连续 20 轮以上持平或下降就可以手动停掉不用等早停触发。4. 小数据集训练的避坑清单从标注到推理的五个翻车点4.1 标注框把货架边缘框进去导致模型学偏现象模型在验证集上能把人框出来但框明显偏大经常把旁边的货架也包进去。原因标注时标注人员为了保险把工人周围的货架边缘也框进了边界框模型学到的是人货架的组合特征。解决重新检查标注确保边界框紧贴人体轮廓对于被货架遮挡的工人只框可见部分不要脑补完整人体。4.2 验证集 mAP 很高但实际推理全是误检现象验证集 mAP0.5 到了 0.85但拿几张新图测试模型把纸箱堆、拖车、甚至地面反光都识别成人。原因验证集和训练集来自同一批数据分布完全一致模型只是记住了这批数据的特征没有学到泛化能力。解决从原始数据里额外留出 20 到 30 张完全不参与训练和验证的测试图训练结束后用这批图做最终评估。如果测试集表现远低于验证集说明过拟合严重需要加增强或减模型。4.3 图像尺寸不一致导致训练时隐式缩放失真现象训练能跑但推理时检测框位置偏移尤其是图像边缘的目标。原因数据集中图像分辨率不统一YOLO 默认会缩放到imgsz指定的大小如果原始图像长宽比差异大缩放后目标变形模型学到的框位置和实际不对应。解决训练前统一检查图像尺寸分布对长宽比差异过大的图像做 padding 而不是直接拉伸。from PIL import Image import os from collections import Counter # 统计图像尺寸分布 sizes Counter() for f in os.listdir(~/workspace/warehouse_split/images/train): img Image.open(os.path.join(~/workspace/warehouse_split/images/train, f)) sizes[img.size] 1 for size, count in sizes.most_common(10): print(f尺寸 {size}: {count} 张)如果统计结果里出现超过 5 种不同尺寸且最大最小长宽比差距超过 2:1就值得做一次统一的 letterbox 预处理。4.4 类别配置文件写错导致训练不报错但结果全乱现象训练正常跑完loss 也在降但推理时所有框的类别都是 0或者置信度极低。原因data.yaml里的nc类别数和names类别名不匹配或者标签文件里的类别索引超出了nc范围。YOLO 在某些版本里不会对类别越界做严格校验导致训练时静默出错。解决训练前用 2.2 节的校验脚本跑一遍确认所有标签的类别索引都在[0, nc-1]范围内。4.5 学习率太大把预训练权重带偏导致不收敛现象训练前 10 轮 loss 剧烈震荡mAP 一直是 0或者 loss 直接变成 nan。原因初始学习率设成了 0.01 或更高对于 623 张图的小数据集来说梯度更新太猛预训练权重被破坏。解决把lr0降到 0.001 甚至 0.0005同时加warmup_epochs5让学习率在前 5 轮从极小值线性升到设定值给模型一个适应过程。5. 把 623 张图的模型用到位推理调优与数据回流的实操技巧训练结束拿到best.pt只是第一步真正决定这个方案值不值得投入的是推理阶段的调优和数据回流机制。我见过太多人训完模型直接拿默认参数去跑结果因为置信度阈值不合适要么漏检一堆要么误检满屏然后得出小数据集训出来的模型不能用的结论。实际上调参空间比想象中大得多。先说推理时的三个关键参数。conf置信度阈值默认是 0.25但在仓库工人检测场景里我一般会先把它降到 0.15 跑一遍看召回率能到多少再逐步往上加找到召回和误检的平衡点。iou是 NMS 的 IoU 阈值默认 0.7如果工人密集站立这个值要降到 0.5 左右否则相邻两个人的框会被合并成一个。imgsz推理分辨率可以和训练时不同但不要低于训练分辨率的一半否则小目标全丢。# 用不同置信度阈值批量测试找到最佳工作点 for conf in 0.15 0.20 0.25 0.30 0.35; do echo conf$conf yolo detect val \ model~/workspace/runs/warehouse_yolov8s/weights/best.pt \ data~/workspace/warehouse_split/data.yaml \ conf$conf \ iou0.5 \ imgsz640 \ splitval done跑完这组对比你会得到一张置信度 vs mAP 的对应表。通常在小数据集上最佳 conf 会比默认值低 0.05 到 0.1因为模型本身置信度输出偏保守。再说数据回流。623 张图训出来的模型部署后一定会遇到漏检和误检。这些错误样本是最有价值的训练数据因为它们来自真实分布而且正好是模型的薄弱点。我的习惯是每次推理后把置信度在 0.1 到 0.3 之间的模糊样本单独存下来人工确认后补标积累到 50 到 100 张就重新训一版。这样迭代三轮左右模型在真实场景的表现会有明显提升比一次性堆几千张图效果好得多。from ultralytics import YOLO import cv2 import os model YOLO(~/workspace/runs/warehouse_yolov8s/weights/best.pt) uncertain_dir ~/workspace/uncertain_samples os.makedirs(uncertain_dir, exist_okTrue) # 对一批新图推理保存模糊样本 test_images [img_001.jpg, img_002.jpg, img_003.jpg] # 替换为实际路径 for img_path in test_images: results model(img_path, conf0.1, iou0.5) for r in results: boxes r.boxes if boxes is None: continue # 筛选置信度在0.1到0.3之间的框 uncertain [b for b in boxes if 0.1 float(b.conf) 0.3] if uncertain: img cv2.imread(img_path) for b in uncertain: x1, y1, x2, y2 map(int, b.xyxy[0]) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 255), 2) cv2.putText(img, f{float(b.conf):.2f}, (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 1) save_name os.path.join(uncertain_dir, os.path.basename(img_path)) cv2.imwrite(save_name, img) print(f保存模糊样本: {save_name})这段代码的逻辑是用低置信度阈值推理把置信度落在 0.1 到 0.3 之间的框画出来存成新图人工过一遍确认是漏检还是误检然后针对性补标。参数conf0.1是故意设低的目的是把模型犹豫的样本都捞出来宁可多捞一些人工筛也不要漏掉真正的问题样本。最后说一个我踩过的坑不要用验证集的指标来决定模型是否上线。验证集 mAP 到 0.8 不代表实际能用因为验证集和训练集同分布。我现在的习惯是训练结束后一定留出至少 30 张从未参与任何训练的图做最终测试这 30 张图的 mAP 才是我判断模型能不能用的依据。如果测试集 mAP 比验证集低超过 15 个点说明过拟合严重需要回头加数据或减模型而不是硬着头皮部署。希望帮到你。本文还有配套的精品资源点击获取