ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MMDetection目标检测实战:从环境搭建到模型部署全流程

MMDetection目标检测实战:从环境搭建到模型部署全流程

1. 项目缘起与整体设计思路

目标检测这个方向,我从几年前开始断断续续地做,踩过的坑不算少。早期用原生深度学习框架手写检测网络,光是数据加载和锚框生成就能耗掉一整天,更别提后面还要自己实现各种数据增强、学习率调度、分布式训练。后来接触到MMDetection这个开源工具箱,第一感觉是“终于有人把脏活累活都干了”。它把目标检测拆成了几个高度解耦的模块——骨干网络、颈部、检测头、数据流水线、训练调度——每个模块都可以独立替换,配置文件一改就能跑通一套新实验。这篇文章我想围绕“MMDetection目标检测实例”这个主题,把从环境搭建到模型训练、再到推理部署的完整链路讲清楚,同时把那些官方文档里不会写、但实际跑起来一定会遇到的细节问题一并交代。

先说清楚这个内容适合谁看。如果你刚接触目标检测,想找一个能快速跑通、又能深入定制的框架,那MMDetection是绕不开的选择;如果你已经用过其他检测框架,但被配置文件体系搞得一头雾水,这篇文章会帮你把配置的层级关系和继承逻辑理顺;如果你正在做实际项目,需要把检测模型落地到具体场景,那后面关于数据格式转换、训练调参和推理加速的部分应该对你有直接帮助。整篇内容我会尽量用从业者之间交流的口吻来写,不堆砌公式,重点放在“为什么这么做”和“实际怎么做”上。

MMDetection的核心设计哲学是“配置驱动”。你几乎不需要写Python训练脚本,所有实验设置都通过一个或多个配置文件来描述。这种设计的好处是实验可复现性极强——同一个配置文件在任何机器上跑出来的结果应该是一致的(前提是随机种子固定、硬件环境相近)。但代价是配置文件体系有一定学习成本,尤其是当配置继承层级变多之后,追踪一个参数最终生效的值需要一点耐心。我个人的经验是,先把单文件配置跑通,再逐步引入继承和模块化,不要一上来就搞复杂的多级继承,那样出了问题很难定位。

从整体架构来看,MMDetection把检测任务拆成了几个关键组件。骨干网络负责从输入图像中提取多尺度特征图,常用的有ResNet、Swin Transformer等;颈部网络负责对特征图进行融合和增强,比如FPN、PAFPK;检测头则负责在特征图上预测类别和边界框,分为单阶段和双阶段两大类。数据流水线负责从原始标注文件读取数据,经过一系列增强变换后送入网络。训练调度器管理学习率、优化器和训练轮次。这套模块化设计让替换组件变得非常方便,比如你想把ResNet换成Swin Transformer,只需要改配置里的骨干网络类型和预训练权重路径,其他部分基本不用动。

我选择用MMDetection来做目标检测实例,还有一个很实际的原因:它的模型库非常全。从经典的Faster R-CNN、YOLO系列,到较新的DETR、DINO、RTMDet,几乎主流检测算法都有官方实现和预训练权重。这意味着你可以直接拿一个在COCO上预训练好的模型,在自己的数据集上微调,往往用几百张图就能得到一个可用的检测器。对于工业场景下样本量有限的情况,这个特性非常关键。另外,MMDetection的推理工具链也比较完善,训练完的模型可以方便地导出成ONNX或其他格式,方便后续部署。

2. 环境搭建与依赖管理实操

2.1 硬件与基础软件选型

环境搭建这一步看似简单,但实际是最容易出问题的地方。我见过太多人卡在版本不兼容上,折腾一两天都跑不起来。先说硬件,目标检测对显存的需求比图像分类大不少。以COCO数据集、输入尺寸1333×800为例,Faster R-CNN在训练时大概需要8GB以上显存,如果用小批量或者更小的输入尺寸,6GB也能勉强跑。如果你用的是消费级显卡,建议至少8GB显存起步,不然很多模型只能看不能跑。当然,如果只是做推理,显存需求会小很多,4GB左右就能跑大部分模型。

