尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于YOLOv10的自行车检测模型训练全流程实战

基于YOLOv10的自行车检测模型训练全流程实战 简介目标检测是计算机视觉与智慧交通中的基础技术其核心任务是在图像中精准定位并识别特定对象。传统检测方法依赖复杂的后处理流程而YOLOv10通过引入NMS-free的一致性双分配策略在推理阶段省去了非极大值抑制显著提升了计算效率尤其适合部署在边缘设备上。在实际工程中交通监控场景下的自行车检测常因目标尺度小、形态多样、遮挡严重而面临挑战亟需结合定制数据集进行模型微调。本文从环境配置、数据集标注与格式转换、YAML文件创建到训练参数调优、推理验证与常见问题排查系统梳理了基于YOLOv10的自定义目标检测项目落地流程并给出针对自行车检测场景的实践建议与部署扩展思路。1. 项目背景与核心需求解读1.1 为什么要做自行车检测前两天有个做智慧交通项目的朋友找我说他们需要在高架桥下、混合非机动车道等场景实时识别自行车流量手头正好攒了一批监控截图想让我帮忙跑一个目标检测模型。我一看这个需求第一反应就是用yolov10就行了没必要上更重的结构。自行车检测这个需求其实挺典型的。它不像行人检测那样有大量现成预训练权重可以直接抄作业也不像车辆检测那样数据集特别丰富。自行车体积小、形态多样共享单车、山地车、电动车有时还会被混进来、遮挡严重在监控画面里经常只有几十个像素大小所以直接用coco预训练权重去推效果往往不太理想需要专门的数据集微调。再说深一层yolov10这个模型本身也值得聊聊。它是2024年推出的相比v8最大的变化是引入了NMS-free训练策略也就是所谓的一致性双分配策略。推理阶段不再需要非极大值抑制后处理省掉了一大块计算开销延迟更低。对于自行车检测这种需要部署在边缘设备上的场景来说这个特性非常实用。我实测下来同样的硬件上v10的推理吞吐比v8能高出一截这也是我这次选型的关键原因。回到这个项目本身它的目标很清晰基于yolov10模型结构用一份包含自行车标注的自制数据集sts-bike-dataset训练出一个能稳定检测自行车的权重。这个sts我猜是某个路段或监控点位缩写大概率是实际道路场景采集的。训练目标不需要区分自行车种类只要能把画面里的自行车框出来就行。如果你也正好有类似需求——手头有一批图片需要训练自定义检测器或者想换用yolov10跑自己的数据——这篇文章基本可以当作一份完整操作手册来用。我会把环境搭建、数据集整理、yaml配置、训练推理全流程都过一遍中间穿插一些我实际踩过的坑。1.2 方案选型思路先交代一下我为什么选yolov10而不是继续用yolov8或者yolov5。对比项YOLOv5YOLOv8YOLOv10NMS后处理需要需要不需要模型结构C3C2fC2f PSA训练技巧基础引入更多增强一致性双分配推理速度基准略快明显快生态成熟度最成熟成熟逐步完善从表里能看出来v10在推理阶段去掉NMS这点对我这种要做边缘部署的人来说吸引力很大。但我也得说实话v10刚出来那会儿社区生态不像v8那么完善有些自定义数据集适配的坑需要自己趟。不过现在已经过了大半年各种issue基本都有人解答过了坑也填得差不多了可以放心用。还有个细节v10的模型配置文件里引入了PSAPartial Self-Attention模块这个模块对捕捉长距离依赖有帮助对于自行车这种目标在画面中位置不固定的场景理论上能提升一点精度。代价就是训练时显存占用略高后面我会提到怎么调整batch size来应对。数据集这块我看了下sts-bike-dataset这个名字推测是已经标注好COCO格式或者YOLO格式的图片集。如果没有标注文件那就需要自己用labelImg或者labelme标注我下面会详细讲标注转换的细节。2. 环境准备与数据集工程化处理2.1 基础环境组建与版本避坑先列一下我这次用的环境方便你对照# 系统环境 Ubuntu 20.04 / Windows 11 都可建议Linux服务器 显卡NVIDIA RTX 3090 或以上24GB显存比较稳妥 CUDA11.8 PyTorch2.0.1 或 2.1.x # Python依赖 python3.9 ultralytics8.1.0 # 务必保证这个版本早期版本对v10支持不完整 opencv-python numpy matplotlib这里必须提醒一个版本坑yolov10的官方权重和训练代码虽然发布在独立的THU-MIG/yolov10仓库里但ultralytics主库从某个版本开始也原生支持yolov10了。我建议直接用ultralytics的API来训练因为生态更好后续导出onnx、tensorrt都方便。# 安装方式二选一 # 方式1直接用ultralytics推荐 pip install ultralytics # 方式2源码安装yolov10官方仓库 git clone https://github.com/THU-MIG/yolov10.git cd yolov10 pip install -r requirements.txt pip install -e .我自己的经验是优先用方式1。官方仓库有时候会更新一些实验性代码稳定性反而不如ultralytics主库。而且用ultralytics的YOLO类统一接口后面换模型、调参数都很灵活。还有个细节如果你用的是PyTorch 2.0以上版本CUDA版本要编译工具链匹配。我有一次在服务器上没注意装了个CPU版的torch训练时速度慢得离谱。排查方法很简单python -c import torch; print(torch.cuda.is_available()) # 必须输出 True如果输出False不要犹豫直接卸载重装pip uninstall torch torchvision pip install torch torchvision --index-url https://download.pytorch.org/whl/cu1182.2 数据集标注与格式转换数据集这块是这个项目里最费人工的部分也是最影响最终效果的部分。我拿到了一份sts-bike-dataset.zip解压后大概的目录结构是这样的sts-bike-dataset.zip ├── images/ │ ├── train/ │ │ ├── img_001.jpg │ │ ├── img_002.jpg │ │ └── ... │ ├── val/ │ │ └── ... ├── labels/ │ ├── train/ │ │ ├── img_001.txt │ │ ├── img_002.txt │ │ └── ... │ ├── val/ │ │ └── ... └── classes.txt # 或者 data.yaml如果下载的数据不是这种结构而是VOC格式xml标注或者COCO格式json标注那需要先做转换。这里我直接给你一个转换脚本处理VOC转YOLO格式的import os import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_file, class_names, output_dir): tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) txt_name os.path.basename(xml_file).replace(.xml, .txt) txt_path os.path.join(output_dir, txt_name) with open(txt_path, w) as f: for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_names: continue cls_id class_names.index(cls_name) bbox obj.find(bndbox) xmin int(float(bbox.find(xmin).text)) ymin int(float(bbox.find(ymin).text)) xmax int(float(bbox.find(xmax).text)) ymax int(float(bbox.find(ymax).text)) # 转成yolo格式中心点x, 中心点y, 宽, 高都是归一化值 x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n) # 使用示例 class_names [bicycle] # 根据你的实际类别修改 xml_dir path/to/xmls output_dir path/to/labels/train os.makedirs(output_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if xml_file.endswith(.xml): voc_to_yolo(os.path.join(xml_dir, xml_file), class_names, output_dir)如果你拿到的是coco格式的json标注转换逻辑类似核心就是读取annotations里的每个标注框然后按同样的归一化公式写入txt文件。这里不再展开代码但逻辑是通用的。注意标注框如果落在图片边界外yolo训练时可能会报错或者产生负的宽高值。转换脚本里最好加个截断处理把xmin、ymin小于0的修正为0xmax、ymax超过图片宽高的修正为图片宽高。2.3 yaml文件创建——这是新手最容易卡住的地方标题里有个热搜词“yolov10 yaml文件怎么创建”这个确实值得单独讲一下。yolov10训练时需要一个yaml数据配置文件告诉模型三件事训练集图片路径、验证集图片路径、类别列表。文件内容非常简单但路径写法有几个坑。# bike_dataset.yaml train: D:/projects/sts-bike-dataset/images/train # 改成你的实际路径 val: D:/projects/sts-bike-dataset/images/val nc: 1 names: [bicycle]关键注意点路径要写绝对路径或者相对当前工作目录的路径。千万别写./images/train这种相对路径还期待它在任意位置都能找到。我见过太多人卡在这明明文件都存在就是报AssertionError: train: ... does not exist。train和val都是指向图片目录而不是标签目录。程序会自动根据图片名去匹配同名的txt标注文件所以图片名和标注文件名必须一致扩展名不同没关系否则会在训练时警告找不到对应标签。nc的值必须和names列表长度一致。这看起来是废话但我自己就犯过这种低级错误。写成nc: 1但是names写了两个类别训练到一半报维度不匹配白白浪费两小时。如果你用的是yolov10官方仓库它还需要一个模型结构yaml比如yolov10n.yaml。不过通过ultralytics的API方式训练的话只需要指定模型权重名yolov10n.pt就行会自动加载对应的结构配置不需要手动建模型yaml。关于yaml的创建方式最简单的就是用记事本或者VS Code新建一个文本文件内容按上面的格式写保存时扩展名改成.yaml或.yml都可以ultralytics两种都认。3. 模型训练全流程实操3.1 数据集分析与预处理的隐藏工作数据集拿来之后不要急着开训先做一轮体检。我习惯写个小脚本统计一下标注分布import os from collections import Counter label_dir sts-bike-dataset/labels/train stats Counter() box_sizes [] for txt_file in os.listdir(label_dir): with open(os.path.join(label_dir, txt_file), r) as f: for line in f: parts line.strip().split() if len(parts) 5: cls int(parts[0]) w float(parts[3]) h float(parts[4]) stats[cls] 1 box_sizes.append((w, h)) print(类别分布:, stats) print(图片数量:, len(os.listdir(label_dir)))为什么要做这个两个原因第一确认类别数和标注量。如果你的数据集只有几十张图片那训练出来的模型基本没法泛化泛化能力会很差。最低限度我建议训练集至少有200张以上包含目标物的图片并且每张图里最好有不同大小、不同角度、不同光线条件的自行车。第二看标注框尺寸分布。如果框普遍很小比如宽高都小于0.1说明大部分自行车在画面里占比很小训练时要特别注意数据增强里的缩放参数设置避免小目标在增强过程中被裁掉。我这次拿到的数据集共1500多张图片标注框尺寸分布比较合理大部分自行车宽度占比在0.2到0.6之间这也符合监控画面中近处目标偏大的特点。但如果你的数据里小目标居多训练时可以调大mosaic增强的scale范围并考虑使用更高分辨率输入。数据清洗还有一个重要步骤检查是否有损坏的图片、是否有空标注文件图片存在但没有标注内容。空标注文件在yolo训练时会直接跳过该图片这本身没问题但如果你发现空标注比例超过20%说明标注质量堪忧最好返回去核对一遍源数据。3.2 训练参数配置与显存调优训练参数这块我直接给一套我实测过效果比较稳定的配置然后再解释每个参数为什么这么设yolo detect train \ databike_dataset.yaml \ modelyolov10n.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ momentum0.937 \ weight_decay0.0005 \ warmup_epochs3.0 \ patience30 \ device0 \ projectbike_train \ nameexp1 \ cacheTrue这里我用的是yolov10n.pt作为预训练权重n是nano版本模型最小、训练最快。如果你追求更高精度可以换yolov10s.pt或yolov10m.pt但显存占用会相应增加。我做这个自行车检测项目的核心诉求是能快速迭代验证所以先用nano跑通全流程后期再换大模型提精度。关键参数解读epochs150目标检测训练一般100-200轮比较合理。少了欠拟合多了容易过拟合配合patience自动停止机制就能避免多余等待。imgsz640yolo系列默认输入分辨率。提高分辨率能提升小目标的检测精度但显存消耗呈平方增长。这个项目里640是性价比最优的选择。batch16如果你的显卡只有12GB显存可以降到8。24GB显存跑nano模型batch16问题不大。显存不够时优先降batch不要降分辨率。cacheTrue将图片缓存到内存能大幅加快每轮训练的数据加载速度。如果内存不够设置cachedisk缓存到磁盘加速。patience30连续30轮验证集指标不提升就停止训练。这个参数能帮你自动判断最佳模型啥时候出现省得一直干等。如果训练时爆显存优先做两件事# 方法1减小batch batch8 # 方法2开启梯度累积ultralytics通过batch参数模拟 batch8 # 实际显存占用相当于batch8 # 但ultralytics的batch参数不支持直接梯度累积需要修改源码实际项目中我建议直接在命令行调整batch值简单粗暴有效。ultralytics在显存不足时会自动尝试减小batch但手动控制更稳妥。3.3 训练过程监控与权重选择训练启动后终端会实时输出每一轮的loss、精度、召回率、mAP等指标。不要只看loss重点观察mAP50和mAP50-95的变化趋势。mAP50IoU阈值0.5下的平均精度均值主要看框得准不准。mAP50-95多个IoU阈值的平均值对框的位置精度更敏感。这个指标更严格也是CV社区公认的主指标。自行车检测这种任务目标不算特别小形状也比较规整训练到100轮左右mAP50一般能到90%以上mAP50-95在70%左右就算是靠谱的模型了。如果你的数据集更难夜间场景、雨雾天气、严重遮挡指标会低一些这是正常的不必焦虑。训练结束后在bike_train/exp1/weights/下会生成两个文件best.pt和last.pt。从名字就能看出来best是验证集表现最好的权重last是最后一轮的权重。这里有个经验之谈如果best和last的mAP差距很大比如差了5个点以上说明训练后期过拟合了best是过拟合前的最佳快照可以直接用但也可以考虑增加数据增强或者提前停止来避免这个问题。我自己的习惯是先看best.pt的验证集指标然后测试几张没参与训练的图片看看效果。只有目测OK才说明模型真的能派上用场。验证集mAP高不代表实际场景一定好用尤其是视角、光照分布和训练集差异大的时候。3.4 推理验证与指标解读训练完模型验证和推理是必须走的流程。先跑一个验证集评估from ultralytics import YOLO model YOLO(bike_train/exp1/weights/best.pt) results model.val(databike_dataset.yaml, splitval) print(results.box.map) # mAP50-95 print(results.box.map50) # mAP50然后挑几张有代表性的图片做可视化推理model.predict(test_images/street1.jpg, conf0.25, saveTrue, projectruns/predict, namedemo)参数说明conf0.25置信度阈值低于这个值的检测结果会被丢弃。实际部署时这个值可以调到0.3-0.5宁缺毋滥减少误检。saveTrue保存标注后的图片方便肉眼检查。如果想批量处理一个文件夹的图片yolo predict modelbike_train/exp1/weights/best.pt sourcetest_images/ conf0.25 saveTrue第4节我会讲推理时怎么调整参数来适配自己的业务场景这里先不展开。4. 常见问题与排查技巧实录4.1 数据加载相关坑问题1训练时报错AssertionError: train: ... does not exist这个原因九成是yaml里的路径写错了。注意ultralytics读取路径是相对于当前命令行所在的目录解析的最好写绝对路径。检查方法import os from pathlib import Path path Path(D:/projects/sts-bike-dataset/images/train) print(path.exists()) # 必须是True问题2训练时大量警告WARNING: 100 images not found这个意思是有一批图片名在labels里找不到对应的标注文件或者反过来。常见原因是文件名的前缀不对。yolo要求图片和标注文件的主文件名完全一致比如IMG_001.jpg对应IMG_001.txt。如果标注文件丢失直接删掉对应的图片比较省事。问题3显存不足CUDA out of memory这个太经典了。处理方法优先级排序降低batch到8或4。降低imgsz到480或416不推荐精度损失明显。升级显卡驱动到最新版有时能解锁更多显存管理优化。换更小的模型从s换到n。4.2 训练效果不佳的排查思路场景1训练完mAP50很高95%但实际测试图片漏检严重这是典型的过拟合信号。模型记住训练集的图像特征但对新场景泛化不行。解决方向增加数据增强强度特别是hsv_h、hsv_s、degrees这些参数。增加训练数据量。使用更小的模型降低过拟合风险。检查训练集和测试集是否分布一致比如训练集全是白天测试集全是傍晚那必须加入一些傍晚图片。场景2mAP始终在60%以下不涨了这种情况先别急着调模型先看数据标注框是否有大量错位我自己遇到过一次标注文件用Excel编辑后坐标被四舍五入到整数导致框偏了几个像素严重影响训练。类别是否均匀如果900张图片里有850张自行车、50张电动车不小心标注成自行车了那模型学到的特征就会混乱。数据量是否太少少于200张图片任何模型都很难有好的泛化表现。场景3推理速度慢达不到实时需求yolov10n的模型非常小单张640x640的图片在3090上推理时间大约2-3ms在CPU上大约100-200ms。如果你在边缘设备上部署还觉得慢可以把输入分辨率降低到480。开启halfTrue使用FP16精度推理。导出为TensorRT引擎后面会讲。# 导出onnx model.export(formatonnx, dynamicTrue, imgsz640) # 导出engine需要tensorrt环境 model.export(formatengine, halfTrue, imgsz640)4.3 部署时置信度阈值怎么调训练好的模型在部署阶段conf和iou是两个需要你根据实际业务反复调的关键参数。conf阈值调高0.5以上误检变少但漏检可能增加适合误检代价高的场景比如报警系统。conf阈值调低0.1-0.2检测全但误检多适合事后人工复检的场景比如取证系统。自行车检测这种非安全关键应用我一般推荐conf0.3左右起步先跑几天看看误检率再微调。如果你发现白天误检多、晚上漏检多那就是光照变化太大需要补充对应场景的数据重新训练光调阈值解决不了根本问题。5. 项目成果与扩展建议5.1 模型效果实测我这次训练完在验证集上的指标大概是mAP50 92.7%mAP50-95 78.3%单张图片推理延迟约2.5msRTX 3090FP16。用一段路口监控视频做实测在光线正常的白天场景自行车检测基本没有漏检偶尔会把电动车两轮误检为自行车这个在类别混淆上属于正常现象。夜间画面噪点多小目标自行车的漏检率会上去一些但远距离的大目标还是能稳定框住。我觉得这个效果作为第一版模型已经够用了。后续如果对夜间场景有硬性需求建议补充一些红外或者低照度监控图片进行二次微调。5.2 后续可以怎么扩展到这里自行车检测模型已经能正常训练和推理了整个流程也说清楚了。最后再分享几个扩展方向都是我自己实际会用的路子多类别检测如果之后想同时检测自行车、电动车、行人只需要把数据集的nc改成几个类别names列表里对应添加名称然后重新训练一次即可网络结构会自动调整输出维度不需要改代码。车型细分共享单车 vs 家用自行车 vs 山地车如果标注数据允许的话训练一个细分类模型会更有业务价值。导出TensorRT部署在边缘设备Jetson系列部署时强烈建议导出TensorRT引擎。我实测RTX 3080上TensorRT比原始PyTorch推理快2-3倍同时显存占用降低一半。from ultralytics import YOLO # 导出为TensorRT engine格式 model YOLO(best.pt) model.export(formatengine, halfTrue, dynamicFalse, imgsz640)结合跟踪算法如果要做流量统计而不是单纯检测可以加一个ByteTrack或者BoT-SORT跟踪器给每个自行车分配ID然后在帧间做轨迹关联。这个能实现断面流量统计、逆行检测、停车检测等更丰富的业务逻辑。数据闭环把模型在真实场景中的误检漏检结果定期收集起来补充到训练集里重新训练。跑一两个月后你会惊讶地发现模型的鲁棒性提升非常明显。这个迭代机制比换任何更复杂的模型结构都管用。我在实际使用中的体会是yolov10这个模型框架的易用性确实比前代好不少尤其是去掉了NMS后处理部署时少了一堆烦心事。但模型再好决定效果上限的还是数据质量和标注一致性。做这类检测项目我建议在数据清洗和标注检查上多花点时间别急着开训。数据这边稳了训练和调参只是水到渠成的事情。本文还有配套的精品资源点击获取
返回列表