mmdetection 港中文媒体实验室开源的检测工具箱和评估基准

mmdetection商汤开源的用于深度学习目标检测的库, 相比于早先开源的Detectronmaskrcnn-benchmark 和 SimpleDet具有以下特性:

  1. 模块化设计,将检测或者分割任务分解成几个模块,通过模块的组合即可完成相应的任务
  2. 开箱即用,实现了多种目标检测和分割算法,易于配置和使用
  3. 高效 所有对包围框和掩码的操作都可以在GPU上完成
  4. 领先性, 获得过2018年COCO检测比赛的冠军,并且还在不断进化

如果不熟悉检测的原理,可以参看深入理解one-stage目标检测算法,视频教程参看目标检测7日打卡营

  1. 不得不知的 MMDetection 学习路线
  2. 轻松掌握 MMDetection 中常用算法(一):RetinaNet 及配置详解
  3. mmdetection之模型注册
  4. mmclassification项目阅读系列文章 mmclassification源码阅读(三) registry类注册机制

安装

首先这个库是依赖pytorch的它有多个分支,master分支需要1.5以上,  旧的1.*版支持pytorch1.1-1.4

2020年5月6日发布了2.*版,提升训练速度高达25%以上,但是和之前的并不兼容,以前的模型需要重新训练或者转换

首先安装pytorch, ubuntu16上使用pip安装即可:

pip3 install torch torchvision

然后克隆代码安装 

git clone https://github.com/open-mmlab/mmdetection.git
cd mmdetection
pip install -r requirements/build.txt
pip install "git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI"
pip install -v -e .  # or "python setup.py develop"

Model Zoo提供了上百个基于已有数据训练的模型,并且支持诸如VOC、COCO、CityScapes和LVIS等标准数据集自己训练, 这里提供基于训好模型推理、测试模型精度和训练自己模型等三种使用方法.

1. 基于训好模型推理

李模型是通过*.py文件配置的,参数保存在checkpoint里, 如果你是初学者,我们推荐使用 Faster RCNN上手,它的配置文件是 configuration file,参数为 checkpoint file (将其下载并保存治安checkpoints文件夹里, 没有的话自己新建一个, git配置里默认忽略这个文件夹里面的内容防止仓库无限扩张).

from mmdet.apis import init_detector, inference_detector
import mmcv

# Specify the path to model config and checkpoint file
config_file = 'configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py'
checkpoint_file = 'checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'

# build the model from a config file and a checkpoint file
model = init_detector(config_file, checkpoint_file, device='cuda:0')

# test a single image and show the results
img = 'test.jpg'  # or img = mmcv.imread(img), which will only load it once
result = inference_detector(model, img)
# visualize the results in a new window
model.show_result(img, result)
# or save the visualization results to image files
model.show_result(img, result, out_file='result.jpg')

# test a video and show the results
video = mmcv.VideoReader('video.mp4')
for frame in video:
    result = inference_detector(model, frame)
    model.show_result(frame, result, wait_time=1)

为了尽可能减少你写代码,here提供了一些脚本

基于图片推理

python demo/image_demo.py ${IMAGE_FILE} ${CONFIG_FILE} \${CHECKPOINT_FILE} \
    [--device ${GPU_ID}] [--score-thr ${SCORE_THR}]
python demo/image_demo.py demo/demo.jpg configs/faster_rcnn_r50_fpn_1x_coco.py \
    checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth --device cpu

基于摄像头实时推理

python demo/webcam_demo.py ${CONFIG_FILE} \${CHECKPOINT_FILE} \
    [--device ${GPU_ID}] [--camera-id ${CAMERA-ID}] [--score-thr ${SCORE_THR}]
python demo/webcam_demo.py configs/faster_rcnn_r50_fpn_1x_coco.py \
    checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth

数据准备

在coco数据及上训练的话需要下载coco数据集,解压后新建一个data文件夹,并用软连接指向它,解压前总计大小为26.8G

如果需要转换数据