基础软件方面,我强烈建议用Linux环境来做训练,Windows下虽然也能跑,但分布式训练和一些自定义算子的编译会麻烦很多。Python版本建议3.8到3.10之间,太新的版本有些依赖包还没跟上。CUDA版本要和你的显卡驱动匹配,这个不用追求最新,稳定就好。我个人的习惯是用conda创建一个独立环境,避免和系统Python混在一起。创建环境的命令很简单:

conda create -n mmdet python=3.9 -y conda activate mmdet

接下来是PyTorch的安装。这里有个关键点:PyTorch版本、CUDA版本和MMDetection版本三者必须匹配。MMDetection的官方文档里有一张兼容性表格,建议在动手之前先查一下。以我最近一次搭建为例,用的是PyTorch 2.0 + CUDA 11.8 + MMDetection 3.x系列,整体比较稳定。安装PyTorch的命令根据CUDA版本不同会有差异,建议直接去PyTorch官网查对应的安装命令,不要凭记忆写。

2.2 MMDetection及其依赖的安装

MMDetection的安装方式有几种,我推荐用MIM工具来装,这是官方维护的包管理工具,能自动处理依赖关系。先安装MIM:

pip install -U openmim mim install mmengine mim install "mmcv>=2.0.0"

这里要注意,MMCV是MMDetection的核心依赖,它包含了很多计算机视觉相关的底层算子。MMCV的版本必须和MMDetection版本匹配,否则会出现各种奇怪的错误。用MIM安装的好处是它会自动选择兼容的版本。装完MMCV之后,再安装MMDetection本身:

mim install mmdet

如果你想用最新的开发版功能,也可以从源码安装:

git clone https://github.com/open-mmlab/mmdetection.git cd mmdetection pip install -v -e .

从源码安装的好处是你可以直接修改框架代码来调试,但缺点是每次更新都要重新编译。对于大多数使用者来说,用MIM安装就足够了。

安装完成后,一定要验证一下是否成功。可以跑一个简单的Python脚本来检查:

import mmdet print(mmdet.__version__) from mmdet.apis import init_detector, inference_detector print("MMDetection imported successfully")

如果这一步报错,大概率是MMCV版本不匹配或者CUDA环境有问题。我遇到最多的情况是MMCV编译时用的CUDA版本和当前环境不一致,解决办法是卸载MMCV重新用MIM安装,让它自动匹配当前环境的CUDA版本。

提示:如果你在服务器上有多张显卡,建议在安装前先设置好CUDA_VISIBLE_DEVICES环境变量,避免安装过程中用到错误的显卡。

2.3 验证环境是否可用

环境装好之后,别急着上自己的数据,先用官方提供的小demo验证一下整个链路是否通畅。MMDetection的代码仓库里有一个demo脚本,可以下载一张示例图片,用预训练的Faster R-CNN模型做推理,然后把结果可视化出来。这个脚本会用到模型下载功能,第一次运行时会自动从官方服务器下载预训练权重,文件大概几百兆,需要一点时间。

跑通这个demo的意义在于:它验证了从模型加载、图像预处理、前向推理到结果可视化的完整流程。如果这一步能出图,说明你的环境基本没问题,后面遇到问题就可以排除环境因素,专注于数据和配置。我见过不少人跳过这一步,直接上自己的数据集,结果出了问题不知道是环境问题还是数据问题,排查起来非常痛苦。

验证的时候可以留意一下推理速度。在单张显卡上,Faster R-CNN处理一张图片大概需要0.1到0.3秒,具体取决于输入尺寸和显卡性能。如果你发现推理速度异常慢,比如好几秒一张,那可能是没有用上GPU,或者模型被放在了CPU上。可以在代码里加一行model.cfg.device来确认模型实际运行的设备。

3. 数据准备与格式转换的核心细节

3.1 目标检测数据集的常见格式

目标检测的数据标注格式有好几种,常见的有COCO格式、VOC格式、YOLO格式,以及一些标注工具自己导出的格式。MMDetection原生支持COCO格式和VOC格式,其中COCO格式是最推荐的,因为它对类别不平衡、小目标等情况的处理更完善,而且MMDetection的很多高级功能(比如类别平衡采样)都是基于COCO格式设计的。

