MMDetection 入門使用教學

張家銘
13 min readJan 22, 2022

MMDetection 是商湯和港中文大學針對物件偵測推出的一個開源工具箱,它基於 PyTorch 實現了大量的物件偵測算法,目前支援了 11 種 Backbone、56 種物件偵測算法:

  • Backbone: VGG、ResNet、Swin 等
  • Anchor-based: R-CNN 系列、YOLOv3、SSD、RetinaNet 等
  • Anchor-free: FCOS、ATSS、YOLOX 等
  • Transformer: DETR 等

這個工具箱把資料集建構、模型搭建、訓練策略等過程都封裝成了模塊,通過模塊調用的方式,能夠以很少的代碼量實現一個新算法,大大提高了代碼複用率。

安裝 MMDetection

推薦使用 MIM 來安裝 MMDetection,:

$ pip install openmim
$ mim install mmdet
$ git clone https://github.com/open-mmlab/mmdetection.git
$ cd mmdetection

MIM 能夠自動的安裝 OpenMMLab 的項目以及對應的依賴包。

驗證

為了驗證是否正確安裝了 MMDetection 和所需的環境,我們可以運行範例的 Python 代碼來初始化偵測器並推理一個影像:

Config 解說

作者為了可以提高代碼複用率,所以 config 支持繼承的操作,通過 _base_ 變量來實現,_base_ 是一個 list 類型變量,裡面存放的是要繼承配置文件的路徑,任何配置文件往上追朔都會繼承以下四種類型的文件:

  • 模型(models)
  • 資料集 (datasets)
  • 訓練策略(schedules)
  • 運行時的默認配置 (default_runtime)

配置文件名稱的命名風格如下:

{model}_{backbone}_{neck}_{schedule}_{dataset}
  • {model}: model 種類,例如:faster_rcnn, mask_rcnn 等。
  • {backbone}:Backbone 種類,例如:r50 (ResNet-50), x101 (ResNeXt-101) 等。
  • {neck}:Neck 種類,例如:fpn, pafpn, nasfpn, c4 等。
  • {schedule}: 訓練方案,選項是 1x、 2x、 20e 等。1x 和 2x 分別代表 12 epoch 和 24 epoch,20e 在級聯 (Cascaded) 模型中使用,表示 20 epoch。
    {dataset}:資料集,例如:coco、 cityscapes、 voc_0712、 wider_face 等。

這邊看一下基本的 faster_rcnn_r50_fpn_1x_coco.py 長怎樣:

_base_ = [
'../_base_/models/faster_rcnn_r50_fpn.py', # models
'../_base_/datasets/coco_detection.py', # datasets
'../_base_/schedules/schedule_1x.py', # schedules
'../_base_/default_runtime.py' # default_runtime
]

我們將 faster_rcnn_r50_fpn_1x_coco.py 裡面的 Models, Datasets, schedules, default_runtime 的配置文件給各位看一下:

Models 配置文件

這邊只寫出文件重點,如果想看詳細配置可以看 faster_rcnn_r50_fpn.py

model = dict(
type='FasterRCNN', # 偵測模型名稱
backbone=dict(type='ResNet', ...), # Backbone
neck=dict(type='FPN', ...), # Neck
roi_head=dict(
type='StandardRoIHead', # Head
...,
loss_cls=dict(type='CrossEntropyLoss', ...), # 分類損失函數
loss_bbox=dict(type='L1Loss', ...) # 迴歸損失函數
),
train_cfg=dict(
assigner=dict(...), # BBox Assigner
sampler=dict(...), # BBox Sampler
...
),
test_cfg=dict(
nms=dict(...), # NMS後處理
...
)
)

Datasets 配置文件

這邊只寫出文件重點,如果想看詳細配置可以看 coco_detection.py