pip install cityscapesscripts
python tools/convert_datasets/cityscapes.py ./data/cityscapes --nproc 8 --out_dir ./data/cityscapes/annotations

目录结构为

mmdetection
├── mmdet
├── tools
├── configs
├── data
│   ├── coco
│   │   ├── annotations
│   │   ├── train2017
│   │   ├── val2017
│   │   ├── test2017
│   ├── cityscapes
│   │   ├── annotations
│   │   ├── leftImg8bit
│   │   │   ├── train
│   │   │   ├── val
│   │   ├── gtFine
│   │   │   ├── train
│   │   │   ├── val
│   ├── VOCdevkit
│   │   ├── VOC2007
│   │   ├── VOC2012

基于训好模型测试其精度,基本的调用为

python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}] [--show]

# multi-gpu testing
bash tools/dist_test.sh ${CONFIG_FILE} ${CHECKPOINT_FILE} ${GPU_NUM} [--out ${RESULT_FILE}] [--eval ${EVAL_METRICS}]
  • 其中CONFIG_FILE是配置文件,CHECKPOINT_FILE是参数文件,RESULT_FILE是保存的结果文件,如果没有指定就不会保存结果
  • EVAL_METRICS是评估的标准,依赖于数据集,COCO使用的是proposal_fastproposalbboxsegm等,而PASCAL VOC使用的是mAPrecall
  • --show 如果指定的话,会新开一个窗口并且把结果绘制上去, 只在单GPU测试和调试时起作用,请确保你的机器上有GUI环境,不然会报cannot connect to X server的错误
  • --show-dir 在那些没有GUI环境的机器上可以将结果绘制到指定文件夹下
  • --show-score-thr 滤除低于这个阈值的检测结果

示例,假设已经下载参数文件到checkpoints文件里了.

测试Faster RCNN并可视化结果, 参数和配置在这里可以找到.

python tools/test.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py \
    checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth --show

将结果保存的话是

python tools/test.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x.py  checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \
    --show-dir faster_rcnn_r50_fpn_1x_results

在VOC数据集测试mAP是

python tools/test.py \configs/pascal_voc/faster_rcnn_r50_fpn_1x_voc.py \
    checkpoints/faster_rcnn_r50_fpn_1x_voc0712_20200624-c9895d40.pth --eval mAP

在标准数据集上训练

非常重要: 默认配置学习率是8卡,每卡2张图片设置的,根据线性缩放原则,如果你卡数不同或者每卡图片不同的话需要适当调整. 也就是说4卡 每卡2张时lr为0.01的话,16卡 每卡4张就应该改成0.08(0.01*4*2)

单GPU训练

python tools/train.py  ${CONFIG_FILE} [optional arguments]

多GPU训练

bash ./tools/dist_train.sh ${CONFIG_FILE} ${GPU_NUM} [optional arguments]

自动获取所有可用显卡个数的话

python3 tools/train.py configs/pascal_voc/ssd300_voc.py `nvidia-smi -L | wc -l`
python3 tools/test.py configs/pascal_voc/ssd300_voc.py checkpoints/ssd300_voc/epoch_24.pth --eval mAP

引言

我们提出了MMDetection,一个包含了很多目标检测和实例分割方法的工具箱,它从我们团队获得COCO2018挑战赛冠军的代码上修改而来并且包含了很多流行的方法和对应的模块.它不仅包含训练和推理的代码,还提供了超过200个网络的预训练模型的权重. 我们坚信这是目前位置最全的代码库,本文详细描述这个工具箱的各种特性,还包括不同方法、组件以及超参数在评估集上的分析.我们希望这个这个工具箱和评估基准能够为不断增长的研究社区提供一个灵活的工具来重现现有的方法以此来促进新方法的诞生, 代码和模型可以在mmdetection获取,这个仓库开发很活跃我们仍然在不断更新它.