COCO格式的标注文件是一个JSON文件,里面包含了图像信息、标注信息、类别信息三大部分。图像信息记录了每张图的文件名、宽高、ID;标注信息记录了每个边界框的坐标、类别ID、所属图像ID;类别信息则是一个类别ID到类别名称的映射。这个结构看起来简单,但实际转换时容易出问题的地方不少。比如坐标格式,COCO用的是左上角坐标加宽高,而有些标注工具导出的是左上角和右下角坐标,转换时需要做一次计算。再比如类别ID,COCO格式要求从1开始连续编号,0通常保留给背景类,如果你的类别ID不连续,训练时可能会出现类别索引越界的问题。

VOC格式则是每张图对应一个XML文件,里面用<object>标签记录每个目标的信息。VOC格式的好处是直观易读,但缺点是文件数量多,管理起来不如单个JSON文件方便。如果你手头的数据是VOC格式,MMDetection也支持直接读取,但需要在配置里指定数据集类型为VOCDataset,并且把标注文件按类别整理好。

3.2 从原始标注到COCO格式的转换

实际项目中,我们拿到的标注数据往往不是标准格式。可能是用某个标注工具导出的CSV,也可能是自己写的标注脚本生成的JSON。这时候就需要写一个转换脚本,把原始标注转成COCO格式。这个脚本的核心逻辑其实不复杂:遍历所有标注记录,按图像分组,为每张图分配一个唯一的图像ID,为每个标注分配一个唯一的标注ID,然后按照COCO的JSON结构组织数据。

我写转换脚本的时候有几个习惯。第一,图像ID和标注ID都用整数,并且从1开始连续编号,避免出现奇怪的ID导致后续处理出错。第二,类别名称到类别ID的映射单独维护一个字典,转换时统一查表,不要在每个标注里硬编码类别ID。第三,转换完成后一定要做一次校验,统计一下每类的标注数量、每张图的标注数量分布,看看有没有异常。我遇到过标注文件里混入了空标注的情况,就是某个目标没有任何边界框信息,这种脏数据如果不提前清理,训练时可能会报错或者导致模型学到错误的东西。

转换脚本写完之后,建议先用一个小规模子集跑一遍,确认生成的JSON文件结构正确,再用全量数据。校验的时候可以用Python的json库加载文件,检查几个关键字段是否存在、类型是否正确。比如images列表里每个元素应该有id、file_name、width、height;annotations列表里每个元素应该有id、image_id、category_id、bbox、area、iscrowd。其中area是边界框面积,iscrowd表示是否是密集区域,这两个字段在训练时会被用到,不能省略。

3.3 数据增强策略的选择与配置

数据增强是目标检测训练中非常重要的一环,尤其是当训练数据有限的时候。MMDetection内置了丰富的数据增强变换,从基础的随机翻转、随机裁剪,到高级的Mosaic、MixUp、CopyPaste,基本覆盖了主流方法。但增强策略不是越多越好,用错了反而会降低模型性能。

我的一般原则是:先分析数据特点,再选择增强方式。如果数据里目标尺寸普遍偏小,那随机缩放和Mosaic增强会比较有效,因为它们能增加小目标在训练中出现的频率。如果数据里目标分布比较集中,那随机裁剪可以帮助模型学习在不同位置检测目标。如果数据里存在类别不平衡,那可以尝试CopyPaste增强,把稀有类别的目标复制粘贴到其他图像中,增加稀有类别的样本量。

配置增强策略的时候,要注意变换的顺序。一般来说,几何变换(缩放、裁剪、翻转)应该放在颜色变换(亮度、对比度调整)之前,因为几何变换会改变像素的空间位置,先做几何变换再做颜色变换更符合直觉。另外,一些增强方式之间有冲突,比如Mosaic和随机裁剪同时用可能会导致目标被过度切割,反而影响训练。我通常会在配置文件里把增强策略分成几组,每组单独测试效果,最后再组合起来。

注意:数据增强只在训练阶段启用,验证和测试阶段必须关闭所有随机增强,只保留必要的预处理(如归一化、尺寸调整)。这一点在配置里通过train_pipeline、val_pipeline、test_pipeline三个不同的流水线来区分。

4. 配置文件体系与模型训练全流程

4.1 配置文件的结构与继承机制

