首页 / 资讯中心 / 文章详情

AGV仓储机器人目标检测数据集:从标注到训练的避坑指南

AGV仓储机器人目标检测数据集:从标注到训练的避坑指南 ★ FEATURED ARTICLE
简介面向仓储物流场景的AGV机器人识别任务数据集包含一千五百一十四张实拍图像及完整标注涵盖三个类别即G1PB2000_Paleteira_AGVS BYD、G1RB5000和AGV-P。数据同时提供YOLO格式的文本标签与VOC格式的XML标签并附类别信息配置文件可直接用于YOLO系列及Faster Rcnn、SSD等主流目标检测模型的训练。所有图片与文本标签已按训练集、验证集和测试集划分完毕省去自行分集的预处理步骤压缩包内文件组织规范便于导入实验和二次开发。压缩包共两千个文件其中文本标签一千五百一十个XML标签四百八十九个配置文件一个整体大小八十二点三六兆字节结构清晰。目前已有三百八十三人学习使用适合智能仓储与机器人视觉识别方向的开发者、研究人员快速启动项目也可作为算法效果对比与参数调整的基础数据。1. AGV 仓储机器人识别数据集目标检测任务里最容易低估的一环做 AGV 仓储机器人视觉的人大概率都有过这种经历算法模型换了好几个版本YOLO 从 v5 追到 v8精度就是卡在某个点位上不去。后来仔细排查才发现问题压根不在模型结构而是训练数据本身——类别分布不均匀、标注框有偏移、小目标样本太少、背景负样本缺失。这个 AGV 仓储机器人识别数据集就是冲着这些痛点来的。它面向的是仓储物流场景下的目标检测落地覆盖料箱、货架、托盘、人员、AGV 本体等典型类别标注格式是 YOLO 的 txt 格式可以直接喂给 YOLOv5/YOLOv8 这类主流检测框架跑训练。适合正在做仓储机器人视觉方案、AGV 调度系统配套感知模块或者拿真实业务数据做算法验证的工程师。比你自己从零标注省下大量时间而且类别体系、标注边界都按实际场景规范化过踩坑率低不少。2. 数据集构成与标注规范先搞清楚往里喂的是什么2.1 标签体系与场景分布仓储 AGV 的识别任务和通用目标检测有个明显的不同目标的类别层次非常垂直而且强依赖具体业务场景。一般会按「搬运对象 — 基础设施 — 动态障碍物」三类来组织搬运对象包括料箱、货架、托盘基础设施常见的是地面二维码、导轨、月台边缘动态障碍物则是人员、其他 AGV、叉车。这个数据集的标签体系基本也是这么设计的每张 JPEG 图片对应一个同名 txt 标注文件每行记录一个目标实例。拿到数据集第一步我建议先做标签分布摸底不要直接开训。用下面这个脚本统计每个类别的实例数量和图片数量判断是否存在明显的长尾分布import os from collections import Counter label_dir labels/train class_names [box, shelf, pallet, person, agv, forklift] cls_counter Counter() img_with_anno 0 total_imgs 0 for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue total_imgs 1 fpath os.path.join(label_dir, fname) with open(fpath, r) as f: lines f.readlines() if len(lines) 0: img_with_anno 1 for line in lines: parts line.strip().split() if len(parts) 1: cls_counter[int(parts[0])] 1 print(f总图片数: {total_imgs}, 有标注图片数: {img_with_anno}) for cls_id, cnt in sorted(cls_counter.items()): cls_name class_names[cls_id] if cls_id len(class_names) else funknown_{cls_id} print(f类别 {cls_id} ({cls_name}): {cnt} 个实例)运行这个脚本后你看到的类别分布直接决定后续策略。比如 person 和 forklift 的实例数远少于 box那么训练时就要给这些少数类提高 loss 权重或者做针对性的过采样。另一个值得关注的数字是「有标注图片数」和「总图片数」的比值——如果大量图片是纯背景负样本那是好事训练出来的模型误检率会更低如果这个比例接近 1说明数据集几乎全是正样本后面需要自己补充背景图。2.2 标注质量检查与清洗标注质量是数据集能不能用的分水岭。仓储场景里常见的标注问题有三类第一类是框的边界卡在目标边缘导致 IoU 计算时目标框和真实框对不齐第二类是漏标小目标比如远处的料箱被直接忽略第三类是类别混淆托盘和货架在视觉上某些角度很像标注员容易标串。检查标注质量有个高效的做法统计每个标注框的宽高分布和相对图片尺寸的比例。仓储场景中料箱这类目标有固定的物理尺寸在固定高度相机下其像素宽高应该落在一个集中区间。如果某个类别的框面积异常大或异常小大概率是标注问题# 统计每张图的标注框数量分布异常集中的要复查 awk {print FILENAME, NF} labels/train/*.txt | awk {print $1, $2} | sort | uniq -c | sort -rn | head -20这条命令会把每张图片的标注框数量列出来正常情况大多数图片有 1~5 个目标。如果发现某些图片有几十个框检查是不是把地面纹理、阴影误标成了目标如果大量图片只有 1 个框且集中在某一类检查是不是漏标了同场景的其他类别。我一般会抽样 5%~10% 的图片用标注可视化工具叠加标签确认这一步看起来费时但能帮你省掉后面模型反复调优的大把时间。常用的标注工具有 labelImg、X-AnyLabeling、LabelStudio 等其中 X-AnyLabeling 支持加载 YOLO 格式直接校对比较适合做质量抽检。3. 标注格式转换与训练集构建把数据变成模型能吃的样子3.1 统一为 YOLO txt 格式这个数据集给到的是 YOLO 格式但实际项目里你经常会拿到 VOC 的 XML 或者 COCO 的 JSON。如果你需要把格式统一到 YOLO核心就是坐标系的换算。YOLO 格式的五个数字分别是类别 id、归一化中心 x、归一化中心 y、归一化宽 w、归一化高 h。归一化是指除以图片的原始宽高。从 VOC XML 转 YOLO 的脚本我一般这样写import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_dir, classes): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) base os.path.splitext(os.path.basename(xml_path))[0] out_path os.path.join(out_dir, base .txt) with open(out_path, w) as f: for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h f.write(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}\n) classes [box, shelf, pallet, person, agv, forklift] xml_dir annotations/xml out_dir labels/yolo os.makedirs(out_dir, exist_okTrue) for xml_name in os.listdir(xml_dir): if xml_name.endswith(.xml): voc_to_yolo(os.path.join(xml_dir, xml_name), out_dir, classes)逻辑说明脚本每个 XML 文件对应生成一个 txt 文件类别名通过 classes 列表映射成整数 id。注意两点一是在转换前确认 XML 里的类是闭集不要在映射过程中静默丢弃未知类别否则会出现训练时类别 id 与标签对不上的问题二是如果用的是 Rotated 标注带有角度信息的旋转框直接转成 YOLO 水平框会丢失角度信息更适合结合 SAHI 这类切片推理方案来处理。3.2 目录结构与数据划分策略YOLO 训练数据目录组织标准化后后续的流程会省心很多。建议按下面的结构组织datasets/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamltrain 和 val 的划分要特别小心——按图片随机划分是最简单的方式但如果同一场景拍了多张连续帧直接随机切分会导致训练集和验证集出现数据泄露你会在训练指标上看到虚高的 mAP。正确做法是按场景或按时间切片划分保证同一个物理场景的连续帧落在同一个集合里。划分脚本用随机种子控制可复现性import os import random import shutil random.seed(42) image_dir images/all label_dir labels/all val_ratio 0.2 imgs [f for f in os.listdir(image_dir) if f.endswith(.jpg)] random.shuffle(imgs) val_count int(len(imgs) * val_ratio) val_imgs set(imgs[:val_count]) train_imgs imgs[val_count:] for split, img_list in [(train, train_imgs), (val, val_imgs)]: os.makedirs(fimages/{split}, exist_okTrue) os.makedirs(flabels/{split}, exist_okTrue) for img in img_list: shutil.copy(os.path.join(image_dir, img), os.path.join(fimages/{split}, img)) label_name os.path.splitext(img)[0] .txt label_src os.path.join(label_dir, label_name) if os.path.exists(label_src): shutil.copy(label_src, os.path.join(flabels/{split}, label_name))这个脚本的 val_ratio 设置成 0.2 是常见做法如果数据量大到几千张0.15 甚至 0.1 也可以。关键是那个random.seed(42)固定种子后每次执行划分结果一致后期做消融实验或者复现论文结果时不会因为数据划分不同出现偏差。data.yaml 文件里要指定路径和类别名。类别名顺序必须和标注文件里的类别 id 完全对应YOLO 的类别 id 是从 0 开始的索引。如果标注意见里出现class_names [box, ...]但在 data.yaml 里写成了names: [pallet, ...]模型训练起来会直接乱套。4. 训练与调优避坑四个高频翻车点及排查方案4.1 类别 id 不连续导致 loss 异常现象训练一开始 loss 就非常大或者 loss 下降极慢甚至出现 NaN。原因标注文件里出现了超出 data.yaml 类别数量的 id。比如你定义 6 个类别但标注文件里出现了 id 为 7 或者 8 的标签这通常是在标注阶段使用了多套标签体系、合并数据时没统一类别映射导致的。解决在训练前做一次全局标签扫描检查 max id 是否小于类别总数。我曾经在处理这个数据集时发现部分 txt 文件里混入了另一个项目标注的9和10主语料 6 个类别这两个多余 id 直接把训练搞崩了。现在我都会在训练前跑一遍for f in labels/train/*.txt; do awk {print $1} $f done | sort -n | uniq all_class_ids.txt cat all_class_ids.txt如果输出里有超出0~5的数字直接定位到对应 txt 文件修正标签。4.2 小目标漏检与标注框偏移现象训练完成后验证集 mAP 看着还行但到了实际仓库测试远处或画面边缘的料箱检测不到检测框明显偏离目标中心。原因两个源头叠加。一个是标注阶段框太贴目标边缘没有留出适当余量导致模型学到的框偏紧IoU 阈值一高就被判为漏检另一个是下采样倍数太高小目标经过网络多层下采样后特征图上的像素占比太小。仓储场景里相机架高俯拍目标在画面中占的面积比例通常很小。解决标注阶段给框留 1% 的余量训练时把输入分辨率提上去——YOLOv8 默认 640仓储场景我建议直接拉到 960 或 1280如果你的显存撑得住同时开启 mosaic 增强。Mosaic 增强对提升小目标 recall 有明显作用它把四张图拼接成一张等于变相增加了每个目标在训练图里的上下文信息。4.3 训练集和验证集数据泄露现象训练过程 loss 正常下降验证集 mAP 高到离谱但一到现场测试表现很差。原因划分数据集的时候按文件名随机 shuffle同一批连续帧被分到了 train 和 val 两个集合。模型在验证集上「见过」几乎一样的图指标自然虚高。这在监控视频截帧类数据里特别常见——这个 AGV 数据集如果是按视频流截帧的就很容易踩中这个坑。解决不能按文件随机切分要按视频片段或采集时间切分。我处理的方案是先把所有图片按文件名前缀的采集批次分组同一组的图片要么全部进 train要么全部进 val。4.4 类别不平衡导致少数类 AP 极低现象总的 mAP 有 0.8 以上但单独看 person 或 forklift 的 AP 只有 0.3。原因这个数据集里料箱、货架的数量远多于人员和叉车模型天然偏向多数的类别少数类在训练中被大类的梯度淹没。解决给少数类加 loss 权重。YOLOv8 支持在损失函数里按类别配置权重也可以在数据层面做 oversampling——把少数类的图片复制几份放进训练集。更稳的做法是加入负样本。AGV 路径上经常出现人形轮廓的阴影、货架缝隙这类「像人但不是人」的区域如果不作为背景参与训练模型就会把阴影误检成人。我一般在训练集里额外准备 5% 的纯负样本图片这些图片不标注任何框作用是让模型学到「这些场景里没有目标」。5. 训练参数配置与验证技巧让结果有说服力5.1 从预训练权重开始微调拿到数据别从零训练。从 COCO 预训练权重微调是通用做法收敛快且精度高。YOLOv8 的启动命令yolo train modelyolov8m.pt datadata.yaml epochs150 imgsz960 batch16 device0,1 patience30 projectruns/agv参数说明modelyolov8m.pt用 COCO 预训练权重初始化m 是中等模型AGV 识别场景不算极端复杂m 是性价比均衡点imgsz960是针对小目标做的输入分辨率提升显存不够就降到 640 但小目标 recall 会受影响patience30表示连续 30 个 epoch 验证集指标不提升就早停防止过拟合device0,1是多卡训练单卡就写 0。仓储场景的训练我一般不开 mosaic 的全程启用——前 70% 的 epoch 开启后面关掉。原因是 mosaic 生成的合成图与真实场景分布有偏移后期关掉用原始图精调可以拉回分布。YOLOv8 里可以设置mosaic0.7配合close_mosaic30表示后 30 个 epoch 关闭 mosaic 增强。5.2 用可视化脚本定位漏检与误检训练完别只盯 mAP。mAP 是聚合指标它不告诉你模型在车间哪个位置翻车。我的习惯是随机抽一批验证集图片把预测框和真实框画在同一张图上肉眼扫一遍。写个简单的可视化脚本做预测结果对比import cv2 from ultralytics import YOLO model YOLO(runs/agv/weights/best.pt) img cv2.imread(val_samples/0001.jpg) results model.predict(img, conf0.25, iou0.45) for r in results: boxes r.boxes for box in boxes: x1, y1, x2, y2 box.xyxy[0].tolist() cls_id int(box.cls[0]) conf float(box.conf[0]) cv2.rectangle(img, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2) cv2.putText(img, f{cls_id} {conf:.2f}, (int(x1), int(y1) - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) cv2.imwrite(val_pred.jpg, img)这里conf0.25是置信度阈值iou0.45是 NMS 阈值。低一点的置信度阈值能看到更多漏检候选如果这里都检不出来那就是模型能力问题而不是阈值问题。我在实际项目里通常把 conf 降到 0.1 做一次分析目的就是看模型到底有没有学到目标的位置而不是被阈值挡住了。5.3 mAP 与混淆矩阵的可信度判断最后验证时不要只汇报一个 mAP0.5 了事mAP0.5:0.95 才是更有说服力的指标。它在多个 IoU 阈值下计算 AP 再取平均对框的定位精度更敏感。AGV 仓储场景如果 mAP0.5 过 0.9 但 mAP0.5:0.95 只有 0.5说明模型能框住目标但框的位置和真实位置偏差较大这种精度做料箱抓取可能不够。另外重点看混淆矩阵——person 和 forklift 之间、pallet 和 shelf 之间的混淆是仓储场景的老问题。如果这两个类别互相误检多半是训练数据里两个类别的样本背景太类似补充两者各自独立场景的负样本能有效缓解。做目标检测这些年我最大的感受是模型结构决定精度上限数据标注和数据分布才是决定你能不能摸到那个上限。从那以后我每次接到一个新的检测任务无论数据集是不是现成的都强制走一遍「标签分布统计 → 标注质量抽检 → 按场景划分 → 负样本补充」四步再好的模型结构也替代不了这一步的功夫。希望这份数据集和这些经验能帮你在 AGV 视觉落地上少走一段弯路。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站