
简介这是一份面向目标检测任务的数据集检测目标为起重机crane包含约2900张已标注图像对应的YOLO格式标签文件可直接用于YOLOv5、YOLOv8等主流检测模型的训练与评估。数据集已预先划分训练集与验证集免去自行整理的步骤。压缩包内共有2000个文件主体为1999个txt标注文件记录目标类别与归一化边界框坐标另有1个Python脚本show.py可辅助可视化标注结果、检查数据质量。资源包整体约146.53MB体量适中适合个人学习与小规模项目验证。目前已有498人学习下载。该数据集类别单一专注起重机定位能减少背景与多类别干扰适合验证检测网络在特定工业目标上的性能配合YOLO改进实战系列文章使用可更直观地比较改进前后的效果是一份兼具基础训练与算法探索价值的数据基础。1. 起重机检测数据集2900张YOLO标注图能直接拿来训练吗做施工安全监测、港口设备管理或者起重机作业区巡检的视觉方案时最卡进度的往往不是模型选型而是标注数据。公开的起重机图片不缺但零散下载的图没有统一尺寸、没有标签文件背景还掺着大量行人、车辆和塔吊钢索直接拿去训练第一个epoch就跑出一堆离谱的误检。这套约2900张、已标注、YOLO格式的起重机图像目标检测数据解决的就是这个起步问题拿到手不需要再做标注工具选型和人工拉框目录整理完就能喂给YOLO系模型做训练。适合正在做工业安全检测、吊装作业区域监控或港口无人化项目的算法工程师也适合拿来跑通一套完整的目标检测训练流程。2900张图对一个单类别检测任务来说处在够用但不算充裕的区间。它的价值不是让你刷出SOTA精度而是帮你把数据清洗、标签校验、训练配置、指标验证这一整条链路先跑通。下面按我自己的落地习惯从数据整理开始到训练参数、踩坑点、验证方法完整过一遍。2. 拿到数据集先做的三件事目录整理、标签校验与类别统计2.1 目录结构按YOLO训练惯例重新组织文件不管数据原来的压缩包内结构长什么样我拿到手的第一件事永远是先把目录改成YOLO标准布局。Ultralytics YOLO训练时默认按images和labels两个大类去读数据图片路径和标签路径一一对应这个结构不理顺后续训练时会出现大量label not found或者image not found的报错而且很难排查是路径问题还是文件缺失问题。crane_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/YOLO格式的数据集约定是图片在images目录下同名.txt标签文件放在labels目录下文件名必须完全一致不含扩展名部分相同。比如crane_001.jpg对应的标签文件必须是crane_001.txt放在labels的对应子目录里。train/val/test的划分比例我一般按8:1:1如果有官方划分文件就直接沿用没有就自己写脚本按文件名随机分配。标签文件的内容是每行一个目标格式为class_id center_x center_y width height前四个坐标值是归一化到0~1之间的小数不是像素值。这点我见过太多人踩坑——拿标注软件导出的像素坐标直接当YOLO格式用训练出来的框全部偏移到图像角落。2.2 标签校验脚本先跑一遍别急着开训练标签文件数量对得上、图片能打开不代表数据能用。我每次拿到外部数据集都会先跑一个校验脚本检查四件事标签文件是否为空、坐标值是否都在[0,1]区间内、类别ID是否在合法范围内、图片尺寸与标签数据是否匹配。import os from pathlib import Path label_dirs [labels/train, labels/val, labels/test] valid_classes {0} # 单类别场景下class_id只能是0 for label_dir in label_dirs: if not os.path.exists(label_dir): print(fmissing dir: {label_dir}) continue for txt in Path(label_dir).glob(*.txt): lines txt.read_text().strip().split(\n) if not lines or lines[0] : print(fempty label: {txt}) continue for line in lines: parts line.split() if len(parts) ! 5: print(fbad format: {txt} - {line}) continue cid, cx, cy, w, h int(parts[0]), float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) if cid not in valid_classes: print(finvalid class: {txt} - {cid}) if not (0 cx 1 and 0 cy 1 and 0 w 1 and 0 h 1): print(fcoord out of range: {txt} - {line})这段脚本的逻辑很简单但能挡住大多数脏数据问题。class_id越界通常说明标注人员把类别编号从1开始而YOLO规定从0开始坐标超过1说明标注工具导出的是像素坐标而非归一化坐标空标签文件如果大量出现大概率是标注遗漏或者导出中断这种图片要么补标要么直接丢弃不然训练时背景样本远多于目标样本模型会偏向把起重机漏检。跑完校验后我还会统计一下每张图的目标数量分布。如果大部分图片只有1~2个目标而少量图片有8~10个目标训练时需要考虑目标密度差异。YOLO本身对多目标图有mosaic增强来补充上下文但如果数据集里目标数量分布极端不均衡val阶段的小目标检测指标会非常难看。2.3 类别统计与样本分析判断单类别模型还是多类别拆分起重机检测这类任务有个特殊点塔吊、履带吊、汽车吊、港口门座机在视觉上差异很大但标签可能统一叫crane。我的建议是用脚本统计一下不同类别ID的频率如果标签里有多个类别ID先确认每个ID对应什么类型的起重机。类别合并还是拆分直接影响训练难度。from collections import Counter def count_classes(label_dir): counter Counter() for txt in Path(label_dir).glob(*.txt): for line in txt.read_text().strip().split(\n): parts line.split() if len(parts) 5: counter[int(parts[0])] 1 return counter如果某个类别ID只出现几十次而另一个类别出现两千多次硬要按多类别训练小类别的AP会被拉得很低。这种情况下我倾向把所有类别合并成单一crane类训练一个单类别检测器再通过后处理按长宽比或检测框面积做细分。这不是模型能力不够是数据量撑不起类别间差异建模强行做只会得到一个对某个类过拟合、对其他类漏检的模型。3. 用YOLOv8跑通起重机检测训练最小命令与关键参数调优3.1 安装环境与验证GPU先跑通最小训练流程训练YOLOv8系列的常见做法是用Ultralytics框架。环境配置的时候注意一个点PyTorch版本要和CUDA版本匹配否则GPU不可用训练直接落到CPU上2900张图跑100个epoch可能要十几个小时。pip install ultralytics python -c import torch print(cuda available:, torch.cuda.is_available()) print(gpu name:, torch.cuda.get_device_name(0) if torch.cuda.is_available() else cpu) 这一步输出的cuda available如果显示False先别急着调训练参数回头检查PyTorch的CUDA版本编译是否匹配。黑匣子最容易翻车的就是这里——代码跑起来了但实际用的是CPU几个小时后看loss曲线还下不去白白浪费时间。3.2 编写data.yaml配置指向刚才整理好的目录YOLO训练需要一份数据集配置文件内容是指明train/val图片路径和类别名称列表。这里的路径我建议写成绝对路径尤其在跨机器拷贝数据时相对路径容易踩坑。path: /home/yourname/crane_dataset train: images/train val: images/val test: images/test names: 0: cranepath是数据集根目录train和val相对于根目录写。如果你的数据集标签里类别ID是0那names列表只填一个crane如果标签里有多个ID按顺序一一对应。这里填错会导致训练时class name映射错乱验证阶段画出的混淆矩阵看起来全是对角线实际类别语义完全对不上。3.3 最小训练命令从n模型开始在数据质量还没完全确认之前不要直接上大模型。我一般用YOLOv8nnano版本先跑一个短训练流程几十个epoch就能看出loss是否正常下降、验证集是否有检出效果。这个步骤是数据质量的试金石跑通了再换s或m版本提升精度。yolo detect train \ modelyolov8n.pt \ datacrane.yaml \ epochs100 \ imgsz640 \ batch16 \ device0逐项拆解一下这些参数。modelyolov8n.pt会从官方仓库自动下载预训练权重这是YOLO系列的标准做法用COCO上预训练的权重做初始化迁移到起重机检测上收敛更快。imgsz640是输入图像尺寸YOLOv8默认支持640如果原始图片是1080P甚至更高分辨率可以尝试768或896但显存占用会上去。batch16是批次大小显存不够时报CUDA out of memory就降到8或4。训练跑完后在runs/detect/train/目录下会生成weights/best.pt和last.pt前者是验证集上指标最好的权重后者是最后一个epoch的权重。做推理和导出部署一律用best.pt这是刚入坑的人最容易搞反的。3.4 三个必调参数图像尺寸、batch与早停策略imgsz、batch和patience是我在起重机检测这类工业场景下最常调的三组参数。如果标注框里的小目标占比高——比如远景塔吊在画面里只有几十个像素——imgsz建议直接上896小目标在640分辨率下特征几乎被池化弄丢了。batch要兼顾显存和BN稳定性太小的batch比如2会让BatchNorm的统计量不稳定训练后期loss震荡。patience是早停参数默认100意思是验证集指标连续100个epoch不提升就停止。yolo detect train \ modelyolov8s.pt \ datacrane.yaml \ epochs200 \ imgsz896 \ batch8 \ patience30 \ device0把patience从100降到30或50是迁移学习场景下比较实用的做法。因为预训练权重已经提供了良好的特征提取能力模型在几十个epoch内就能收敛到较好状态后面的epoch大多是过拟合噪声。我看到太多人在小数据集上让模型跑满几百个epoch最后验证集mAP50不升反降这就是过拟合信号早停能自动拦下来。4. 数据增强与预训练权重小数据集训练不翻车的两个支点4.1 从COCO域到起重机域预训练权重为什么值得依赖2900张图对单类别检测来说偏少但有一个重要的优势来源COCO预训练权重。YOLOv8的官方权重是在COCO 80类上训练出来的虽然COCO里没有crane起重机这个类但其中的卡车、公交车、飞机等大型刚性物体与起重机在形状特征上有共享的视觉模式——直线边缘、大面积金属表面、结构化部件。加载预训练权重后backbone已经学会了通用的边缘、纹理、形状特征fine-tune时只需要调整检测头对起重机这个类的响应。这就是为什么我强烈不建议用随机初始化的权重从头训练。2900张图从头训练目标检测头需要同时学习特征提取和类别判别样本量根本不够结果就是训练集loss降到很低验证集mAP一塌糊涂。加载预训练权重后即使只训练50个epoch效果也远好于从头训200个epoch。4.2 增强参数怎么配mosaic、翻转与色彩扰动Ultralytics YOLOv8在训练时默认开启mosaic增强它会把4张图拼成一张增加目标上下文多样性。对小数据集mosaic是提升泛化能力最有效的增强手段没有之一。但需要注意如果数据集中大部分图片只含单个目标mosaic过度使用会让模型学习到图片里总有很多目标的偏置推理时对单目标场景反而犹豫。# dataset.yaml 同目录下可以新建 augment.yaml 覆盖默认增强参数 hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4 degrees: 10.0 translate: 0.1 scale: 0.5 fliplr: 0.5 mosaic: 1.0这里的degrees10是允许图像随机旋转不超过10度。起重机检测场景里吊臂的朝向是随机的旋转增强能模拟不同角度。但旋转角度别设太大超过30度时框的标注会引入大量背景噪声而且起重机有明确的上/下方向结构转太多会让模型学出矛盾的特征。fliplr0.5是水平翻转这个对起重机来说几乎是免费的增强因为起重机的左右结构在视觉上是对称的。色彩扰动参数hsv_h、hsv_s、hsv_v对应色调、饱和度和明度的随机变化幅度。工业场景下拍摄环境变化大阴天、逆光、黄昏都会让画面颜色偏移这几个参数的设置能显著提升模型对环境光变化的鲁棒性。但幅度别抄网上那些竞赛配置——那些是针对自然图像的大扰动工业场景如果调太大会破坏起重机金属表面的灰黑色调特征。4.3 训练策略对比从头训、冻结backbone、partial freeze的取舍数据量不足时一个实用的技巧是冻结backbone训练。YOLOv8的模型结构分为backbone特征提取和head检测头加载预训练权重后backbone里的知识是通用的——边缘、纹理、形状——这些特征在起重机域和COCO域是共通的不需要大幅改动。而head部分需要针对crane类重新适配。我一般在小数据集上这么做第一个阶段冻结backbone只训练head跑30个epoch第二个阶段解冻backbone用很小的学习率整体微调20~30个epoch。from ultralytics import YOLO model YOLO(yolov8s.pt) # 第一阶段冻结backbone层 for name, param in model.model.named_parameters(): if name.startswith(model.0) or name.startswith(model.1) or name.startswith(model.2): param.requires_grad False model.train(datacrane.yaml, epochs30, imgsz896, batch8, lr00.005)这个方案的原理很简单冻结backbone可以让模型在前30个epoch专注于学习起重机这个类别与背景的区分避免backbone在少量数据上被大幅扰动而丢失通用特征。第二个阶段解冻后用小学习率lr00.001左右做全模型微调让backbone的高层特征向起重机域做细微适配。两个阶段用同一个训练目录第二个阶段会自动从last.pt继续训练配合早停保证不跑过头。5. 起重机标注数据的常见坑格式、漏标与样本失衡排查5.1 坐标归一化翻车像素坐标当YOLO坐标用了现象训练出来的模型检测框整体偏移框的中心点偏向图像的某个角落同一个目标在不同位置检测结果不一致。原因标签文件里的坐标是标注工具导出的像素坐标而YOLO格式要求的是归一化坐标。比如一张1920x1080的图目标中心点像素坐标是(960, 540)归一化后应该是(0.5, 0.5)。直接拿像素坐标训练模型会把960理解成960倍图像宽度输出坐标直接飞掉。解决写一个批量转换脚本读取图片实际宽高把像素坐标全部除以宽高。转换完成后重新跑一遍标签校验脚本确认所有坐标都在[0,1]区间内。这个坑我几乎在每个外部数据集上都会遇到一轮防不胜防。5.2 空标签文件漏标图片混进了训练集现象训练过程正常loss下降也正常但验证集的召回率明显偏低尤其是某些特定场景比如远景、逆光、遮挡下完全检测不到目标。原因部分标注人员在标注时跳过了难例——太远的、太暗的、遮挡严重的图直接没标生成了空标签文件。这些图片混入训练集后模型会学到这种场景下没有目标导致实际推理时对这些场景产生漏检。解决训练前用脚本把所有空标签文件筛出来逐个看图决定是补标还是剔除。如果剔除图片文件也要一并剔除保持images和labels同步。如果漏标的是难例我建议补标而不是剔除因为难例对提升模型鲁棒性价值最大。5.3 样本不平衡重卡与轻型吊机分布差异过大现象训练集里某类起重机占了90%另一类只占10%。训练出的模型对大比例类别检出很好小比例类别AP几乎为0。原因标注时没有考虑类别均衡数据采集本身偏向了特定场景。比如从港口监控视频抽取的图大多是门座机和岸边集装箱起重机履带吊样本极少。解决先按3.3的统计脚本确认类别分布。如果小类别样本实在太少少于50张建议把小类别合并到crane大类用单类别模型去检测所有起重机再用后处理按框的宽高比或长宽比做细分。如果小类别样本在100张以上可以用数据复制或增强来补——对小类别图片做翻转、旋转、亮度变化生成2~3倍的增广数据再参与训练。5.4 标签与图片文件名不匹配静默失败最坑现象训练时没有任何报错但训练集里实际参与训练的图片数量远小于目录里图片数量。看训练日志发现每张图的标签都是空的loss曲线波动剧烈。原因图片文件是001.jpg、002.jpg标签文件却是IMG_001.txt、IMG_002.txt之类的命名文件名主体不一致。YOLO训练时找不到匹配的标签文件会把该图片当作背景样本处理不产生检测loss。解决用脚本做一次文件名对齐以图片文件名为基准把标签文件重命名成同名。具体做法是用Python遍历所有.jpg文件去labels目录找对应的.txt找不到就用write_images.txt文件输出缺失列表人工检查这些图是否真的需要标签。5.5 一个反直觉的经验训练集mAP高但验证集低先怀疑数据划分泄露现象训练集mAP50超过90%验证集只有60%而且验证集图片感觉和训练集长得很像——同一个工地的不同帧。原因数据划分时按文件名随机分配导致同一个视频序列的相邻帧分别进了训练集和验证集。模型在训练集里看到的画面和验证集高度相似验证指标虚高。真正上线时遇到不同场景、不同光线条件性能立刻掉下来。解决数据划分时按视频序列或拍摄时间分组确保同一个场景的连续帧只进一个集合。这个事在数据准备阶段就要规划好等训练完再重新划分数据集等于前面白干。6. 用混淆矩阵和PR曲线验证效果并导出部署训练结束不是终点验证才是。很多人只看训练loss和最后一个epoch的mAP就说模型训好了然后部署到现场发现一片误检。我的习惯是训完先跑一次完整的验证生成混淆矩阵和PR曲线然后挑几张没参与训练的现场图做推理确认框的位置和置信度合理最后才导出ONNX部署。YOLOv8的验证命令直接用model.val()即可它会输出包括mAP50、mAP50-95、每个类别的AP值、混淆矩阵和PR曲线图保存到runs/detect/val目录下。看混淆矩阵时重点关注对角线之外的值——如果某个类别的ground truth经常被预测为背景说明漏检严重如果背景列的值很高说明误检多在复杂背景区域。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) metrics model.val(datacrane.yaml, splittest) print(metrics.box.map50) print(metrics.box.map) # mAP50-95验证通过后导出ONNX是部署前的一步关键操作。YOLOv8官方CLI支持一行命令导出导出后可以用ONNX Runtime做推理摆脱PyTorch依赖在Jetson或者带NPU的边缘设备上跑得更快。yolo export modelruns/detect/train/weights/best.pt formatonnx opset12导出成功后我还会用ONNX Runtime加载这个文件拿同一张测试图对比PyTorch推理结果确认两者输出的框坐标和置信度一致。这一步是防止导出过程中算子兼容问题导致的精度损失。以前碰到过在自定义算子上导出的ONNX在CPU上结果正常、在NPU上结果异常的情况后来就是靠这种对比排查出来的。最后分享一个我自己的习惯每次训练完我会把最优参数组合、数据增强配置、验证指标写在一个training_card.md文件里连同数据集版本号一起归档。这样三个月后再回来调模型不用翻聊天记录和shell历史打开卡片就能复现。这个习惯帮我省了太多重复摸索的时间也让我对数据集的每一次迭代都有清晰记录。做目标检测这些年最大的体会是数据集的质量决定了模型的天花板参数调优只是接近这个天花板的手段。如果你手里有一套标注干净、格式统一的起重机数据YOLOv8的整套流程跑下来从一个能用的基线模型到部署版本通常只需要一两天时间。希望这套流程对你有所帮助。本文还有配套的精品资源点击获取