MMDetection的配置文件体系是整个框架最核心也最容易让人困惑的部分。一个完整的配置通常由多个文件组成,通过_base_字段实现继承。基础配置里定义了模型结构、数据集、训练调度等通用设置,子配置只需要覆盖需要修改的部分。这种设计的好处是复用性高,比如你想把Faster R-CNN的骨干网络从ResNet50换成ResNet101,只需要在子配置里改一行model.backbone.depth=101,其他部分自动继承。

但继承也带来了一个问题:当配置层级变多时,追踪一个参数最终生效的值会变得困难。我的经验是,在调试配置时,用MMDetection提供的配置打印工具把最终合并后的配置输出出来,看看每个参数实际是什么值。这个工具在tools/misc/print_config.py里,运行后会生成一个完整的配置文件,所有继承和覆盖都已经合并好了。对于复杂的配置,我建议在修改任何参数之前先打印一遍,心里有数再动手。

配置文件的组织方式也有讲究。我通常会把配置分成几个层次:最底层是数据集配置,定义数据路径、类别数、流水线;中间层是模型配置,定义骨干网络、颈部、检测头;最上层是运行时配置,定义优化器、学习率、训练轮次。这样分层之后,换数据集只需要改底层,换模型只需要改中间层,运行时配置基本不动。这种组织方式在同时跑多个实验的时候特别有用,可以避免配置之间的相互干扰。

4.2 模型选择与骨干网络替换

MMDetection支持的模型非常多,从经典的两阶段检测器到最新的基于Transformer的检测器都有。选择哪个模型,主要看你的应用场景和计算资源。如果追求精度且不在乎速度,Faster R-CNN系列和Cascade R-CNN系列是比较稳妥的选择;如果追求速度且精度要求不是极致,YOLO系列和RTMDet系列更合适;如果数据量很大且希望模型有更强的泛化能力,可以尝试基于Transformer的DETR系列。

骨干网络的选择同样重要。ResNet系列是最常用的,稳定且预训练权重丰富。Swin Transformer在精度上通常优于ResNet,但计算量更大,训练时需要更多显存。如果你用的是比较新的MMDetection版本,还可以尝试ConvNeXt、EfficientNet等骨干网络。替换骨干网络的时候要注意,不同骨干网络输出的特征图通道数和步长可能不同,颈部和检测头的输入通道数需要相应调整。MMDetection的配置继承机制可以自动处理一部分通道数匹配,但有些情况下还是需要手动指定。

我个人的经验是,如果是在COCO这样的大数据集上训练,骨干网络的差异会比较明显,Swin Transformer通常能比ResNet高出几个点。但如果是在小数据集上微调,骨干网络的差异就没那么大了,这时候更重要的是数据质量和增强策略。另外,预训练权重的加载也很关键,用ImageNet预训练的骨干网络初始化,通常比随机初始化收敛快很多,尤其是在小数据集上。

4.3 训练参数设置与学习率调度

训练参数里最重要的几个是学习率、批量大小和训练轮次。学习率的设置和批量大小强相关,一般来说批量越大,学习率可以设得越大。MMDetection的默认配置里,批量大小通常是16(8张显卡每张2张图),学习率是0.02。如果你只有一张显卡,批量大小可能只能设到2或4,这时候学习率要相应调小,否则训练容易发散。一个经验公式是:学习率与批量大小成正比,批量缩小4倍,学习率也缩小4倍。

学习率调度策略也很关键。MMDetection默认用的是阶梯下降,在指定的轮次把学习率乘以一个衰减系数。这种策略简单有效,但在训练后期学习率可能降得太低,导致模型无法进一步优化。另一种常用的策略是余弦退火,学习率按余弦曲线平滑下降,训练后期还能保持一定的学习率,有助于跳出局部最优。我通常会在训练轮次较多的时候用余弦退火,轮次较少的时候用阶梯下降。

训练轮次要根据数据集大小和模型复杂度来定。COCO数据集上,Faster R-CNN通常训练12到24个epoch就能收敛。如果是在自己的小数据集上微调,可能5到10个epoch就够了。判断是否收敛的一个简单方法是看验证集上的损失曲线,如果连续几个epoch验证损失不再下降,甚至开始上升,那大概率是过拟合了,应该停止训练或者增加正则化。我习惯在训练时开启验证集评估,每个epoch结束后自动计算mAP,这样能直观地看到模型性能的变化。

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

