MMDetectionV2 + Colab

MMDetectionV2 + Colab 超详细教程及踩坑实录

文章目录

    • 前言
    • 一、环境配置
    • 二、准备自己的数据集
      • Aug.14更新
    • 三:修改config文件
      • 3.1 文件结构
      • 3.2 (本地)修改config文件
        • 3.2.1 (本地)构造自己模型的权重文件
        • 3.2.2 (本地)修改配置文件
      • 3.3 在colab上修改config
      • 3.5 在线训练
      • 3.6 在线可视化模型效果
      • 3.7 在线inference
      • 4. 延伸思考
      • 5. 总结

前言

为了参加讯飞的X光目标检测竞赛,我们组研究了目前通用的几种框架。包括Detectron2, Maskrcnn Benchmark和mmdetectionV2,最后决定采用MMDetectonV2,因为他有以下的几个特性:

  • 相比较来说非常丰富的模型库可供选择。基础模型包括:
    1. Faster rcnn
    2. Mask rcnn
    3. Rpn rcnn
    4. Cascade mask rcnn
    5. Cascade rcnn
    6. Retinanet (据说精度差不多的情况下,inference速度最快,可以以后再多了解一下。
  • 较多参考资料
  • 安全的License,Apache License 2.0

先说明下,为什么我要这么执着的使用Colab:

  1. Colab Pro订阅能够提供一般学生无法获得的算力资源:P100, 16g内存,$9.9/month简直在做慈善。
  2. 服务器在国外,免除网速烦恼。所有模型,包都是秒下秒装。虽然每个session重启都要重新装包,不过有这个速度完全不用担心花费过多时间。
  3. 小白能专注上手跑模型,调参本身。配置环境的痛苦,想想你们学者最开始装Docker、Anaconda等工具的时候,一不小心环境全乱了,电脑都打不开,几个小时一事无成的感觉,懂得都懂。

However, 为了获得以上的好处,我尝试在mmdetection官网提供的tutorial 中更改,结果一言难尽。同时,目前绝大多数的mmdetection的笔记都是基于1.x版本,而且几乎没有在Colab环境的配置教程。基本所有能踩的坑我全部踩了个遍,为了纪念一下也为了给其他的目标检测学习者提供一下参考,就有了这篇笔记。
在主体上我将采用colab tutorial的框架来介绍,但是仍然强烈建议在本地安装配置好mmdetectionV2,能省下大把力气。

一、环境配置

# Check nvcc version
!nvcc -V
# Check GCC version
!gcc --version

编写时间:2020.8.11,colab预设为pytorch1.6.0 Cuda 10.1 gcc 7.5.0

# install dependencies: (use cu101 because colab has CUDA 10.1)
# 目前mmdetection只支持pytorch1.5.1及以下版本,使用1.6版本会报各种错。
!pip install -U torch==1.5.1+cu101 torchvision==0.6.1+cu101 -f https://download.pytorch.org/whl/torch_stable.html
# !pip install -U torch==1.6+cu101 torchvision==0.7.0+cu101 -f https://download.pytorch.org/whl/torch_stable.html# install mmcv-full thus we could use CUDA operators,此步需要花费大量时间,be patient
!pip install mmcv-full
# 在2020二月份pycocotools api有更新,而colab没有配置最新的包,需要在这里重新安装,看情况需不需要重启runtime
# install albumentations
!pip install -U git+https://github.com/albu/albumentations --no-cache-dir
!pip install "git+https://github.com/open-mmlab/cocoapi.git#subdirectory=pycocotools"# Install mmdetection
!rm -rf mmdetection
!git clone https://github.com/open-mmlab/mmdetection.git
%cd mmdetection!pip install -e .# install Pillow 7.0.0 back in order to avoid bug in colab
!pip install Pillow==7.0.0
# Check Pytorch installation
import torch, torchvisionprint(torch.__version__, torch.cuda.is_available())# Check MMDetection installation
import mmdetprint(mmdet.__version__)# Check mmcv installation
from mmcv.ops import get_compiling_cuda_version, get_compiler_versionprint(get_compiling_cuda_version())
print(get_compiler_version())

Output:
1.5.1+cu101
True 2.3.0
10.1
GCC 7.5

挂载在自己的drive上:

from google.colab import drivedrive.mount('/content/drive')

在colab上,使用%cd或os.chdir(’…’)来切换工作目录

import os
os.chdir('../content/drive/My Drive/mmdetection')
!pwd
!ls

output:
/content/drive/My Drive/mmdetection/mmdetection
configs docs mmdet.egg-info requirements setup.cfg tools
demo LICENSE pytest.ini requirements.txt setup.py
docker mmdet README.md resources tests

二、准备自己的数据集

这是非常重要的一步,请务必按照以下的Tree准备自己的数据集,能给自己省下大量的麻烦。

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

这次任务中,提供给我们的是voc格式的数据。第一步需要做转化,voc2coco.ipynb.
具体操作在这里不详细展开,我将来会详细写一篇各数据集转化到VOC,COCO数据集格式的文章。

Aug.14更新

本地做了mixup strategy数据增广,具体实现见后续博客。
每次做完本地的数据增广后,需要转化成COCO再重新上传。因为COCO的格式需要所有注释放在同一个json文件中,所以需要重新生成。

三:修改config文件

这里是我花了最多时间的地方,在tutorial中,官方是载入了一个config和它对应的模型,之后在colab即ipython 中用命令一行一行修改,这种方法在你非常明确MMDetectionV2的config结构和训练方式的情况下,是有一定灵活性的。但是如果不了解config的搭建方法,这会让你非常懵逼,多达一百多行的config命令实在非常难以轻松上手。这里我会介绍两种方法,一种是在本地修改好config文件上传,同时会介绍如何在colab cells中用命令修改。

3.1 文件结构

.
├── coco_exps
├── configs         #configs主要修改的部分在这里,训练config也是从这里继承的
│   ├── albu_example
│   ├── atss
│   ├── _base_          #最根本的继承
│   │   ├── datasets  #存在着不同数据集的训练方法,包含train_pipeline(augmentation), test_pipeline(TTA), data(batch_size, data root)等信息
│   │   ├── models #保存着基础模型,需要在这里修改num_classes来适配自己的任务
│   │   └── schedules #保存着lr_schedule:1x, 2x, 20e,每x意味着12个epochs
│   ├── carafe    
│   ├── cascade_rcnn
│   ├── cityscapes
│   ├── cornernet
│   ├── dcn
│   ├── deepfashion
│   ├── detectors
│   ├── double_heads
│   ├── dynamic_rcnn
│   ├── empirical_attention
│   ├── faster_rcnn
│   ├── fast_rcnn
│   ├── fcos
│   ├── foveabox
│   ├── fp16
│   ├── free_anchor
│   ├── fsaf
│   ├── gcnet
│   ├── gfl
│   ├── ghm
│   ├── gn
│   ├── gn+ws
│   ├── grid_rcnn
│   ├── groie
│   ├── guided_anchoring
│   ├── hrnet
│   ├── htc
│   ├── instaboost
│   ├── legacy_1.x
│   ├── libra_rcnn
│   ├── lvis
│   ├── mask_rcnn
│   ├── ms_rcnn
│   ├── nas_fcos
│   ├── nas_fpn
│   ├── pafpn
│   ├── pascal_voc
│   ├── pisa
│   ├── point_rend
│   ├── regnet
│   ├── reppoints
│   ├── res2net
│   ├── retinanet
│   ├── rpn
│   ├── scratch
│   ├── ssd
│   └── wider_face
├── data
│   └── coco        #把整理好的coco数据集放在这里
│       ├── annotations
│       ├── test2017
│       ├── train2017
│       └── val2017
├── mmdet            #这里存放着mmdet的一些内部构件
│   ├── datasets        #需要在这里的coco.py更改CLASSES,相当于Detectron2注册数据集
│   │   ├── pipelines
│   │   │   └── __pycache__
│   │   ├── __pycache__
│   │   └── samplers
│   │       └── __pycache__
│   ├── core         
│   │   ├── evaluation #在这里修改evaluation相关的config。如在coco_classes中修改return的classes_names

3.2 (本地)修改config文件

这里非常建议在本地修改config文件再上传到drive上,或者在colab提供的文件目录中修改。如图所示:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YfTjwL0L-1597826737896)(evernotecid://BC7CFB48-5C18-439C-ADB2-AD1171DE2741/appyinxiangcom/18838120/ENResource/p258)]

因为colab使用的ipython shell,每个参数的修改都需要使用cfg的api去修改,很容易漏项或lose track,而且mmdetection V2有一个非常精密的inherit config系统,不用结构化的IDE修改实在有点可惜。最后一点,在后期inference testset的时候,必须从.py文件中读取test_config,为什么不一劳永逸呢?

3.2.1 (本地)构造自己模型的权重文件

这里有争议,我在线训练并不需要修改权重,使用的预训练.pth模型在num_classes不匹配时会提示,然后自动适配cascade_rcnn_r50_1x.py中的num_classes。
不过修改后肯定不会错。

import torch
pretrained_weights  = torch.load('checkpoints/mask_rcnn_r50_fpn_1x_coco_20200205-d4b0c5d6.pth')num_class = 1
pretrained_weights['state_dict']['roi_head.bbox_head.fc_cls.weight'].resize_(num_class+1, 1024)
pretrained_weights['state_dict']['roi_head.bbox_head.fc_cls.bias'].resize_(num_class+1)
pretrained_weights['state_dict']['roi_head.bbox_head.fc_reg.weight'].resize_(num_class*4, 1024)
pretrained_weights['state_dict']['roi_head.bbox_head.fc_reg.bias'].resize_(num_class*4)torch.save(pretrained_weights, "mask_rcnn_r50_fpn_1x_%d.pth"%num_class)

其中num_class为你要训练数据的类别数 (不用加1) V2已经修改了,num_classes不再包含背景。

3.2.2 (本地)修改配置文件

  1. mmdet/coco.py
    在这里修改类别。
@DATASETS.register_module()
class CocoDataset(CustomDataset):#CLASSES = ('person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',#           'train', 'truck', 'boat', 'traffic light', 'fire hydrant',#          'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog',#         'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe',#           'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',#          'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat',#         'baseball glove', 'skateboard', 'surfboard', 'tennis racket',#           'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl',#          'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot',#         'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',#           'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop',#          'mouse', 'remote', 'keyboard', 'cell phone', 'microwave',#         'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock',#           'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush')#在这里修改你所需要的CLASSESCLASSES =('knife, scissors, lighter, zippooil, pressure, slingshot, handcuffs, nailpolish, powerbank, firecrackers')
  1. configs/_base_/datasets/coco_detection.py
    在train pipeline修改Data Augmentation在train
dataset_type = 'CocoDataset'
data_root = 'data/coco/'
img_norm_cfg = dict(mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
# 在这里加albumentation的aug
albu_train_transforms = [dict(type='ShiftScaleRotate',shift_limit=0.0625,scale_limit=0.0,rotate_limit=0,interpolation=1,p=0.5),dict(type='RandomBrightnessContrast',brightness_limit=[0.1, 0.3],contrast_limit=[0.1, 0.3],p=0.2),dict(type='OneOf',transforms=[dict(type='RGBShift',r_shift_limit=10,g_shift_limit=10,b_shift_limit=10,p=1.0),dict(type='HueSaturationValue',hue_shift_limit=20,sat_shift_limit=30,val_shift_limit=20,p=1.0)],p=0.1),dict(type='JpegCompression', quality_lower=85, quality_upper=95, p=0.2),dict(type='ChannelShuffle', p=0.1),dict(type='OneOf',transforms=[dict(type='Blur', blur_limit=3, p=1.0),dict(type='MedianBlur', blur_limit=3, p=1.0)],p=0.1),
]
train_pipeline = [dict(type='LoadImageFromFile'),dict(type='LoadAnnotations', with_bbox=True, with_mask=True),#据说这里改img_scale即可多尺度训练,但是实际运行报错。dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),dict(type='Pad', size_divisor=32),dict(type='Albu',transforms=albu_train_transforms,bbox_params=dict(type='BboxParams',format='pascal_voc',label_fields=['gt_labels'],min_visibility=0.0,filter_lost_elements=True),keymap={'img': 'image','gt_masks': 'masks','gt_bboxes': 'bboxes'},
#train_pipeline = [
#    dict(type='LoadImageFromFile'),
#    dict(type='LoadAnnotations', with_bbox=True),
#    dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
#    dict(type='RandomFlip', flip_ratio=0.5),
#    dict(type='Normalize', **img_norm_cfg),
#    dict(type='Pad', size_divisor=32),
#    dict(type='DefaultFormatBundle'),
#    dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']),]
# 测试的pipeline
test_pipeline = [dict(type='LoadImageFromFile'),dict(type='MultiScaleFlipAug',# 多尺度测试 TTA在这里修改,注意有些模型不支持多尺度TTA,比如cascade_mask_rcnn,若不支持会提示# Unimplemented Errorimg_scale=(1333, 800),flip=False,transforms=[dict(type='Resize', keep_ratio=True),dict(type='RandomFlip'),dict(type='Normalize', **img_norm_cfg),dict(type='Pad', size_divisor=32),dict(type='ImageToTensor', keys=['img']),dict(type='Collect', keys=['img']),])
]
# 包含batch_size, workers和路径。
# 路径如果按照上面的设置好就不需要更改
data = dict(samples_per_gpu=2,workers_per_gpu=2,train=dict(type=dataset_type,ann_file=data_root + 'annotations/instances_train2017.json',img_prefix=data_root + 'train2017/',pipeline=train_pipeline),val=dict(type=dataset_type,ann_file=data_root + 'annotations/instances_val2017.json',img_prefix=data_root + 'val2017/',pipeline=test_pipeline),test=dict(type=dataset_type,ann_file=data_root + 'annotations/instances_val2017.json',img_prefix=data_root + 'val2017/',pipeline=test_pipeline))
evaluation = dict(interval=1, metric='bbox')

其中,batch_size和路径等频繁修改的参数在colab中可以快速修改:

# 举例
cfg.samples_per_gpu = 4
cfg.data.train.ann_file = '...'
cfg.data.train.img_prefix = '...'
cfg.data.train.pipeline = train_pipeline
  1. configs/_base_/models/cascade_rcnn_r50_fpn.py
    我们选用的是dcn/cascade_rcnn_r101_20e.py模型进行训,mmdetectionV2的继承比较复杂,但是可维护性较好。一路到底,最根本的继承还是base model中的cascade_rcnn_r50_fpn.py,主要的改动也是在这里进行。
# model settings
model = dict(type='CascadeRCNN',pretrained='torchvision://resnet50',backbone=dict(type='ResNet',depth=50,num_stages=4,out_indices=(0, 1, 2, 3),frozen_stages=1,norm_cfg=dict(type='BN', requires_grad=True),norm_eval=True,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_generator=dict(type='AnchorGenerator',scales=[8],ratios=[0.5, 1.0, 2.0],strides=[4, 8, 16, 32, 64]),bbox_coder=dict(type='DeltaXYWHBBoxCoder',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)),# 在这里修改num_classes.    roi_head=dict(type='CascadeRoIHead',# 3个stage就意味着要改三个num_classesnum_stages=3,stage_loss_weights=[1, 0.5, 0.25],bbox_roi_extractor=dict(type='SingleRoIExtractor',roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0),out_channels=256,featmap_strides=[4, 8, 16, 32]),bbox_head=[dict(type='Shared2FCBBoxHead',in_channels=256,fc_out_channels=1024,roi_feat_size=7,# 这里修改,原为80.注意这里不需要加BG类(+1)num_classes=10,bbox_coder=dict(type='DeltaXYWHBBoxCoder',target_means=[0., 0., 0., 0.],target_stds=[0.1, 0.1, 0.2, 0.2]),reg_class_agnostic=True,loss_cls=dict(type='CrossEntropyLoss',use_sigmoid=False,loss_weight=1.0),loss_bbox=dict(type='SmoothL1Loss', beta=1.0,loss_weight=1.0)),dict(type='Shared2FCBBoxHead',in_channels=256,fc_out_channels=1024,roi_feat_size=7,# 这里修改,原为80.注意这里不需要加BG类(+1)num_classes=10,bbox_coder=dict(type='DeltaXYWHBBoxCoder',target_means=[0., 0., 0., 0.],target_stds=[0.05, 0.05, 0.1, 0.1]),reg_class_agnostic=True,loss_cls=dict(type='CrossEntropyLoss',use_sigmoid=False,loss_weight=1.0),loss_bbox=dict(type='SmoothL1Loss', beta=1.0,loss_weight=1.0)),dict(type='Shared2FCBBoxHead',in_channels=256,fc_out_channels=1024,roi_feat_size=7,# 这里修改,原为80.注意这里不需要加BG类(+1)num_classes=10,bbox_coder=dict(type='DeltaXYWHBBoxCoder',target_means=[0., 0., 0., 0.],target_stds=[0.033, 0.033, 0.067, 0.067]),reg_class_agnostic=True,loss_cls=dict(type='CrossEntropyLoss',use_sigmoid=False,loss_weight=1.0),loss_bbox=dict(type='SmoothL1Loss', beta=1.0, loss_weight=1.0))]))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,# 在这里可以修改为'soft_nms'nms=dict(type='nms', iou_threshold=0.5),max_per_img=100))
  1. mmdetection/configs/_base_/default_runtime.py /
    这里比较简单,我是为了要用Tensorboard查看训练,所以在这里解掉注释。
    可以从官网下载预训练模型,放在checkpoint/…文件夹中,在这里的load_from中写入路径就可以加载权重训练了。
checkpoint_config = dict(interval=1)
# yapf:disable
log_config = dict(interval=50,hooks=[dict(type='TextLoggerHook'),# 解掉注释就能看到Tensorboard了dict(type='TensorboardLoggerHook')])
# yapf:enable
# 在这里也可以修改load_from 和 resume_from
dist_params = dict(backend='nccl')
log_level = 'INFO'
load_from = None
resume_from = None
workflow = [('train', 1)]

这里,load_from和resume_from都可以在colab上在线设置

cfg.load_from = ’...'
cfg.resume_from = '...'
  1. mmdetection/configs/_base_/schedules/schedule_20e.py
    这里是调整学习率的schedule的位置,可以设置warmup schedule和衰减策略。
    1x, 2x分别对应12epochs和24epochs,20e对应20epochs,这里注意配置都是默认8块gpu的训练,如果用一块gpu训练,需要在lr/8
# optimizer
optimizer = dict(type='SGD', lr=0.02/8, momentum=0.9, weight_decay=0.0001)
optimizer_config = dict(grad_clip=None)
# learning policy
lr_config = dict(policy='step',warmup='linear',warmup_iters=500,warmup_ratio=0.001,step=[16, 19])
total_epochs = 20
  1. mmdetection/mmdet/core/evaluation/class_names.py
    这里把coco_classes改成自己对应的class名称,不然在evaluation的时候返回的名称不对应。
def coco_classes():return ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train','truck', 'boat', 'traffic_light', 'fire_hydrant', 'stop_sign','parking_meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep','cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella','handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard','sports_ball', 'kite', 'baseball_bat', 'baseball_glove', 'skateboard','surfboard', 'tennis_racket', 'bottle', 'wine_glass', 'cup', 'fork','knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange','broccoli', 'carrot', 'hot_dog', 'pizza', 'donut', 'cake', 'chair','couch', 'potted_plant', 'bed', 'dining_table', 'toilet', 'tv','laptop', 'mouse', 'remote', 'keyboard', 'cell_phone', 'microwave','oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase','scissors', 'teddy_bear', 'hair_drier', 'toothbrush']return ['knife, scissors, lighter, zippooil, pressure, slingshot, handcuffs, nailpolish, powerbank, firecrackers']

总结一下,需要在本地修改的参数有(以使用dcn/cascade_rcnn_r101_20e.py为例):

1.  mmdet/datasets/coco.py
2.  configs/\_base_/default_runtime.py
3.  configs/\_base_/datasets/coco_detection.py
4.  configs/\_base_/models/cascade_rcnn_r50_20e.py
5.  mmdet/core/evaluation/class_names.py

当把这些修改好的文件上传后,有时需要等待1分钟左右让colab与drive同步。

3.3 在colab上修改config

  1. 载入修改好的config
from mmcv import Config
import albumentations as albu
cfg = Config.fromfile('./configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_20e_coco.py')
  1. 可以使用以下的命令检查几个重要参数:
cfg.data.train
cfg.total_epochs
cfg.data.samples_per_gpu
cfg.resume_from
cfg.load_from
cfg.data
...
  1. 改变config中某些参数
from mmdet.apis import set_random_seed# Modify dataset type and path# cfg.dataset_type = 'Xray'
# cfg.data_root = 'Xray'cfg.data.samples_per_gpu = 4
cfg.data.workers_per_gpu = 4# cfg.data.test.type = 'Xray'
cfg.data.test.data_root = '../mmdetection_torch_1.5'
# cfg.data.test.img_prefix = '../mmdetection_torch_1.5'# cfg.data.train.type = 'Xray'
cfg.data.train.data_root = '../mmdetection_torch_1.5'
# cfg.data.train.ann_file = 'instances_train2014.json'
# # cfg.data.train.classes = classes
# cfg.data.train.img_prefix = '../mmdetection_torch_1.5'# cfg.data.val.type = 'Xray'
cfg.data.val.data_root = '../mmdetection_torch_1.5'
# cfg.data.val.ann_file = 'instances_val2014.json'
# # cfg.data.train.classes = classes
# cfg.data.val.img_prefix = '../mmdetection_torch_1.5'# modify neck classes number
# cfg.model.neck.num_outs
# modify num classes of the model in box head
# for i in range(len(cfg.model.roi_head.bbox_head)):
#     cfg.model.roi_head.bbox_head[i].num_classes = 10# cfg.data.train.pipeline[2].img_scale = (1333,800)cfg.load_from = '../mmdetection_torch_1.5/coco_exps/latest.pth'
# cfg.resume_from = './coco_exps_v3/latest.pth'# Set up working dir to save files and logs.
cfg.work_dir = './coco_exps_v4'# The original learning rate (LR) is set for 8-GPU training.
# We divide it by 8 since we only use one GPU.
cfg.optimizer.lr = 0.02 / 8
# cfg.lr_config.warmup = None
# cfg.lr_config = dict(
#     policy='step',
#     warmup='linear',
#     warmup_iters=500,
#     warmup_ratio=0.001,
#     # [7] yields higher performance than [6]
#     step=[7])
# cfg.lr_config = dict(
#     policy='step',
#     warmup='linear',
#     warmup_iters=500,
#     warmup_ratio=0.001,
#     step=[36,39])
cfg.log_config.interval = 10# # Change the evaluation metric since we use customized dataset.
# cfg.evaluation.metric = 'mAP'
# # We can set the evaluation interval to reduce the evaluation times
# cfg.evaluation.interval = 12
# # We can set the checkpoint saving interval to reduce the storage cost
# cfg.checkpoint_config.interval = 12# # Set seed thus the results are more reproducible
cfg.seed = 0
set_random_seed(0, deterministic=False)
cfg.gpu_ids = range(1)
# cfg.total_epochs = 40# # We can initialize the logger for training and have a look
# # at the final config used for training
print(f'Config:\n{cfg.pretty_text}')
  1. 使用Tensorboard进行可视化
    如果有在default_runtime中解除注释tensorboard,键入下面的命令可以开启实时更新的tensorboard可视化模块。
# Load the TensorBoard notebook extension
%load_ext tensorboard
# logdir需要填入你的work_dir/+tf_logs
%tensorboard --logdir=coco_exps_v4/tf_logs

3.5 在线训练

如果以上的configs都做了正确的修改,直接运行下面的代码就可以开始训练了。

import mmcv
import matplotlib.pyplot as plt
import copy
import os.path as ospfrom mmdet.datasets import build_dataset
from mmdet.models import build_detector
from mmdet.apis import train_detector# Build dataset
datasets = [build_dataset(cfg.data.train)]# Build the detector
model = build_detector(cfg.model, train_cfg=cfg.train_cfg, test_cfg=cfg.test_cfg)
# Add an attribute for visualization convenience
model.CLASSES = datasets[0].CLASSES# Create work_dir
mmcv.mkdir_or_exist(osp.abspath(cfg.work_dir))
print(model)
train_detector(model, datasets, cfg, distributed=False, validate=True)

这里的validate其实很玄学,有些时候运行完第一个epoch后的validate过程会中断报错。以下是我碰到的报错和解决办法:

Error: List range out of index.

一般报这个错,就要求你检查num_classes到底有没有修改正确。一定要在选用的模型的base model中修改所有的num_classes,并且注意MMDV2开始不需要num_classes+1(背景类)了。

ValueError: Expected x_max for bbox(0.94, 0.47, 1.003, 0.637, 0) to be in range[0,1], got 1.003.

这个错误是Albumentation报的错,需要检查的是configs/_base_/coco_detection.py中的数据增广albu部分是否正确,我的这个任务虽然是COCO格式的数据集但是不知道为什么需要在这里用pascal_voc格式的转化。从Coco改回pascal_voc就不报错了。

dict(type='Albu',transforms=albu_train_transforms,bbox_params=dicttype='BboxParams',format='pascal_voc',.......}

另外还有一个可能是在其他数据集转化到CoCo格式数据集的过程中代码出错,w,h需要xmax-xmin-1来转化,仔细检查一下。

OSError: Can't read data (file read failed: time = Mon May 20 00:34:07 2019
, filename = '/content/drive/My Drive/train/trainX_file1', file descriptor = 83, errno = 5, error message = 'Input/output error', buf = 0xc71d3864, total read size = 42145, bytes this sub-read = 42145, bytes actually read = 18446744073709551615, offset = 119840768)

这个是colab的bug,一般这个情况下先检查是不是指向的文件corrupt了,如果不是的话,可以试着重启runtime。如果还是不能load,可以用重新force remount,一般就会解决了。

Cuda out of memory

经典爆显存错误。需要注意的是中途停止训练后需要重启runtime才可以重置显存的占用量。所以碰到很多奇怪的错误第一件事可以尝试重新runtime。

...."Acyclic'

追溯可以看到,lr_schedule是一个pop的函数读取的,也就是说读取一次就没了。所以每次终止训练后,需要从config重新导入一次。

3.6 在线可视化模型效果

在模型训练完之后,除了看tensorboard或者log的可视化结果,也可以自己选出几个图片看看效果。

from mmdet.apis import init_detector, inference_detector, show_result_pyplot
import mmcv
import random# Use your modified config file
config_file = './configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_20e_coco.py'
# Use your trained model
checkpoint_file = './coco_exps_v4/latest.pth'
# build the model from a config file and a checkpoint file
model = init_detector(config_file, checkpoint_file, device='cuda:0')
# get random test image and visualize it with model
images = os.listdir('data/coco/test2017')
rand_num = random.randint(0, len(images))
image = 'data/coco/test2017/'+images[rand_num]
result = inference_detector(model, image)# show the results
show_result_pyplot(model, image, result)

在这里插入图片描述

可以看到20个epoch的效果还可以,检出率和准确率都还可以接受。

3.7 在线inference

时间原因我们没有做出一个在线inference的脚本。采取的方案是下载下来到本地,在本地进行inference。代码如下

from argparse import ArgumentParserfrom mmdet.apis import inference_detector, init_detector, show_result_pyplotfrom glob import glob
import os
from tqdm import tqdmdef get_single_out(result,score_thr):tmp=[i.tolist() for i in result]res=[i.tolist() for i in result]# print(res)for cls_idx,item in enumerate(tmp):if(len(item)!=0):res[cls_idx]=[i for i in item if i[4]>score_thr]# print(res)return resdef main():parser = ArgumentParser()parser.add_argument('--imgdir',default='./data/coco/test2017', help='Image file')parser.add_argument('--config',default='./configs/dcn/cascade_rcnn_r101_fpn_dconv_c3-c5_20e_coco.py', help='Config file')parser.add_argument('--checkpoint',default='coco_exps_v4/epoch_7.pth', help='Checkpoint file')parser.add_argument('--device', default='cuda:0', help='Device used for inference')parser.add_argument('--score-thr', type=float, default=0.01, help='bbox score threshold')args = parser.parse_args()imgdir=args.imgdirimgs=glob(os.path.join(imgdir,"*.jpg"))imgs.sort()out=[]# build the model from a config file and a checkpoint filemodel = init_detector(args.config, args.checkpoint, device=args.device)for imgpath in tqdm(imgs):print(imgpath)# # test a single imageresult = inference_detector(model, imgpath)single_out=get_single_out(result,args.score_thr)out.append(single_out)# # show the results# show_result_pyplot(model, imgpath, result, score_thr=args.score_thr)#将结果写入到文件中f=open('coco_exps_v4/output_8_softnms.json','w')f.write(str(out))f.close()if __name__ == '__main__':main()

最后的结果是本次比赛要求的格式,读者可以根据需要修改成适合自己的任务。

4. 延伸思考

基础的训练任务到这里就告一段落了,但是对于一个项目或者一个比赛来说,只掌握基础的训练技巧是远远不够的。比如我简短涉及到的soft_nms,多尺度训练,TTA,这些tricks可以一定程度上提高成绩,但我认为相比较聚焦于tricks,一个highlevel的视角更重要。以下是我认为完成一个任务需要具备的几个条件:

1. 对于数据的深入了解。包括但不限于:w、h的分布,分辨率的分布,目标物体的w/h比(用来确定anchor shape)
2. 整体的思路要清晰:选用不同的baseline model测试,加tricks,怎么对数据集做处理,以及实验记录。
3. 有时候算力确实是决定一个队伍能走多远的瓶颈。

5. 总结

作为一个只了解目标检测原理的小白,经过几十个小时的摸索,我能够掌握mmdetection+colab的基础操作和相关error的debug,这个过程还是比较有成就感的。中间参考了许多CSDN和知乎的大佬的博客,让我受益良多,也让我觉得有必要整理一下自己的踩坑实录,这篇文章权当做抛砖引玉,给其他大佬们一些启发。中间如果有不正确和不efficient的部分欢迎探讨。
我今后会发表更多的与目标检测相关的工具的详细教程以及论文笔记,有兴趣的朋友欢迎关注。
都看到这里了,点个赞呗。

本文链接http://smartadmin.com.cn/smartadmin/show-1159.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/251930.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

刚刚,OpenStack 第 19 个版本来了,附28项特性详细解读!

刚刚,OpenStack 第 19 个版本来了,附28项特性详细解读! OpenStack Stein版本引入了新的多云编排功能,以及帮助实现边缘计算用例的增强功能。 OpenStack由一系列相互关联的项目组成,这些项目可以以不同的组合方式组合在…

SQL作业:综合练习(二)的返评

一:作业题目:综合练习(二) 二:题目要求: 1、创建数据库CPXS,保存于E盘根目录下以自己学号姓第一个字母(阿拉伯数字大写字母)方式创建的文件夹中,初始大小5MB&…

paddlepaddle-VisualDL2.0对项目进行可视化调参

如果需要更好的阅读体验,可以在ai studio上fork该项目:使用VisualDL2.0对项目进行可视化调参 调参是深度学习必须要做的事情。数据和模型处理好后,需要进行模型训练,这个时候就需要进行调参了。一种好的参数配置,可以…

第一、二次实训作业

1.编写程序: 声明一个整型变量a,并赋初值5,在程序中判断a是奇数还是偶数,然后输出判断的结果。 package 判断奇偶; public class liux { public static void main(String[] args){ int x5; if(x%20){ System.out.println("这…

推荐一款作图工具

以前看到别人的时序图觉得好好看,然后就想这都是用的什么工具画出来的呢?然后看到了一个师兄用的这个工具,真的挺好用的。这是是试用版的界面。类图我觉着看起来效果都挺不错的。转载于:https://www.cnblogs.com/tuhooo/p/8874410.html

【codeforces】【比赛题解】#849 CF Round #431 (Div.2)

cf的比赛越来越有难度了……至少我做起来是这样。 先看看题目吧:点我。 这次比赛是北京时间21:35开始的,算是比较良心。 【A】奇数与结束 "奇数从哪里开始,又在哪里结束?梦想从何处起航,它们又是否会破灭呢&#…

PaddleDetection支持的数据格式

PaddleDetection支持的数据格式 目前#PaddleDetection支持43种数据格式:coco voc widerface。在这里我们主要说明一下如何使用自定义COCO进行目标检测、实例分割;如何使用自定义VOC数据集进行目标检测。在PaddleDetection新的版本中,我们将数…

[dts]Device Tree机制【转】

转自:https://www.cnblogs.com/aaronLinux/p/5496559.html 转自:http://blog.csdn.net/machiner1/article/details/47805069 ------------------Based on linux 3.10.24 source code 参考/documentation/devicetree/Booting-without-of.txt文档 目录 1.…

AntiSamy测试

AntiSamy为owasp针对xss提供的处理库,可以配置xml策略来决定过滤的内容,比如标签、属性、css等,自定义策略给开发人员使用成本比较高,AntiSamy也提供了几个内置的策略,其安全级别也不同,过滤的内容也不一样…

SoJpt Boot 2.2-3.8 发布,Spring Boot 使用 Jfinal 特性极速开发

开发四年只会写业务代码,分布式高并发都不会还做程序员? 在Spring Boot框架下使用Jfinal特性极速开发,可以在Spring Boot中向使用Jfinal一样使用Enjoy、Aop、Controller等一系列方法(如: getFile(), renderFile....),以及ActiveRecord SoJpt Boot&…

3轴机器人各关节运动学建立,python编程,非常容易理解

分类:机器人学 一、问题描述 如右图所示的三自由度机械臂,关节1和关节2相互垂直,关节2和关节3相互平行。如图所示,所有关节均处于初始状态。 要求: (1) 定义并标注出各关节的正方向; (2) 定义机器人基坐标系&#x…

Win 10 源码一览:0.5T 代码、400 万文件、50 万文件夹

Windows 操作系统本身是不开源的,但是近日微软内核工程师 Axel Rietschin 发表了一篇博客,带大家一窥了 Windows 10 内核的魅力。 Axel 介绍,Windows 10 与 Windows 8.x、7、Vista、XP、2000 和 NT 的代码库是相同的,其中每一代都…

JDK+Tomcat搭建JSP运行环境--JSP基础

一、搭建JSP运行环境之前需要了解的基本知识 配置JSP运行环境之前,我们需要了解JSP的运行机制。只有了解JSP运行机制后,我们才能知道为什么要搭建JSP运行环境?如何去搭建JSP运行环境?为什么要配置Tomcat、JDK? JSP(Java Sever Page)即Java服…

Docker容器的自动化监控实现

本文由 网易云 发布。 近年来容器技术不断成熟并得到应用。Docker作为容器技术的一个代表,目前也在快速发展中,基于 Docker的各种应用也正在普及,与此同时 Docker对传统的运维体系也带来了冲击。我们在建设运维平台的过程中,也需…

人工智能实战小程序之语音_前端开发

1. 人工智能实战小程序之准备工作 2. 人工智能实战小程序之语音_前端开发 今天这部分主要讲小程序前端功能的开发由于我偏后端,css是我的弱项,可能很多人和我一样开发小程序不知道如何下手,希望本篇文章对你有帮助我的学习路线是:…

当TFS/VSTS遇上Power BI

引言众所周知,要对TFS进行深入的图表分析,往往需要依赖于SQL Server Analysis Service和SQL Server Reporting Service。虽然随着TFS对敏捷项目的支持,内置了诸如累积流图、燃尽图等快捷图表;并且在最新的版本中还可以在仪表盘和查…

HashMap深度解析:一文让你彻底了解HashMap

写在前面HashMap是Map族中最为常用的一种,也是 Java Collection Framework 的重要成员。本文首先给出了 HashMap 的实质并概述了其与 Map、HashSet 的关系,紧接着给出了 HashMap 在 JDK 中的定义,并结合源码分析了其四种构造方式。最后&#…

python_线程、进程和协程

线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。 1 #!/usr/bin/env python2 #codingutf-83 __author__ yinjia4 5 6 import threading,time7 8 def show(arg):9 time.sleep(2) 10 print(线程: str(arg)) 11 12 for i in range(…

第四章:手机平板要兼顾-探究碎片

碎片是什么? 碎片(Fragment)是一种可以嵌入在活动(Activity)中的 UI 片段,它能让程序更加合理和充分的利用大屏幕的空间,因而在平板上应用的非常广泛。 碎片的使用方式 静态嵌入动态加载碎片和活…

Android Studio 3.4增可视化资源管理工具 可管理和预览项目资源

经过6个月的开发时间,网络大厂17日发布了最新版的App开发IDE Android Studio 3.4,现在就能够下载使用,除了有超过300个错误修护和稳定度增强之外,在开发、建置和测试App阶段,都推出了一些小的新功能和工具,…