资讯动态

Faster R-CNN与YOLOv5飞机目标识别实战:从数据转换到训练推理

发布时间:2026/10/1 11:52:44 来源:尧图企业网站定制
简介对于希望训练飞机目标识别模型的开发者此压缩包以FasterRCNN与YOLOv5为核心覆盖数据准备、模型训练与验证全流程兼顾二阶段检测与单阶段检测两种范式适合有深度学习基础、想对比算法效果的读者。包内共616个文件其中220张JPG航空影像与99个XML、197个TXT标注构成可直接使用的数据集41个PY脚本负责数据增强、格式转换与训练流程36个YAML文件用于调整模型结构7个JSON及Dockerfile、Shell脚本支持环境配置与推理部署整体仅26.36MB。已有808人学习。资源内含可直接运行的训练代码、数据划分与格式转换工具可输出坐标识别结果结合图片和标注完成端到端飞机检测训练同时通过对比两类算法在速度和精度上的表现帮助读者直观理解候选区域生成与单阶段回归的原理为迁移到其他遥感目标识别场景提供完整起点。1. 用 Faster R-CNN 和 YOLOv5 训飞机目标识别先分清两条技术路线飞机目标识别这类项目我拆过不止一次结论往往和很多人预想的相反Faster R-CNN 这类二阶段模型识别精度更高、漏检更少但推理速度让它很难上实时视频流YOLOv5 这类一阶段模型速度快很多却需要在训练阶段反复调参才能压住小目标误检。这份项目资源正好把两条路线都摆出来了——用 FasterRCNN 和 yolov5 分别训练飞机目标识别覆盖了从数据集整理、环境配置到坐标输出的完整链路。对于想跑通算法对比、或者要把检测结果进一步落到坐标识别场景的开发者来说它能直接减少三到五天的环境调试时间。下面我从算法选型开始拆最后落到推理和坐标提取的实操上。2. 算法选型two-stage 与 one-stage 在飞机场景下的取舍2.1 Faster R-CNNRPN 与 Anchor 在飞机检测里的价值Faster R-CNN 把检测拆成两个阶段第一阶段用 Region Proposal NetworkRPN在特征图上生成候选区域第二阶段对候选区域做分类和边框精修。这个流程决定了它在飞机目标上的表现飞机是刚性目标轮廓相对规整背景要么是天空要么是机场跑道RPN 生成的候选框能把飞机从复杂纹理中剥离出来分类器再对框内内容做细判所以误检率和漏检率都低。但代价也很直接一张 1024×1024 的图像在 GPU 上推理Faster R-CNN 通常要跑 100 到 300 毫秒二阶段里的 RoI 池化和两次边框回归都会吃时间。我在实际项目里一般把它用在离线分析或者对漏检极度敏感的安防场景比如机场跑道异物检测、卫星影像飞机统计这类任务不要求实时但对召回率要求极高。用 Faster R-CNN 训练飞机数据集时Anchor 参数是第一个需要手动干预的地方。默认的 Anchor 比例是 0.5、1.0、2.0对应的是通用目标但飞机在航拍图里长宽比经常超过 2.5翼展和机身长度差异大默认 Anchor 会导致候选框和真实框的 IoU 偏低RPN 很难学到有效的正样本。训练前要统计训练集中所有标注框的宽高比把 Anchor 比例改成覆盖 1.5 到 4.0 的区间面积尺度和特征图的感受野要匹配。2.2 YOLOv5单阶段输出坐标与类别概率的实时路径YOLOv5 走的是另一条路没有独立的 Proposal 阶段图像进入网络后直接在一次前向传播里输出每个位置的边界框坐标、置信度和类别概率。它的核心是 Anchor 加网格预测每个网格单元负责预测多个 Anchor 框的偏移量配合置信度阈值和 NMS 做后处理。这条路径让 YOLOv5 在同样硬件上能做到 60 到 100 FPS是 Faster R-CNN 的十倍以上。飞机目标识别用 YOLOv5我认为关键在输入分辨率和 Anchor 的匹配关系。如果飞机在图中只占 20×20 像素同时把输入分辨率从 640 调到 1280让每个目标占据的像素更多会比单纯调 Anchor 效果好得多。YOLOv5 提供自动 Anchor 计算功能它会用 k-means 在训练集上重新聚类得到适合数据集的 Anchor 尺寸我每次都会用这个功能而不是直接沿用 COCO 预训练权重自带的 Anchor。YOLOv5 的后处理也值得细说NMS 的 IoU 阈值和置信度阈值直接影响飞机检测结果。阈值设得高能过滤误检但也会把置信度低的小飞机一起过滤掉设得低漏检少了但虚警会增多。我习惯先从低置信度阈值 0.1 开始看原始检测结果统计误检分布再逐步调高而不是一开始就追求纯净的输出。2.3 Faster R-CNN 与 YOLOv5 的硬件与精度对比对比维度Faster R-CNNYOLOv5检测流程候选区域生成 分类精修单次前向直接输出定位和分类小目标召回率高RPN 的密集采样占优中依赖输入分辨率和 Anchor 设计推理速度同硬件5-10 FPS60-100 FPS误检率较低中等需调 NMS 和置信度阈值显存占用较高二阶段特征缓存多较低模型结构更轻适合场景离线分析、高召回率任务实时视频流、边缘设备部署这张表就是我选型时的判断骨架。实测中同样的飞机数据集Faster R-CNN 的 mAP 通常会比 YOLOv5s 高出 2 到 5 个百分点尤其在包含大量小飞机的航拍图上差异会拉开。但换成 YOLOv5x 模型精度差距会被缩小速度依然占优。这个项目里两条路线都给了训练入口目的就是让你在同一份数据上感受这种差异。3. 把数据集整理成可训练格式COCO/VOC 与 YOLO 坐标转换3.1 训练集与验证集的来源从 COCO 文件到项目目录项目目录里出现了COCO_val2014_*图像和bus.jpg这里容易产生一个误解训练飞机目标识别用的却是 COCO 验证集图片。COCO 验证集里确实包含少量飞机类别样本但更像是一个拿来验证模型的基准数据。我的实际做法是把项目内的 COCO 图片作为外部验证集单独建目录存放不参与训练专门用来测试模型在未见数据上的表现。bus.jpg是 YOLOv5 官方仓库自带的一张测试图里面有大巴车没有飞机用它做飞机检测测试不会输出有效结果。如果你想快速验证模型推理链路是否正常可以先用它确认程序不报错再换成实际的飞机图片看检测效果。很多新手直接把bus.jpg放进数据集训练结果类别数对不上训练直接崩溃这是第一个要避开的坑。3.2 坐标识别的前提将 COCO JSON 转成 YOLO 格式目标识别的核心产物是边界框坐标但 YOLOv5 要求的是归一化的文本格式每一行代表一个目标格式是class_id x_center y_center width height所有值都是相对图像宽高的比例范围在 0 到 1 之间。Faster R-CNN 训练用的 torchvision 接口则要求 COCO 格式的 JSON 或 PyTorch 字典。下面这段脚本演示了把 COCO JSON 转成 YOLO 格式的核心逻辑。import json import os def coco_to_yolo(json_path, img_dir, output_dir, class_map): with open(json_path, r) as f: coco_data json.load(f) # 建立图片 ID 到文件名的映射 img_id_to_file {} for img_info in coco_data[images]: img_id_to_file[img_info[id]] img_info[file_name] # 按图片 ID 收集所有标注框 anns_by_img {} for ann in coco_data[annotations]: img_id ann[image_id] if img_id not in anns_by_img: anns_by_img[img_id] [] anns_by_img[img_id].append(ann) os.makedirs(output_dir, exist_okTrue) for img_id, anns in anns_by_img.items(): file_name img_id_to_file[img_id] img_h [x[height] for x in coco_data[images] if x[id] img_id][0] img_w [x[width] for x in coco_data[images] if x[id] img_id][0] label_path os.path.join(output_dir, os.path.splitext(file_name)[0] .txt) with open(label_path, w) as out_f: for ann in anns: cat_id ann[category_id] if cat_id not in class_map: continue # COCO 的 bbox 是 [x, y, width, height] x, y, w, h ann[bbox] # 转成 YOLO 需要的中心点坐标格式 x_center (x w / 2) / img_w y_center (y h / 2) / img_h w_norm w / img_w h_norm h / img_h out_f.write(f{class_map[cat_id]} {x_center:.6f} {y_center:.6f} {w_norm:.6f} {h_norm:.6f}\n) # class_map 举例假设只保留飞机类别COCO 里 airplane 的类别 id 是 5 # class_map {5: 0}这段脚本的关键在于 COCO 使用左上角坐标加宽高的表示法YOLO 使用中心点加宽高的表示法不清除这一点就会得到偏出目标一半位置的错误框。class_map用来完成类别 id 的重映射原始 COCO 有 80 个类别但我们的任务只需要飞机一个类如果不重映射模型会试图学习 80 个输出类别和数据集标注对不上。3.3 数据划分与场景采样飞机数据集和通用目标数据集有一个显著差异场景单一。如果所有训练图片都来自同一种拍摄角度或同一个机场模型很容易过拟合到背景上。划分训练集和测试集时不要随机划分要按拍摄场景分层抽样。我的习惯是首先保证训练集里包含高空俯拍、低空斜拍和卫星影像三种视角每种视角的比例大致控制在 631。验证集只从每种视角中抽少量代表图片确保验证时能看到不同视角的表现。其次训练集里的小目标比例如果低于 10%模型基本学不到小飞机特征我一般会把小目标样本复制加权或者用 Mosaic 增强让它们和背景混叠。数据增强也不是越多越好。YOLOv5 默认开启 HSV 色彩增强但飞机数据集里天空背景占了大面积过度的色相抖动会把蓝天变成奇怪的紫色模型被迫去学习颜色无关的特征。训练飞机目标时我会把hsv_h从默认的 0.015 降到 0.005保留少量增强防止过拟合又不破坏天空色彩的一致性。4. 训练环境搭建与超参数配置从 Dockerfile 到命令行4.1 用 Dockerfile 固化训练环境项目目录里直接出现了 Dockerfile这是把环境固化的最直接方式。目标识别训练的复制成本高模型依赖、CUDA 版本、Python 包版本任何一个不一致训练结果都可能和原始作者对不上。用 Dockerfile 可以保证环境一致下面是一个针对 YOLOv5 训练的 Dockerfile 示例。# 使用 PyTorch 官方镜像CUDA 11.7 对应 pytorch 2.0 FROM pytorch/pytorch:2.0.0-cuda11.7-cudnn8-runtime # 安装系统级依赖 RUN apt-get update apt-get install -y git vim libgl1-mesa-glx \ rm -rf /var/lib/apt/lists/* # 安装 YOLOv5 需要的 Python 依赖 RUN pip install opencv-python4.8.1.78 \ pyyaml tqdm matplotlib seaborn \ pandas requests thop --no-cache-dir # 设置工作目录并克隆仓库 WORKDIR /workspace RUN git clone https://github.com/ultralytics/yolov5 # 挂载点训练数据和权重放在这里 VOLUME [/workspace/datasets]这个 Dockerfile 里的libgl1-mesa-glx是 OpenCV 读取图片时的底层依赖漏掉它训练时经常会报找不到libGL.so.1的错误新手经常在这个地方翻车。PyTorch 官方镜像自带 CUDA 和 cuDNN比逐项安装省事。如果你的 GPU 驱动版本较老无法运行 CUDA 11.7就要把基础镜像换成pytorch/pytorch:1.13.1-cuda11.6-cudnn8-runtime这个兼容范围更宽。不用 Docker 的话用 conda 创建环境也完全可以核心依赖项保持跟 Dockerfile 一致即可。我一般在 Docker 里跑训练镜像conda 环境留给推理和二次开发用两边独立不容易互相污染。4.2 YOLOv5 训练自己的数据集官方脚本与数据 YAML做好格式转换后训练 YOLOv5 需要准备一个数据配置文件。不要直接改 COCO 的 YAML而是新建一个aircraft.yaml指向你自己的数据集路径。# aircraft.yaml # 训练集和验证集的图片路径可以是绝对路径或相对路径 train: /workspace/datasets/aircraft/train/images val: /workspace/datasets/aircraft/val/images # 类别数量 nc: 1 # 类别名称顺序必须和标注文件里的 class_id 对应 names: [airplane]训练启动命令我一般写成python train.py \ --data aircraft.yaml \ --weights yolov5s.pt \ --img 1280 \ --batch-size 8 \ --epochs 200 \ --cache \ --project aircraft_results \ --name exp01这里--img 1280是特意选的航拍图和普通街拍图不一样飞机目标占比通常较小把输入分辨率从默认的 640 提升到 1280 能显著改善小目标召回率代价是显存翻倍。如果显卡显存只有 8Gbatch-size 必须降到 8 甚至 4配合--cache把图片预加载到内存能加快每一轮的读取速度。--weights yolov5s.pt会用 COCO 预训练权重做迁移学习相比从头训练能省下三分之一的训练时间而且收敛更稳定。训练过程中的输出重点看val/box_loss和val/cls_loss曲线这两条线如果在验证集上持续走低到平稳说明模型在收敛。监控到第 50 轮时如果val/mAP0.5没有超过 0.3大概率是数据格式或 Anchor 出了问题可以先停掉训练去检查标注文件。4.3 Faster R-CNN 训练用 torchvision 快速起步Faster R-CNN 的训练复杂度比 YOLOv5 高一个量级需要自己写数据加载器和训练循环。用 torchvision 的预训练模型做迁移学习是最快的路径它提供了完整的 Faster R-CNN 实现只需要替换 BoxHead 的类别数。import torchvision from torchvision.models.detection import FasterRCNN from torchvision.models.detection.rpn import AnchorGenerator # 加载预训练的骨干网络 backbone torchvision.models.mobilenet_v3_large(pretrainedTrue).features backbone.out_channels 960 # 定义适合飞机长宽比的 Anchor 生成器 anchor_generator AnchorGenerator( sizes((16, 32, 64, 128),), aspect_ratios((1.5, 2.0, 3.0, 4.0),) ) # 构建 Faster R-CNN 模型num_classes 包含背景类 model FasterRCNN( backbone, num_classes2, # 背景 飞机 rpn_anchor_generatoranchor_generator )这段代码里的aspect_ratios是我根据飞机目标长宽比统计后填进去的和 YOLOv5 自动聚类 Anchor 的效果类似。torchvision 的 FasterRCNN 默认用的是 RPN 加 FPN 的组合如果你希望效果更强可以直接使用最高级的fasterrcnn_resnet50_fpn_v2但显存占用会明显上升。训练时学习率从 0.005 起步每 5 个 epoch 衰减一次500 张图片的飞机数据集50 到 80 个 epoch 基本能收敛。跑通一版 Faster R-CNN 后再对比同一个验证集上的 mAP 和 YOLOv5 的差距是这套项目最有价值的实验。5. 避坑指南飞机目标识别训练中的六个翻车点5.1 现象训练 loss 降到 0.05但测试 mAP0模型训练时 loss 很低验证和测试时却一个目标都检测不到这是目标识别项目里最常见的翻车场景。原因通常出在数据加载环节而不是模型本身最常见的是类别 id 错位COCO 中飞机是类别 id 5如果直接在class_map里把 id 写成了 0模型实际的监督信号全是错的。另一种可能时训练集和验证集的标注框格式不一致训练用 YOLO 归一化格式验证却用了绝对像素坐标。解决方法是先做数据回读验证写一段脚本读回训练集的.txt标注文件在原图上画出框肉眼确认每一个框都贴住飞机目标再做训练。我每次跑新数据集前都强制走一遍这个检查花十分钟能省一天排错时间。5.2 现象小目标飞机漏检严重航拍图中飞机目标可能只有 20×20 像素即便训练收敛推理时这些目标还是会被遗漏。原因是输入分辨率不足模型的特征图下采样步长导致小目标信息丢失。解决的优先级顺序是先把输入分辨率从 640 提升到 1280再开启 YOLOv5 的 TTATest Time Augmentation最后才考虑换更大的模型。TTA 会让推理速度变慢接近一倍但在小目标居多且不要求实时的场景下收益明显。我之前在一个 3000 张图的测试集上对比过分辨率提升加 TTA 可以让小目标召回率从 0.38 提升到 0.62。5.3 现象验证集坐标偏移一个身位检测框整体往左上或右下偏移位置不对齐。这个现象基本可以断定是坐标转换时中心点和左上角坐标搞混了。COCO 的bbox字段是[x_min, y_min, width, height]转成 YOLO 格式时要先计算中心点x_center x_min width/2如果直接套用了原来的x_min整个框会偏移半个身位。另一个常见位置是转换时忘了除图像宽度和高度输出了绝对像素坐标训练时模型完全无法收敛。解法没有捷径只能把转换脚本里的每一步都打出来人工核对我通常会在每 100 张训练图上随机挑 5 张画框验证确认无误后再进入训练环节。5.4 现象Docker 内训练速度比本机慢 30%Docker 容器训练速度明显下降首先检查是不是没有用 GPU 资源启动容器。docker run时忘了加--gpus all参数容器就会退回 CPU 运算速度差距当然巨大。还有一种可能性是容器内没有安装和宿主机匹配的 CUDA 驱动虽然依赖装的是 CUDA 11.7但实际运行在 CPU 上。解决方法是先用docker run --gpus all启动容器然后在容器内运行python -c import torch; print(torch.cuda.is_available())确认输出为True。如果为False检查启动命令和 NVIDIA Container Toolkit 是否安装。5.5 现象预训练权重与类别数不匹配直接加载官方yolov5s.pt训练只有一个类的数据集时模型能跑通但加载的模型头部的输出层维度是 80 类加背景与我们的nc1不匹配。YOLOv5 内部会自动裁剪预训练权重中分类层的部分但决定权在nc参数如果aircraft.yaml里nc写成了 80就会保留很大一个分类头导致模型参数冗余训练变慢且容易过拟合。正确做法是明确nc1同时让names和类别 id 一一对应。如果从零开始训练不想用预训练权重--weights参数可以指定为--weights 但收敛速度如果不介意倒是还行实测会慢一倍以上。5.6 现象COCO val 图片推理结果为空用项目自带的 COCO 验证集图片做推理时一张飞机都检测不到。这通常不是模型问题而是这些图片里的目标本身非常小超过了模型当前输入分辨率能感知的极限。COCO val 图多数为 640×480 到 1024×768飞机和常见比赛用图不同要么只有一两架飞机要么在画面中极小。解决方法是先挑一张包含清晰飞机的图片做测试比如从训练集里取一张标注框最大图确认推理链路没问题再做批量验证。如果项目里的 COCO 图片中飞机果然很小把推理输入分辨率提高到 1280 再看一般就能出结果。6. 推理验证与坐标导出把检测结果变成可用数据6.1 使用项目内的 COCO 图片快速验证模型训练完成后第一步不是批量跑测试集而是用一套固定的图片做回归验证。我从项目目录里选 3 张 COCO 图片建立了一个验证脚本每次模型更新后都跑一遍避免改了一版参数后旧的目标检测不出来了。# 用 YOLOv5 做单张图片推理测试 import torch # custom 参数指定训练好的权重文件 model torch.hub.load(ultralytics/yolov5, custom, pathaircraft_results/exp01/weights/best.pt, force_reloadTrue) model.conf 0.15 # 初期调低阈值观察全部潜在目标 model.iou 0.45 # NMS 的 IoU 阈值 results model(COCO_val2014_000000475710.jpg) results.show() # 输出检测结果表格 df results.pandas().xyxy[0] print(df)model.conf 0.15这一步很关键验证时把置信度阈值设得很低就是为了不漏看任何可能的检测输出。如果框特别多说明模型误检严重如果框没有说明模型没学到这个尺度的目标。先看结果再调阈值比直接拿默认值 0.25 盲跑要高效得多。6.2 目标中心坐标与实际经纬度/像素坐标的换算检测模型给出的xyxy是像素坐标落地到具体应用场景时坐标识别更关注目标中心点。中心点换算不复杂xc (x1 x2) / 2yc (y1 y2) / 2再除以图片宽高就得到归一化坐标。如果你有图像的投影参数可以继续把像素坐标投到经纬度上但那是另一个坐标系变换的子话题了。实测项目中我一般把归一化中心坐标存成 JSON留给后续的跟踪模块或地理信息系统使用。值得提醒的是检测框的精度受到标注框质量影响如果训练时的标注框本身就偏差两三个像素中心点也会有同样偏移所以在标注阶段就要留意框边贴住机翼边缘。6.3 批量推理导出 CSV从模型输出到业务数据把整张测试集跑一遍并导出 CSV是模型交付给业务方的标准动作。import torch import pandas as pd model torch.hub.load(ultralytics/yolov5, custom, pathaircraft_results/exp01/weights/best.pt) model.conf 0.25 model.iou 0.5 # 假设 test_images 是已准备好的测试图路径列表 import glob image_paths glob.glob(test_images/*.jpg) rows [] for path in image_paths: results model(path) df results.pandas().xyxy[0] img_name path.split(/)[-1] for _, row in df.iterrows(): x_center (row[xmin] row[xmax]) / 2 y_center (row[ymin] row[ymax]) / 2 rows.append({ image: img_name, x_center: round(x_center, 2), y_center: round(y_center, 2), w: round(row[xmax] - row[xmin], 2), h: round(row[ymax] - row[ymin], 2), conf: round(row[confidence], 4), }) output_df pd.DataFrame(rows) output_df.to_csv(aircraft_detections.csv, indexFalse)这段代码把每张图的检测框、置信度、中心点坐标全部落盘为 CSV在飞机定点计数和目标筛选场景下可以直接交给下游使用。批量推理时如果图片数量大建议加torch.cuda.synchronize()做 GPU 同步避免上一张图的推理还没完成就读取输出导致数据错位。把项目资料完整跑一遍后我的习惯是每次新数据集进来都强制走一遍数据回读画框、预训练权重裁剪检查、低阈值推理探索这三个步骤再把 Docket 训练和本地推理的环境分开维护。这套流程看着绕路实际能帮你提前滤掉八成以上的训练翻车点。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