Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用

-----该博客参考了一些大神的博客,在此表示感谢------

Mmdetection是商汤科技和香港中文大学开源的一个目标检测工具箱,目前支持了常见的目标检测网络Faster-RCNN、Mask-RCNN、Fast-RCNN、SSD、Cascade-RCNN等;
该工具箱具有以下三点优势:performance稍高、训练速度稍快、所需显存稍小

文章地址:https://arxiv.org/pdf/1906.07155.pdf
github地址:https://github.com/open-mmlab/mmdetection

一、安装环境

基本配置

  1. Ubuntu16.04
  2. CUDA9.0+Cudnn7.1
  3. Python3.5
  4. Pycharm2019
  5. pytorch1.0

此次安装MMDetection工具箱没有使用anaconda,而是采用python创建了虚拟环境,功能和anaconda创建的虚拟环境一样,都是为了避免污染系统,其可以防止在系统的Python解释器中避免安装包的混乱和版本冲突,因此创建一个隔离区域,在这个区域里安装各种我们所需要的依赖包。下面将对整个安装配置过程进行介绍:

1. Ubuntu下安装python虚拟环境
(1) 首先需要安装virtualenv

#python3环境下安装(默认系统为Python3)
sudo pip install virtualenv

(2) 创建虚拟环境目录,在ubuntu的home下创建一个文件夹,名称可以自己定义,我这里采用env

lm@lm:~$ mkdir env
lm@lm:~$ virtualenv -p python env

(3) 运行虚拟环境
安装好之后,运行虚拟环境

lm@lm:~$ source .env/bin/activate
(.env) lm@lm:~$

在这里插入图片描述
(4) 退出虚拟环境

(.env) lm@lm:~$ deactivate

虚拟环境创建好后,就可以在这个环境中安装各种需要的包,例如numpy, pytorch,tensorflow等等。
这是我目前安装的所有包,都在.env环境下,可以通过pycharm查看,解释器的路径为:~/.env/bin/python3.5。
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第1张图片和anaconda一样,如果需要在终端下运行程序,首先需要进入这个虚拟环境,然后加载各种包,如果打开终端直接import,就会提示找不到。
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第2张图片Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第3张图片
Python虚拟环境安装好后,就可以在该环境下安装MMDetection工具箱所需要的各种包。
最新发布的MMDetection目标检测工具的安装需求如下:

  • Linux
  • Python 3.5以上版本
  • Pytorch1.0以上版本
  • CUDA9.0以上版本
  • NCCL 2.0以上版本
  • GCC 5.0以上版本(最好升级到5.0以上,不然后面会出现错误)
  • mmcv包

关于显卡驱动、CUDA和Cudnn的安装,这里忽略,可以百度搜索相关博客
下面主要介绍其他部分

2. 安装Pytorch1.0以上版本
这里采用pip方式安装
首先在Pytorch官网根据自己的系统配置,选择合适的pytorch版本。
下面只是参考流程,安装时根据自己需要安装

lm@lm:~$ source .env/bin/activate
(.env) lm@lm:~$ pip3 install https://download.pytorch.org/whl/cpu/torch-1.0.1.post2-cp35-cp35m-linux_x86_64.whl
(.env) lm@lm:~$ pip3 install torchvision
# 安装numpy
(.env) lm@lm:~$ pip install numpy

# 测试是否安装成功
(.env) lm@lm:~$ python
Python 3.5.2 (default, Nov 12 2018, 13:43:14) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import torch as t
>>> 

3. 安装Cython

(.env) lm@lm:~$ pip install cython

4. 安装mmcv

(.env) lm@lm:~$ git clone https://github.com/open-mmlab/mmcv.git
cd mmcv
pip install . # 注意最后的点不要掉了

5. 查看和安装gcc

(.env) lm@lm:~$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.11' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11) 

这里我的gcc版本为5.4.0。
gcc安装和更新如下:

(.env) lm@lm:~$ sudo apt-get install build-essential
(.env) lm@lm:~$ gcc--version

