简介:这份文档面向具备一定Python与计算机视觉基础的入门级研究人员和工程技术人员,系统讲解YOLOv5目标检测框架的本地环境搭建与基本使用流程。内容从系统要求切入,明确Windows、macOS或Linux平台及Python 3.6以上版本的前提,并针对GPU加速场景说明CUDA 10.2与cuDNN 7.6以上的版本匹配要求,随后依次覆盖依赖库安装、官方源码获取、预训练模型下载与示例检测运行,最后简要引介基于自定义数据集的模型训练与参数调整思路,兼顾理论教学与工程实践参考。资源包共1个docx文件,约19KB,以图文步骤形式组织,便于按章节对照操作。目前已有238人学习,适合初次接触YOLOv5、希望快速跑通检测流程并理解环境配置要点的读者,也可作为课程实验或项目搭建的辅助材料。
1. 从一张工地监控截图说起:YOLOv5 到底能帮你干什么
上周有个做安防的朋友甩给我一张截图,画面里安全帽、反光背心、人员、叉车全被框了出来,每个框上还带着类别和置信度。他问我这套东西部署要多少钱,我说你先别谈钱,本地一台带独显的机器就能跑起来,代码是开源的,模型权重直接下。这就是 YOLOv5 的日常——实时目标检测里落地最广的一档框架,PyTorch 生态,训练和推理脚本都给你写好了,改几行参数就能从“检测 COCO 八十类”切到“检测你自己的几类目标”。这份资源是一套完整的搭建与检测实操教程,从环境准备、依赖安装、拉源码、跑通第一张图,一直讲到用自定义数据集训练。适合刚接触计算机视觉、手里有 Python 基础、想把目标检测真正跑起来而不是停在论文里的开发者和工程技术人员。下面我按自己拆项目的顺序,把每一步的命令、参数和容易翻车的地方讲透。
2. 环境与依赖:把 PyTorch、CUDA、cuDNN 这条链先理顺
2.1 为什么先建虚拟环境而不是直接 pip
目标检测项目的依赖又重又杂,torch、torchvision、opencv、numpy、matplotlib 版本之间互相咬,直接装在系统 Python 里,跑崩一次想回退都难。我一般第一步就是隔离环境,Anaconda 装不装都行,装了省事,不装用 venv 也一样。教程里给的是 conda 方案,Python 定在 3.8,这个版本对 PyTorch 各版本兼容性最好,别贪新上 3.11、3.12,有些轮子还没跟上。
# 创建名为 yolov5_env 的独立环境,指定 Python 3.8 conda create --name yolov5_env python=3.8 # 激活环境,后续所有命令都在这个环境里执行 conda activate yolov5_env--name后面是环境名,随便起,但建议带上项目标识,机器上环境多了不容易混。激活之后命令行前面会出现(yolov5_env),看到这个前缀才说明你进对环境了。这一步看着简单,实际最常见的错误是“装完依赖发现装到了 base 环境”,原因就是忘了激活或者中途开了新终端。养成习惯:每开一个新终端,先conda activate yolov5_env再干活。
2.2 PyTorch 与 CUDA 的版本对齐
这是整个搭建里最容易翻车的一环。PyTorch 的 GPU 版本是跟 CUDA 运行时绑定的,你装的 torch 轮子自带一份 CUDA 运行时,但驱动得系统里有,且驱动支持的 CUDA 版本不能低于轮子要求的版本。教程里给的是 CUDA 11.3 对应的安装命令,实际动手前先跑一句nvidia-smi,看右上角那个 CUDA Version,它代表你驱动能支持到的上限。
# GPU 环境:安装带 CUDA 11.3 支持的 PyTorch pip install torch torchvision # 纯 CPU 环境:装 CPU 版,体积小、不依赖显卡 pip install torch torchvision cpuonly这里有个血泪经验:pip install torch torchvision默认拉的是哪个版本,取决于你的 pip 源和平台,不一定带 CUDA。稳妥做法是去 PyTorch 官方给的安装命令生成页,按你的系统和 CUDA 版本复制那条完整命令,通常长这样pip install torch==x.x.x+cu113 torchvision==x.x.x+cu113 -f https://...。装完立刻验证,别等跑检测时才发现是 CPU 版:
import torch # 打印版本和 CUDA 是否可用,False 说明装成了 CPU 版或驱动不匹配 print(torch.__version__, torch.cuda.is_available()) # 可用时再看显卡型号和显存,显存决定你能开多大 batch print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "CPU only")torch.cuda.is_available()返回 False 的排查顺序是:驱动有没有装、nvidia-smi能不能出画面、装的 torch 是不是 cu 版本、CUDA 运行时版本是否高于驱动支持上限。cuDNN 一般随 torch 轮子一起带,不用单独装,教程里提的 cuDNN 7.6 是下限要求,实际以 torch 自带为准。
2.3 拉源码与装项目依赖
环境好了,把项目代码拿下来。注意别在随便一个目录里 clone,后面训练产物、数据集路径都相对项目根目录走,路径乱了很麻烦。
# 克隆项目仓库并进入目录 git clone https://github.com/ultralytics/yolov5.git cd yolov5 # 安装项目声明的全部依赖 pip install -r requirements.txtrequirements.txt里锁了一批库的版本,包括 opencv-python、pillow、pyyaml、tqdm 这些。装的时候如果报某个包编译失败,八成是缺系统级编译工具,Linux 上补build-essential,Windows 上装 Visual C++ Build Tools。装完可以用pip list扫一眼,确认 torch 版本没被 requirements 里的宽松约束降级覆盖掉——这是另一个隐蔽的坑,requirements 里如果写了torch>=1.7,pip 可能觉得你已装的满足条件就不动,也可能顺手给你换个版本,装完再验一次torch.cuda.is_available()最保险。
3. 跑通第一次检测:detect.py 的参数逐个拆开看
3.1 权重文件与目录约定
YOLOv5 提供 s、m、l、x 几个规格,字母越大网络越深、精度越高、速度越慢。教程用 yolov5s.pt,这是最小的一档,几 MB 大小,CPU 上也能跑出能看的结果,适合第一次验证链路通不通。
# 下载最小的预训练权重到项目根目录 wget https://github.com/ultralytics/yolov5/releases/download/v5.0/yolov5s.ptWindows 上没有 wget,用浏览器下或者 PowerShell 的Invoke-WebRequest都行,关键是文件落在项目根目录,因为 detect.py 默认按相对路径找权重。权重文件本质是个字典,里面存了模型结构和训练好的参数,加载时框架会按结构重建网络再灌参数,所以权重和代码版本差太多会报 key 不匹配,这也是为什么建议权重和仓库版本尽量对齐。
3.2 detect.py 的核心参数与一次完整调用
检测脚本的参数不少,但真正天天调的就那么几个。先看一次完整调用,再逐个说。
# 对单张图片做检测:权重、输入源、推理尺寸、置信度阈值、NMS 的 IoU 阈值 python detect.py --weights yolov5s.pt --source test.jpg --img 416 --conf 0.4 --iou 0.5--weights指定模型权重路径,可以换成自己训练出来的best.pt。--source是最灵活的一个,可以是单张图、一个目录、一段视频文件,甚至填0调摄像头实时检测。--img是推理时的输入分辨率,必须是 32 的倍数,416 比默认的 640 快不少,代价是小目标容易漏,工地那种远景小目标场景我一般还是回到 640。--conf是置信度阈值,低于它的框直接丢,调高框变少变准、调低召回上来但误检多。--iou是 NMS 的 IoU 阈值,同一个物体被预测出多个框时,重叠度超过这个值的低分框会被压掉,调太低会把挨得近的两个真实目标误合并,调太高又压不干净。
脚本跑完,结果默认落在runs/detect/exp下,第二次跑会变成exp2、exp3,不会覆盖。输出图里框的颜色按类别区分,左上角带类别名和置信度。如果一张图跑完啥框都没有,先别怀疑模型,把--conf降到 0.1 再看,很多时候是阈值卡太死。
3.3 从脚本入口看推理链路
想改检测行为,得知道 detect.py 里发生了什么。核心链路是:读图 → letterbox 缩放填充到 32 的倍数 → 归一化转 tensor → 送进模型前向 → 输出一堆候选框 → NMS 过滤 → 按原图比例还原坐标 → 画框存图。其中 letterbox 那步是很多人忽略的细节,它保持长宽比缩放再补灰边,避免直接拉伸导致目标变形,还原坐标时也要按同样的比例反算,自己写后处理时这里算错,框就会整体偏移。
# 伪代码示意 detect.py 的核心推理段,帮助理解参数作用位置 img = letterbox(im0, new_shape=img_size)[0] # 保持比例缩放并填充 img = img[:, :, ::-1].transpose(2, 0, 1) # BGR 转 RGB,HWC 转 CHW img = np.ascontiguousarray(img) / 255.0 # 归一化到 0~1 pred = model(img_tensor)[0] # 前向,得到候选框 pred = non_max_suppression(pred, conf_thres, iou_thres) # 按 conf 和 iou 过滤conf_thres和iou_thres就是命令行传进来的--conf和--iou,它们作用在 NMS 这一步,而不是模型内部。理解这一点很关键:模型输出的原始候选框数量是固定的,你调阈值只是决定留哪些,不会让模型“看得更准”。想让模型本身更准,得走训练那条路。
4. 训练自己的数据集:配置、启动与产物解读
4.1 数据集格式与 data.yaml
YOLO 系列的数据标注格式是每张图配一个同名 txt,每行一个目标,格式为类别索引 中心x 中心y 宽 高,后四个都是相对图像尺寸归一化到 0~1 的值。目录一般组织成 images/train、images/val 和对应的 labels/train、labels/val。标注工具导出时选 YOLO 格式即可,别导成 VOC 的 xml,虽然框架有转换脚本,但多一道转换多一次出错机会。
数据准备好后写一个 data.yaml,告诉训练脚本去哪找图、有几类、类名是什么:
# data.yaml 示例:路径、类别数、类名三块是必须的 train: ../dataset/images/train val: ../dataset/images/val nc: 3 names: ['helmet', 'vest', 'person']train和val写图片目录,框架会自动去找同级的 labels 目录。nc是类别数,必须和 names 长度一致,写错了训练能启动但类别会错位。names的顺序就是标注文件里类别索引对应的名字,标错顺序是最隐蔽的错误之一,训练 loss 看着正常,检测出来类别全乱。
4.2 改模型配置与启动训练
模型配置文件在models/yolov5s.yaml,里面主要是 depth_multiple、width_multiple 和 backbone、head 的结构定义。换类别数只需要改nc这一项,别去动网络结构,除非你清楚自己在干什么。
# 用预训练权重做迁移学习,训练自定义数据集 python train.py --img 416 --batch 16 --epochs 300 \ --data data/mydata.yaml --cfg models/yolov5s.yaml \ --weights yolov5s.pt --cache--batch 16是每步喂多少张图,显存不够就往下调,8 甚至 4 都行,batch 太小梯度噪声大会影响收敛,可以配合调小学习率。--epochs 300是过数据集的轮数,小数据集一两百轮就够,看验证集指标不再涨就可以停。--weights yolov5s.pt是迁移学习的关键,从预训练权重起步比从零训练收敛快得多,小数据集上效果差距非常明显。--cache把图片缓存进内存加速读取,数据集大到内存放不下时要去掉,否则会吃满内存被系统杀掉。
训练产物落在runs/train/exp下,重点看两个文件:weights/best.pt是验证集指标最好的权重,results.png里画了各类 loss 和 mAP 曲线。曲线是判断训练状态的窗口——训练 loss 一直降但验证 mAP 不涨甚至掉,就是过拟合,该加数据增强或者减轮数;两个 loss 都居高不下,可能是学习率太大或者标注有问题。
4.3 用训练结果做推理与指标验证
训练完拿 best.pt 跑一次检测,确认端到端没问题:
# 用自己训练的权重检测,输入源换成验证集里的图 python detect.py --weights runs/train/exp/weights/best.pt --source ../dataset/images/val --conf 0.25自定义模型第一次跑,--conf建议先给低一点,比如 0.25,看召回情况再往上调。验证指标除了看 results.png,还可以跑val.py得到精确的 mAP:
# 在验证集上评估,输出 mAP@0.5 和 mAP@0.5:0.95 python val.py --weights runs/train/exp/weights/best.pt --data data/mydata.yaml --img 416mAP@0.5 看整体检出能力,mAP@0.5:0.95 更严格,看框的定位精度。两个数差得特别大,说明框画得不够准,可能是标注框本身松紧不一,或者输入分辨率太低。
5. 避坑与排查:这几处我踩过,你别再踩
5.1 现象:训练一开始就报显存不足
原因通常是 batch 或 img 开太大,或者--cache把大数据集全塞进了内存。解决是先降 batch 到 8 甚至 4,img 从 640 降到 416,去掉--cache,再用nvidia-smi观察显存占用曲线,确认稳定后再逐步往上加。别一上来就拉满,训练中途 OOM 比启动就 OOM 更气人。
5.2 现象:检测结果框位置整体偏移
原因多半是输入尺寸不是 32 的倍数,或者自己改后处理时 letterbox 的缩放比例没对上。解决是确认--img传的是 32 的倍数(320、416、640),自己写推理代码时严格复用框架的 letterbox 和 scale_coords 逻辑,别手写坐标还原。
5.3 现象:训练 loss 正常但检测类别全错
原因是 data.yaml 里 names 的顺序和标注文件里的类别索引对不上。解决是抽几张图,用标注工具重新打开核对类别名,再对照 yaml 里的顺序,逐类确认。这个错误不会让训练报错,只会让结果悄悄错,属于典型的黑匣子问题。
5.4 现象:pip 装完 torch 后 CUDA 不可用
原因是装成了 CPU 版轮子,或者驱动支持的 CUDA 版本低于轮子要求。解决是先nvidia-smi看驱动上限,再去官方安装页复制对应版本的完整命令重装,装完用torch.cuda.is_available()验证,别靠猜。
5.5 现象:验证集 mAP 很高,实际场景一塌糊涂
原因是训练集和实际场景分布差太远,比如训练图都是白天、清晰、正对镜头,实际是夜间、模糊、斜拍。解决是往训练集里补真实场景的图和对应的困难样本,做针对性增强,别指望调推理阈值能救回来。
6. 二次开发:把检测能力接进自己的业务链路
跑通只是起点,真正落地时没人会让你手动敲 detect.py。我一般的做法是把模型加载和推理封装成一个常驻服务,业务侧通过接口传图、拿结构化结果。核心是把 detect.py 里那套 letterbox、前向、NMS、坐标还原抽出来,去掉画图存盘的部分,直接返回[x1, y1, x2, y2, conf, cls]的列表。
import torch, cv2 from models.common import DetectMultiBackend from utils.augmentations import letterbox from utils.general import non_max_suppression, scale_coords # 服务启动时加载一次,别每次请求都加载,加载权重是重操作 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") model = DetectMultiBackend("runs/train/exp/weights/best.pt", device=device) model.eval() def infer(image_path, conf=0.25, iou=0.45, imgsz=640): im0 = cv2.imread(image_path) # 保持比例缩放到 imgsz,返回缩放后的图和原始尺寸比例 img = letterbox(im0, imgsz, stride=32, auto=True)[0] img = img[:, :, ::-1].transpose(2, 0, 1) # BGR->RGB, HWC->CHW img = torch.from_numpy(img).to(device).float() / 255.0 img = img.unsqueeze(0) # 补 batch 维度 pred = model(img)[0] pred = non_max_suppression(pred, conf, iou) results = [] for det in pred: if len(det): # 把缩放图上的坐标还原回原图尺寸 det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() for *xyxy, c, cls in det: results.append([int(v) for v in xyxy] + [float(c), int(cls)]) return results这段代码里几个点值得说。DetectMultiBackend是框架封装的统一加载入口,能自动识别权重格式,比手动拼模型结构省事。stride=32和auto=True让 letterbox 自动算填充量,保证尺寸对齐。scale_coords那步千万别省,省了返回的坐标就是缩放图上的,业务侧拿去画框会整体偏小。model.eval()也要记得,训练模式下的 BN 层行为不一样,推理结果会飘。
改造方向上,如果业务是视频流,把逐帧读图换成cv2.VideoCapture循环,推理部分不变,注意控制帧率别把 GPU 打满。如果要多路并发,模型实例共享、请求排队,别每个请求 new 一个模型。想再快,可以导出 ONNX 或 TensorRT 引擎,用export.py一条命令搞定,推理侧换成对应的 runtime,速度能提一截,代价是后处理逻辑要自己接。
验证改造是否正确的办法很土但有效:拿同一张图,分别走原始 detect.py 和你的封装函数,把两边的框坐标和置信度打出来对比,数值一致才算接对了。我吃过一次亏,封装时把 RGB 和 BGR 搞反了,检测框位置对但类别置信度普遍偏低,查了大半天才发现是通道顺序问题。从那以后我每次封装推理代码,都强制拿原脚本的输出做一次逐框比对,对上了再往业务里接。希望帮到你。
本文还有配套的精品资源,点击获取