dataset_type = 'CocoDataset'      # 資料集名稱
data_root = 'data/coco/' # 資料集根目錄
img_norm_cfg = dict(...) # 影像標準化
train_pipeline = [...] # 訓練資料處理Pipeline
test_pipeline = [...] # 測試資料處理Pipeline
data = dict(
samples_per_gpu=2, # 每張GPU上的 batch_size
workers_per_gpu=2, # GPU數量
train=dict( # 訓練集配置
type=dataset_type,
ann_file='...', # 標註資料集
img_prefix='...', # 影像位置前綴
pipeline=train_pipeline), # 訓練資料處理Pipeline
val=dict(...), # 驗證集配置
test=dict(...), # 測試集配置
evaluation = dict(interval=1, metric='bbox')

Schedules 配置文件

這邊只寫出文件重點,如果想看詳細配置可以看 sehedules_1x.py

optimizer = dict(type='SGD', ...) # 學習優化器
optimizer_config = dict(...)
lr_config = dict(...) # 學習率策略
runner = dict( # 跑12個epochs
type='EpochBasedRunner',
max_epochs=12)

default_runtime 配置文件

這邊只寫出文件重點,如果想看詳細配置可以看 default_runtime.py

checkpoint_config = dict(interval=1) # checkpoint 的保存間隔
log_config = dict(
interval=50, # 印出 log 的間隔
hooks=[dict(...)]) # 記錄 log 的記錄器
dist_params = dict(backend='nccl') # 設置分佈式訓練的參數
log_level = 'INFO' # log 的級別
load_from = None # 加載預訓練模型
resume_from = None # 從 checkpoint 恢復訓練
workflow = [('train', 1)] # runner 的工作流程
work_dir = '...' # checkpoint 的保存路徑

如果想改一點配置內容,例如想將原本的 l1loss 改成用 iou loss,那可以先繼承 faster_rcnn_r50_fpn_1x_coco.py 後,再去改動 model 中 loss 的部份,例如 faster_rcnn_r50_fpn_iou_1x_coco.py

_base_ = './faster_rcnn_r50_fpn_1x_coco.py'
model = dict(
roi_head=dict(
bbox_head=dict(
reg_decoded_bbox=True,
loss_bbox=dict(type='IoULoss', loss_weight=10.0))))

由於多層的繼承和模塊化可能會很難看到 config 的全貌,這邊提供了方便的工具可以檢查配置文件,可以使用 print_config.py 將整個架構印出來,並輸出成 config.txt 檔:

# python tools/misc/print_config.py $CONFIG_FILE_PATH
$ python tools/misc/print_config.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py > config.txt

訓練自己的資料集

官方提供 COCO 格式來訓練,那我們來教如何訓練自己的資料集。

1.標記資料

可以先使用 label 工具來進行 label,推薦使用 labelimg

  • windows 用戶:可以直接去下載編譯好的版本 labelimg
  • mac 用戶:使用 pip install labelimg 安裝,再用 labelimg 指令打開程式

使用 Open Dir 讀進自己的資料集,label 完後存成 PascalVOC 格式方便做之後的處理

存成 PascalVOC 格式可以得到對應的 xml 檔案

2.轉換成 COCO 格式

我們需要將標記好的 xml 檔資料轉換成 COCO 的格式,先將標記好的資料放在 mmdetection/datasets 裡,裡面要包含訓練的影像 (jpg) 和對應的標註 (xml),這邊提供我標記好的汽車檔案,接著我們使用 train_val_data_split_coco.py 來生成對應的資料夾結構和切分資料集,這邊設置的比例為 9:1,大家也可自行調整

$ cd mmdetection/datasets
$ wget https://github.com/d246810g2000/mmdetection/blob/main/data.zip?raw=true -O data.zip
$ unzip data.zip
$ wget https://raw.githubusercontent.com/d246810g2000/mmdetection/main/train_val_data_split_coco.py
$ python train_val_data_split_coco.py

執行完後會得到指定的資料夾結構和對應的 instances_train2017.json 和 instances_val2017.json 檔

  • annotations 放對應的 instances_train2017.json 和 instances_val2017.json 檔
  • train2017 放訓練集影像
  • val2017 放驗證集影像

3. 修改配置文件

我們選擇用 faster_rcnn 來示範,首先 _base_ 先繼承 ‘./faster_rcnn_r50_fpn_1x_coco.py’,接著再給裡面類別的部分,這邊只有一個類別,所以我們將 80 改成 1,以下為實際範例:

這邊有提供貼心的工具去可視化你的標註結果,如果有成功畫出來就代表是可以訓練的,我把它放在 vis_gt 這個資料夾中:

$ python tools/misc/browse_dataset.py --output-dir vis_gt configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco_car.py
用 browse_dataset.py 可視化的結果

4. 開始訓練

由於車子的資料太少,訓練效果不易見,這邊我使用貓狗資料集來訓練,公開資料集在此:https://public.roboflow.com/object-detection/oxford-pets/2

單 GPU 訓練:

$ python ./tools/train.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco_pet.py

多 GPU 訓練:

$ ./tools/dist_train.sh configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco_pet.py

訓練歷史分析:

$ python ./tools/analysis_tools/analyze_logs.py plot_curve work_dirs/faster_rcnn_r50_fpn_1x_coco_pet/20220122_170738.log.json --out vis_log --keys bbox_mAP
train history

5. 模型測試

$ python ./tools/test.py configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco_pet.py work_dirs/faster_rcnn_r50_fpn_1x_coco_pet/latest.pth --eval bbox
測試結果

6. 模型推理

command line 使用:

$ python demo/image_demo.py demo/cat.jpg configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco_pet.py work_dirs/faster_rcnn_r50_fpn_1x_coco_pet/latest.pth

還有高層 python API 的使用:

推理結果

Reference

--

--