6. 安装mmdetection目标检测工具包
这里以我的安装为例,在home下创建MMDetection文件夹

(.env) lm@lm:~$ cd MMDetection
(.env) lm@lm:~/MMDetection$ git clone https://github.com/open-mmlab/mmdetection.git
(.env) lm@lm:~/MMDetection/mmdetection$

# 在最新发布的mmdetection工具箱中,对前版本的mmdetection进行了升级,没有了compile.sh文,因此,只需要执行下面的语句即可
(.env) lm@lm:~/MMDetection/mmdetection$ python setup.py develop

完成后的截图如下:
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第4张图片这里,checkpoints,test_image, save_image, my_configs是自己后面创建的,分别用来存放节点文件,测试图像/视频,检测结果保存,以及自己训练时的config文件。
至此,mmdetection目标检测工具包安装完成,为了验证是否安装成功,下面来通过新建一个demo进行测试。

二、测试验证

测试验证主要以object detection为主,当然也可以是instance segmentation。
在pycharm下打开到mmdetection目录下,新建一个test.py文件,设置好Interpreter环境——即创建好的python虚拟环境。该测试文件的主要功能是:
(1) 对单张图片进行测试,并显示结果
(2) 对文件夹下的批量图像进行测试,并保存在save_image下
(3) 对视频文件进行测试。
在test.py中采用的模型为Faster_RCNN_FPN_resnet50,由于通过url下载模型的速度很慢,这里将faster_rcnn_r50_fpn_1x_20181010-3d1b3351.pth下载完后放在checkpoints文件夹下。test_image为测试图片和视频,如下:
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第5张图片下面是test.py文件

import os
import mmcv
from mmcv.runner import load_checkpoint
from mmdet.models import build_detector
from mmdet.apis import init_detector, inference_detector, show_result
import argparse

parser = argparse.ArgumentParser(description='MMDetection test!')
parser.add_argument('--test_type',
                    default='video_test',
                    help="'single_image_test', 'list_image_test' or 'video_test")
args = parser.parse_args()

# 加载config文件
config_file = 'configs/faster_rcnn_r50_fpn_1x.py'
checkpoint_file = 'checkpoints/faster_rcnn_r50_fpn_1x_20181010-3d1b3351.pth'

# 加载模型和节点文件
model = init_detector(config_file, checkpoint_file, device='cuda:0')
print('Test Model is:', model)

# (1)单幅图像测试
if args.test_type == 'single_image_test':
    img = './test_image/4.jpg'
    result = inference_detector(model, img)
    show_result(img, result, model.CLASSES)

# 批量图像测试
if args.test_type == 'list_image_test':
    test_path = './test_image/'
    save_path = './save_image/'
    filelist = os.listdir(test_path) # 打开文件夹
    total_num = len(filelist) #得到文件夹中图像的个数
    for i in range(total_num):
        jpg_name = test_path + filelist[i]
        result = inference_detector(model, jpg_name)
        show_result(jpg_name, result, model.CLASSES, show=False, out_file= save_path + 'result_{}.jpg'.format(filelist[i][:-4]))

# 视频文件测试
if args.test_type == 'video_test':
    video = mmcv.VideoReader('./test_image/video.mp4')
    for frame in video:
        result = inference_detector(model, frame)
        show_result(frame, result, model.CLASSES, wait_time=1)

1. 单幅图像测试结果
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第6张图片
2. 批量图像测试结果
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第7张图片Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第8张图片Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第9张图片Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第10张图片
3. 视频文件测试
读者可以根据代码自己去下载视频测试。

instance segmentation的测试结果
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第11张图片
通过测试的结果来看,效果并不是很好,还是需要根据数据集,进行训练再测试。

4. 检测框和字体颜色的修改
另外,有的希望能够更改检测bounding box的颜色,或者是字体的颜色,可以按照如下进行更改:
在mmdetection/mmdet/apis下找到inference.py文件,对函数show_result进行如下修改(这里只截取inference.py文件下的show_result进行展示):