支持的框架

  • 单阶段的方法: SSD、RetineNet、GHM、FCOS和FSAF等
  • 两阶段的方法: Faset R-CNN、Faster R-CNN、R-FCN、Mask R-CNN等
  • 多阶段方法: Cascade R-CNN

通用的模块和方法: 混合精度训练、Soft-NMS、在线难例挖掘、可变形卷积、从头训练、同步批处理、权重标准化、高分辨率网络、导向锚点

在mmdetection中,将所有的检测器进行抽象成以下几个类(class):

  1. backbone: 骨干网络,用于从图片中提取特征
  2. Nect: (脖子很形象)用于连接backbone和head, 主要是对backbone提取得到的feature map进行修正或者组合,常见的就是FPN(FPN中核心就是多维度特征组合的方法, 将三个尺度得到的feature map进行组合)
  3. DenseHead(AnchorHead/AnchorFreeHead): 对特征图的密集位置进行操作(dense location),包括:AnchorHead, AnchorFreeHead。
  4. ROIExtractor: 从单个或者多个feature map中提取ROI, 最经典的是RoIPooling
  5. RoIHead (BBoxHead/MaskHead): 将ROI提取得到的feature作为输入, 进行基于任务的预测,如:预测坐标和类别,bbox预测与回归,mask预测。

模块功能/作用
Backbone提取图片特征
Neck将提取得到的特征进行融合或者直接用提取的特征
DenseHead类似RPN,也类似yololayer, 从特征图中得到框的信息,类的信息
ROIExtractor结合DenseHead提出的框以及Neck得到的特征进行特征提取
RoIHead将从ROIExtractor中提取得到的内容进行任务的预测

3.2训练流水线

提供了一些回调方便在训练前后、训练epoch前后、训练batch前后添加自定义的操作

评估

实验设置

数据集. 支持VOC格式和COCO格式的数据集,我们把COCO2017作为所有方法主要的评估数据集因为其更有挑战性并且更广泛使用.我们使用train作为训练集使用val进行评估

实现细节. 除非特别说明,默认采用如下配置(1)图像在不改变宽高比下会被缩放到1333*800(2)使用8卡V100,批大小为16(每张卡处理2张图像)(3)训练的调度和Detectron相同,1x表示12个epoch,2x表示24个epoch,20e在级联方法中使用,表示20个epcoh。

评估指标. 我们使用COCO数据的标准的指标,IoU从0.5到0.95都被评估,RPN使用AR和mAP评估

4.2 评估结果

主要结果. 我们在COCO2017val上对不同方法进行了评估,包括SSD、RetineNet、Faster RCNN、Mask RCNN和级联RCNN、混合任务训练以及FCOS等. 我们评估了4个广泛使用的基底,ResNet-50、ReNet-101、ResNet-101-32x4d和ResNeXt-101-64x4d,我们在图3报告这些方法的推理速度和框、mask的AP值,推理时间是在一块V100上获得的.

和其他代码库的比较. 除了MMDetection之外,还有很多其他诸如Detectron、maskrcnn-benchmark和SimpleDet等代码库,他们分别是基于caffe2、pytorch和MXNet的,我们从精度、速度和内存占用等三个方面比较了Detectron (@a6a835f), maskrcnn- benchmark (@c8eff2c) and SimpleDet (@cf4fce4) .Mask-RCNN和RetinaNet被选为两阶段和单阶段的代表,由于其他的代码库也在开发之中,在他们,模型库中的性能可能是过时的,而且结果是在不同的设备上取得的,为了公平起见,我们把这些代码拉到了同样的环境下,结果在表2中可得。不同框架的内存占用是通过不同的方式得到的,MMDetection选取所有GPU的最大值,maskrcnn-benchmark选的是0号GPU的值,并且都是通过torch.cuda.max memory allocated() pytoch的API调用获取的.Detectron使用caffe2的API caffe2.python.utils.GetGPUMemoryUsageStats()”,而SimpleDet使用英伟达自带的工具nvidia-smi,通常说来,MMDetection和maskrcnn-benchmark 是相似的并且比别的占用要低。

