三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

MMRotate旋转目标检测实战:从环境配置到模型训练全流程详解

MMRotate旋转目标检测实战:从环境配置到模型训练全流程详解

1. 从零上手MMRotate:一个旋转目标检测框架的实战入门

如果你正在处理遥感影像、文本检测或者任何需要精确框出倾斜物体的任务,那么“水平框”的局限性你一定深有体会。一个水平矩形框住一个倾斜的飞机或船只,会引入大量无关的背景噪声,严重影响后续的分类、识别精度。这就是旋转目标检测(Rotated Object Detection)要解决的问题。而MMRotate,作为OpenMMLab生态中专门为此诞生的框架,正逐渐成为这个领域研究和应用的首选工具。今天,我就以一个实际使用者的角度,带你从环境搭建到跑通第一个训练,完整地走一遍MMRotate的基本使用流程,重点分享那些官方文档可能一笔带过,但实际操作中却至关重要的细节和“坑点”。

MMRotate并非一个孤立的框架,它深度构建在MMDetection和MMCV之上。这意味着你得到的不仅是一个旋转框的实现,更是一整套成熟的检测框架生态:丰富的数据集支持、灵活的模型架构、高效的训练策略以及可视化的调试工具。对于刚接触的开发者或研究者,最大的价值在于其统一、模块化的设计,让你能快速复现SOTA论文,或者将自己的创新点无缝集成到流水线中。接下来,我们将从最根本的环境准备开始,一步步揭开它的面纱。

2. 环境部署:避开版本依赖的“深水区”

环境配置是万里长征第一步,也是最容易让人崩溃的一步。MMRotate的依赖链相对较长,版本兼容性要求严格,一步错可能导致后续所有步骤报出令人费解的错误。

2.1 基础环境与PyTorch安装

首先,强烈建议使用Anaconda或Miniconda创建一个独立的Python环境,这是管理复杂深度学习项目依赖的最佳实践。假设我们创建一个名为mmrotate的环境:

conda create -n mmrotate python=3.8 -y conda activate mmrotate

接下来安装PyTorch。这里有一个关键点:你需要根据自己是否有GPU以及CUDA版本来选择命令。前往 PyTorch官网 获取最准确的安装命令。例如,对于CUDA 11.3的用户:

pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cu113

对于仅使用CPU的用户,则安装CPU版本。务必在安装后验证PyTorch能否正确识别你的硬件:

import torch print(torch.__version__) print(torch.cuda.is_available()) # GPU用户检查此项 print(torch.cuda.get_device_name(0)) # 如果可用,打印GPU型号

2.2 MMCV与MMDetection的精准安装

这是整个流程中最容易出错的环节。MMRotate依赖于特定版本的MMCV和MMDetection。官方推荐使用mim(OpenMMLab的包管理工具)来安装,这能最大程度保证兼容性。

pip install openmim mim install mmcv-full==1.7.1 # 安装完整版的MMCV,包含所有CUDA算子

安装MMCV-full通常耗时较长,因为它需要从源码编译CUDA扩展。确保你的系统已安装与PyTorch对应的CUDA工具链和nvcc编译器。接下来安装MMDetection:

mim install mmdet==2.28.2

重要提示:请务必核对MMRotate当前官方文档或requirements.txt中指定的MMCV和MMDet版本。上述版本号在撰写本文时是兼容的,但框架迭代很快,直接使用mim install mmdet安装最新版可能导致接口不匹配。安装后,可以简单测试MMDet是否正常:

from mmdet.apis import init_detector print(‘MMDetection导入成功‘)

2.3 MMRotate本体的安装与验证

完成前置依赖后,安装MMRotate本身。推荐从GitHub克隆最新代码进行安装,这样便于后续查阅源码和可能的修改。

git clone https://github.com/open-mmlab/mmrotate.git cd mmrotate pip install -v -e . # “-e”代表以可编辑模式安装,对源码的修改会直接生效