训练启动之后,监控训练过程是必不可少的。MMDetection默认会把训练日志输出到终端和日志文件里,日志里包含了损失值、学习率、数据加载时间等信息。损失值是最直观的指标,但要注意区分不同损失项的含义。目标检测的损失通常由分类损失和回归损失两部分组成,分类损失反映模型对类别的判断能力,回归损失反映模型对边界框位置的预测精度。如果分类损失下降但回归损失不降,可能是边界框的编码方式或者回归损失函数需要调整。

除了损失值,还要关注学习率的变化。如果学习率在训练过程中突然变得很小,可能是调度器配置有问题。另外,数据加载时间也是一个容易被忽视的指标。如果数据加载时间远大于模型前向传播时间,说明数据流水线是瓶颈,可以考虑增加数据加载的进程数或者优化增强操作。我遇到过因为数据增强里用了太复杂的变换,导致GPU利用率只有30%的情况,后来简化了增强策略,GPU利用率直接上去了,训练速度也快了不少。

日志里还会输出显存占用情况。如果显存占用接近显卡上限,训练可能会因为显存不足而中断。这时候可以尝试减小批量大小、降低输入尺寸、或者使用梯度累积来模拟更大的批量。梯度累积的原理是多次前向传播后再统一更新参数,这样可以在显存有限的情况下达到和更大批量类似的效果。MMDetection的配置里可以通过optim_wrapper的accumulative_counts参数来设置梯度累积步数。

5. 推理部署与常见问题排查

5.1 模型推理与结果可视化

训练完成之后,下一步就是用训练好的模型做推理。MMDetection提供了简洁的推理接口,加载模型和配置文件后,直接调用inference_detector函数就能得到检测结果。推理结果是一个列表,每个元素对应一个类别,包含了该类别的所有检测框和置信度。可视化的时候,可以用MMDetection内置的可视化工具,把检测框画在图像上,同时显示类别标签和置信度。

推理阶段有几个参数需要关注。一个是置信度阈值,低于这个阈值的检测框会被过滤掉。阈值设得太低会引入大量误检,设得太高会漏掉一些真实目标。我通常会在验证集上画一下不同阈值下的精度-召回曲线,找一个平衡点。另一个是NMS的IoU阈值,用来去除重叠的检测框。这个阈值设得太低会过度抑制,导致相邻目标被误删;设得太高会保留太多重叠框。默认的0.5到0.7之间通常比较合适,具体要看目标的密集程度。

可视化的时候,我习惯把原始图像和检测结果并排显示,方便对比。如果检测结果不理想,可以逐张图分析是漏检还是误检。漏检通常是因为目标太小、太暗、或者被遮挡;误检通常是因为背景纹理和目标相似,或者置信度阈值设得太低。针对不同的问题,后续的优化方向也不同。漏检多的话可以考虑增加数据增强、调整锚框尺寸、或者换一个对小目标更友好的模型;误检多的话可以考虑增加负样本、调整损失函数权重、或者提高置信度阈值。

5.2 常见报错与排查思路

跑MMDetection的过程中,报错是家常便饭。我把常见的报错分成了几类,每一类都有对应的排查思路。第一类是环境相关的报错,比如ImportError、ModuleNotFoundError,通常是依赖包版本不匹配或者没有安装。排查方法是检查MMCV、MMEngine、PyTorch的版本是否兼容,可以用pip list查看已安装的版本,对照官方文档的兼容性表格。

第二类是数据相关的报错,比如KeyError、IndexError,通常是标注文件格式不对或者类别ID不连续。排查方法是加载标注文件,检查关键字段是否存在、类别ID是否从1开始连续编号、图像路径是否正确。我遇到过一个很隐蔽的问题:标注文件里的图像文件名带了路径前缀,但实际图像文件在另一个目录下,导致数据加载时找不到文件。这种问题看报错信息往往不明显,需要实际去检查文件路径。

