简介本资源面向计算机视觉学习者与目标检测工程实践者提供一套细分类型飞机、鸟类与无人机的YOLOv5检测训练方案重点解决细粒度识别中机型区分难、样本组织繁琐的问题适合具备一定深度学习基础、希望快速复现实验或搭建演示系统的开发者。压缩包共约2000个文件以1994个txt标签文件为主体另含3个Python脚本与3份PDF说明文档整体约924.72MB标签已按YOLO格式划分train、val、test并附data.yaml可直接用于yolov5、yolov7、yolov8等框架训练。数据集规模超过一万张覆盖多种飞机型号、鸟类与无人机目标目录结构已配置完毕省去清洗与划分环节。配套PyQt界面脚本与使用说明便于将训练好的模型封装为可视化检测工具同时提供环境配置教程帮助读者打通从数据准备到界面部署的完整链路。目前已有467人学习下载适合作为细粒度检测课程设计、毕业项目或算法对比实验的起点。1. 从一堆飞机鸟群视频里怎么把无人机和客机分清楚上个月帮一个做低空安防的朋友看数据他手里攒了 1 万多张从公开视频里抽帧的图里面混着客机、螺旋桨小飞机、各种鸟还有四旋翼无人机。他一开始想用 COCO 预训练的 YOLOv5 直接跑结果模型把无人机和鸟全归成bird把远处的客机认成airplane根本没法用。问题不在模型在标签——COCO 里压根没有细分飞机型号和无人机这两个类你让它怎么分。这份资源解决的就是这个事一套已经标好、划分好、配好data.yaml的 YOLO 格式数据集加上一个能直接跑起来的 PyQt5 检测界面。数据集覆盖飞机细分型号、鸟类、无人机三类目标标签是 txt 格式train/val/test 已经切分完毕YOLOv5、YOLOv7、YOLOv8 都能直接拿去训练。适合两类人一类是想练手目标检测但懒得自己标数据的另一类是做低空监测、机场净空、生态观测这类场景、需要一个能区分这是鸟还是无人机的基线模型的。下面我按自己拆包复现的顺序把环境、数据、训练、界面、坑一条条讲清楚。2. 拆包先看目录数据集结构与 YOLO 标签格式核对拿到一个检测数据集我第一件事不是急着训练而是先把目录结构和标签格式核对一遍。这一步花十分钟能省掉后面几个小时的报错排查。这份资源的目录组织是标准的 YOLO 检测格式但有几个细节需要确认尤其是类别索引和data.yaml的对应关系。2.1 目录树与文件职责解压后大致是这样一个结构文件名以实际为准这里按 YOLO 惯例还原dataset/ ├── images/ │ ├── train/ # 训练集图片 │ ├── val/ # 验证集图片 │ └── test/ # 测试集图片 ├── labels/ │ ├── train/ # 训练集标签与图片同名 .txt │ ├── val/ │ └── test/ └── data.yaml # 数据集配置文件图片和标签是同名配对的images/train/xxx.jpg对应labels/train/xxx.txt。YOLO 训练时靠文件名匹配所以任何一张图缺了同名 txt训练阶段会直接报No labels found或者静默跳过。我一般会先跑一段脚本核对配对情况import os img_dir dataset/images/train lbl_dir dataset/labels/train imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir)} lbls {os.path.splitext(f)[0] for f in os.listdir(lbl_dir)} missing_lbl imgs - lbls # 有图没标签 missing_img lbls - imgs # 有标签没图 print(缺标签的图:, len(missing_lbl)) print(缺图的标签:, len(missing_img))这段逻辑很直白用集合差集找出不配对的样本。missing_lbl不为空说明有图没标训练时这些图会被忽略missing_img不为空说明标签是孤儿不影响训练但说明数据整理有残留。正常情况两个都应该是 0。2.2 标签格式与类别索引YOLO 的 txt 标签每行是class_id x_center y_center width height后四个都是归一化到 0~1 的相对坐标。打开一个标签文件看一眼cat dataset/labels/train/Pexels-Videos-2068519_mp4-6_jpg.rf.152992a221524d15e4dc36a2ab9d647a.txt你会看到类似0 0.512 0.334 0.221 0.180这样的行。这里最容易翻车的是类别索引class_id是从 0 开始的整数它对应data.yaml里names列表的下标。如果data.yaml写的是[plane, bird, drone]那0就是 plane1是 bird2是 drone。一旦标签生成时用的类别顺序和data.yaml不一致模型学出来的就是错位的——把无人机当鸟而且 loss 还降得很正常属于典型的玄学问题。核对方法很简单统计一下所有标签里出现过的 class_idimport glob from collections import Counter counter Counter() for f in glob.glob(dataset/labels/train/*.txt): with open(f) as fp: for line in fp: if line.strip(): counter[int(line.split()[0])] 1 print(counter)如果输出里出现了3或更大的 id而data.yaml只有 3 个类说明标签和配置对不上必须回去查生成脚本。这份资源号称可区分具体飞机型号意味着飞机类可能不止一个 id具体几个类要以data.yaml的names长度为准不要凭感觉假设。2.3 data.yaml 的关键字段data.yaml是训练入口核心就四个字段path: ./dataset # 数据集根目录 train: images/train # 相对 path 的训练图路径 val: images/val test: images/test nc: 3 # 类别数 names: [plane, bird, drone] # 类别名顺序即 class_idnc必须等于names的长度也必须等于标签里最大 class_id 1。这三个数任何一个对不上训练要么报维度错误要么静默学错。我见过有人改了names忘了改ncYOLOv5 直接抛Label class X exceeds ncY这种还算好的至少报错了。真正坑的是nc对了但names顺序错了训练全程无异常推理时类别全乱。提示path字段在 YOLOv5 里是相对当前工作目录解析的不是相对 yaml 文件。所以训练命令在哪个目录下执行path就要按那个目录来写否则会报找不到图片。3. 环境配置与训练从 PDF 教程到实际跑通 YOLOv5资源里附了两份环境配置 PDF教程1、教程2覆盖 YOLOv3 到 YOLOv8 的安装。PDF 适合照着装但实际跑的时候版本冲突才是大头。这一章我按自己复现的路径把环境、训练命令、参数含义和验证方法串一遍。3.1 环境搭建与版本选择YOLOv5 对 PyTorch 和 CUDA 版本比较敏感。我一般用 conda 隔离环境避免污染主环境conda create -n yolov5 python3.9 -y conda activate yolov5 # 按显卡 CUDA 版本装 PyTorch这里以 CUDA 11.8 为例 pip install torch2.0.1 torchvision0.15.2 --index-url https://download.pytorch.org/whl/cu118 # 克隆 YOLOv5 并装依赖 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt版本选择上Python 3.9 是兼容性最稳的区间3.11 以上有些依赖会编译失败。PyTorch 2.x 配 CUDA 11.8 是目前主流组合。如果你只有 CPU把--index-url那行换成 CPU 版即可但训练 1 万多张图会非常慢建议至少有一张 8G 显存的卡。装完验证一下 GPU 是否可用import torch print(torch.__version__) print(torch.cuda.is_available()) # 应为 True print(torch.cuda.get_device_name(0))cuda.is_available()返回 False 是最常见的翻车点八成是 PyTorch 版本和驱动不匹配重装对应 CUDA 版本的 torch 即可。3.2 训练命令与关键参数数据配好、环境通了训练命令本身不复杂python train.py \ --data dataset/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0 \ --project runs/train \ --name plane_bird_drone逐个说参数。--weights yolov5s.pt是预训练权重从 COCO 迁移过来比从头训收敛快得多s是 small 版本速度和精度平衡显存不够就换nnano精度要求高换m或l。--img 640是输入分辨率无人机和鸟在画面里往往很小如果小目标漏检严重可以提到 1280但显存占用会翻几倍。--batch 16是批大小8G 显存跑 640 分辨率大概能到 16爆显存就往下调。--epochs 100对 1 万多张图通常够用看验证集 mAP 是否还在涨不涨就可以停。训练过程中重点盯三个指标box_loss、obj_loss、mAP0.5。前两个持续下降是正常的mAP0.5是验证集上的平均精度它才是判断模型好坏的依据。如果 loss 降但 mAP 不涨多半是过拟合或者标签有问题。3.3 用 test.py 验证与推理资源里带了test.py训练完可以直接拿它跑测试集python test.py \ --weights runs/train/plane_bird_drone/weights/best.pt \ --data dataset/data.yaml \ --img 640 \ --task test--task test会在 test 集上算 mAP 并输出每类的 AP。这里要注意test 集必须和训练时用的 val 集分开否则评估结果虚高。如果 test 的 mAP 比 val 低很多说明模型泛化不行可能是数据分布不均——比如无人机样本远少于鸟模型就偏向鸟。单张图推理看效果python detect.py \ --weights runs/train/plane_bird_drone/weights/best.pt \ --source dataset/images/test \ --img 640 \ --conf-thres 0.25 \ --save-txt--conf-thres 0.25是置信度阈值低于它的框不输出。小目标场景可以降到 0.1 看召回但误检会变多。--save-txt会把检测结果存成 YOLO 格式方便和真值对比。我一般会挑几张无人机和鸟同框的图重点看这类样本最能暴露模型到底有没有学会区分。4. PyQt5 界面把训练好的模型包成能点的工具训练脚本跑通只是第一步真正交付给非技术同事用得有个界面。资源里的pyqt5使用说明.pdf和share.py就是干这个的。这一章讲界面怎么和模型对接、参数怎么暴露、以及打包时容易踩的坑。4.1 界面与推理逻辑的对接PyQt5 界面的核心是把选图 → 推理 → 显示结果这条链路串起来。share.py里通常是这样组织的import sys import cv2 import torch from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QFileDialog from PyQt5.QtGui import QPixmap, QImage class DetectWindow(QMainWindow): def __init__(self): super().__init__() self.model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, force_reloadFalse) self.model.conf 0.25 # 置信度阈值 self.model.iou 0.45 # NMS 的 IoU 阈值 self.init_ui() def init_ui(self): self.setWindowTitle(飞机-鸟类-无人机检测) self.btn QPushButton(选择图片, self) self.btn.clicked.connect(self.load_image) self.label QLabel(self) self.label.resize(640, 480) def load_image(self): path, _ QFileDialog.getOpenFileName(self, 选图, , Images (*.jpg *.png)) if not path: return results self.model(path) # 推理 results.render() # 画框 img results.ims[0] # 拿到带框的 numpy 图 img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) h, w, c img.shape qimg QImage(img.data, w, h, c * w, QImage.Format_RGB888) self.label.setPixmap(QPixmap.fromImage(qimg)) if __name__ __main__: app QApplication(sys.argv) win DetectWindow() win.show() sys.exit(app.exec_())逻辑说明torch.hub.load直接加载本地best.ptforce_reloadFalse避免每次启动重新下载。self.model.conf和self.model.iou是两个最该暴露给用户的参数——前者控制灵敏度后者控制重叠框的合并。results.render()会把检测框画到原图上results.ims[0]拿到的是 BGR 格式的 numpy 数组转成 RGB 才能给 Qt 显示。QImage那行的c * w是每行字节数stride写错会导致图像错位或花屏。4.2 参数暴露与交互设计界面好不好用关键看参数有没有暴露出来。我一般会在界面上加两个滑块分别控制conf和ioufrom PyQt5.QtCore import Qt from PyQt5.QtWidgets import QSlider self.conf_slider QSlider(Qt.Horizontal, self) self.conf_slider.setRange(1, 99) # 对应 0.01 ~ 0.99 self.conf_slider.setValue(25) self.conf_slider.valueChanged.connect(self.update_conf) def update_conf(self, value): self.model.conf value / 100.0setRange(1, 99)是因为 Qt 滑块只接受整数用 1~99 代表 0.01~0.99回调里除以 100 还原。这样用户拖动滑块就能实时调灵敏度不用改代码。iou同理。另外建议加一个保存结果按钮把带框的图存下来方便出报告。4.3 打包成 exe 的注意事项要发给别人用通常用 PyInstaller 打包pyinstaller --noconfirm --windowed --name 检测工具 \ --add-data best.pt;. \ --add-data yolov5;yolov5 \ share.py--add-data是把模型权重和 yolov5 源码目录一起打进去格式是源路径;目标路径Windows 用分号Linux 用冒号。--windowed去掉控制台窗口。打包后最常见的坑是torch.hub.load找不到模型——因为打包后工作目录变了得用sys._MEIPASS定位资源import sys, os def resource_path(rel): base getattr(sys, _MEIPASS, os.path.abspath(.)) return os.path.join(base, rel)然后pathresource_path(best.pt)。不处理这个exe 在别人机器上必崩。5. 避坑与排查那些训练日志不会告诉你的问题这一章是我自己复现和帮人排查时攒下来的每条都按现象 → 原因 → 解决写都是训练日志里看不出来的。现象训练 loss 正常下降但推理时所有目标都标成同一个类。原因data.yaml的names顺序和标签生成时的类别顺序不一致模型学的是错位映射。这种情况 loss 不会异常因为模型确实在拟合只是拟合错了。 解决用 2.2 节的统计脚本打印标签里实际出现的 class_id 分布和data.yaml的names逐一对齐。如果发现某个 id 的样本数异常少或异常多基本就是顺序错了。现象小目标远处的鸟、小无人机大量漏检mAP 上不去。原因输入分辨率 640 对小于 32×32 像素的目标不友好下采样后特征几乎消失。 解决把--img提到 1280同时--batch减半防爆显存或者在数据加载时开启 mosaic 增强YOLOv5 默认开让模型多见小目标拼接场景。如果还不行考虑换l或x大模型小目标检测对大模型更友好。现象PyQt5 界面点选择图片没反应或者显示一片黑。原因QImage的 stride 参数写错或者 numpy 数组不是连续的results.ims[0]经过 render 后可能不连续。 解决显示前加img np.ascontiguousarray(img)保证内存连续stride 用img.strides[0]而不是手算c * w。黑屏多半是通道顺序错了确认转成了 RGB。现象打包成 exe 后报FileNotFoundError: best.pt。原因PyInstaller 打包后资源被解压到临时目录sys._MEIPASS代码里用的相对路径找不到文件。 解决用 4.3 节的resource_path函数统一处理资源路径所有--add-data加进去的文件都走这个函数定位。现象训练到一半显存溢出CUDA out of memory。原因--batch太大或者--img提太高或者 dataloader 的workers太多导致内存碎片。 解决先把--batch降到 8 或 4再不行降--img。YOLOv5 支持--batch -1自动批大小让它自己找上限。另外--workers在 Windows 上设太大反而慢设 0 或 2 即可。注意改任何参数后重新训练最好换个--name别覆盖上一次的runs/train/xxx否则权重和日志混在一起回头对比实验都分不清哪次是哪次。6. 进阶技巧用 test.py 做类别级误差分析定位到底哪类拖后腿训练完看一个总 mAP 是不够的你根本不知道是飞机分不清型号还是鸟和无人机混了。真正有用的做法是拿test.py的输出做类别级误差分析。YOLOv5 的test.py在--task test模式下会输出每类的 P、R、mAP0.5、mAP0.5:0.95但默认只打印汇总。我一般会加--verbose让它逐类打印然后把结果存下来对比。具体操作先跑一次基线把每类指标记下来。python test.py \ --weights runs/train/plane_bird_drone/weights/best.pt \ --data dataset/data.yaml \ --img 640 \ --task test \ --verbose \ --save-json--save-json会生成一个predictions.json里面是每张图的检测框和置信度。有了这个文件就能做更细的分析——比如专门统计真值是 drone 但被预测成 bird的样本有多少。这类混淆矩阵用confusion_matrix.png也能看YOLOv5 训练结束会自动生成在runs/train/xxx/下横轴真值纵轴预测对角线越深越好非对角线的亮块就是混淆重灾区。我自己的习惯是如果发现 drone 和 bird 混淆严重先别急着调模型回去看数据。十有八九是这两类的样本在视觉上确实像——比如远距离的四旋翼和展翅的鸟轮廓接近。这时候要么补更多区分性强的样本近距离无人机、飞行姿态明显的鸟要么在推理时对这两类单独调高conf阈值宁可漏检也别误判。低空安防场景里把鸟误报成无人机带来的处置成本远高于漏掉一只鸟。另一个技巧是分分辨率测试。同一组权重分别用--img 640和--img 1280跑 test对比小目标类别的 mAP 变化。如果 1280 下无人机 mAP 明显涨说明你的场景小目标多部署时就该用高分辨率哪怕推理慢一点。这个对比花不了多少时间但能直接决定上线参数。还有个容易被忽略的点test.py的--task除了test还有val和speed。--task speed会测推理速度输出预处理、推理、NMS 各阶段耗时。部署到边缘设备前我一定先跑一遍 speed看看在目标硬件上能不能达到实时。如果 NMS 耗时占比高说明检测框太多调高conf或iou能压下来。从那以后我每次拿到新数据集都强制先跑一遍类别级误差分析再决定要不要调模型——因为大部分模型不行的问题根子都在数据和标签上光调超参数是治标不治本。这套流程走下来你手里就不只是一个能跑的模型而是一个知道边界在哪、哪里会翻车的模型。希望帮到你。本文还有配套的精品资源点击获取