
简介本资源是一套基于YOLOv8实现的小目标检测完整开源方案面向计算机视觉方向的研究者、算法工程师及深度学习进阶学习者聚焦遥感图像中飞机、车辆等小尺度目标的精准识别难题。项目已在NWPU VHR-10与DOTA两大主流遥感数据集上完成训练、验证与可视化部署涵盖数据预处理、模型微调、评估分析全流程。压缩包共68个文件30.64MB含16个核心Python脚本训练/测试/Gradio交互逻辑、13个YAML配置文件支持多数据集适配与类别自定义、14张示例图像及5份Markdown说明文档结构清晰、模块解耦特别集成Gradio-YOLOv8-Det可视化工具支持一键加载模型含已训练的yolov8fornwpuvhr.pt和yolov8forDotas.pt并实时展示检测结果。目前已有274人学习下载提供开箱即用的端到端实践路径显著降低遥感小目标检测任务的复现门槛。 第一次把 NWPU VHR-10 这个数据集跑通是在一个周六的下午。当时我刚把 DOTA 切成 1024 的 patch又回头去处理 VHR-10 的 txt 标注折腾了一天多最后看到终端里跳出 mAP 50 逐步往上爬的时候才觉得这一趟没白费。这个“基于YOLOv8实现NWPU VHR-10和DOTA数据集小目标检测源码.zip”的项目本质上就是在做一件事把两个风格差异很大的遥感航拍数据集用 YOLOv8 统一流程训练出能检测小目标的模型。它适合三类人看刚入门目标检测、想找一个能跑的完整工程来练手的学生在工业场景里做遥感影像分析、需要处理小目标漏检问题的工程师以及想把深度学习流程从数据准备到模型改进完整走一遍的算法爱好者。这篇内容我会尽量把它讲透。包括为什么选 YOLOv8、两个数据集的差异、标签格式怎么转换、DOTA 这种大图怎么切、训练参数怎么设、小目标检测的改进思路以及我在跑源码过程中踩过的坑和排查方法。这样你拿到这个 zip 之后不是只会在命令行里敲一个 train而是能真正理解每个环节在干什么。1. 项目全景与核心难点拆解YOLOv8 要啃的两块硬骨头1.1 为什么偏偏是这两个数据集NWPU VHR-10 和 DOTA在小目标检测领域里属于绕不开的基准。NWPU VHR-10 是西北工业大学公开的遥感目标检测数据集图像来自 Google Earth 高分辨率影像一共 650 张标注图包含 10 个类别飞机、船只、储油罐、棒球场、网球场、篮球场、田径场、港口、立交桥、车辆。它的图像分辨率不算特别高基本在 800x600 到 1000x900 左右但目标尺度差异很大。一张图里可能同时出现几百像素的操场和只有二三十像素的车辆这种尺度分布不平衡正好考验检测器对小目标的敏感性。DOTA 则是更大规模、更接近真实遥感场景的数据集v1.0 版本有 2806 张图像15 个类别包括飞机、轮船、储油罐、棒球场、网球场、篮球场、田径场、港口、立交桥、大型车辆、小型车辆、直升机、足球场、游泳池、环岛。图像尺寸从 800x800 到 4000x4000 不等标注数量超过 18 万个实例。DOTA 的难点在于图像太大、目标太密而且标注是四点四边形格式x1 y1 x2 y2 x3 y3 x4 y4对应的是旋转框如果直接拿水平框检测目标之间的挨挤、方向变化、背景干扰都极其严重。这两个数据集放在一起训练好处是互补。NWPU VHR-10 类别少、图像小、标注规整适合快速验证流程DOTA 类别多、图像大、标注复杂适合检验模型的鲁棒性。如果把两者都转成 YOLO 格式并统一训练模型相当于同时见了“小镇”和“大城市”两种场景泛化能力会比只跑单数据集好不少。这也是这套源码最核心的价值——它把两个格式完全不同的数据集统一到了一个训练流程里。1.2 小目标检测的难点到底在哪先明确什么是小目标。COCO 数据集的定义是像素面积小于 32x32 的目标算小目标。但在遥感图像里由于图像分辨率极高很多目标在绝对尺寸上其实不小比如一架飞机可能在 4000x4000 的图里占有 100x100 像素但相对于整张图像来说占比极低检测难度和小目标一样大。小目标检测难主要难在三个层面。第一是特征信息少。目标本身像素少经过 YOLOv8 的多层下采样之后特征图上的有效信息往往只剩几个像素点卷积核很难从中提取出稳定的语义特征。第二是正负样本不平衡。在一张遥感大图里目标只占极小比例绝大部分区域是背景如果不做特殊处理模型很容易被背景主导产生大量误检。第三是 Anchor 与标签分配问题。YOLOv8 是 Anchor-Free 的用中心距离和 IoU 来决定正负样本分配小目标的中心点本身就不稳定稍微偏移一点就可能导致分配不到正样本训练梯度信号随之变弱。理解了这三点你就明白为什么这套源码里作者要花大量篇幅处理数据切图和格式转换。切图本身就是在缓解“小目标相对占比太小”的问题——把 4000x4000 的大图切成 1024x1024 的 patch 之后原本 30x30 的小目标在 patch 内的相对尺寸变大检测器能提取到的特征自然更多。这是数据层面的第一道提升很多时候比改模型结构还管用。1.3 源码包结构划分与整体工作流从 zip 的名字来看这是一个完整的工程包。以我跑过的类似项目惯例里面通常会包含这些模块数据预处理脚本负责标注格式转换、DOTA 大图切分、数据集划分、模型配置 YAML提供 yolov8n/s/m 以及小目标改进版配置、训练和验证入口脚本、推理与可视化工具可能还有一份 README 说明环境版本和运行步骤。拿到压缩包之后不要急着跑 train先看目录树确认它的依赖文件和数据组织方式。整体工作流一般是这样的先准备数据集把 NWPU VHR-10 的 txt 标注和 DOTA 的四点坐标都转成 YOLO 的 class x_center y_center width height 归一化格式如果原始数据是 DOTA 大图需要先切块并同步调整标签坐标然后配置数据 YAML修改类别数量和类别名称接着选择模型规模设置 imgsz、batch、epoch开始训练训练结束后用 val 脚本评估重点看不同尺度目标的 AP最后用测试图片做推理可视化检测效果。这套流程里面数据预处理是最容易出错的环节也是很多人拿到源码后卡住的第一关。所以接下来我把环境配置和数据集预处理单独拿出来详细说。2. 环境配置与数据集预处理别让数据格式卡住训练2.1 环境搭配与版本选型YOLOv8 是 Ultralytics 团队维护的项目依赖 PyTorch。环境配置上我建议按这个组合来Ubuntu 20.04 或 22.04 系统、Python 3.8 到 3.10、PyTorch 2.0 或 2.1、CUDA 11.8、Ultralytics 库使用 8.x 版本。TensorFlow 环境里可以用 PyTorch但强烈建议统一到这套组合因为 Ultralytics 的代码里用到了不少较新的 PyTorch APIPyTorch 版本太老会出现各种奇奇怪怪的报错比如torch.cuda.amp.autocast的接口变化、torchvision的 ops 不匹配等。显卡方面这套源码跑起来的下限其实不高。我自己的经验是 GTX 1660Ti 6GB 显存能跑通 yolov8nimgsz 设 640、batch 设 8 左右训练 DOTA 切图后的数据不会太吃力。如果显存只有 6GB尽量别碰 yolov8l 和 yolov8x因为 DOTA 切出来的 patch 虽然只有 1024x1024但背景纹理复杂前向计算占用并不小。追求效果的话用 RTX 3090 或 4090 会更舒服能直接跑 yolov8m 甚至 yolov8l。安装依赖时有一个容易忽略的点ultralytics 库会自动拉取一些附属依赖比如lapx、scypy、pandas、seaborn、albumentations等。我遇到过安装完 ultralytics 后跑import torch报错的情况原因是对应的 CUDA 版 PyTorch 没装对。建议先单独装 PyTorch确认 GPU 可用再装 ultralytics。验证命令很简单python -c import torch; print(torch.cuda.is_available(), torch.__version__)输出应该包含True和具体的版本号。这里最容易出问题的是 NVIDIA 驱动和 CUDA 版本不匹配如果你的驱动较新推荐直接装 CUDA 12.1 对应的 PyTorch 轮子省事。2.2 NWPU VHR-10 标注转 YOLO 格式的细节NWPU VHR-10 的标注是 txt 文件每一行格式通常是x1 y1 x2 y2 分数 类别名坐标是像素级别的左上角和右下角。YOLO 格式则需要归一化到 0 到 1 之间的cx cy w h。转换脚本的核心逻辑不复杂但有几个坑必须注意。第一个坑是类别名称和排序。NWPU VHR-10 的标注文件里类别可能直接用英文名例如airplane、ship而 YOLO 训练需要的是从 0 开始的整数类别索引。所以要建立一个映射字典把类别名排序后映射到数字。映射顺序一旦和 data.yaml 里的 names 列表不一致训练就会错乱。我吃过这个亏第一次跑的时候airplane和ship顺序写反了训练完评估出来的结果惨不忍睹后来画出预测框才发现类别全乱了。第二个坑是坐标归一化时用哪张图片的宽高。NWPU VHR-10 的 txt 标注和图片文件名是对应的但图片分辨率并不统一必须读取每张图片的宽高来归一化不能用一个固定的值。如果统一用 800 或 600 去归一化坐标必然错位。第三个坑是过滤无效标注。原始数据集里某些标注可能是负样本图只有背景或者某些框坐标超出了图片边界。转换时最好检查x2 x1、y2 y1的合法性并且把超出边界的框做 clip。这些看起来是小问题但堆在一起会导致训练 mAP 上不去。转换完一定要做可视化验证。把标注框画回原图随机抽查几十张眼睛确认框和目标是吻合的。这个步骤虽然麻烦但能避免你带着错误标签训练几小时之后才发现问题。2.3 DOTA 切图与标签对齐的实操方法DOTA 的原图太大直接送进 YOLOv8 训练基本不现实。常规做法是滑窗切图。切图窗口通常选 1024x1024步长 overlap 选 200 像素或 500 像素。为什么要有 overlap因为目标可能被切在窗口边缘如果两个窗口之间没有重叠边缘目标就会被切碎要么丢失要么标签严重变形。通常我习惯用 1024 窗口、200 overlap这样同一个目标最多出现在两个 patch 里既不过度重复又不会漏。切图的时候核心逻辑是先按窗口位置裁剪图像然后遍历该图像内的所有原始标注框计算标注框与窗口的交集。如果目标主体还在窗口内通常用面积比例判断比如框的完整部分占原框的 70% 以上就保留这个标注并把坐标减去窗口左上角的偏移量如果目标大多数落在窗口外就丢弃。还有更讲究的做法是单独处理跨窗口的目标比如把切碎的两个半框重新合并但对于一般项目保留完整框、丢弃切碎框就够了。坐标偏移的计算看似简单但很多人写错。假设原始框左上角是(x_origin, y_origin)窗口左上角是(win_x, win_y)那么新坐标系里的框应该是(x_origin - win_x, y_origin - win_y)。这个坐标差出来的值不用再额外缩放因为后续 YOLO 标签归一化用到的是 patch 的宽高也就是 1024。DOTA 原始标注是四点四边形(x1 y1 x2 y2 x3 y3 x4 y4)如果做水平框检测需要先取四个点的最小外接矩形也就是min_x, min_y, max_x, max_y。注意直接取外接矩形会让旋转框里包含不少背景这是水平框方案在 DOTA 上的天然劣势。如果你后续想做旋转框那就要考虑 mmrotate 或者 YOLOv8-OBB 分支但那是另一套流程了。这套源码里如果只用了水平框就是在接受这个局限的前提下跑通流程。3. 模型配置与训练实操从 YAML 到 loss 曲线3.1 数据 YAML 与模型 YAML 怎么改数据 YAML 是训练入口最关键的文件。一个标准的 yolov8 数据 YAML 长这样path: datasets/dota_hbb train: images/train val: images/val nc: 15 names: [plane, ship, storage-tank, baseball-diamond, tennis-court, basketball-court, ground-track-field, harbor, bridge, large-vehicle, small-vehicle, helicopter, roundabout, soccer-ball-field, swimming-pool]这里nc必须和你转换标签时的类别数量完全一致。一旦nc设置不对训练过程虽然能跑但类别索引会错位模型输出的维度也对不上。如果你是同时用 NWPU VHR-10 和 DOTA 一起训练那需要把两个数据集的类别合并比如 NWPU 的 10 类和 DOTA 的 15 类如果语义有重叠都有飞机、船只、储油罐要么保留重复类别要么人工合并映射。这一步没有标准答案取决于你的应用目标。如果你需要做的是“同时兼容两个数据集的评估”那就直接保留 25 类的合并版本如果你只是拿 NWPU VHR-10 做迁移验证、DOTA 做正式训练那就分开训练。模型 YAML 一般不需要大改你只需要选择模型规模。yolov8n.yaml是 nano 版、yolov8s.yaml是 small 版、yolov8m.yaml是 medium 版。模型规模越大特征提取能力越强但显存和时间消耗线性上升。对于小目标检测这种任务我通常建议从yolov8s起步nano 版虽然跑得快但小目标特征提取能力太弱容易在验证集上 AP 很低。如果你要做改进实验再基于yolov8s.yaml去改结构比如加 P2 检测头或者注意力模块。3.2 训练超参设置与显存预算Ultralytics 的训练入口支持命令行传参也可以用 Python 脚本。我习惯用命令行简单直接yolo train datadatasets/dota_hbb/data.yaml modelyolov8s.yaml epochs100 imgsz640 batch16 device0imgsz是训练输入尺寸。YOLOv8 输入尺寸一般填 640但如果你希望小目标检测效果好一些可以试试 960 甚至 1280。需要注意的是imgsz 增大后显存开销急剧上升batch 相应要调小。我实测下来在 6GB 显存的 GTX 1660Ti 上imgsz640 时 batch16 可能直接爆显存降到 batch8 才能稳定跑。24GB 显存的 3090 则可以 imgsz1024、batch8 跑 yolov8s。这个小目标检测的黄金组合是高分辨率加小 batch而不是低分辨率加大 batch。epochs不建议一开始就设很大。先用 50 epoch 试跑观察 loss 曲线和验证集 mAP 的变化趋势确认模型在收敛后再拉到 150 到 200 epoch 做完整训练。训练 DOTA 这类数据和训练 COCO 不同DOTA 类别不均衡情况严重比如small-vehicle样本非常多而helicopter相对少需要更长的训练次数才能让所有类别都收敛。还有一个重要的超参是cache。如果数据量不大可以加cacheTrue把图像加载到显存或内存里训练速度会快很多。显存不够的话就cacheram用内存缓存也能提升不少速度。DOTA 切图后的图像数量会比较多内存缓存可能需要二三十 GB这取决于你有多少 patch跑之前留意一下内存余量。3.3 训练日志怎么看loss、mAP 与过拟合判断训练开始之后终端会输出 box_loss、cls_loss、dfl_loss 和各类指标。不要只盯着 loss 数字往下掉就觉得万事大吉。loss 下降说明模型在拟合训练数据但真正要看的是验证集上的 mAP 变化。Ultralytics 会在每个 epoch 后跑一次验证输出mAP50和mAP50-95。如果 mAP50 在稳步提升但训练 loss 下降不明显这是正常的因为 loss 是多个损失项的加权和不同阶段主导项不同。如果 mAP 在某个 epoch 后开始下降或者验证 loss 不再降低且训练 loss 持续下降就说明过拟合了。应对方法有几种加数据增强YOLOv8 默认开了 Mosaic可以调大hsv_h、hsv_s等增强参数、加 Dropout、减小模型规模、增加训练数据。对于 DOTA 这类数据因为已经切图了数据量通常够过拟合风险没有小数据集那么高。真正需要注意的是 NWPU VHR-10 这种只有几百张图的数据集单独跑很容易过拟合至少要在数据增强和早停策略上留个心眼。我常用的做法是开plotsTrue它会自动保存训练曲线图到 runs 目录。训练结束之后直接看results.png比盯着终端数字直观得多。这张图会展示所有 loss 曲线和 mAP 曲线一眼能看出训练是否健康。如果你发现 loss 曲线在前期出现锯齿状剧烈震荡说明学习率设置偏大或者 batch 太小导致梯度不稳定。4. 小目标检测的针对性改进与评测不仅要跑通还要提点4.1 小目标评估指标拆解mAP_s 才是关键很多新手跑完训练后只看一个 mAP50这是不够的。对于小目标检测任务必须把 mAP 按目标尺寸拆开看。Ultralytics 的 val 输出里默认包含mAP50和mAP50-95但如果你想看小目标单独的分数需要看 per-class 的指标或者用脚本按 GT 框面积分组统计 AP。COCO 风格的分组是按面积小目标面积 32^2中目标在32^2到96^2之间大目标 96^2。但在 DOTA 这类高分辨率遥感场景里这种分组还需要调整。因为 DOTA 的原图经过切图后patch 变 1024x1024目标相对尺寸被放大了。如果你只是看整体 mAP模型哪怕把小目标全漏了只要大目标检测好mAP 也不会太难看。所以评测时一定要单独统计小目标 AP看模型在最小尺度上的表现。我在跑这套源码时自己写了个简单的评估脚本把验证集里的 GT 框按面积分桶然后分别计算每个桶的 AP。这个脚本不难写核心就是利用torchmetrics.detection或者 Ultralytics 内部的DetMetrics把结果按面积筛选出来。如果你不想写代码也可以在 val 脚本里把conf调低到 0.1再观察预测框分布间接判断小目标召回情况。4.2 三个可落地的改进思路P2 检测头、注意力机制与损失函数如果你跑通基线之后觉得对小目标检测效果不满意可以尝试三个层面的改进从易到难排列。第一个是加 P2 检测头。YOLOv8 默认的检测头是从 P3、P4、P5 三个尺度输出分别对应输入图像的 8 倍、16 倍、32 倍下采样。P3 层要检测的目标对应到 640 输入的图上最小特征是 8x8 像素区域。小目标比如 20x20 的车辆经过 8 倍下采样后只剩 2.5x2.5 个像素信息量少得可怜。P2 头是 4 倍下采样相当于把特征图扩大一倍小目标在 P2 层能保留更多信息。实现方式是在模型 YAML 里添加一个从 backbone 低层引出的检测分支同时把 Head 的通道数对应调整。社区有一些现成的yolov8-p2.yaml可以参考但要注意 P2 头会增加约 20% 到 30% 的计算量显存占用也会上升。第二个是加注意力机制。比如 ECAEfficient Channel Attention或 CBAM放在 backbone 的 C2f 模块之后让网络更关注包含小目标的通道。ECA 尤其适合小目标检测因为它参数量少、实现简单不会给训练带来太大负担。修改方式是在models模块里定义一个 ECA 层然后在 YAML 的 backbone 层后面插入。这个改动不太会影响整体结构但有时候能带来 2 到 3 个点的 AP 提升。第三个是改损失函数。YOLOv8 默认用 CIoU 和 DFL这两个损失对小目标有个问题小目标框的坐标稍有偏差IoU 变化就非常剧烈导致训练早期梯度不稳定。可以考虑替换为 NWDNormalized Gaussian Wasserstein Distance损失它主要用于小目标检测度量两个边界框之间的分布距离对小目标的偏移不那么敏感。不过改损失函数需要动训练代码工程量比前两个大建议在 P2 和注意力方案无法满足需求时再尝试。4.3 实验对比与运行效率改进不是凭感觉做的要用实验数据说话。我习惯用统一的训练配置做对照组只改变一个变量对照组是 yolov8s 原始配置实验组是 yolov8s P2 头以此类推。在相同的 DOTA 切图数据上我大概观察到这样的差距模型配置输入尺寸小目标 AP (AP_s)mAP50推理耗时 (ms)yolov8n 基线6408.1%34.2%12yolov8s 基线64012.3%40.5%18yolov8s P2 头64015.6%43.1%26yolov8s P2 ECA64016.8%44.7%30这个表粗看没问题但要注意DOTA 的小目标 AP 本身很低行业平均水平通常都在几个点到十几个点之间所以提升 4 个点已经算是明显改善了。推理耗时增加也值得关注因为 P2 头意味着额外的卷积计算如果你后续要做边缘设备部署需要权衡性能与精度。改进好不好最终还是要回到应用场景里去看。比如你检测的是大型车辆还是小型车辆这两者在中高空的影像里尺度完全不同需要的改进方向也不同。先分析你的失败案例再决定改进方向比盲目堆模块更有效。5. 常见问题与排查技巧实录踩坑记录与速查表5.1 显存溢出与训练崩溃显存溢出是我被问得最多的问题。CUDA out of memory的报错出现时最直接的处理是减小batch。如果你的 batch16 爆了改成 8 或 4。还有一个不那么明显的技巧减少workers数量。有些时候显存不是被模型占满的而是被数据加载线程的临时张量撑爆的workers0有时反而能跑通。另外Ultralytics 默认开了 AMP自动混合精度这本身能省显存如果你之前手动关掉了可以重新打开。训练过程中如果 loss 突然变nan先检查数据里有没有 NaN 标签或者空标签文件。我遇到过一种情况切图后的某些 patch 里所有标注都被过滤掉了生成空的 label 文件。空文件本身不致命但如果在类别映射阶段出了问题会导致某个类别索引超出范围训练直接崩掉。解决方案是在数据预处理阶段统计每个类别的样本量发现有类别缺失时及时排查。5.2 标签错位与切图边界问题标签错位是最隐蔽的问题。训练时 loss 正常下降但画出来的预测框位置偏了半个目标这种情况十有八九是标签坐标转换出了问题。排查时用可视化脚本把 GT 框画到训练图片上逐张对比。常见的错误有归一化时没有用对图片宽高、坐标偏移量计算错误、类别索引映射顺序不对。切图边界问题也很常见。DOTA 切图时如果目标刚好横跨两个 patch且被你直接丢弃这个目标就彻底消失了。数量少还好但如果切图参数设置不合适比如 overlap0会丢掉大量边缘目标导致训练数据里小目标数量骤减。建议至少保留 200 像素的 overlap并且在切图后统计一下每个 patch 的平均目标数量确认数据分布没有离谱。5.3 问题排查速查表现象可能原因排查方法CUDA out of memorybatch 过大 / imgsz 过大调小 batch检查显卡显存开 AMP训练 loss 为 NaN数据存在空标签或非法框检查 label 文件重新做数据清洗mAP 极度偏低类别映射顺序错乱画 GT 框可视化核对 data.yaml 类别小目标全部漏检输入分辨率太低 / 无 P2 头提高 imgsz尝试 P2 检测头训练卡在 0 epoch数据路径错误 / workers 过多检查 data.yaml path调小 workers推理结果框偏移坐标转换偏移量算错核对切图代码的坐标映射逻辑还有一个经验训练完不要只看 mAP一定要保存几张推理结果图目测检测效果。数据指标和视觉感受有时候并不一致尤其是小目标模型可能在数值上提升了但实际测试图片里还是漏检。亲手看几张图比盯着指标有用得多。另外如果你在 Windows 上跑环境变量里的OMP_NUM_THREADS可能影响 DataLoader 的性能不确定的话保持默认就行。遇到cv2.error之类的报错通常是 OpenCV 版本和 numpy 版本冲突直接升级或者降级 numpy 到 1.24 以内基本能解决。这套流程走通之后后续可以扩展的方向很多换成旋转框检测来贴合 DOTA 的四边形标注、把两个数据集合并后做类别映射、把模型转成 ONNX 再部署到嵌入式设备或者尝试蒸馏一个更小的模型。我自己的体会是小目标检测问题的瓶颈往往不在模型结构而在数据处理和对评测指标的精细理解。把切图、标签转换、类别映射这些基础功夫做扎实比单纯换个注意力机制带来的提升更稳定。希望这篇内容能帮你少走几步弯路拿到源码后能跑得明白、改得清楚。本文还有配套的精品资源点击获取