不同GPU的推理速度. 不同的研究者会使用不同的GPU,因此我们评估了它们在不同GPU上的速度,例如TITAN X, TITAN Xp, TITAN V, GTX 1080 Ti, RTX 2080 Ti 和 V100,表4展示了三个不同模型在这些GPU上的推理速度,请注意这些服务器的硬件配置可能并不完全一致,但是也能提供一个评估速度的基准。

混合精度训练. MMDetection支持混合精度训练以便减少内存占用来提升训练速度但却不损失精度.maskrcnn-benchmark通过apex支持混合精度训练SimpleDet也有它自己的实现,但是Detectron还不支持混合精度训练.表3展示了不同代码库的比较.我们在同样的V100节点上进行测试,此外我们还探究了不同模型使用混合精度训练的有效性,可以看到大的BatchSize节省的内存更加明显,当批大小达到12的的时候需要的内存几乎是FP32的一半,特别在RetineNet等简单的网络下节省的内存更多.

多节点的可扩展性.  由于MMDetection支持分布式训练,我们测试了其在8,16,32和64个GPU的扩展性,我们把Mask-RCNN作为评估方法并且在另外一个V100集群上进行,和11一样,基础学习率根据不同的批大小进行线性调整,表5表明我们的代码获得了金近乎线性的加速比.

5. 宝贵的经验

通过MMDetection,我们在很多重要组件和超参数上获得了很多重要的经验,我们希望这些学习能够给大家带来更好的实践,更公平的饿比较来促进不同方法的发展.

5.1 回归损失

多任务学习损失警用用来训练目标检测,其包含分类损失和坐标回归分支。最近涌现了很多的损失,有界Iou损失、IoU损失、GIoU损失、平衡化L1损失,而L1损失是最简单直接的形式了。但是这些不同的方法是在不同的设置下实现的。因此这儿我们在相同的环境下评估这些损失的作用。需要注意分配给回归损失的权重,我们使用粗略的网格搜索来获得每个损失最佳的设置。

表5表明简单的提高平滑L1损失的权重就可以提升0.5个点。不调节损失权重的情况下,L1损失比pin平滑L1损失高0.6的点但是提高权重后却并不会有什么收益. L1损失相比平滑L1损失有更大的值,特别是对那些比较精确的包围框。根据23的分析,更好的提升包围框的梯度能够提升定位的精度.L1的损失值本身就很大了,提升它的权重并不会表现的更好。平衡L1损失比L1损失提升了0.3个点但是我们发现更大的退化.基于IoU的损失比除了平衡化L1损失之外都会有轻微的提升,GIoU比IoU高0.1个点但是需要更大的权重

5.2归一化层

训练检测器时的批大小经常为2因为显存不够,因此BN层经常被冻住,对BN层来说有两类通常的设置(1)是否去更新统计量均值和方差,(2)是否更新仿射参数r和b. 遵循pytorch的命名,我们把1和2分别定义为评估模式和梯度反传.评估模式意味着均值和方差不再更新,而需要反传意味着仿射参数在训练过程中也会更新.除了冻住BN层的参数外,还有其他的方法比如同步化BN、组归一化等. 我们先评估不同基底下BN不同的设置,再比较BN和同步化BN以及组归一化的作用

BN设置. 我们在Mask-RCNN下评估评估模式和梯度反传不同的设置,在1x和2x训练调度下.表6表明当我们把评估模式关闭并且不再更新梯度后使用小的BatchSize更新参数严重损害了精度.和eval=True,梯度反传=True相比降低了3.1个点。是否固定仿射参数在1x训练下只低0.1个点但是当多训练几个epoch到2x时能查0.5个点.在MMDetection中评估模式设为True,梯度反传也设为True.