第三类是显存相关的报错,比如CUDA out of memory。这个最直接的解决办法是减小批量大小或输入尺寸。如果减小之后还是不够,可以尝试用混合精度训练,把部分计算从FP32转到FP16,能省不少显存。MMDetection的配置里可以通过optim_wrapper的type设置为AmpOptimWrapper来开启混合精度。另外,推理阶段可以用torch.no_grad()上下文管理器来关闭梯度计算,也能省显存。

第四类是训练不收敛的问题,损失值一直不下降或者震荡。这种情况通常是学习率设得太大、数据增强太激进、或者模型初始化有问题。排查方法是先把学习率调小一个数量级,关掉所有数据增强,用最简单的配置跑一遍,看看能不能收敛。如果能收敛,再逐步加回增强和学习率,找到出问题的环节。

5.3 模型导出与部署注意事项

训练好的模型最终是要部署到实际环境中的,MMDetection支持把模型导出成ONNX格式,方便后续用推理引擎加速。导出的时候要注意,有些自定义算子可能不被ONNX支持,需要替换成标准算子。另外,导出后的模型输入输出格式可能和训练时不同,需要仔细核对。我通常会在导出后用一个简单的Python脚本加载ONNX模型,跑一张测试图,对比导出前后的输出是否一致。

部署的时候,推理速度是一个关键指标。如果是在服务器上部署,可以用TensorRT对ONNX模型做进一步优化,通常能获得几倍的加速。如果是在边缘设备上部署,可能需要把模型量化成INT8,牺牲一点精度换取更快的速度。量化的过程中要注意校准数据的代表性,校准数据分布和实际推理数据差异太大会导致精度下降明显。

还有一个容易被忽视的问题是预处理和后处理的一致性。训练时的图像预处理(归一化参数、输入尺寸)必须和推理时保持一致,否则模型性能会下降。后处理里的NMS阈值、置信度阈值也要和验证时保持一致。我见过有人训练时用了一个预处理参数,推理时忘了改,结果mAP掉了十几个点,排查了半天才发现是预处理不一致。

6. 实操心得与避坑经验

6.1 数据质量比模型选择更重要

这句话听起来像老生常谈,但实际做项目的时候,很多人还是会把大量时间花在调模型上,而忽视了数据质量。我自己的经验是,在一个标注质量高的数据集上,用一个中等复杂度的模型,效果往往比在一个标注质量差的数据集上用最先进的模型要好。标注质量包括边界框的精确度、类别标签的准确性、以及标注的一致性。如果同一个目标在不同图像里的标注标准不一致,模型很难学到稳定的特征。

检查数据质量的一个实用方法是随机抽取几十张图,把标注框画出来,肉眼检查一遍。看看有没有漏标、错标、边界框明显偏移的情况。如果发现问题,及时修正。另外,可以统计一下每个类别的样本数量,如果某些类别样本极少,考虑做数据增强或者调整损失函数的类别权重。我遇到过一个项目,某个类别的样本只有十几张,模型对这个类别的检测效果一直很差,后来用CopyPaste增强把样本量扩到了几百张,效果明显改善。

6.2 从小规模实验开始逐步放大

新手容易犯的一个错误是一上来就用全量数据、最大模型、最长训练轮次跑实验,结果跑了一天发现配置有问题,白白浪费时间和算力。我的习惯是先在小规模子集上做快速实验,比如从训练集里抽100张图,用一个小模型跑几个epoch,确认整个流程通畅、损失能下降、验证集能出结果。这个过程可能只需要十几分钟,但能帮你排除大部分配置错误。

小规模实验通过之后,再逐步放大到全量数据。放大的过程中,批量大小和学习率要同步调整,数据增强策略也可以逐步加入。我通常会把实验分成几个阶段:第一阶段只做基础预处理,不加任何随机增强;第二阶段加入几何变换;第三阶段加入颜色变换和高级增强。每个阶段都验证一下性能变化,这样能清楚地知道每种增强方式带来的收益。

6.3 版本兼容性是最大的坑

MMDetection的版本更新比较快,不同版本之间的API和配置格式可能有变化。我强烈建议在项目开始时就锁定版本,不要随意升级。如果必须升级,先在一个独立环境里测试,确认所有功能正常后再迁移。版本兼容性问题最常出现在MMCV和MMDetection之间,以及PyTorch和CUDA之间。我的做法是在项目目录下放一个requirements.txt文件,记录所有依赖包的精确版本号,这样换机器或者重装环境时可以直接复现。