def show_result(img,
                result,
                class_names,
                score_thr=0.3,
                wait_time=0,
                show=True,
                out_file=None):
    """Visualize the detection results on the image.

    Args:
        img (str or np.ndarray): Image filename or loaded image.
        result (tuple[list] or list): The detection result, can be either
            (bbox, segm) or just bbox.
        class_names (list[str] or tuple[str]): A list of class names.
        score_thr (float): The threshold to visualize the bboxes and masks.
        wait_time (int): Value of waitKey param.
        show (bool, optional): Whether to show the image with opencv or not.
        out_file (str, optional): If specified, the visualization result will
            be written to the out file instead of shown in a window.

    Returns:
        np.ndarray or None: If neither `show` nor `out_file` is specified, the
            visualized image is returned, otherwise None is returned.
    """
    assert isinstance(class_names, (tuple, list))
    img = mmcv.imread(img)
    img = img.copy()
    if isinstance(result, tuple):
        bbox_result, segm_result = result
    else:
        bbox_result, segm_result = result, None
    bboxes = np.vstack(bbox_result)
    # draw segmentation masks
    if segm_result is not None:
        segms = mmcv.concat_list(segm_result)
        inds = np.where(bboxes[:, -1] > score_thr)[0]
        for i in inds:
            color_mask = np.random.randint(0, 256, (1, 3), dtype=np.uint8)
            mask = maskUtils.decode(segms[i]).astype(np.bool)
            img[mask] = img[mask] * 0.5 + color_mask * 0.5
    # draw bounding boxes
    labels = [
        np.full(bbox.shape[0], i, dtype=np.int32)
        for i, bbox in enumerate(bbox_result)
    ]
    labels = np.concatenate(labels)
    mmcv.imshow_det_bboxes(
        img,
        bboxes,
        labels,
        class_names=class_names,
        score_thr=score_thr,
        bbox_color='red',
        text_color='blue',
        font_scale=0.5,
        show=show,
        wait_time=wait_time,
        out_file=out_file)
    if not (show or out_file):
        return img

在倒数第八行和第九行,分别是text_color=‘blue’, bbox_color=‘red’。这里根据自己的喜好,随意更改bbox的颜色和文本的颜色。更改的结果如下所示:
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第12张图片Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第13张图片

三、利用MMDetection目标检测工具箱训练自己的数据集

1. 创建自己的数据集
MMDetection工具箱主要支持PASCAL VOC和COCO两种数据集格式,
(1) VOC格式的数据就是xml格式的标注数据,不过VOC规定了xml文件中各个节点的标签名字,统一了标注风格。
(2) COCO数据集是一种json格式的标注形式。

如果需要训练自己的数据集,最好将目标数据集的标注格式转换为VOC或COCO格式才行。使用标注工具LabelImg就可以产生VOC格式的标注文件,使用Labelme可以产生COCO格式的标注文件。
如果其他公开的数据集,没有提供VOC或者COCO格式的话,需要自己编码实现标注风格的转换,再进行训练。

这里以我自己的数据集为例,采用VOC格式,在文件夹下的目录如下:
----data
--------VOCdevkit
------------VOC2007
----------------Annotations
----------------JPEGImages
----------------ImageSets
--------------------Main
------------------------test.txt
------------------------train.txt
------------------------trainval.txt
------------------------val.txt
文件夹Annotations中存放voc2007格式的标注数据文件,JPEGImages存放图片文件,ImageSets存放测试文件test.txt, 训练文件train.txt, 验证文件val.txt和trainval.txt文件。

2. 修改config文件
为了避免修改MMDetection中原有的config文件,这里在mmdetection文件夹下创建一个新的my_config文件夹,里面存放训练模型需要的config文件,如下:
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第14张图片这里以faster_rcnn_r50_fpn_1x模型为例,config文件的内容如下:
由于这里采用的是VOC数据格式,因此在下面的config文件中,主要修改文件中的训练集、验证集和测试集下的路径:

# model settings 模型设置
model = dict(
    type='FasterRCNN',  #model类型
    pretrained='modelzoo://resnet50', # 预训练模型:imagenet-resnet50
    
    backbone=dict(
        type='ResNet', # 骨干网络类型
        depth=50, # 网络深度
        num_stages=4, #resnet的stage数量
        out_indices=(0, 1, 2, 3), # 输出的stage序号
        frozen_stages=1,
        style='pytorch'),
    neck=dict(
        type='FPN',
        in_channels=[256, 512, 1024, 2048],
        out_channels=256,
        num_outs=5),
    rpn_head=dict(
        type='RPNHead',
        in_channels=256,
        feat_channels=256,
        anchor_scales=[8],
        anchor_ratios=[0.5, 1.0, 2.0],
        anchor_strides=[4, 8, 16, 32, 64],
        target_means=[.0, .0, .0, .0],
        target_stds=[1.0, 1.0, 1.0, 1.0],
        loss_cls=dict(
            type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0),
        loss_bbox=dict(type='SmoothL1Loss', beta=1.0 / 9.0, loss_weight=1.0)),
    bbox_roi_extractor=dict(
        type='SingleRoIExtractor',
        roi_layer=dict(type='RoIAlign', out_size=7, sample_num=2),
        out_channels=256,
        featmap_strides=[4, 8, 16, 32]),
    bbox_head=dict(
        type='SharedFCBBoxHead',
        num_fcs=2,
        in_channels=256,
        fc_out_channels=1024,
        roi_feat_size=7,
        num_classes=81,
        target_means=[0., 0., 0., 0.],
        target_stds=[0.1, 0.1, 0.2, 0.2],
        reg_class_agnostic=False,
        loss_cls=dict(
            type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0),
        loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0)))

# 模型训练和测试设置
# model training and testing settings
train_cfg = dict(
    rpn=dict(
        assigner=dict(
            type='MaxIoUAssigner', #bounding box的最大IOU设置
            pos_iou_thr=0.7,  # 正样本iou
            neg_iou_thr=0.3,  # 负样本iou
            min_pos_iou=0.3,  # 最小正样本iou
            ignore_iof_thr=-1),
        sampler=dict(
            type='RandomSampler', # 随机采样
            num=256,
            pos_fraction=0.5,
            neg_pos_ub=-1,
            add_gt_as_proposals=False),
        allowed_border=0,
        pos_weight=-1,
        debug=False),
    rpn_proposal=dict(
        nms_across_levels=False,
        nms_pre=2000,
        nms_post=2000,
        max_num=2000,
        nms_thr=0.7,
        min_bbox_size=0),
    rcnn=dict(
        assigner=dict(
            type='MaxIoUAssigner',
            pos_iou_thr=0.5,
            neg_iou_thr=0.5,
            min_pos_iou=0.5,
            ignore_iof_thr=-1),
        sampler=dict(
            type='RandomSampler',
            num=512,
            pos_fraction=0.25,
            neg_pos_ub=-1,
            add_gt_as_proposals=True),
        pos_weight=-1,
        debug=False))
test_cfg = dict(
    rpn=dict(
        nms_across_levels=False,
        nms_pre=1000,
        nms_post=1000,
        max_num=1000,
        nms_thr=0.7,
        min_bbox_size=0),
    rcnn=dict(
        score_thr=0.05, nms=dict(type='nms', iou_thr=0.5), max_per_img=100)
    # soft-nms is also supported for rcnn testing
    # e.g., nms=dict(type='soft_nms', iou_thr=0.5, min_score=0.05)
)