“-v”参数会输出详细的安装信息,方便排查问题。安装完成后,进行一个简单的功能验证:

python demo/image_demo.py demo/demo.jpg \ configs/rotated_faster_rcnn/rotated_faster_rcnn_r50_fpn_1x_dota_le90.py \ checkpoints/rotated_faster_rcnn_r50_fpn_1x_dota_le90-0393aa5c.pth \ --out-file result.jpg

如果找不到checkpoints,可以先从Model Zoo下载预训练权重。这个命令会使用一个示例配置和模型对示例图片进行推理,并保存结果。如果运行成功并生成了result.jpg,那么恭喜你,最艰难的环境配置已经通过了。

注意:在整个安装过程中,如果遇到任何“No module named ‘xxx‘”的错误,请首先检查是否在正确的conda环境下操作,然后根据错误信息,使用pip install安装对应的缺失包。网络问题可能导致下载失败,请考虑配置pip国内镜像源。

3. 理解核心概念:旋转框的表示法与数据集格式

在写第一行训练代码之前,必须理解MMRotate处理旋转框的核心逻辑,这直接关系到你如何准备数据以及理解模型输出。

3.1 旋转框的两种主流表示法

旋转矩形框通常用一个五元组 (x, y, w, h, θ) 表示,其中 (x, y) 是中心点坐标,w和h是宽和高,θ是旋转角度。但“角度”的定义和“宽高”的对应关系,存在不同约定,MMRotate主要支持两种:

  1. OpenCV定义 (oc):角度θ表示矩形框顺时针旋转的角度。这是DOTA数据集采用的格式。在这种定义下,旋转0度的矩形框,其“宽”边是水平的。
  2. 长边定义 (le90/le135):角度θ表示长边(w)与x轴正方向的夹角,取值范围通常是[-90°, 0°)或[-45°, 135°)等。这种定义下,宽w始终代表长边,高h代表短边,避免了因旋转90度导致宽高互换的歧义。

为什么这很重要?因为你在配置文件中必须指定angle_version参数(例如‘oc‘‘le90‘),模型训练和评估时所有的角度计算逻辑都会据此调整。用错了版本,模型永远学不对。DOTA数据集通常使用‘le90‘

3.2 DOTA数据集格式解析与准备

DOTA是一个大规模遥感图像旋转目标检测数据集,是检验旋转检测模型的“基准考场”。其官方格式如下:

  • 图像:巨大的原始图像(如4000x4000像素)。
  • 标注:一个与图像同名的.txt文件。每行代表一个实例,格式为:x1 y1 x2 y2 x3 y3 x4 y4 category_name difficult其中(x1, y1) ... (x4, y4)是四边形四个顶点的坐标(顺时针或逆时针),category_name是类别名,difficult表示是否为难例(1或0)。

MMRotate无法直接处理这种大图和四边形标注。因此,必须经过一个预处理步骤,将其转换为MMRotate支持的格式。这个过程通常包括:

  1. 图像切分 (Image Splitting):将大图切割成重叠的小图块(如1024x1024),以便GPU能够处理。
  2. 标注转换 (Annotation Transformation):将每个四边形标注,根据切分位置,分配到各个小图块中,并将四边形转换为旋转矩形框(五参数)。
  3. 生成COCO风格JSON:最终,MMRotate需要的是类似COCO数据集的.json标注文件,里面以字典形式组织图像信息、标注信息(包含旋转框参数)和类别信息。

MMRotate在tools/data/dota目录下提供了预处理脚本。典型的使用流程是:

# 假设DOTA数据集原始目录结构为:DOTA/ {images, labelTxt} # 在mmrotate目录下执行 python tools/data/dota/split/img_split.py --base-json tools/data/dota/split/split_configs/ss_train.json python tools/data/dota/split/img_split.py --base-json tools/data/dota/split/split_configs/ss_val.json

