MMDetection v2.22.0实战:从环境搭建到模型训练与部署全流程

发布时间:2026/7/29 9:57:52
MMDetection v2.22.0实战:从环境搭建到模型训练与部署全流程 1. 从零开始为什么选择MMDetection v2.22.0如果你正在计算机视觉领域尤其是目标检测方向摸索想找一个既强大又相对容易上手的框架来训练自己的数据那么MMDetection绝对是一个绕不开的名字。我最早接触它是在处理一个工业质检项目时当时需要快速验证几个不同的检测模型在特定瑕疵上的效果。市面上框架很多但要么配置繁琐要么生态封闭直到用了MMDetection那种“开箱即用”和“模块化”的体验让我决定把它作为团队的主力工具之一。今天我们就以v2.22.0这个经典稳定版本为例手把手走一遍用自己数据集训练模型的完整流程。为什么是v2.22.0在深度学习框架的迭代中新版本往往带来新特性但也可能引入新的兼容性问题或改动。v2.22.0属于MMDetection 2.x系列的后期版本它已经包含了大量主流的检测模型如Faster R-CNN、YOLOv3、RetinaNet、Cascade R-CNN等代码结构清晰社区资料和解决方案非常丰富对于入门和实际项目部署来说稳定性和可复现性比追求最新版更重要。它能帮你把注意力集中在数据、模型和任务本身而不是没完没了地解决环境冲突。这个过程的核心无非是三步准备数据、配置环境、启动训练。但每一步里都有不少细节比如数据该怎么标注成框架认识的格式配置文件里那一大堆参数到底怎么调训练时出了错该怎么看日志排查。网上很多教程只给命令不说原理跟着做很容易卡住。这篇文章我会结合我多次从零搭建的经验把这些容易踩坑的地方都掰开揉碎了讲清楚目标是让你不仅能跑通更能理解背后的逻辑真正把MMDetection用起来。2. 环境搭建避坑指南与版本锁定策略搭建环境是万里长征第一步也是最容易劝退新手的一步。很多人在这里耗费大量时间最后因为版本冲突而放弃。我们的核心策略是严格锁定版本尤其是PyTorch和CUDA的对应关系。MMDetection v2.22.0发布于一段时间前它对PyTorch和CUDA的版本有特定要求不匹配会导致各种离奇错误。2.1 基础环境配置CUDA、PyTorch与MMCV首先你需要确定自己显卡的CUDA版本。在命令行输入nvidia-smi右上角会显示CUDA Version比如12.1。注意这个“CUDA Version”指的是你的显卡驱动最高支持的CUDA运行时版本不代表你系统里已经安装了该版本的CUDA Toolkit。为了兼容性我们通常安装一个略低于此版本的CUDA Toolkit。例如驱动显示12.1我们可以选择安装CUDA 11.3或11.1。根据MMDetection v2.22.0的官方文档它通常兼容PyTorch 1.6到1.9。我个人的经验是PyTorch 1.8.1 CUDA 11.1的组合最为稳定。以下是具体的安装命令假设已安装Anaconda# 创建一个新的conda环境python版本建议3.7或3.8 conda create -n mmdet python3.8 -y conda activate mmdet # 安装PyTorch 1.8.1和对应的torchvisionCUDA版本为11.1 # 请务必从PyTorch官网历史版本页面获取准确的命令以下为示例 conda install pytorch1.8.1 torchvision0.9.1 torchaudio0.8.1 cudatoolkit11.1 -c pytorch -c conda-forge注意-c pytorch -c conda-forge指定了下载通道有时conda默认源速度慢或找不到包可以尝试添加国内镜像源或者使用pip安装pip install torch1.8.1cu111 torchvision0.9.1cu111 torchaudio0.8.1 -f https://download.pytorch.org/whl/torch_stable.html接下来是安装MMCV。这是OpenMMLab系列框架的底层计算机视觉库MMDetection依赖于它。这里有一个巨大的坑MMCV的版本必须与PyTorch、CUDA版本严格匹配并且有“mmcv”和“mmcv-full”之分。对于训练和推理我们需要功能完整的mmcv-full。MMCV-full需要通过源码编译或寻找预编译的wheel包。最可靠的方法是使用OpenMMLab官方提供的安装命令。对于PyTorch 1.8.1和CUDA 11.1命令如下pip install mmcv-full1.3.17 -f https://download.openmmlab.com/mmcv/dist/cu111/torch1.8.0/index.html请注意上面链接中的cu111对应CUDA 11.1torch1.8.0对应PyTorch主版本。即使你是PyTorch 1.8.1通常也兼容torch1.8.0的mmcv。如果找不到完全对应的版本选择最接近的。安装成功后可以在Python中import mmcv测试。2.2 安装MMDetection与验证基础环境就绪后安装MMDetection本身反而简单了。我们选择v2.22.0版本。# 克隆仓库也可以直接pip安装但克隆更方便后续查看代码和配置文件 git clone https://github.com/open-mmlab/mmdetection.git cd mmdetection # 切换到v2.22.0标签 git checkout v2.22.0 # 以可编辑模式安装 pip install -v -e . # “-e”代表可编辑模式这样你修改代码库中的配置文件后无需重新安装即可生效。安装完成后进行一个简单的验证确保框架核心功能正常import mmdet print(mmdet.__version__) # 应该输出 2.22.0 或类似 from mmdet.apis import init_detector, inference_detector print(导入成功)此外强烈建议运行一下项目自带的单元测试特别是对检测器的基础测试python -m pytest tests/test_models/test_detectors.py -v如果这些步骤都没报错那么恭喜你最磨人的环境关已经过了。记住这个环境组合PyTorch 1.8.1 CUDA 11.1 mmcv-full 1.3.17 mmdet 2.22.0以后在相同机器上复现项目会非常轻松。3. 数据准备从原始标注到MMDet标准格式框架装好了接下来是你的数据。模型训练的好坏七分靠数据。MMDetection支持多种数据格式但最通用、最推荐的是COCO格式。即便你的数据现在是VOC格式、YOLO格式或者自定义格式最终都需要转换成COCO格式。COCO格式是一个JSON文件结构清晰包含了图像信息、标注信息、类别信息等。3.1 COCO数据格式深度解析很多教程只告诉你把数据转成COCO格式但没讲清楚这个JSON文件里每个字段到底什么意思出了问题都不知道怎么改。我们来详细拆解一下一个标准的COCO格式JSON文件主要包含以下几个顶级字段images: 一个列表列表中的每个元素是一张图片的信息字典。annotations: 一个列表列表中的每个元素是一个目标实例的标注信息字典。categories: 一个列表列表中的每个元素是一个物体类别的信息字典。images字段示例{ images: [ { id: 1, // 图片的唯一ID必须是整数从1开始递增 file_name: train_001.jpg, // 图片文件名 height: 600, // 图片高度像素 width: 800 // 图片宽度像素 }, // ... 更多图片 ] }关键点id必须唯一且连续虽然不是绝对强制但强烈建议height和width必须准确因为后续计算anchor、评估指标时会用到。annotations字段示例{ annotations: [ { id: 1, // 标注的唯一ID整数全局唯一 image_id: 1, // 对应图片的id表示这个目标在哪张图里 category_id: 1, // 对应类别的id表示这个目标属于哪一类 bbox: [100, 150, 50, 80], // 边界框 [x, y, width, height] (左上角x, y, 宽 高) area: 4000.0, // 边界框的面积 width * height iscrowd: 0 // 是否为拥挤人群标注0表示否1表示是。通常目标检测设为0。 }, // ... 更多标注 ] }关键点bbox的格式是[x, y, width, height]这是COCO的标准和某些格式[x_min, y_min, x_max, y_max]不同转换时务必注意。area字段在计算某些评估指标如Average Precision时会用到需要计算准确。iscrowd通常设为0除非你在处理密集、重叠严重的场景。categories字段示例{ categories: [ { id: 1, // 类别的唯一ID整数建议从1开始0通常保留为背景 name: cat // 类别名称字符串 }, { id: 2, name: dog } ] }关键点id最好从1开始连续递增。这个id会直接映射到模型输出的类别索引。在配置文件中你需要用classes (cat, dog)这样的元组按顺序列出所有类别名顺序必须和这里id的顺序一致。3.2 数据转换实战与脚本编写假设你有一批用LabelImg标注的VOC格式XML文件数据。你需要写一个Python脚本将它们转换为COCO格式。下面是一个简化但核心逻辑完整的示例import os import json import xml.etree.ElementTree as ET from PIL import Image def voc_to_coco(voc_annotations_dir, images_dir, output_json_path): 将VOC格式标注转换为COCO格式。 Args: voc_annotations_dir: VOC XML文件所在目录。 images_dir: 图片文件所在目录。 output_json_path: 输出的COCO格式JSON文件路径。 coco_data { images: [], annotations: [], categories: [] } # 1. 定义类别这里需要你根据自己数据集修改 # 类别ID必须和XML文件中的name对应并确保顺序。 classes [cat, dog, person] # 示例类别 for i, cls in enumerate(classes, start1): # id从1开始 coco_data[categories].append({id: i, name: cls, supercategory: none}) # 创建类别名到ID的映射 cat_name_to_id {cls: i for i, cls in enumerate(classes, start1)} annotation_id 1 # 标注ID计数器 image_id 1 # 图片ID计数器 # 2. 遍历所有XML文件 for xml_file in os.listdir(voc_annotations_dir): if not xml_file.endswith(.xml): continue xml_path os.path.join(voc_annotations_dir, xml_file) tree ET.parse(xml_path) root tree.getroot() # 获取图片文件名和尺寸 filename root.find(filename).text img_path os.path.join(images_dir, filename) if not os.path.exists(img_path): print(f警告图片文件 {img_path} 不存在跳过此标注。) continue with Image.open(img_path) as img: width, height img.size # 添加图片信息到images列表 coco_data[images].append({ id: image_id, file_name: filename, height: height, width: width }) # 3. 处理该图片中的所有目标标注 for obj in root.findall(object): cls_name obj.find(name).text # 如果类别不在预设列表中跳过或报错 if cls_name not in cat_name_to_id: print(f警告发现未知类别 {cls_name}已跳过。) continue cat_id cat_name_to_id[cls_name] bndbox obj.find(bndbox) # VOC格式是 [xmin, ymin, xmax, ymax] xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 转换为COCO格式 [x, y, width, height] coco_bbox [xmin, ymin, xmax - xmin, ymax - ymin] area (xmax - xmin) * (ymax - ymin) # 添加标注信息到annotations列表 coco_data[annotations].append({ id: annotation_id, image_id: image_id, category_id: cat_id, bbox: coco_bbox, area: area, iscrowd: 0 }) annotation_id 1 image_id 1 # 4. 保存为JSON文件 with open(output_json_path, w, encodingutf-8) as f: json.dump(coco_data, f, ensure_asciiFalse, indent2) print(f转换完成共处理 {len(coco_data[images])} 张图片{len(coco_data[annotations])} 个标注。保存至 {output_json_path}) # 使用示例 voc_to_coco( voc_annotations_dir./VOCdevkit/VOC2007/Annotations, images_dir./VOCdevkit/VOC2007/JPEGImages, output_json_path./annotations/train_coco.json )运行这个脚本你会得到一个标准的train_coco.json文件。用同样的方法生成验证集val_coco.json和测试集可选。最后你的数据目录结构应该像这样mmdetection_project/ ├── data/ │ └── my_dataset/ │ ├── train/ │ │ ├── image_001.jpg │ │ └── ... │ ├── val/ │ │ ├── image_100.jpg │ │ └── ... │ └── annotations/ │ ├── train_coco.json │ └── val_coco.json ├── mmdetection/ (框架代码) └── ...4. 配置文件模型训练的核心蓝图MMDetection采用模块化设计其强大和灵活之处很大程度上体现在配置Config系统上。所有关于模型结构、数据流水线、训练策略、运行设置的参数都集中在一个.py配置文件中。对于新手直接修改官方提供的配置文件是最快的方式。4.1 配置文件结构与继承机制MMDetection的配置文件使用一种“继承”机制这让你可以复用基础配置只修改需要变动的部分大大减少了代码冗余和出错概率。我们以训练一个Faster R-CNN模型为例。首先在mmdetection/configs目录下找到基础配置文件例如faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py。我们不直接修改这个文件而是创建一个新的配置文件比如在configs目录下新建my_configs/faster_rcnn_my_dataset.py。新配置文件的开头通常是这样的# 新配置文件my_configs/faster_rcnn_my_dataset.py # 继承基础配置 _base_ ../faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py # 接下来我们只需要覆盖或新增需要修改的配置项_base_指定了父配置文件。子配置文件会加载父文件的所有配置然后用自己的内容去覆盖父文件中同名的配置项。这是一种“差分更新”的思想。4.2 关键配置项修改详解我们需要修改以下几个核心部分1. 数据相关配置 (Data Pipeline):这是修改最多的地方。我们需要告诉框架数据在哪、是什么格式、如何读取和增强。# 修改数据集类型和路径 dataset_type CocoDataset # 我们使用的是COCO格式 classes (cat, dog, person) # 你的类别元组必须和COCO JSON中categories的顺序一致 data dict( # 每张GPU的图片数 (batch size)。根据你的GPU内存调整。如果内存不足就调小。 samples_per_gpu2, # 每个GPU的worker数用于数据加载。通常设为GPU数量的2-4倍。 workers_per_gpu2, # 训练数据配置 traindict( typedataset_type, # 关键指定你的COCO格式标注文件路径 ann_filedata/my_dataset/annotations/train_coco.json, # 关键指定图片文件的前缀路径 img_prefixdata/my_dataset/train/, # 指定我们自定义的类别覆盖基础配置中的默认COCO类别 classesclasses, # 数据增强流水线通常直接复用基础配置的除非你有特殊需求 # pipeline_base_.train_pipeline ), # 验证数据配置 valdict( typedataset_type, ann_filedata/my_dataset/annotations/val_coco.json, img_prefixdata/my_dataset/val/, classesclasses, # 验证集通常不需要数据增强 # pipeline_base_.test_pipeline ), # 测试数据配置可选 testdict( typedataset_type, ann_filedata/my_dataset/annotations/val_coco.json, # 可以用验证集做测试 img_prefixdata/my_dataset/val/, classesclasses, # pipeline_base_.test_pipeline ) )2. 模型配置 (Model):主要是修改检测头bbox_head中的类别数使其等于你的数据集类别数。Faster R-CNN的检测头是Shared2FCBBoxHead。model dict( # 修改RPN区域提议网络和ROI Head中的类别数 rpn_headdict( # anchor生成器通常不用改 ), roi_headdict( bbox_headdict( # 关键将num_classes修改为你的类别数例如3 num_classes3, ) ) )3. 训练策略配置 (Schedule):包括学习率、优化器、训练轮次epoch等。# 优化器配置通常使用SGD optimizer dict(typeSGD, lr0.02, momentum0.9, weight_decay0.0001) optimizer_config dict(grad_clipNone) # 梯度裁剪通常不需要 # 学习率调度器 lr_config dict( policystep, # 使用步进式下降 warmuplinear, # 使用线性学习率预热有助于训练初期稳定 warmup_iters500, # 预热迭代次数 warmup_ratio0.001, # 起始学习率为 base_lr * warmup_ratio step[8, 11]) # 在第8和第11个epoch时学习率乘以gamma默认0.1 # 总训练轮次 runner dict(typeEpochBasedRunner, max_epochs12) # 训练12个epoch # 日志打印间隔 log_config dict(interval50, hooks[dict(typeTextLoggerHook)])4. 运行时配置 (Runtime):工作目录、加载预训练模型、 checkpoint保存频率等。# 工作目录用于保存训练日志和模型权重 work_dir ./work_dirs/faster_rcnn_my_dataset # 从预训练模型加载权重。这是迁移学习的关键能极大加速收敛。 load_from checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth # 你可以从MMDetection官方Model Zoo下载对应的预训练模型 # https://github.com/open-mmlab/mmdetection/tree/v2.22.0/configs/faster_rcnn # 每隔多少个epoch保存一次模型权重 checkpoint_config dict(interval1)重要提示load_from加载的是包含主干网络如ResNet和检测头等全部权重的预训练模型。如果你的类别数和COCO80类不同框架会自动处理检测头最后一层权重不匹配的问题通常是随机初始化新增或减少的权重。这是MMDetection非常方便的一个特性。5. 启动训练与监控命令、日志与问题排查配置完成后就可以启动训练了。训练命令很简单但背后的监控和问题排查才是重点。5.1 单GPU与多GPU训练命令如果你的机器只有一张GPU使用以下命令python tools/train.py configs/my_configs/faster_rcnn_my_dataset.py如果你有多张GPU比如4张可以使用分布式训练来加速./tools/dist_train.sh configs/my_configs/faster_rcnn_my_dataset.py 4dist_train.sh脚本会自动处理分布式训练的启动。后面的数字4代表使用的GPU数量。5.2 训练过程监控与日志解读训练开始后控制台会输出大量日志。你需要学会看这些日志来监控训练状态和发现问题。2023-XX-XX 12:00:00,000 - mmdet - INFO - workflow: [(train, 1)], max: 12 epochs 2023-XX-XX 12:00:00,100 - mmdet - INFO - Checkpoints will be saved to /path/to/work_dirs/faster_rcnn_my_dataset by HardDiskBackend. ... [] 100/100, 2.2 task/s, elapsed: 45s, ETA: 0s ... Epoch [1][50/100] lr: 1.000e-02, eta: 1:30:00, time: 0.350, data_time: 0.010, memory: 3421, loss_rpn_cls: 0.1234, loss_rpn_bbox: 0.0456, loss_cls: 0.5678, loss_bbox: 0.2345, loss: 0.9713lr: 当前学习率。在warmup阶段会从很小的值线性增长到预设值。eta: 预计剩余训练时间。time: 一个batch的处理时间。data_time: 数据加载时间。如果这个时间很长可能是数据读取如从网络硬盘或数据增强太慢可以考虑增加workers_per_gpu或优化数据管道。memory: GPU显存占用MB。loss_xxx: 各项损失值。loss_rpn_cls/bbox是RPN网络的分类和回归损失loss_cls/bbox是ROI Head的分类和回归损失。loss是总损失。正常情况随着训练进行各项损失应该呈现总体下降趋势并逐渐趋于平稳。可能会有波动但大方向是下降。异常情况Loss为NaN这是最常见的问题之一。通常意味着学习率lr设置得太高导致梯度爆炸。解决方案立即停止训练将配置文件中的lr调小一个数量级例如从0.02调到0.002然后重新开始。也可以尝试在optimizer_config中启用梯度裁剪dict(grad_clipdict(max_norm35, norm_type2))。Loss不下降可能的原因有学习率太低数据标注有严重错误模型复杂度与任务不匹配如用大模型学太简单的任务可能欠拟合。解决方案检查数据标注尝试调高学习率或者换一个更简单的模型。分类损失loss_cls特别高而回归损失loss_bbox正常可能类别数num_classes设置错误或者预训练模型加载有问题。5.3 模型评估与权重保存训练过程中默认会根据evaluation配置在配置文件中通常继承自基础配置在验证集上定期评估。评估指标主要是COCO风格的mAP平均精度。你可以在日志中看到类似输出Epoch [12][100/100] ... Saving checkpoint at 12 epochs ... [] 100/100, 5.6 task/s, elapsed: 18s ... Average Precision (AP) [ IoU0.50:0.95 | area all | maxDets100 ] 0.356 Average Precision (AP) [ IoU0.50 | area all | maxDets100 ] 0.589 Average Precision (AP) [ IoU0.75 | area all | maxDets100 ] 0.381 ...AP [ IoU0.50:0.95 ]是主指标即在IoU阈值从0.5到0.95步长0.05上平均的AP值。这个值越高模型整体性能越好。AP50和AP75分别代表IoU阈值为0.5和0.75时的APAP50通常最高。训练完成后所有模型权重和训练日志都保存在work_dir我们之前设置的./work_dirs/faster_rcnn_my_dataset中。其中latest.pth: 最后一个epoch的权重。epoch_x.pth: 第x个epoch保存的权重根据checkpoint_config的间隔。*.log.json: 包含所有训练日志的JSON文件可以用TensorBoard等工具可视化。*.py: 训练时使用的配置文件的副本。通常我们选择在验证集上mAP最高的那个epoch的权重文件作为最终模型。6. 模型测试与推理验证训练成果训练结束后我们需要用训练好的模型在测试集或新图片上跑一下看看实际效果。6.1 使用测试脚本进行批量评估MMDetection提供了对测试集进行标准评估的脚本# 单GPU测试 python tools/test.py \ configs/my_configs/faster_rcnn_my_dataset.py \ work_dirs/faster_rcnn_my_dataset/epoch_12.pth \ --eval bbox # 评估边界框检测指标 # 多GPU测试 ./tools/dist_test.sh \ configs/my_configs/faster_rcnn_my_dataset.py \ work_dirs/faster_rcnn_my_dataset/epoch_12.pth \ 4 \ # GPU数量 --eval bbox--eval bbox指定评估目标检测的边界框指标。你也可以用--eval proposal来评估RPN阶段的提议质量。命令会输出详细的COCO评估指标。6.2 编写推理脚本进行单张图片预测更多时候我们想对单张图片或一个文件夹的图片进行可视化推理。MMDetection提供了高级APIinit_detector和inference_detector。下面是一个完整的推理脚本示例import mmcv from mmdet.apis import init_detector, inference_detector, show_result_pyplot import cv2 # 配置文件和训练好的模型权重路径 config_file configs/my_configs/faster_rcnn_my_dataset.py checkpoint_file work_dirs/faster_rcnn_my_dataset/epoch_12.pth # 初始化检测器 # devicecuda:0 表示使用第一块GPUcpu表示使用CPU model init_detector(config_file, checkpoint_file, devicecuda:0) # 测试单张图片 img_path test_image.jpg # 你的测试图片路径 result inference_detector(model, img_path) # 可视化结果并保存 # score_thr 是置信度阈值低于此阈值的结果不显示 vis_img show_result_pyplot(model, img_path, result, score_thr0.5) # 或者使用mmcv的imshow会弹出窗口 # mmcv.imshow(vis_img, result) # 保存可视化图片 cv2.imwrite(result.jpg, vis_img) # 如果你想获取结构化的预测结果 # result 是一个列表每个元素对应一个类别的检测结果数组Nx5格式为 [x1, y1, x2, y2, score] for class_id, dets in enumerate(result): if len(dets) 0: print(f类别 {class_id} ({classes[class_id]}) 检测到 {len(dets)} 个目标:) for det in dets: bbox det[:4].astype(int) # 整数边界框 score det[4] # 置信度 print(f 边界框: {bbox}, 置信度: {score:.4f})这个脚本会加载模型对图片进行预测并画出检测框。你可以调整score_thr来控制显示哪些检测结果。阈值设得太低会看到很多误检假阳性设得太高可能会漏掉一些不自信的正确检测假阴性。通常需要在验证集上统计不同阈值下的精确率Precision和召回率Recall来选择一个平衡点。6.3 常见推理问题与调优检测框太多、太杂乱这是置信度阈值score_thr设置过低导致的。尝试调高阈值比如从0.3调到0.5或0.7。漏检严重可能是阈值设得太高或者模型在该类别的表现不佳。可以调低阈值或者检查训练数据中该类别的样本是否足够标注是否准确。检测框位置不准回归损失loss_bbox可能没有充分收敛。可以尝试增加训练轮次epoch或者检查数据增强是否过于剧烈如过大的随机裁剪、缩放导致模型难以学习精确位置。推理速度慢Faster R-CNN是两阶段检测器速度相对较慢。如果对速度要求高可以考虑换用单阶段检测器如RetinaNet、YOLOv3MMDetection中也提供了实现或FCOS。在配置文件中可以通过设置model.test_cfg.rcnn.score_thr和model.test_cfg.rcnn.nms的iou_threshold来在测试阶段进行后处理优化但提升有限。7. 进阶调优与实战经验分享跑通第一个模型只是开始。要让模型在实际场景中表现良好还需要一系列的调优工作。这里分享几个我实践中觉得特别有用的点。7.1 数据增强的针对性调整默认配置文件中的数据增强流水线pipeline是针对通用场景如COCO设计的。对于你的特定数据集可能需要调整。例如小目标检测如果你的目标很小可以减弱随机裁剪RandomCrop的强度或者去掉可能把小目标裁掉的数据增强。光照变化大的场景可以加强色彩抖动ColorJitter、对比度调整等。数据量少需要更激进的数据增强来防止过拟合如MixUp、MosaicYOLO系列常用等。修改数据增强需要在配置文件的train_pipeline部分进行。例如增加随机亮度对比度调整# 在配置文件中修改 train_pipeline [ dict(typeLoadImageFromFile), dict(typeLoadAnnotations, with_bboxTrue), dict(typeResize, img_scale(1333, 800), keep_ratioTrue), dict(typeRandomFlip, flip_ratio0.5), # 新增随机亮度对比度 dict(typeColorJitter, brightness0.2, contrast0.2, saturation0.2, hue0.1), dict(typeNormalize, **img_norm_cfg), dict(typePad, size_divisor32), dict(typeDefaultFormatBundle), dict(typeCollect, keys[img, gt_bboxes, gt_labels]), ]7.2 学习率与优化器策略学习率是训练中最重要的超参数之一。如果损失曲线震荡很大或者收敛很慢首先考虑调整学习率。基础学习率lr规则对于batch size为N的情况常设lr 0.01 * N / 16当使用SGD时。因为我们之前设samples_per_gpu2如果用了4张GPU总batch size是8那么lr 0.01 * 8 / 16 0.005。这是一个经验起点。使用自动学习率查找器一种更科学的方法是进行一次学习率范围测试LR Range Test。虽然MMDetection没有内置但你可以手动进行用一个很小的学习率开始训练每个batch指数增加学习率绘制损失vs学习率的曲线。找到损失开始下降最快且稳定的那个学习率区间。优化器选择SGD with momentum是检测任务中的常青树通常能取得最好的精度。Adam系列优化器可能收敛更快但最终精度有时不如SGD。对于新任务可以都试试。7.3 模型选择与迁移学习技巧MMDetection Model Zoo里有很多预训练模型。如何选择精度优先Cascade R-CNN, HTC, Dynamic R-CNN。这些模型结构更复杂通常mAP更高但速度慢。速度优先YOLOv3, RetinaNet, FCOS。这些是单阶段检测器推理速度快适合实时应用。平衡型Faster R-CNN with FPN是一个很好的基准模型精度和速度比较均衡。迁移学习的关键使用预训练权重务必设置load_from。这能提供良好的底层特征提取能力。冻结骨干网络Backbone如果你的数据集很小比如几百张与预训练数据如ImageNet差异不大可以考虑在训练初期冻结骨干网络的前几层甚至全部只训练检测头RPN和ROI Head。这可以防止小数据过拟合并加速训练。在配置文件中可以这样设置# 在配置文件的custom_hooks部分添加 custom_hooks [dict(typeFreezeLayersHook, frozen_layers[backbone], )] # 或者更精细地控制先冻结训练若干epoch再解冻 custom_hooks [dict(typeFreezeLayersHook, frozen_layers[backbone], thaw_epoch5)]类别不平衡处理如果你的数据中“猫”的图片远多于“狗”模型会偏向于预测“猫”。可以在roi_head.bbox_head.loss_cls中设置class_weight来给少数类别更高的损失权重或者使用Focal LossRetinaNet默认使用来抑制简单负样本的影响。7.4 训练中断与恢复训练12个epoch可能需要几个小时甚至几天。如果训练中途因为断电或错误中断了怎么办MMDetection支持断点续训。假设你在第5个epoch时中断了work_dir里会保存epoch_5.pth和latest.pth。要从中断处继续训练只需在训练命令后加上--resume-from参数python tools/train.py configs/my_configs/faster_rcnn_my_dataset.py \ --resume-from work_dirs/faster_rcnn_my_dataset/latest.pth框架会自动加载模型权重、优化器状态和学习率调度器状态并从第6个epoch开始训练。这比从头开始训练节省了大量时间。整个过程走下来从环境搭建、数据准备、配置修改、训练监控到推理测试每一个环节都有需要注意的细节。MMDetection的强大在于其统一和模块化一旦掌握了这套流程你可以非常快速地在不同的检测模型Faster R-CNN, YOLOv3, RetinaNet...和不同的数据集之间切换实验。最开始可能会觉得配置文件复杂但熟悉之后你会发现通过修改一个配置文件就能控制整个实验效率非常高。