ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv5实战:环境配置、数据集训练与边缘部署全流程

YOLOv5实战:环境配置、数据集训练与边缘部署全流程 简介这份文档面向具备一定Python与计算机视觉基础的入门级研究人员和工程技术人员系统讲解YOLOv5目标检测框架的本地环境搭建与基本使用。内容从系统要求入手涵盖Windows、macOS、Linux三类操作系统Python 3.6以上版本以及GPU加速所需的CUDA 10.2与cuDNN 7.6以上版本并逐步介绍依赖库安装、官方源码获取、预训练模型下载与示例检测运行最后延伸至自定义数据集训练等进阶方向。资源包为1个docx文档大小约19KB结构紧凑便于按步骤对照操作。目前已有238人学习下载。读者可借此掌握从环境准备到首个检测实例的完整流程理解置信度阈值、非极大抑制等关键参数含义并了解依据自有训练资料优化模型的思路既可作为理论教学材料也可供实际工程项目参考。1. YOLOv5搭建与目标检测从环境配置到训练自己数据集的完整路径很多做视觉项目的工程师第一次跑 YOLOv5卡住的地方往往不是网络结构而是环境。PyTorch 版本、CUDA 驱动、torchvision 三者对不上import torch直接报错好不容易跑通官方detect.py换成自己的数据集又发现标注格式不对、类别文件路径写错、训练 loss 不降。YOLOv5 搭建与目标检测详解这件事核心就三块把环境配到能跑推理把数据整理成 YOLO 格式把训练参数调到收敛。它适合刚接触目标检测、想用自己数据训一个可用模型的工程师也适合需要把模型量化后部署到 RK3568、树莓派 4B 这类边缘设备的开发者。下面按我实际落地的顺序从环境、数据、训练、避坑到进阶验证一步步拆开讲。2. 环境配置与最小推理验证先让官方权重跑起来2.1 为什么优先用 conda 隔离而不是直接 pipYOLOv5 对 PyTorch 和 torchvision 的版本匹配很敏感。我见过太多人全局 pip 装完结果和系统里已有的 CUDA 版本打架torch.cuda.is_available()返回 False训练直接掉到 CPU 上一个 epoch 跑半小时。常见做法是用 conda 建一个独立环境把 Python 版本锁在 3.8 到 3.10 之间再按官方 requirements 装依赖。这样即使后面要试 YOLOv11 或者别的检测框架也不会互相污染。具体步骤是先建环境再装 PyTorch最后装 YOLOv5 仓库的依赖。注意 PyTorch 的安装命令要去官网按你的 CUDA 版本生成不要照抄别人的。如果你机器没有 NVIDIA 显卡就装 CPU 版训练会慢但推理验证没问题。# 创建独立环境Python 版本建议 3.8-3.10 conda create -n yolov5 python3.9 -y conda activate yolov5 # 安装 PyTorch这里以 CUDA 11.8 为例实际按官网命令替换 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 克隆 YOLOv5 仓库并安装依赖 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt这段命令的逻辑是conda 负责隔离 Python 运行时pip 负责装 PyTorch 和项目依赖。参数上唯一要改的是 PyTorch 的 index-url它决定了你装的是 CUDA 版还是 CPU 版。装完后必须验证不验证等于没装。# 验证 PyTorch 和 CUDA 是否可用 python -c import torch; print(torch.__version__); print(torch.cuda.is_available())如果输出 True说明 GPU 可用如果 False先别急着往下走去查显卡驱动和 CUDA 版本是否匹配。这一步是后面所有训练的前提。2.2 用官方权重跑通第一张图推理环境好了之后不要急着训自己的数据先用官方 coco 权重跑一张图确认推理链路是通的。YOLOv5 仓库自带detect.py默认会下载yolov5s.pt权重。我一般会指定--source为一张本地图片--weights用默认的--conf先设 0.25 看效果。# 用官方 yolov5s 权重对单张图片做推理 python detect.py --weights yolov5s.pt --source data/images/bus.jpg --conf 0.25 --device 0参数说明--weights是权重文件路径第一次运行会自动下载--source可以是图片、文件夹、视频甚至摄像头编号--conf是置信度阈值低于这个值的框会被过滤--device 0表示用第一块 GPUCPU 则写cpu。运行结束后结果默认保存在runs/detect/exp下打开图片能看到框和类别标签就说明推理链路完全通了。这一步的价值在于把「环境问题」和「数据问题」分开。如果官方权重都跑不出框那一定是环境或权重加载的问题跟你的数据集无关。先解决这个再进入数据准备。3. 数据集准备与 YOLO 格式转换标注、划分、配置文件三件事3.1 标注格式的选择与转换脚本YOLOv5 只认一种标注格式每张图对应一个同名 txt每行是class_id x_center y_center width height且坐标都是归一化到 0 到 1 之间的相对值。如果你用 LabelImg 标的是 VOC 的 XML或者用 Labelme 标的是 JSON都需要转。我一般用 LabelImg 直接选 YOLO 格式标注省去转换但如果拿到的是 VOC 数据就得写脚本转。import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, img_w, img_h, class_map): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] bbox obj.find(bndbox) x1 float(bbox.find(xmin).text) y1 float(bbox.find(ymin).text) x2 float(bbox.find(xmax).text) y2 float(bbox.find(ymax).text) # 归一化并转为中心点加宽高 x_c (x1 x2) / 2.0 / img_w y_c (y1 y2) / 2.0 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{cls_id} {x_c:.6f} {y_c:.6f} {w:.6f} {h:.6f}) return lines这段代码的逻辑是读 XML取每个目标的类别名和边界框坐标把绝对坐标转成归一化的中心点加宽高。参数上class_map是你自己定义的类别名到 id 的映射必须和后面 data.yaml 里的 names 顺序一致。img_w和img_h是原图宽高不能搞错否则框会偏。转换完每张图生成一个 txt放在和图片同名的路径下。3.2 数据集目录结构与 data.yaml 配置YOLOv5 对目录结构有约定常见做法是建一个 datasets 文件夹里面分 images 和 labels各自再分 train、val、test。图片和标注文件同名只是后缀不同。然后写一个 data.yaml告诉训练脚本去哪里找数据、有哪些类别。# data.yaml path: ./datasets/mydata train: images/train val: images/val test: images/test nc: 3 names: [person, car, dog]参数说明path是数据集根目录train、val、test是相对 path 的图片路径nc是类别数names是类别名列表顺序必须和标注里的 class_id 对应。这里最容易翻车的是路径写错比如 train 写成绝对路径但换机器就失效或者 names 顺序和标注不一致导致类别全乱。我一般会在训练前用一个小脚本抽查几张图的标注确认框的位置和类别是对的。提示如果数据集里有些图片没有目标对应的 txt 可以是空文件但不能没有。YOLOv5 会跳过空标注图但缺文件会报错。3.3 用脚本检查标注是否越界标注越界是训练不收敛的常见原因之一。归一化坐标如果小于 0 或大于 1YOLOv5 在数据加载时可能直接报错或者产生异常框。我习惯在训练前跑一个检查脚本把所有 txt 读一遍发现越界就打印文件名和行号。import os def check_labels(label_dir): for txt in os.listdir(label_dir): if not txt.endswith(.txt): continue with open(os.path.join(label_dir, txt)) as f: for i, line in enumerate(f): parts line.strip().split() if len(parts) ! 5: print(f格式错误: {txt} 第{i1}行) continue cls_id, x, y, w, h map(float, parts) if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): print(f越界: {txt} 第{i1}行 - {line.strip()})这段脚本不依赖任何第三方库直接遍历 labels 目录。参数上只需要把label_dir换成你的标注文件夹路径。跑完如果没有输出说明标注基本干净如果有输出就按文件名去修对应标注。这一步花几分钟能省掉训练时几个小时的排查。4. 训练自己的数据集参数怎么设、日志怎么看、模型怎么选4.1 从 yolov5s 开始而不是一上来就上大模型YOLOv5 有 s、m、l、x 几个版本参数量和精度递增。我一般先用 yolov5s 跑一遍确认数据管线和训练流程没问题再换大模型提精度。因为大模型训练慢如果数据有问题用大模型试错成本太高。训练命令用train.py指定 data.yaml、权重、batch size、epochs 和图片尺寸。# 用 yolov5s 在自己的数据集上训练 python train.py --data data/mydata.yaml --weights yolov5s.pt --batch-size 16 --epochs 100 --img 640 --device 0参数说明--data是上一步写的 data.yaml--weights用官方预训练权重做迁移学习比从头训快很多--batch-size根据显存调显存不够就往下减常见 8 或 16--epochs一般 100 到 300看数据量--img是输入尺寸640 是默认值小目标多可以试 1280但显存和速度会变--device指定 GPU。训练日志会打印每轮的 box_loss、obj_loss、cls_loss 和 mAP重点看 mAP 是否在涨loss 是否在降。4.2 超参数文件里真正值得改的几个YOLOv5 的超参数在data/hyp.scratch.yaml里很多人直接默认跑。但有几个参数对结果影响明显学习率lr0、权重衰减weight_decay、锚框anchors、数据增强里的mosaic和mixup。我一般会先默认跑一轮看 mAP 曲线如果前期震荡大就把lr0从 0.01 降到 0.001如果过拟合就把mixup打开或加大weight_decay。# hyp.scratch.yaml 里几个关键项 lr0: 0.01 # 初始学习率小数据集建议 0.001 lrf: 0.01 # 最终学习率系数 momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3.0 mosaic: 1.0 # 马赛克增强概率小数据集建议保持 1.0 mixup: 0.0 # 混合增强过拟合时开到 0.1-0.2参数说明lr0太大容易震荡太小收敛慢mosaic把四张图拼成一张对小目标检测很有效但训练后期可以关掉让模型适应真实分布mixup把两张图按透明度叠加能缓解过拟合但可能让早期收敛变慢。这些没有绝对最优值得结合你的数据量和 mAP 曲线调。4.3 训练日志里该盯哪几个指标训练开始后控制台会输出类似Epoch gpu_mem box_loss obj_loss cls_loss labels img_size的表。box_loss 是边界框回归损失obj_loss 是目标置信度损失cls_loss 是分类损失。三个 loss 整体应该下降如果某个一直不降说明对应部分有问题。比如 cls_loss 不降可能是类别标注错了obj_loss 不降可能是背景图太多或标注框有问题。验证集上的 mAP0.5 和 mAP0.5:0.95 是最终指标。mAP0.5 涨到 0.8 以上通常算可用但具体看任务难度。如果训练集 mAP 很高而验证集很低就是过拟合需要加数据或加增强。如果两者都低就是欠拟合需要加训练轮数或换大模型。5. 避坑与排查训练不收敛、显存爆、推理结果乱5.1 训练 loss 不降反升现象训练几个 epoch 后 box_loss 或 cls_loss 突然飙升mAP 掉到接近 0。原因通常是学习率太大或者标注里有大量错误框把梯度带偏了。解决先把lr0降到 0.001 甚至 0.0005再跑一遍如果还不行用第 3 章的检查脚本把标注过一遍重点看有没有类别 id 超出nc范围或者坐标越界。我遇到过标注里 class_id 写成 3 但nc只有 3合法 id 是 0、1、2训练直接崩。5.2 显存不足报 CUDA out of memory现象训练刚开始就报显存不够或者跑几个 batch 后爆。原因batch-size太大、img尺寸太大、模型太大。解决先把--batch-size减半比如从 16 降到 8如果还爆把--img从 640 降到 416再不行就换 yolov5n 或 yolov5s。另外训练时关掉其他占显存的程序用nvidia-smi看谁在占。注意 YOLOv5 的--batch-size是总 batch不是单卡多卡时要注意。5.3 推理时框的位置对但类别全错现象detect.py跑出来框的位置挺准但类别标签全是错的或者置信度很低。原因data.yaml 里的names顺序和训练时不一致或者推理时加载的权重和 data.yaml 不匹配。解决检查训练时用的 data.yaml 和推理时的是不是同一个names列表顺序必须完全一致。另外推理时如果没指定--dataYOLOv5 会用默认 coco 的类别名导致标签错乱。正确做法是推理时也带上--data data/mydata.yaml。5.4 验证集 mAP 很高但实际用效果差现象训练日志里 mAP0.5 到 0.9 了但拿新图片去测漏检和误检严重。原因验证集和训练集分布太接近或者数据增强太强导致模型没学到真实分布。解决把验证集换成完全独立的图片不要从训练集里随机抽训练后期把mosaic关掉用--close-mosaic 10让最后 10 个 epoch 用真实图片微调。另外检查验证集里是不是有和训练集重复的图重复会导致虚高。5.5 从 VOC 转 YOLO 后框整体偏移现象转换后的标注框位置整体偏了比如所有框都往左上角移。原因转换时用的img_w和img_h不是原图尺寸或者 XML 里的尺寸和实际图片不一致。解决转换脚本里不要硬编码宽高用 PIL 或 OpenCV 读原图拿真实尺寸。另外有些 VOC 数据集的 XML 里size标签写的是缩放后的尺寸和实际图片不符要以实际图片为准。6. 进阶验证与边缘部署前的量化检查训练出一个 mAP 不错的模型只是第一步真正要落地到 RK3568、树莓派 4B 或者 ROS 无人小车上还得过量化这一关。我一般会在训练结束后做三件事导出 ONNX、用 ONNX Runtime 验证精度、再决定是否量化。导出命令很简单但要注意--img和训练时一致--batch-size设为 1 方便部署。# 导出 ONNX 模型opset 12 兼容性较好 python export.py --weights runs/train/exp/weights/best.pt --include onnx --img 640 --batch-size 1 --opset 12参数说明--weights指向训练好的 best.pt--include onnx表示导出 ONNX--opset 12是算子集版本RK3568 的 NPU 工具链对 12 支持较好--batch-size 1是部署时的常见 batch。导出后先用 ONNX Runtime 跑几张验证图和 PyTorch 的结果对比如果框的偏差在几个像素内说明导出没问题。import onnxruntime as ort import numpy as np sess ort.InferenceSession(best.onnx) input_name sess.get_inputs()[0].name # 假设 img 是预处理后的 1x3x640x640 数组 img np.random.randn(1, 3, 640, 640).astype(np.float32) outputs sess.run(None, {input_name: img}) print(outputs[0].shape)这段代码只是验证 ONNX 模型能不能加载和推理输出 shape 应该是(1, 25200, nc5)之类。如果加载报错多半是 opset 版本或算子不支持可以试 opset 11 或 13。量化到 INT8 时一定要用校准集不能随便拿几张图糊弄否则精度掉得厉害。我一般从验证集里抽 100 到 200 张做校准量化后再跑一遍 mAP掉点超过 3 个点就考虑混合量化或换更保守的量化策略。最后说个我自己的习惯每次训完模型不管 mAP 多高我都会拿一批完全没参与训练的真实场景图跑一遍人工看漏检和误检。因为日志里的数字是平均出来的真实场景里的光照、遮挡、小目标才是检验模型的试金石。这个习惯帮我省过好几次「指标好看但上线翻车」的后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表