这些脚本会读取配置文件(其中定义了切分尺寸、重叠率等参数),自动完成切分和标注转换,并在data目录下生成处理后的trainval文件夹以及对应的annfiles务必仔细阅读和修改split_configs里的json文件,确保路径正确。这是数据准备中最关键的一步,出错会导致后续训练找不到标签或标签错误。

4. 配置文件:模型训练的灵魂

MMRotate采用基于Python的配置文件系统,所有组件(模型、数据、训练策略等)都在一个.py文件中定义。理解并正确修改配置文件是核心技能。

4.1 配置文件的结构解剖

我们以configs/rotated_faster_rcnn/rotated_faster_rcnn_r50_fpn_1x_dota_le90.py为例。它通常通过_base_继承多个基础配置文件,形成一种层次结构:

_base_ = [ ‘../_base_/datasets/dota.py‘, # 数据加载和增强配置 ‘../_base_/schedules/schedule_1x.py‘, # 学习率调度器、优化器配置 ‘../_base_/default_runtime.py‘ # 日志、钩子、评估器等运行时配置 ]

然后,它会在本地覆盖或新增特定设置:

# 模型定义 model = dict( type=‘RotatedFasterRCNN‘, backbone=..., neck=..., rpn_head=..., roi_head=..., train_cfg=..., test_cfg=... ) # 数据管道:在继承的基础上进行修改 data = dict( samples_per_gpu=2, # 批大小,根据GPU内存调整 workers_per_gpu=2, # 数据加载线程数 train=dict(...), val=dict(...), test=dict(...) ) # 优化器配置 optimizer = dict(type=‘SGD‘, lr=0.005, momentum=0.9, weight_decay=0.0001) # 学习率是关键参数

4.2 关键参数调优与实践建议

对于初学者,以下几个参数的调整最为常见且重要:

  1. 学习率 (lr)optimizer字典中的lr。这是最重要的超参数之一。官方配置通常针对8卡GPU设置(如lr=0.01)。当你使用单卡或双卡训练时,必须按线性规则缩放学习率。例如,8卡lr=0.01,则单卡应改为lr=0.01 / 8 = 0.00125。这是一个非常经典的“坑”,学习率过大会导致训练发散(loss变成NaN),过小则收敛缓慢。

  2. 批大小 (samples_per_gpu)data字典中的samples_per_gpu。它受限于你的GPU显存。如果出现“CUDA out of memory”错误,首先尝试减小这个值。注意,一些与批大小相关的技术(如BatchNorm)可能会受此影响,但对于检测任务,通常较小的批大小(如2或4)也能工作。

  3. 数据增强:在train_pipeline中定义。默认配置可能包含随机翻转、旋转、亮度对比度变化等。对于遥感数据,随机旋转(Rotate)增强尤其有效,因为它本身就与旋转不变性的目标一致。你可以调整prob(概率)或level(强度)来增加或减少增强的力度。

  4. 锚点框 (Anchor):在rpn_headanchor_generator中设置。旋转检测的锚点框也是旋转的。你需要关注scales(尺度)、ratios(宽高比)和rotations(旋转角度集合)。对于DOTA数据集,物体尺度变化大,长宽比多样,默认配置通常已经过优化。但如果你的自定义数据集中物体角度分布有特定规律(如大部分是0度和90度),可以调整rotations参数,例如rotations=[0, 30, 60, 90],以提升召回率。

实操心得:修改配置时,建议先复制一份官方配置文件到你的工作目录(例如my_config.py),然后进行修改。不要直接修改configs目录下的原文件,便于版本管理和对比。使用python tools/train.py my_config.py来启动训练,确保加载的是你的自定义配置。

5. 启动训练与监控:让模型“跑”起来

配置妥当后,就可以开始训练了。MMRotate提供了强大的命令行工具。

5.1 单卡与多卡训练命令

假设你的自定义配置文件为my_rotated_rcnn.py

单GPU训练

python tools/train.py my_rotated_rcnn.py --work-dir ./work_dirs/my_exp

--work-dir指定了实验目录,所有输出(日志、模型权重、配置文件备份)都会保存在这里。务必指定一个清晰的目录名,方便后续管理和比较不同实验。

多GPU分布式训练(例如4卡):

./tools/dist_train.sh my_rotated_rcnn.py 4 --work-dir ./work_dirs/my_exp_dist

使用分布式训练可以显著缩短训练时间,并且通常更稳定。脚本会自动处理进程间的通信。

5.2 训练过程监控与日志解读

启动训练后,控制台会输出大量信息。你需要关注以下几个关键点:

  1. 初始信息:程序会首先打印出完整的配置信息(cfg),请仔细核对,确保所有参数(特别是数据路径、类别数num_classes、角度版本angle_version)都符合你的预期。

  2. 数据加载:会显示数据集加载情况,如“loading annotations into memory... Done”。如果这里卡住或报错,大概率是数据预处理(第3步)或配置文件中的路径有问题。

  3. 训练循环日志:每若干次迭代(iter)会打印一行日志,例如:[epoch 1][iter 20/1000] lr: 1.250e-03, eta: 1 day, 2:30:15, time: 0.512, data_time: 0.102, memory: 3245, loss_rpn_cls: 0.6931, loss_rpn_bbox: 0.1452, loss_cls: 0.5234, loss_bbox: 0.0891, loss: 1.4508

    • lr:当前学习率,检查其变化是否符合调度策略。
    • loss:总损失,以及各个子损失(loss_rpn_clsRPN分类损失、loss_bbox边界框回归损失等)。在训练初期,这些损失应该呈现明显的下降趋势。如果loss长时间不降或变为NaN,需要立即中断训练,检查学习率是否过大、数据是否有错误标注(如坐标越界)。
  4. 验证与评估:按照配置,在每个epoch结束后会对验证集进行评估。输出包括各个类别的平均精度(AP)和平均召回率(AR),以及它们的平均值(mAP,mAR)。mAP是衡量模型性能的核心指标。对于DOTA,由于类别不平衡,关注mAP比单个类别AP更有意义。

5.3 使用TensorBoard进行可视化监控

MMRotate默认集成了TensorBoard日志记录。在训练命令后加上--tensorboard参数,或者在配置文件的log_config钩子中启用,即可在work-dir下生成tf_logs目录。

启动TensorBoard服务:

tensorboard --logdir ./work_dirs/my_exp

然后在浏览器中打开localhost:6006,你可以看到:

  • Scalars:所有损失、学习率、评估指标(mAP)随迭代/epoch的变化曲线。这是观察训练趋势、判断是否过拟合/欠拟合的最直观工具。
  • Images:训练或验证过程中,模型预测结果的可视化。你可以看到模型在当前阶段检测的效果,有助于定性分析。
  • Graph:模型的计算图(对于理解模型结构有帮助)。

一个实用的技巧:同时打开多个实验的TensorBoard日志进行对比,可以非常直观地比较不同超参数(如学习率、数据增强策略)对训练过程的影响。

6. 模型测试与推理:验证成果并实际应用

训练完成后,你需要用训练好的模型在测试集上评估最终性能,并学会如何用它进行单张图片或视频的推理。

6.1 对测试集进行标准评估

假设你的最佳模型权重保存在./work_dirs/my_exp/epoch_12.pth。使用以下命令在测试集上进行评估:

# 单卡测试 python tools/test.py my_rotated_rcnn.py \ ./work_dirs/my_exp/epoch_12.pth \ --eval mAP # 多卡测试 ./tools/dist_test.sh my_rotated_rcnn.py \ ./work_dirs/my_exp/epoch_12.pth \ 4 \ --eval mAP

--eval参数指定评估指标,mAP是旋转目标检测最常用的指标。程序会加载测试集,运行模型,计算所有类别的AP并取平均,最终给出一个mAP分数。这个分数应与验证集上的最终分数接近。如果差距过大,可能意味着模型在验证集上过拟合了。

6.2 单张图片/视频推理与结果可视化

除了定量评估,定性观察模型的检测效果同样重要。MMRotate提供了便捷的演示脚本。

单张图片推理

python demo/image_demo.py \ ${测试图片路径} \ my_rotated_rcnn.py \ ./work_dirs/my_exp/epoch_12.pth \ --out-file ${结果保存路径} \ --device cuda:0 # 指定GPU,或‘cpu‘

运行后,会生成一张带有预测旋转框的图片。框的颜色通常代表不同类别,分数会标注在框上。仔细检查框的角度是否准确、是否包含了错误检测或漏检,这能帮你发现模型在哪些场景下表现不佳。

视频流或摄像头推理

python demo/webcam_demo.py \ my_rotated_rcnn.py \ ./work_dirs/my_exp/epoch_12.pth \ --camera-id 0 # 摄像头ID,默认为0

这个功能对于实时演示或某些动态场景的测试非常有用。它会打开一个窗口,实时显示检测结果。

6.3 常见问题分析与排查思路

即使按照流程操作,你也可能会遇到一些问题。这里分享几个常见问题的排查思路:

  1. 训练Loss为NaN或突然爆炸

    • 首要怀疑对象:学习率过大。立即检查并调低学习率(lr),尤其是单卡训练时是否按规则进行了缩放。
    • 数据问题:检查标注数据中是否存在非法值(如无限大的坐标、负的宽高)。数据增强(如极端的旋转)是否产生了无效的框。
    • 梯度爆炸:可以尝试在配置文件中加入梯度裁剪(optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2)))。
  2. mAP始终很低或为0

    • 数据标注格式错误:这是最常见的原因。再次确认数据预处理步骤是否正确,生成的JSON标注文件中的bbox字段是否是五个数字[cx, cy, w, h, angle],并且角度单位是弧度制还是角度制(MMRotate通常使用弧度)。
    • 类别不匹配:配置文件中的num_classes是否等于你的实际类别数(包括背景类?MMDetection/MMRotate中,num_classes通常指前景类别数,Faster R-CNN等模型中会自动+1背景类,但一些自定义头部可能需要明确指定总数)。最直接的检查方法是打印出数据加载后的第一个batch,查看gt_labels的值是否在有效范围内。
    • 锚点框设置不合理:默认锚点框的尺度(scales)和角度(rotations)与你的数据分布严重不符。可以统计一下你数据集中所有目标的宽高和角度分布,然后调整锚点生成器的参数。
  3. 内存溢出(CUDA out of memory)

    • 降低data中的samples_per_gpu
    • 尝试使用更小的输入图像尺寸(在train_pipelinetest_pipelineResize变换中修改)。
    • 使用更轻量级的骨干网络(如将r50换成r18mobileNet)。
    • 在配置文件中启用fp16(混合精度训练),可以显著减少显存占用并可能加快训练速度。
  4. 评估速度非常慢

    • 测试时数据增强test_pipeline可能过于复杂,特别是多尺度测试(MultiScaleFlipAug)。对于追求速度的部署场景,可以简化为单尺度Resize和简单的翻转增强。
    • 模型本身较大。可以考虑在训练后对模型进行剪枝、量化等优化。

掌握这些基本使用流程和排查方法,你就已经具备了利用MMRotate框架开展旋转目标检测项目的基础能力。从环境搭建到模型产出,每一步的稳健都建立在对其设计理念和细节的充分理解之上。记住,深度学习工程实践,很多时候“魔鬼藏在细节里”,耐心地配置、仔细地观察日志、大胆地假设并小心地验证,是解决问题的唯一途径。

← 返回列表