另外,MMDetection的配置文件格式在不同大版本之间有过变化,比如从2.x升级到3.x时,配置文件的字段名和结构都有调整。如果你在网上找到的教程是基于旧版本的,直接套用到新版本上可能会报错。这时候最好的办法是看官方文档的迁移指南,或者直接参考新版本代码仓库里的示例配置。我一般会以官方示例配置为模板,在上面做修改,而不是从零开始写配置,这样能避免很多格式上的问题。

6.4 训练日志要定期备份

训练一个模型动辄几个小时甚至几天,如果中途因为断电、死机或者误操作导致训练中断,没有备份的话就得从头再来。MMDetection默认会把日志和模型权重保存在工作目录下,我建议定期把日志文件和最新的模型权重备份到另一个位置。另外,可以配置训练过程定期保存检查点,这样即使中断了也能从最近的检查点恢复训练。恢复训练的时候要注意,学习率调度器的状态也需要恢复,否则学习率会从头开始,影响训练效果。

还有一个实用技巧是在训练脚本里加一个自动备份的逻辑,每隔几个epoch就把最新的检查点复制到一个备份目录。这个逻辑可以用Python的shutil库实现,几行代码就能搞定。虽然看起来有点笨,但关键时刻能省下大量重跑的时间。我吃过一次亏,训练到第20个epoch时服务器突然重启,之前只保存了第10个epoch的检查点,结果白白损失了10个epoch的训练量。

6.5 推理速度优化的一些手段

如果模型需要部署到实际业务中,推理速度往往和精度一样重要。除了前面提到的模型导出和量化,还有一些工程上的优化手段。比如把输入图像的尺寸调整到模型支持的最小尺寸,很多模型对输入尺寸有下限要求,但在这个下限之上,尺寸越小推理越快。另外,可以尝试把模型的某些层融合在一起,减少计算量。MMDetection的部署工具链里有一些自动优化工具,可以尝试使用。

还有一个容易被忽视的点是批处理。如果业务场景允许一次处理多张图,把多张图组成一个批次一起推理,通常比逐张推理效率高很多。但批处理会增加显存占用,需要根据实际硬件情况调整批次大小。我通常会在推理脚本里加一个动态批次调整的逻辑,根据当前显存占用自动选择批次大小,这样既能充分利用硬件,又不会因为显存不足而崩溃。

7. 从实例到产品的扩展思路

跑通一个MMDetection目标检测实例只是起点,真正把检测能力落地到产品里,还有很多工作要做。一个常见的扩展方向是增加跟踪功能,在检测的基础上对目标进行跨帧关联,实现视频中的目标跟踪。MMDetection本身不包含跟踪功能,但可以和MMTracking等工具结合使用。另一个方向是增加实例分割,不仅输出边界框,还输出每个目标的像素级掩码,这对需要精细分割的场景很有用。

如果业务场景对实时性要求很高,可以考虑把检测模型和轻量级分类模型结合,先用检测模型定位目标,再用分类模型对目标做细分类。这种两阶段方案在精度和速度之间能取得较好的平衡。另外,如果数据标注成本很高,可以尝试半监督学习或者主动学习,用少量标注数据加上大量未标注数据来训练模型,降低标注成本。

从工程角度看,把训练好的模型集成到现有系统里,需要考虑接口设计、并发处理、异常处理等问题。我通常会把模型封装成一个独立的服务,通过HTTP或gRPC接口对外提供检测能力,这样业务系统不需要关心模型的具体实现,只需要调用接口即可。服务化之后,模型的更新和扩容也变得更灵活,可以在不影响业务系统的情况下升级模型版本。

最后再分享一个小技巧:在项目初期就建立一套评估流程,每次模型更新后自动在固定的测试集上评估性能,记录mAP、推理速度等指标。这样能清晰地看到每次改动的效果,避免凭感觉判断模型好坏。评估流程可以用脚本自动化,每次训练完成后自动触发,结果保存到数据库或者表格里,方便后续对比分析。这个习惯看起来简单,但长期坚持下来,能帮你省下大量重复劳动,也能让模型迭代更有方向感。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进