不同的归一化层. BN层在进来的CNN网络里广泛使用。然后它特别依赖于大的BatchSize来精确的估计均值和方差.通常说来目标检测的批大小要远小于分类的,典型的做法是使用那些预训练的参数而不去更新他们,也被称之为冻住BN.最近,同步化BN和组归一化被提了出来并且被证明了很有用.同步化BN在不同的GPU上计算均值和方差,组归一化把特征分成不同的组然后在每个组内计算均值和方差, 这样有助于缓解小的批大小带来的问题.在MMDetection中这些方法可以通过简单的设置进行切换.

在这里我们试图研究两个问题:(1)不同的归一化层到底有什么区别?(2)检测任务里应该在哪里加BN层?为了回答这两个问题,我们使用Mask-RCNN分别做了三组不同的实验,除了BN层不一样外别的都保持同样的设置.在36中,2fc被替换为4conv,因此我们还设计了另外两组实验来回答这个问题.此外,我们还研究了不同bbox head的作用

表7的结果表明(1)只是替换层的话性能非常接近(2)在bboxmaskhead上使用同步化BN和组归一化没有什么收益(3)把2fc替换为4conv能够使性能提高1.5个点(4)在bbox head中添加更多的卷积层能够获得更好的性能

5.3训练的尺度

在传统方法中,训练图像在不丢失宽高比的情况下被缩放到预定义的尺度.先前的研究倾向于使用1333*800,在MMDtection我们也使用了这个设置. 作为最简单的数据增强方法,多尺度训练在MMDetection也会被使用.还没有类似的研究来评估选择最好尺度的方法. 知道这些设置对高效和有效的训练是非常关键的.目前有两种主流的随机选择尺度的方法,一种是预先定义一系列的尺度然后从里面抽,另外一种是定义一个尺度变换的范围然后随机选一个数,在这里我们将其表示为value模式和range模式,特别的,range模式可以看成预定义步长为1的value模式.

我们使用不同的尺度和模式来训练了Mask-RCNN,并且使用了2x的学习因为更多的数据增强需要更长时间的学习.结果如表8所示,1333x[640:800:32]表示长边是1333,而短边在{640,672,704,736,768和800}中随机选择,也就是value模式.而1333x[640:800]表示短边是在640到800之间随机选的一个值,也就是range模式.从结果不难看出,range模式比value要或多或少的稍微好一些.通常来说更宽的范围会提升不少,特别是最大值扩大之后.特别的,[640:960]比[640:800]在bbox和mask的AP上要好0.4和0.5个点.然而短边的提升却没有带来什么收益,640比480的就可以看出来.

5.4其他的超参数设置

MMDetection主要参考了Detectron的设置,但是也实现了自己的设置.特别的,我们发现Detectron很多设置并不是最优的,特别是对RPN来说.在表9中列出了那些能进一步提升RPN性能的设置, 尽管这些微调能够获得性能上的提升但是为了公平起见,我们也设置成Detectron一样的以便参考.

smoothl1 beta 大多数检测方法将Smooth L1 Loss 实现为torch.where(x < beta, 0.5 ∗ x2/beta, x − 0.5 ∗ beta),其中的beta参数在RPN中被设成了1/9,大量的实验表明调小这个值能够获得轻微的性能提升.

allowed border 在RPN中,预定义的锚点会在每个位置都生成,超出图像边界的锚框在训练过程中会被丢掉,它会被设置成0这意味着任何超出图像边界的框都会被忽略.然而,我们发现放宽这个要求会有不小的收益,如果我们把它设置成无限大,也就是不忽略任何一个锚框,AR将会从57.1提升到57.7.这样在边界附近的真值将会有更多的匹配.

neg pos ub 我们把这个作为正负样本采样时新的超参数. 在训练RPN时为了防止正负样本失衡典型的采样方法时保证固定比例的正负样本.在这里我们使用neg pos ub来控制正负样本的最大比例.把它设置成无限大会导致前面提到的很严重的失衡(负样本很多,正样本没几个),通过把它设置成合理的数值例如3或者5,能够获得1.2和1.1个点的提升.

数据管线

