简介面向目标检测学习与研究者的工具类物体检测数据集聚焦钳子、剪刀、螺丝刀三种常见工具适合模型训练、算法评估与工业场景识别。压缩包共2000个文件绝大多数为XML标注文件1999个另附TXT说明整体83.44MB资源同时提供VOC格式XML标注及YOLO格式标注信息便于接入主流检测流程。数据内容涵盖3668张图片标注框总数3686个类别分布screwdrivers 1712框、pliers 1568框、scissors 406框可为样本均衡与评估分析提供参考。目前已有411人学习适合目标检测入门、迁移学习或工具识别项目使用。标注采用labelImg矩形框完成格式统一规范省去自行采集与标注的时间拿到后即可用于模型训练、调参和对比实验。1. 工具检测数据集钳子、剪刀、螺丝刀识别为什么值得拿它跑通你的第一个YOLO训练做目标检测的人手里最缺的往往不是模型而是一份「拿来就能跑」的数据集。这份【目标检测数据集】工具钳子、剪刀、螺丝刀检测数据集3668张图片、3个类别同时提供VOC和YOLO两种标注格式正好把「格式适配」这个最烦人的环节替你省掉了。钳子、剪刀、螺丝刀这类五金工具识别在工地安全巡检、工位规范管理、工具清点防丢失这些场景里有很实际的需求模型本身不算复杂是典型的中小规模检测任务。适合刚入门目标检测的开发者拿来跑通全流程也适合做工业视觉方案的人快速验证算法选型。数据量不大单卡就能训练踩坑成本低出结果快。2. VOC和YOLO两种标注格式目录结构、XML与txt的对应关系以及一份通用转换脚本2.1 VOC格式到底是什么一张图片对应一个XML文件VOC格式源自PASCAL VOC竞赛后来成了检测领域最通用的数据交换格式之一。它的核心思想很简单每一张图片对应一个同名的XML标注文件检测框和类别信息全部写在这个XML里。拿到数据集后你会看到类似这样的目录结构VOC/ ├── Annotations/ │ ├── 000001.xml │ ├── 000002.xml │ └── ... ├── JPEGImages/ │ ├── 000001.jpg │ ├── 000002.jpg │ └── ... └── ImageSets/ └── Main/ ├── train.txt └── val.txtXML文件里真正有用的字段并不多。打开一个标注文件看一下重点就是object节点下的两个子结构name是类别名bndbox是检测框坐标包含xmin、ymin、xmax、ymax四个整数。filename和folder是给人看的训练时一般用不到。这份工具检测数据集给的XML和图片文件名是一一对应的所以脚本遍历Annotations目录就能拿到全部标注。提示拿到手先别急着写脚本打开一个XML确认坐标是整数且不超过图片宽高是排查标注损坏的第一步。2.2 YOLO格式的核心归一化坐标和类别索引YOLO格式和VOC最大的区别有两点类别名换成了从0开始的数字索引坐标换成了归一化到[0,1]的相对值。每一行代表一个目标五个字段依次是类别索引 中心点x 中心点y 框宽 框高。这份数据集里三类工具的索引约定是钳子pliers0剪刀scissors1螺丝刀screwdriver2。这个顺序必须先在脑子记住训练脚本报错八成和它有关。从VOC转YOLO的换算公式是固定的不存在玄学中心点x等于(xmin xmax) / 2 / 图片宽度中心点y等于(ymin ymax) / 2 / 图片高度框宽等于(xmax - xmin) / 图片宽度框高等于(ymax - ymin) / 图片高度。四个值全部保留6位小数就够了转出来是0到1之间的小数如果出现大于1的值说明原始XML的坐标已经越界。两者的对应关系可以用这张表记信息项VOCXMLYOLOtxt类别name字符串第1列整数索引框中心x(xminxmax)/2第2列框中心y(yminymax)/2第3列框宽xmax-xmin第4列框高ymax-ymin第5列这份工具检测数据集已经把两种格式都对齐转好了你不需要自己动手转。但实际工作中你可能会收集到只有VOC格式的新数据或者想把这份数据扩充进自己的项目所以还是建议留一份通用转换脚本在手边下面这段是我常用的。import os import xml.etree.ElementTree as ET from PIL import Image # 类别索引必须和data.yaml里的names保持一致 CLASS_MAP {pliers: 0, scissors: 1, screwdriver: 2} def voc_to_yolo(xml_path, img_dir, out_dir): tree ET.parse(xml_path) root tree.getroot() img_name root.findtext(filename) img Image.open(os.path.join(img_dir, img_name)) img_w, img_h img.size lines [] for obj in root.iter(object): name obj.findtext(name) if name not in CLASS_MAP: continue box obj.find(bndbox) xmin float(box.findtext(xmin)) ymin float(box.findtext(ymin)) xmax float(box.findtext(xmax)) ymax float(box.findtext(ymax)) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{CLASS_MAP[name]} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) txt_name os.path.splitext(img_name)[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines)) # 使用 xml_path VOC/Annotations/000001.xml out_dir YOLO/labels os.makedirs(out_dir, exist_okTrue) voc_to_yolo(xml_path, VOC/JPEGImages, out_dir)这段脚本的核心逻辑是解析XML的bndbox换算归一化坐标最后写一行txt。CLASS_MAP字典是关键它把类别名映射到索引若有一天类别顺序调整只改这一个地方就能全局生效。img.size取的是宽高不是PIL.Image.size返回的宽,高顺序这个细节容易写反。2.3 拿到数据集后的第一步核对目录结构与类别索引我拿到任何检测数据集的第一件事不是急着训练而是先做一次「静态核对」。这步能拦住后面训练阶段至少一半的黑匣子报错。核对点有三个图片和标注文件的数量是否一致、VOC与YOLO两种格式的标注是否都能找到对应图片、三个类别的分布是否均衡。# 统计图片数量 ls VOC/JPEGImages/*.jpg | wc -l # 统计标注数量 ls VOC/Annotations/*.xml | wc -l # 统计每个类别出现多少次按VOC标注里的name统计 grep -h name VOC/Annotations/*.xml | sort | uniq -c # 抽查YOLO格式的标注看类别索引范围是否在0~2之间 awk {print $1} YOLO/labels/*.txt | sort -n | uniq -cgrep -h name能把所有XML里的类别标签抽出来排序统计一眼看出数据集中哪个类别样本多、哪个少。awk {print $1}则是从YOLO格式的txt里取第一列做同样的统计。两边数量一致且类别索引在0到2之间才说明这份数据是干净的。如果发现图片3668张但标注缺了几张别侥幸直接补上或者剔除对应训练索引训练时缺失标注会导致loss直接算错而且不好排查。3. 用YOLOv8训练这个工具检测数据集从环境到出模型的最小命令3.1 环境准备用conda隔离环境装ultralytics训练YOLO现在最省事的方式是用ultralytics这个库YOLOv8到YOLO11都走同一套命令。建议用conda单独建一个环境避免把系统Python搞乱。Python版本用3.10就好没必要追新。conda create -n tool_detect python3.10 -y conda activate tool_detect pip install ultralyticsultralytics会自动拉上torch、torchvision、opencv这些依赖。装完后可以跑yolo --version确认安装成功。如果你习惯在PyCharm里写代码把项目解释器指到这个conda环境的python就行命令行训练和IDE调试可以共用一套环境。GPU训练建议先确认nvidia-smi能正常输出驱动和CUDA的匹配问题在这类小数据集上不值得花时间折腾。3.2 写一个data.yaml路径、类别名和一个常被忽略的坑ultralytics全家桶都通过一个YAML文件描述数据集的路径、类别数和类别名。很多新手在这里直接踩坑path写成相对路径训练报错找不到图片或者names的顺序和标注txt里的索引对不上导致模型把钳子当成剪刀训练了100个epoch才发现。所以这份data.yaml里的每一行都要较真。# data.yaml path: /home/user/tool_dataset # 数据集根目录建议写绝对路径 train: images/train # 训练集图片相对path的路径 val: images/val # 验证集图片相对path的路径 nc: 3 # 类别数必须和txt索引最大值的1一致 names: 0: pliers 1: scissors 2: screwdrivernames的映射顺序是我反复强调的点。如果你自己重新生成过标注务必让CLASS_MAP、txt里的第一列数字、这里的names三个地方的顺序完全一致。数据集解压后如果data.yaml里边的path是旧机器的路径训练前先改成自己机器上的实际路径这是最常见的报错根源。3.3 开始训练一行命令和它的四个关键参数环境就绪、配置文件写好训练命令就只有一行。为了先跑通流程强烈建议先用最小的nano模型验证数据管道没问题再换s或m模型提精度。数据管道有没有问题前5个epoch就能看出来——loss如果完全不下降查找数据加载环节比调参有意义得多。yolo detect train \ data/home/user/tool_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ device0modelyolov8n.pt会从ultralytics的官方权重目录自动下载预训练权重第一次运行需要联网。用预训练权重做迁移学习在小数据集上收敛明显更快且更稳。epochs100对这个规模的工具检测任务来说够用结合早停一般会在五六十个epoch时停止。imgsz640是速度和精度的平衡点如果你的图片本身分辨率很高且标记的目标很小可以提到960。batch16根据显卡显存调整12G显存跑nano模型完全无压力。如果只有CPU把device0改成devicecpu但训练时间会慢很多3668张图可能要跑几个小时。3.4 训练过程中看什么loss三件套和mAP曲线训练开始后终端会持续输出box_loss、cls_loss、dfl_loss三个损失值以及最后的mAP50和mAP50-95指标。很多新手只盯着loss看其实在这个阶段你更该关注验证集的mAP50有没有在稳步上升。loss下降但mAP不动大概率是类别索引错位或者验证集出问题。训练结束后runs/detect/train目录下会保存最后一轮权重last.pt和最优权重best.pt还有results.png汇总了所有曲线confusion_matrix.png值得放大看。别急着删掉last.pt如果best.pt是在第40轮保存的而你又加了数据有时回退到last.pt换个增强策略反而更优。4. 训练结果与参数调优mAP怎么读、过拟合怎么防、三个必调参数4.1 从results.csv读指标mAP50与mAP50-95的区别训练跑完ultralytics会在结果目录里生成一个results.csv每一行对应一个epoch。不要用眼睛扫终端输出去评估模型用pandas把这个文件读进来才算正式看结果。import pandas as pd df pd.read_csv(runs/detect/train/results.csv) df.columns df.columns.str.strip() # 去掉列名首尾空格 print(df.columns.tolist()) print(df[[epoch, metrics/mAP50(B), metrics/mAP50-95(B)]].tail(10))metrics/mAP50(B)表示IoU阈值取0.5时的平均精度直观反映模型「框框基本框得准不准」。metrics/mAP50-95(B)是对0.5到0.95之间不同IoU阈值求平均要求框和真实位置贴得极其精确所以数值通常会低一截。对于钳子剪刀螺丝刀这类紧凑工具目标mAP50能到0.9以上算很理想mAP50-95在0.7以上已经说明模型质量不错。如果mAP50高但mAP50-95明显低说明检测框边界还不够贴合可以在后处理阶段调整conf阈值或者把imgsz提到960再训一轮。提示别拿mAP50-95当作唯一真理工业场景里只要框的误差不影响后续操作mAP50-95低一点也不致命。4.2 数据增强是这类小数据集的关键mosaic与hsv的取舍3668张、3类放到深度学习里只能算中小规模数据集。工具又长得比较规整——钳子剪刀的金属反光、螺丝刀手柄的颜色和形状都相对单一很容易过拟合。YOLOv8默认开启了mosaic、hsv_h、hsv_s、fliplr等增强策略这是它能靠小数据量打天下的重要原因。我见过有人一上来就把mosaic关掉理由是「我的数据已经很干净了」结果mAP直接掉两三个点。训练命令里通过参数覆盖默认值即可例如yolo detect train \ data/home/user/tool_dataset/data.yaml \ modelyolov8s.pt \ epochs120 \ imgsz640 \ batch16 \ device0 \ mosaic1.0 \ hsv_h0.02 \ hsv_s0.7 \ fliplr0.5mosaic1.0表示每个训练batch里所有图片都可能参与拼接增强这对小数据集相当于免费扩充样本量特别是目标只有一两个的图拼图后模型被迫学习「在一堆工具里找目标」的更难任务。hsv_h是色调扰动幅度0.02属于保守设置适合金属反光明显的工具调太大会让颜色失真。fliplr是水平翻转概率0.5意味着约一半样本会翻转适用于钳子剪刀这类左右对称性不强的工具。如果你的工具存在明显方向性比如某个手柄在特定方向fliplr可以降到0.2甚至关掉但这种场景在五金工具里不常见。4.3 三个必调参数早停、batch大小、imgsz权衡把训练跑通之后真正拉开效果差距的是三个参数早停机制、batch大小、imgsz。三者不是独立的它们共同决定训练能走多远、每次参数更新看了多少样本、模型能看到多细的细节。参数推荐值调参会怎样patience20~30过早停止欠拟合过晚浪费时间且可能过拟合batch显存能承受的最大值的50%~80%太小收敛不稳太大需要降学习率imgsz640 / 960640快但小目标弱960精度高但显存和时间翻倍patience是早停参数默认100。我一般会显式设在训练命令里比如patience30意思是如果连续30个epoch验证集mAP50-95没有提升就停掉训练并保存最后那轮best。对小数据集这个机制特别重要因为模型可能在第50轮就饱和了剩下几十轮纯粹在拟合训练集噪声。batch的选择和显存直接相关16G显存跑nano模型可以试batch32如果显存溢出会直接报CUDA out of memory二分的做法是8、16、24、32这样试。imgsz这个参数最被低估很多人永远用640。如果你的螺丝刀在图片里占不到几十个像素640分辨率下模型可能压根看不清它的刀杆轮廓这时候把imgsz提到960mAP50-95往往有明显改善。代价是显存翻倍训练时间也接近翻倍。4.4 类别不均衡怎么办三样工具数量差异的处理工具类数据集最常见的毛病是类别分布不均衡摄像头对着工位很久拍到的钳子出现的次数远远多于螺丝刀那么模型会对高层特征丰富的类别产生偏置。你前面已经用awk统计过类别数。如果发现资源分布差距超过3:1就得干预了。常见做法有三个第一是通过数据增强给少数类制造更多变化比如对螺丝刀单独做旋转、裁剪扩增第二是调整学习权重YOLOv8训练可以不指定类权重但你可以把少数类图片复制多份进训练集相当于过采样第三最简单的方案是去拍摄场景里刻意多拍一些螺丝刀的近距离照片补充真实样本。三个方案优先级从低到高真实样本永远优于人工扩增。翻车的经验告诉我靠复制粘贴强行凑数短时间内mAP好看但模型在真实环境里遇到新角度螺丝刀时照样漏检。类别不均衡对最终mAP的影响没有前两节说的增强策略大所以别在这里过度用力。5. 避坑指南VOC转YOLO格式、训练路径、类别错位这几个常见坑怎么排查5.1 现象训练完模型把钳子大面积识别成剪刀 原因类别索引错位新手最容易翻车的坑就是类别索引。txt标注第一列是数字data.yaml里names是从0索引的列表一旦两者错位模型就学了一套「错位但自洽」的映射。训练时loss照样降mAP曲线也正常上涨因为模型确实学出了一一对应的关系只不过对应错了。排查方法很简单训练前找一对VOC和YOLO的同名文件人工比对打开一个XML看name再打开对应txt看第一列确认pliers对应0、scissors对应1、screwdriver对应2。如果整批标注的类别顺序有问题直接用我上一章的voc_to_yolo脚本从VOC重新生成YOLO标注改掉CLASS_MAP里的映射即可。5.2 现象数据集解压后训练报错找不到图片 原因路径里有中文目录或空格这个坑特别隐蔽尤其在Windows上解压数据集后文件夹一般位于C:\Users\张三\Downloads\工具数据集ultralytics底层调用图像读取库时对中文路径的兼容性不稳定偶尔能读、偶尔报错表现成「前50个epoch正常某个epoch突然崩溃」这种诡异模式。解决办法不是改代码而是把数据集整个挪到纯英文无空格的路径下比如D:/datasets/tool_dataset。macOS和Linux用户同样不要用带空格或中文的目录名这是图像处理库的通用毛病。我自己的习惯是数据集目录统一放~/datasets/下面工程名和数据都用下划线连接一劳永逸。5.3 现象验证集mAP高达0.98现场测试却一塌糊涂 原因训练集和验证集重叠数据集解压后如果直接按默认目录切分而默认目录恰好是按时间连续采样的极有可能出现同一把钳子的多张连续帧图片被分进训练集和验证集。模型在验证集上考的是「开卷考试」见过类似背景和角度mAP自然虚高。到真正部署环境里光线、桌面纹理、工具摆放角度一变立刻打回原形。排查方法是随机抽验证集20张图去训练集目录里找有没有连续编号的相似图片。解决方式也别无脑重排图片先按文件名做哈希去重确认没有重复帧后再按8:1:1随机切分而不是按目录顺序切。对于视频抽帧得到的数据集这个坑几乎必踩。5.4 现象训练前检查时发现有个别图片标签文件缺失 原因原始采集漏标了部分帧我遇到过一次异常是某个子文件夹的图片全部没有对应txt模型训练没报错但验证时那个类别的recall奇低查了很久才发现是这个文件夹的图参与了模型评估但没有任何标注它们全部被算成了「漏检」。解决分两种如果这张图里确实没有目标应当把图片从训练/验证列表里剔除而不是保留一个空的txt——空txt在ultralytics里会被当成背景负样本。如果图里明显有工具但没标就用labelImg或CVAT补标后再加进训练集不要让数据带伤训练。5.5 现象一开训练就报CUDA out of memory 原因batch和imgsz一次性拉太高这是个硬性的资源问题很多教程默认读者有24G大显存照抄命令自然翻车。11G显存如RTX 2080 Ti跑nano模型imgsz960直接爆显存。先降batch到4再降imgsz到640确保能跑起来然后逐步上调。另外记得在训练命令里加上workers4这个参数控制数据预读线程数默认值在Windows上容易卡死Linux上过高又可能共享内存不足。训练中途不用担心爆显存导致前面的进度白费ultralytics默认每个epoch都会保存checkpoint从上次断点继续加一行resumeruns/detect/train/weights/last.pt即可这算是它的后悔药机制。6. 部署前做完这一步用模型对真实照片做漏检压力测试再导出ONNX6.1 盲测留出一批「没见过的图」做压力测试训练集的mAP只是基本功真正决定模型能不能用的是一次「盲测」。做法是额外收集或从原始全量数据里注意这条会污染测试集此前没有先见之明的话就从验证集抽一小部分挑出20到30张模型训练时完全没见过的钳子剪刀螺丝刀照片最好包含不同光照、不同角度、不同杂乱背景的图。把它们放到一个独立目录运行验证命令yolo detect predict \ modelruns/detect/train/weights/best.pt \ source/home/user/test_imgs \ conf0.25 \ save_txtTrue \ save_confTruesave_txtTrue会为每张测试图输出一个txt标注save_confTrue同时在标注里附上每帧的置信度。盲测时重点看两类错误漏检图上明显有工具但没框出来和误检把螺丝刀手柄当成剪刀。漏检多的回训练集补充同角度样本误检多的把conf阈值提高试试。我自己的习惯是盲测图里至少保证有5张是把工具堆在一起的混乱场景这种场景最能暴露模型的鲁棒性问题。等模型在这批图上的表现稳定了再谈部署。6.2 转向ONNX部署导出和验证的一行命令训练完成后实际部署到服务端或边缘设备通常不用PyTorch直接推理而是导出ONNX格式。一是ONNX不依赖训练环境换个机器不需要额外装torch二是可以配合TensorRT做加速推理时间能缩到几毫秒级别。导出命令很简单yolo export modelruns/detect/train/weights/best.pt formatonnx imgsz640导出的best.onnx默认放在权重同目录下。导出后别急着接业务代码先用同一张测试图对比PyTorch模型和ONNX的推理结果置信度差异在0.01以内才是正常。如果发现ONNX推理结果明显不同先检查导出时imgsz是否和训练时一致——这是导出环节最常踩的坑Train时640、Export时960会让输出特征尺寸错位。至此从一份VOCYOLO双格式数据集到一套可部署的检测模型完整跑通了。以后再做类似项目我会先把数据集的类别分布和格式一致性测一遍再做训练这个习惯帮我省了很多次重训的重复劳动。希望帮到你。本文还有配套的精品资源点击获取