
简介本资源面向计算机、电子信息工程、数学等专业的大学生及算法初学者提供基于DOTA数据集的YOLO目标检测完整训练方案可用于课程设计、期末大作业与毕业设计。包内共18个文件以6个Python脚本、2个cfg网络配置、2个sh训练脚本及names、data等数据索引文件为主另含说明文档与示例图片压缩包约517KB结构清晰便于按模块查阅。资源包含预训练参数、源代码与文档说明代码采用参数化编程注释明细并附运行结果均经测试运行成功方便读者理解YOLO训练流程与参数调整思路。目前已有1323人学习下载适合希望快速上手遥感图像目标检测、复用训练脚本并对照结果排查问题的读者参考。1. DOTA 数据集 YOLOv3 训练包一份能直接跑通的遥感目标检测工程遥感图像里的目标检测和常规 COCO 那套完全不是一回事。DOTA 数据集里的飞机、舰船、储油罐这些目标尺寸小、方向任意、密集排列直接拿 COCO 预训练权重去 finetunemAP 经常卡在 0.3 上下上不去。这份 DOTA-yolov3-master 资源包解决的正是这个断层——它把 DOTA 的旋转框标注转成 YOLO 可吃的水平框格式配好了 dota-yolov3-416.cfg 和 tiny 版本两套网络配置附带预训练参数、训练脚本、测试脚本和一份 README 文档说明。适合正在做遥感检测课程设计、毕设或者想把 YOLO 落地到航拍场景的从业者。整个包我拆过一遍代码注释清楚参数化程度高改几个路径就能跑。2. DOTA 标注格式与 YOLO 转换链路从四点坐标到归一化中心点2.1 为什么 DOTA 不能直接喂给 YOLODOTA 的标注文件是四点坐标格式每行形如x1 y1 x2 y2 x3 y3 x4 y4 category difficult描述的是一个任意方向的旋转矩形。而 YOLOv3 原生只认水平框标签格式是class_id cx cy w h全部归一化到 0~1。这两者之间的鸿沟不是简单取 min/max 就能填平的——直接对四点坐标取外接水平框密集排列的舰船和车辆会大量重叠NMS 阶段互相抑制召回率掉得厉害。资源包里data_transform目录下的dota_utils.py、YOLO_Transform.py、split.py、imagetrans.py四个文件构成了一条完整的转换链路。常见做法是先把 DOTA 大图裁成 1024×1024 的子图split.py 负责再对每个子图做四点转水平框YOLO_Transform.py 负责最后生成 YOLO 格式的 labels 目录。这个顺序不能反先转再裁会导致边界目标被切断后坐标错乱。2.2 转换脚本的核心逻辑与参数YOLO_Transform.py是整个链路里最需要看懂的文件。它的核心函数做三件事读四点坐标、算外接水平框、归一化写入 txt。下面是我从包里摘出来的关键逻辑加上了注释说明# YOLO_Transform.py 核心转换逻辑节选 import os import cv2 import numpy as np def dota_to_yolo(label_path, img_w, img_h, class_map): label_path: DOTA 格式标注文件路径 img_w, img_h: 对应子图的宽高用于归一化 class_map: 类别名到 id 的映射字典从 dota.names 读取 yolo_lines [] with open(label_path, r) as f: for line in f.readlines(): parts line.strip().split() if len(parts) 9: continue # 前8个是四点坐标第9个是类别名 coords list(map(float, parts[:8])) cls_name parts[8] if cls_name not in class_map: continue xs coords[0::2] # x1,x2,x3,x4 ys coords[1::2] # y1,y2,y3,y4 xmin, xmax min(xs), max(xs) ymin, ymax min(ys), max(ys) # 归一化中心点和宽高 cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 过滤掉宽高为0的退化框 if w 0 or h 0: continue yolo_lines.append( f{class_map[cls_name]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f} ) return yolo_lines逻辑说明四点坐标取 x 和 y 各自的最小最大值构成外接水平框这是 DOTA 转 YOLO 的标准做法。归一化用子图的实际宽高不是原图宽高这一点如果搞错所有框的位置都会偏移。参数方面class_map必须和dota.names里的类别顺序严格一致否则训练时类别标签全乱。split.py里的裁剪尺寸默认 1024重叠率一般设 200 像素这个值太小会导致边缘目标被切碎太大会让训练集膨胀好几倍。2.3 转换后的目录结构校验转换完成后标准目录应该是这样dataset/ ├── images/ │ ├── train/ # 裁剪后的子图 jpg │ └── val/ ├── labels/ │ ├── train/ # 对应的 YOLO 格式 txt │ └── val/ └── dota.names # 类别名列表dota.data文件里配置 train 和 valid 的路径以及 names 和 backup 目录。我一般会写一个快速校验脚本检查 images 和 labels 的文件名是否一一对应数量是否相等# 校验 images 和 labels 文件名是否匹配 for f in dataset/images/train/*.jpg; do base$(basename $f .jpg) if [ ! -f dataset/labels/train/${base}.txt ]; then echo 缺失标签: $base fi done这个检查能提前发现转换过程中因为文件名编码或路径问题导致的静默丢失比训练跑完发现 mAP 异常再回头查要省事得多。3. dota-yolov3-416.cfg 参数拆解与训练脚本实操3.1 两套 cfg 的选型依据包里给了dota-yolov3-416.cfg和dota-yolov3-tiny.cfg两个配置文件。416 版本是完整的 Darknet-53 backbone三个 yolo 检测头分别对应 13×13、26×26、52×52 的特征图适合有 GPU 的环境做精度优先的训练。tiny 版本只有两个检测头参数量大概是完整版的六分之一适合显存紧张或者需要快速验证流程的场景。选哪个不是拍脑袋决定的。如果你的 DOTA 子图里小目标占比高比如车辆、小型舰船416 版本的 52×52 特征图对小目标更友好如果主要是飞机、大型储油罐这类中大目标tiny 版本也能跑出可用的结果。我一般先用 tiny 跑 2000 轮验证整个链路通不通确认 loss 正常下降后再切 416 做正式训练。3.2 cfg 里必须改的几个参数打开dota-yolov3-416.cfg有几个地方是必须根据你的数据集调整的参数位置默认值修改依据classes15改成你实际类别数DOTA 原始 15 类filters3×(classes5)每个 yolo 层前的卷积层必须同步改max_batches50200一般设为 classes×2000不少于 6000steps40000,45000设为 max_batches 的 80% 和 90%width/height416显存够可以上 608小目标多建议 608filters这个参数是血泪经验——改了 classes 不改 filters训练直接报维度不匹配而且报错信息不会直接告诉你 filters 错了只会说某个 blob 的通道数对不上。我见过有人在这卡了一下午。3.3 train.sh 与 auto-resume-training.sh 的用法train.sh是标准训练入口核心命令就一行# train.sh 核心内容 ./darknet detector train cfg/dota.data cfg/dota-yolov3-416.cfg \ backup/dota-yolov3-416.backup -gpus 0,1参数说明detector train是 darknet 的训练模式第一个参数是 data 文件路径第二个是 cfg 路径第三个是预训练权重或断点权重路径第一次训练可以指向darknet53.conv.74做迁移学习-gpus 0,1指定多卡单卡去掉这个参数即可。auto-resume-training.sh是个很实用的脚本它检测 backup 目录下最新的权重文件自动从中断处继续训练。逻辑大概是# auto-resume-training.sh 逻辑示意 LATEST$(ls -t backup/*.backup 2/dev/null | head -1) if [ -z $LATEST ]; then echo 无断点从头开始 ./darknet detector train cfg/dota.data cfg/dota-yolov3-416.cfg \ darknet53.conv.74 else echo 从 $LATEST 恢复 ./darknet detector train cfg/dota.data cfg/dota-yolov3-416.cfg $LATEST fi这个脚本解决的是训练中途断电、显存溢出崩溃后手动找断点的麻烦。注意 darknet 每 100 轮存一次 backup如果崩溃时刚好在两次保存之间会丢一点进度但比从头来强太多。3.4 训练过程中的关键观察指标启动训练后终端会持续输出每个 batch 的 loss 和 mAP。重点看三个东西avg loss是否稳定下降、Region 82 Avg IOU是否在 0.6 以上、验证集的 mAP 是否在上升。如果 loss 在某个值附近震荡超过 500 轮不降大概率是学习率需要调整或者标注里有大量错误框。DOTA 数据集里有些类别标注质量参差不齐训练前用test.py可视化一批标注框能提前发现明显错误。4. 预训练参数加载与 test.py 推理验证4.1 预训练权重的两种加载方式包里附带的预训练参数有两种用法。第一种是作为迁移学习起点在train.sh里把权重路径指向预训练文件darknet 会自动加载匹配的层不匹配的层随机初始化。第二种是直接用于推理在test.py里加载权重对单张图或整个测试集做检测。test.py是 Python 写的推理脚本底层调用 darknet 的 shared library 或者直接 subprocess 调 darknet 可执行文件。核心流程是读图 → 预处理resize 到 416 或 608→ 前向推理 → NMS → 画框保存。下面是我常用的验证命令# 单张图推理验证 ./darknet detector test cfg/dota.data cfg/dota-yolov3-416.cfg \ backup/dota-yolov3-416_final.weights test.png -thresh 0.25-thresh 0.25是置信度阈值DOTA 场景下我一般设 0.25 起步密集小目标可以降到 0.15 看召回但误检会明显增多。输出结果默认存predictions.jpg包里自带的output.jpg就是一张推理结果示例。4.2 批量测试与 mAP 计算单张图看效果不够要算 mAP 得用 darknet 的valid模式# 批量验证并计算 mAP ./darknet detector valid cfg/dota.data cfg/dota-yolov3-416.cfg \ backup/dota-yolov3-416_final.weights -out dota_result这会在results/目录下生成每个类别的检测结果 txt然后用官方提供的reval_voc.py或类似脚本对比 ground truth 算 AP。注意valid模式用的是dota.data里valid指向的路径确保那个路径下的图片和标签是完整的验证集不要混入训练数据否则 mAP 虚高没有参考意义。4.3 推理速度与硬件匹配热搜里有人问 T4 上 1080p 25 帧用 TensorRT 跑 YOLO 640 分辨率能支持多少路。这个问题在 DOTA 场景下要换个角度想DOTA 子图是 1024×1024 裁出来的推理时 resize 到 416 或 608T4 上单帧 416 大概 8~12ms608 大概 18~25ms。如果做视频流实时检测还要算上预处理和后处理时间实际路数要打七折。tiny 版本能快 3 倍左右但 mAP 会掉 5~10 个点看你能不能接受。5. 避坑与排查DOTA 转 YOLO 训练中最容易翻车的五个地方5.1 现象训练 loss 从第一轮就是 nan原因标注文件里有坐标超出图片范围或者宽高归一化后大于 1。DOTA 原始标注在裁剪后边缘目标的四点坐标可能部分落在子图外面转换脚本没做裁剪就直接归一化导致 w 或 h 为负数或超过 1。解决在YOLO_Transform.py里加一步坐标裁剪把 x 限制在 [0, img_w]y 限制在 [0, img_h]再做归一化。同时过滤掉裁剪后面积小于 4 像素的框。5.2 现象mAP 始终在 0.1 以下但 loss 看起来正常原因dota.names里的类别顺序和标注文件里的类别名映射不一致。比如 names 里第 0 类是 plane但转换脚本里 class_map 把 plane 映射到了 id 3训练时网络学的是错位的类别。解决写一个检查脚本统计 labels 目录下所有 txt 里出现的 class_id 分布和 dota.names 的行数对比。如果某个 id 从未出现或者分布和预期严重不符就是映射错了。5.3 现象训练到一半显存溢出崩溃原因darknet 的 subdivision 参数设置不合理。batch64 subdivision16意味着每次前向 4 张图但如果图片尺寸从 416 改到了 608显存占用会翻倍。另外多卡训练时-gpus 0,1如果两张卡显存不一致会以小的那张为准。解决显存不够时优先调大 subdivision比如从 16 调到 32而不是减小 batch。subdivision 调大对精度影响很小但能显著降低显存峰值。多卡训练尽量用同型号显卡。5.4 现象推理结果框位置整体偏移原因test.py里 resize 图片时用了 letterbox 填充但画框时没有把填充偏移还原回去。DOTA 子图是正方形resize 到 416 也是正方形理论上不该有偏移但如果测试时用了非正方形图片就会暴露这个问题。解决检查test.py里坐标还原的逻辑确保(x - pad_x) / scale这一步没有漏掉。包里自带的test.png是正方形不容易发现这个问题换一张长方形图测一下就能验证。5.5 现象auto-resume-training.sh 恢复后 loss 突然跳高原因darknet 的 backup 文件保存的是权重不保存优化器状态动量等。恢复训练后优化器从零开始累积前几十轮 loss 会有一个跳变再回落这是正常的。但如果跳变后一直不回落可能是 backup 文件损坏。解决恢复后观察 100~200 轮如果 loss 回落到断点前的水平就没事。如果持续异常换上一个 backup 文件恢复。我一般会保留最近 3 个 backup手动删太旧的避免磁盘占满。6. 从跑通到跑好DOTA 检测的进阶调优与验证习惯跑通整个流程只是起点。DOTA 数据集上想把 mAP 从 0.5 推到 0.7 以上有几个方向值得花时间。第一个是输入分辨率416 对遥感小目标确实不够用改成 608 甚至 768 能带来 3~5 个点的提升代价是训练时间翻倍。第二个是 anchor 聚类DOTA 的目标尺寸分布和 COCO 差异很大用 k-means 在自己的训练集上重新聚类 anchor 尺寸替换 cfg 里的 anchors 行通常能再涨 2~3 个点。第三个是数据增强darknet 自带的旋转、裁剪增强对遥感场景帮助有限可以在转换阶段就做离线增强把训练集扩充 2~3 倍。验证习惯方面我强烈建议每次改完参数不要只看最终 mAP而是把验证集按类别拆开看。DOTA 的 15 类里plane、ship、storage-tank 通常好检而 small-vehicle、large-vehicle 因为目标小且密集AP 往往只有前者的一半。如果某个类别 AP 异常低先回去看那个类别的标注质量而不是盲目调网络。包里test.py支持按类别过滤输出用-class参数指定只看某一类排查起来很方便。还有一个容易忽略的点DOTA 原始数据集有 train/val 的官方划分但很多人转换时把所有数据混在一起自己随机分导致同一张原图裁出的子图同时出现在训练集和验证集里mAP 虚高。正确做法是按原始大图的编号划分确保验证集的子图来自训练集没见过的原图。这个细节在课程设计答辩时如果被问到能体现你对数据泄漏的理解。从那以后我每次做 DOTA 转换都强制走一遍「原图编号划分 → 裁剪 → 转换 → 校验文件名匹配 → 小样本过拟合测试」这个流程确认模型能在一小批数据上把 loss 降到接近零再开正式训练。这个习惯帮我省下了至少三次跑完几天训练才发现数据有问题的后悔药。希望帮到你。本文还有配套的精品资源点击获取