和典型的传统方法一样,mmdetection使用DataSet和DataLoader来加载数据,由于目标检测中图像大小可能并不是相同的,我们在mmcv中提供了一个新的DataContainer来收集和分发数据

数据准备和dataset解耦了,一般说来dataset定义了如何处理标注而数据管线定义了预处理数据的一些步骤

如何使用自己的数据训练?

最简单的方式是转换成VOC格式或者COCO格式,这样你可以在config文件里使用它们。

如果你不想转换标注也是可以的,我们定义了现有的数据集都可以兼容一个简单的标注格式,不管是在线还是离线都是OK的

数据集的标注是一个字典的列表,每个字典对应一个图片它们有三个字段,对于测试图来说含有文件名、宽度和高度,而对于训练图还另外包含一个ann字段,ann字段也是一个包含bboxes和labels字段的字典,它们都是numpy的数组。一些数据集会包含忽略、难例和拥挤等标注,我们提供了bboxes_ignore和labels_ignore来覆盖他们。

就如同下面这个例子

[
    {
        'filename': 'a.jpg',
        'width': 1280,
        'height': 720,
        'ann': {
            'bboxes': <np.ndarray, float32> (n, 4),
            'labels': <np.ndarray, int64> (n, ),
            'bboxes_ignore': <np.ndarray, float32> (k, 4),
            'labels_ignore': <np.ndarray, int64> (k, ) (optional field)
        }
    },
    ...
]

有两种方式来转换自己的数据集

  1. 在线方式:你可以从CustomDataset派生一个新的数据类,里面实现load_annotations(self, ann_file) 和 get_ann_info(self, idx)两个方法,就和VOCDataset那样
  2. 离线方式你可以转换成VOC格式,然后使用CustomDataset

具体修改的步骤:

1.仿照xml_style.py文件实现自己的数据集类

主要实现两个函数load_annotations和get_ann_info,load_annotations用来加载训练图片的形状信息以便能过滤掉一些过小的图片,get_ann_info用来加载每张训练图片的标注信息.

记得使用@DATASETS.register_module注册自己的类,不然会报找不到的错

2.在dataset文件夹下的__init__.py中加载

from .mydataset improt MyDataset

3.修改configs文件里,找一个要训练的网络,将相关信息修改正确,特别是类别数,标注路径等

最后附上 用来测试自己数据集能否正常加载的代码:

import argparse
import os
import cv2
import torch
import mmcv
from mmdet.datasets import build_dataloader, build_dataset

def parse_args():
    parser = argparse.ArgumentParser(description='test loader')
    parser.add_argument('--config', type=str,default="configs/shoes/ssd300_shoes.py", required=False,help='train config file path')
    args = parser.parse_args()
    return args

def main():
    args = parse_args()
    cfg = mmcv.Config.fromfile(args.config)
    dataset = build_dataset(cfg.data.train)
    data_loader = build_dataloader(dataset,1,1,1,dist=False,seed=0)
    for i, data_batch in enumerate(data_loader):
        print(i)
        images = data_batch["img"].data[0]
        gt_bboxes = data_batch["gt_bboxes"].data[0]
        gt_labels = data_batch["gt_labels"].data[0]
        for j in range(len(images)):
            img = images[j].numpy().transpose(1,2,0)
            img = cv2.cvtColor(img,cv2.COLOR_RGB2BGR)
            img += [123.675, 116.28, 103.53]
            img /= 255.
            gt_bbox = gt_bboxes[j].numpy()
            for k in range(len(gt_bbox)):
                bbox = gt_bbox[k]
                gt_label = gt_labels[j].numpy()[k]
                x= bbox[0]
                y= bbox[1]
                x2 = bbox[2]
                y2 = bbox[3]
                cv2.rectangle(img,(x,y),(x2,y2),(255,0,0))
                cv2.putText(img,dataset.CLASSES[gt_label-1],(x,y),1,1,(0,0,255))
            cv2.imshow("img",img)
            cv2.waitKey()

if __name__=="__main__":
    main()

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值