# 数据集设置
# dataset settings
dataset_type = 'VOCDataset'  # 数据集类型
data_root = 'data/VOCdevkit/'  #数据集根目录
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
data = dict(
    imgs_per_gpu=2,  # 每个gpu计算的图像数量
    workers_per_gpu=2,  # 每个gpu分配的线程数
    # 训练集
    train=dict(
        type=dataset_type,
        ann_file=data_root + 'VOC2007/ImageSets/Main/train.txt',
        img_prefix = data_root + 'VOC2007/',
        img_scale=(1000, 600),
        img_norm_cfg=img_norm_cfg,
        size_divisor=32,
        flip_ratio=0.5,
        with_mask=False,
        with_crowd=True,
        with_label=True),
    # 验证集
    val=dict(
        type=dataset_type,
        ann_file=data_root + 'VOC2007/ImageSets/Main/trainval.txt',
        img_prefix=data_root + 'VOC2007/',
        img_scale=(1000, 600),
        img_norm_cfg=img_norm_cfg,
        size_divisor=32,
        flip_ratio=0,
        with_mask=False,
        with_crowd=True,
        with_label=True),
    # 测试集
    test=dict(
        type=dataset_type,
        ann_file=data_root + 'VOC2007/ImageSets/Main/test.txt',
        img_prefix=data_root + 'VOC2007/',
        img_scale=(1000, 600),
        img_norm_cfg=img_norm_cfg,
        size_divisor=32,
        flip_ratio=0,
        with_mask=False,
        with_label=False,
        test_mode=True))

# 优化器-optimizer
# lr为学习率,momentum为动量因子,weight_decay为权重衰减因子
optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001)
optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2))

# 学习策略-learning policy
lr_config = dict(
    policy='step',
    warmup='linear',
    warmup_iters=500,
    warmup_ratio=1.0 / 3,
    step=[8, 11])
checkpoint_config = dict(interval=1)
# yapf:disable
log_config = dict(
    interval=50,
    hooks=[
        dict(type='TextLoggerHook'),
        # dict(type='TensorboardLoggerHook')
    ])
# yapf:enable
# runtime settings
total_epochs = 12
dist_params = dict(backend='nccl')
log_level = 'INFO'
work_dir = './work_dirs/faster_rcnn_r50_fpn_1x' #log文件和模型文件存储路径
load_from = None
resume_from = None
workflow = [('train', 1)]

3. 更改数据集类别文件
我自己的数据集只有两个类别,一个是背景(unknown),一个是目标(sam)。
在mmdetection/mmdet/datasets/下,新建一个voc文件,将里面的CLASSES设置如下:
读者可以根据自己数据集的类别情况进行修改。

from .registry import DATASETS
from .xml_style import XMLDataset

@DATASETS.register_module
class VOCDataset(XMLDataset):

    CLASSES = ('unknown', 'sam')

    def __init__(self, **kwargs):
        super(VOCDataset, self).__init__(**kwargs)
        if 'VOC2007' in self.img_prefix:
            self.year = 2007
        elif 'VOC2012' in self.img_prefix:
            self.year = 2012
        else:
            raise ValueError('Cannot infer dataset year from img_prefix')

如果不采用VOC格式,也可以自己创建,如下:
在mmdetection/mmdet/datasets/下新建一个my_dataset.py文件,文件的内容如下:

from .coco import CocoDataset
from .registry import DATASETS

@DATASETS.register_module
class MyDataset(CocoDataset):
    CLASSES = ('unknown','sam')

然后在__init__.py文件夹下,新增

from .my_dataset import MyDataset

如下:
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第15张图片

4. 模型训练
在mmdetection文件夹下创建模型训练日志的存放文件夹:work_dirs
打开重点,进入虚拟环境,输入如下代码:

(.env) lm@lm:~/MMDetection/mmdetection$ python tools/train.py my_configs/faster_rcnn_r50_fpn_1x.py

得到如下:
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第16张图片这是设置的epochs个数为12,训练完后的结果为:
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第17张图片训练保存的文件如下:
Ubuntu16.04下目标检测工具箱MMDetection的安装、测试和使用_第18张图片4. 模型测试

你可能感兴趣的:(目标检测)