mmdetection是来自商汤和港中文联合实验室openmmlab推出的目标检测工具包,与其同系列的还有基础视觉包mmcv,图像分类mmclassification,还有mmaction,mmaction2等等。
今天第一次尝试使用mmdetection,先进行安装和简单的demo使用。
根据其github的get_started.md介绍进行安装即可
这里介绍一下我的安装过程,亲测没什么问题
Ubuntu 18.04
PyTorch 1.7.0
Cuda 11.1
RTX 3060 Ti
为其新建一个conda环境并激活并安装pytorch(这里就不详细介绍了,网上教程很多,应该不难)
安装mmdetection
pip install openmim
mim install mmdet
以上方式即可自动安装成功mmdetection,get_started.md还提供了一种手动安装的方法,比较麻烦,可以自己去试一下。
这里我们根据商汤给出的教程给出的介绍尝试了一下inference的demo。
使用Faster RCNN进行demo图像的目标检测
安装成功后,新建一个工程即可
mkdir mmdet_proj
cd mmdet_proj
新建一个ipynb文件
(因为这个demo默认要用matplotlib来展示检测结果框,而我是用vscode连接远程服务器进行工作的,所以直接用py文件无法进行结果展示,要savefig的话应该要改一点源码,如果是在本机进行demo尝试的话,py文件应该也可)
import torch
from PIL import Image
from mmdet.apis import inference_detector, init_detector, show_result_pyplot
from mmdet.configs.faster_rcnn import faster_rcnn_r50_fpn_1x_coco
import warnings # 我这里会报一些警告,不影响运行,但影响心情,就先把警告关掉了
warnings.filterwarnings("ignore")
image = 'demo.jpeg'
device = torch.device('cuda:0')
config = '~/anaconda3/envs/[your_conda_env_name]/lib/python3.8/site-packages/mmdet/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py'
checkpoint = 'weights/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth'
model = init_detector(config, checkpoint, device=device)
result = inference_detector(model, image)
show_result_pyplot(model, image, result, score_thr=0.9)
config文件是模型的一些配置,如果是直接拉的mmdet github仓库的话,config是可以按照相对路径拿到的,但我们是mim安装的,所以我就找了一下这个config文件的绝对路径拿过来了。
checkpoint可以从mmdet的Faster RCNN model zoo下载。
运行ipynb文件即可以看到结果啦。
可以看到检测结果还是不错的。
然后我们看一下这个过程中的中间变量都是什么东西。
model:
model # print(model) for .py
FasterRCNN(
(backbone): ResNet(
(conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
(layer1): ResLayer(
# ...
# ...
)
init_cfg={'type': 'Pretrained', 'checkpoint': 'torchvision://resnet50'}
(neck): FPN(
(lateral_convs): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(1, 1), stride=(1, 1))
)
(1): ConvModule(
(conv): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1))
)
(2): ConvModule(
(conv): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))
)
(3): ConvModule(
(conv): Conv2d(2048, 256, kernel_size=(1, 1), stride=(1, 1))
)
)
(fpn_convs): ModuleList(
(0): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
(1): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
(2): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
(3): ConvModule(
(conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
)
)
init_cfg={'type': 'Xavier', 'layer': 'Conv2d', 'distribution': 'uniform'}
(rpn_head): RPNHead(
(loss_cls): CrossEntropyLoss()
(loss_bbox): L1Loss()
(rpn_conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(rpn_cls): Conv2d(256, 3, kernel_size=(1, 1), stride=(1, 1))
(rpn_reg): Conv2d(256, 12, kernel_size=(1, 1), stride=(1, 1))
)
init_cfg={'type': 'Normal', 'layer': 'Conv2d', 'std': 0.01}
(roi_head): StandardRoIHead(
(bbox_roi_extractor): SingleRoIExtractor(
(roi_layers): ModuleList(
(0): RoIAlign(output_size=(7, 7), spatial_scale=0.25, sampling_ratio=0, pool_mode=avg, aligned=True, use_torchvision=False)
(1): RoIAlign(output_size=(7, 7), spatial_scale=0.125, sampling_ratio=0, pool_mode=avg, aligned=True, use_torchvision=False)
(2): RoIAlign(output_size=(7, 7), spatial_scale=0.0625, sampling_ratio=0, pool_mode=avg, aligned=True, use_torchvision=False)
(3): RoIAlign(output_size=(7, 7), spatial_scale=0.03125, sampling_ratio=0, pool_mode=avg, aligned=True, use_torchvision=False)
)
)
(bbox_head): Shared2FCBBoxHead(
(loss_cls): CrossEntropyLoss()
(loss_bbox): L1Loss()
(fc_cls): Linear(in_features=1024, out_features=81, bias=True)
(fc_reg): Linear(in_features=1024, out_features=320, bias=True)
(shared_convs): ModuleList()
(shared_fcs): ModuleList(
(0): Linear(in_features=12544, out_features=1024, bias=True)
(1): Linear(in_features=1024, out_features=1024, bias=True)
)
(cls_convs): ModuleList()
(cls_fcs): ModuleList()
(reg_convs): ModuleList()
(reg_fcs): ModuleList()
(relu): ReLU(inplace=True)
)
init_cfg=[{'type': 'Normal', 'std': 0.01, 'override': {'name': 'fc_cls'}}, {'type': 'Normal', 'std': 0.001, 'override': {'name': 'fc_reg'}}, {'type': 'Xavier', 'layer': 'Linear', 'override': [{'name': 'shared_fcs'}, {'name': 'cls_fcs'}, {'name': 'reg_fcs'}]}]
)
)
由于mmdetection也是基于pytorch的,所以可以看到我们这里的Faster RCNN的检测模型也是一个nn.Module的子类,与我们平时自己使用pytorch定义的模型类似。只不过在mmdetection中已经被封装的很好了。
result:
type(result) # print(type(result)) for .py
len(result)
result[0]
list
80
array([[3.7534842e+02, 1.1917159e+02, 3.8195099e+02, 1.3446083e+02,
1.3552596e-01],
[5.3236182e+02, 1.0955501e+02, 5.4052661e+02, 1.2522261e+02,
8.8892356e-02],
[3.6112421e+02, 1.0904940e+02, 3.6862576e+02, 1.2248302e+02,
7.2088778e-02]], dtype=float32)
这里的result就是我们检测的结果了。其最外层是一个列表,长度为80,这是因为我们使用COCO数据集进行训练的,共有80个类,其返回的结果就是每个类可能存在的边界框。
最外层列表的每个元素即是其中一类可能存在的 n n n 个边界框。每个边界框由四个值来表示,最后一个是置信度,而前四个则是xyhw格式(中心点坐标+高和宽)的边界框坐标。
show_result_pyplot函数中给出的参数 score_thr 即是置信度的阈值,即各个边界框的置信度大于该值时才会被显示。
我们可以将阈值 score_thr更改看一下
result = inference_detector(model, image)
show_result_pyplot(model, image, result, score_thr=0.2) # 将阈值由 0.9 改为 0.2
将阈值由 0.9 改为 0.2,可以明显看到显示出来的边界框个数增多了。
本次mmdet的安装和初步inference demo尝试就记录到这里,后续会继续记录一下笔者使用mmdet的过程。