この記事は?
mmdetectionという物体検出モデルを簡単に利用&構築できる、最近便利に使わせていただいているツールの紹介です。
色々な人が使い方を紹介してくださっている上に、公式にもわかりやすいチュートリアルがあるので自分で記事を書くのもどうかと思ったのですが、一応さらに簡潔でわかりやすいものを目指して書いています。
このツール、データセットさえ用意すればConfigの編集だけである程度なんでもできるので、ぜひ試してみてください。
1. mmdetのインストール
公式のチュートリアルではgithubからcloneしてインストールしていますが、直接pipでインストールできます。
1-1. CUDAのバージョンを確認
あとで必要になるので確認します。
nvcc -V
# nvcc: NVIDIA (R) Cuda compiler driver
# Copyright (c) 2005-2020 NVIDIA Corporation
# Built on Mon_Oct_12_20:09:46_PDT_2020
# Cuda compilation tools, release 11.1, V11.1.105
# Build cuda_11.1.TC455_06.29190527_0
1-2. pytorchのバージョンを確認
こちらも後で必要になるので確認します。
import torch
print(torch.__version__)
# 1.10.0+cu111
print(torch.cuda.is_available())
# True
1-3. mmcvをpipでインストールする
mmdetはmmcvの機能を前提としています。以下の方法でインストールしましょう。
pip install mmcv-full -f https://download.openmmlab.com/mmcv/dist/cu111/torch1.10.0/index.html
ここで、cu111
, torch1.10.0
の部分を先ほど確かめた自分の環境に合わせた数字に置き換えてください。
- mmcv-fullのバージョンが新しすぎると入らない場合があります。
少し古いバージョンを指定してインストールすると上手く動作することがあるようです
pip install mmcv-full==1.4.5 -f https://...
など
1-4. mmdetectionをpipでインストールする
これはとても簡単です。
pip install mmdet
2. 推論を行い動作確認する
2-1. 必要なデータのダウンロード
モデルのデータをダウンロードします。
configファイルを持ってくるためにgithubから公式リポジトリをcloneしていますが、必要なのはconfigs
, tools
, demo
の3つのフォルダのみです。
mkdir checkpoints
wget -c https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco_20210526_095054-1f77628b.pth \
-O checkpoints/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco_20210526_095054-1f77628b.pth
git clone https://github.com/open-mmlab/mmdetection.git
2-2. 推論の実行
公式チュートリアルとconfigへのパスが異なるだけで、同じです。
import mmcv
from mmcv.runner import load_checkpoint
from mmdet.apis import inference_detector, show_result_pyplot
from mmdet.models import build_detector
config = './mmdetection/configs/faster_rcnn/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco.py'
checkpoint = './checkpoints/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco_20210526_095054-1f77628b.pth'
device='cuda:0'
config = mmcv.Config.fromfile(config)
config.model.pretrained = None. # checkpointを読み込むのでいらない
model = build_detector(config.model)
checkpoint = load_checkpoint(model, checkpoint, map_location=device)
# 推論前にクラス数とconfigファイルを読み込ませる必要がある
model.CLASSES = checkpoint['meta']['CLASSES']
model.cfg = config
model.to(device)
model.eval()
# 推論の実行と結果の表示
img = './mmdetection/demo/demo.jpg'
result = inference_detector(model, img)
show_result_pyplot(model, img, result)
こんな画像が表示されたら成功です。
推論だけでしたら、configとcheckpointの部分さえ変えてしまえば動きます。
3. 独自データで訓練を行う
ここからが本番です。
公式では独自のデータに対応させる方法が詳しく書かれていますが、基本的にCOCOなどの形式に沿って独自データを変換してあげたほうが楽です。
ここでは例として、Instance Segmentationのチュートリアルで取り上げられているbaloonデータセットに対して訓練を行ってみます。コードは前述のチュートリアルから引用させていただきました。
3-1. データセットの準備
まず、データをダウンロードします。
!wget https://github.com/matterport/Mask_RCNN/releases/download/v2.1/balloon_dataset.zip
!unzip balloon_dataset.zip > /dev/null
次に、データをCOCO形式へ変換します。
(データによってここは異なるため、非表示にしています。)
convert_balloon_to_coco
import os.path as osp
def convert_balloon_to_coco(ann_file, out_file, image_prefix):
data_infos = mmcv.load(ann_file)
annotations = []
images = []
obj_count = 0
for idx, v in enumerate(mmcv.track_iter_progress(data_infos.values())):
filename = v['filename']
img_path = osp.join(image_prefix, filename)
height, width = mmcv.imread(img_path).shape[:2]
images.append(dict(
id=idx,
file_name=filename,
height=height,
width=width))
bboxes = []
labels = []
masks = []
for _, obj in v['regions'].items():
assert not obj['region_attributes']
obj = obj['shape_attributes']
px = obj['all_points_x']
py = obj['all_points_y']
poly = [(x + 0.5, y + 0.5) for x, y in zip(px, py)]
poly = [p for x in poly for p in x]
x_min, y_min, x_max, y_max = (
min(px), min(py), max(px), max(py))
data_anno = dict(
image_id=idx,
id=obj_count,
category_id=0,
bbox=[x_min, y_min, x_max - x_min, y_max - y_min],
area=(x_max - x_min) * (y_max - y_min),
segmentation=[poly],
iscrowd=0)
annotations.append(data_anno)
obj_count += 1
coco_format_json = dict(
images=images,
annotations=annotations,
categories=[{'id':0, 'name': 'balloon'}])
mmcv.dump(coco_format_json, out_file)
convert_balloon_to_coco(
'balloon/train/via_region_data.json',
'balloon/train/annotation_coco.json',
'balloon/train/')
convert_balloon_to_coco(
'balloon/val/via_region_data.json',
'balloon/val/annotation_coco.json',
'balloon/val/')
これでCOCO形式のデータが用意できました。
3-2. Configの編集
ここが1番重要です。
データに合わせてプリセットのConfigを書き換えていきます。
from mmdet.apis import set_random_seed
# COCO形式のデータが読み込めるように変更
cfg.dataset_type = 'COCODataset'
# アノテーションファイルの場所、画像ファイルの場所、クラス名を記載
# train, validは訓練中に、testはテスト中に使用されるデータの定義
cfg.data.train.ann_file = 'balloon/train/annotation_coco.json'
cfg.data.train.img_prefix = 'balloon/train/'
cfg.data.train.classes = ('balloon',)
cfg.data.val.ann_file = 'balloon/val/annotation_coco.json'
cfg.data.val.img_prefix = 'balloon/val/'
cfg.data.val.classes = ('balloon',)
# ここではvalidと同じにしておく
cfg.data.test.ann_file = 'balloon/val/annotation_coco.json'
cfg.data.test.img_prefix = 'balloon/val/'
cfg.data.test.classes = ('balloon',)
# モデルの出力クラス数を変更
cfg.model.roi_head.bbox_head.num_classes = 1
# 事前学習モデルがある場合には
cfg.load_from = './checkpoints/faster_rcnn_r50_caffe_fpn_mstrain_3x_coco_20210526_095054-1f77628b.pth'
# logなどを吐き出す先を決定
cfg.work_dir = './tutorial_exps'
# 8GPU用に設定されている学習率を元に戻す
cfg.optimizer.lr = 0.02 / 8
cfg.lr_config.warmup = None
cfg.log_config.interval = 10
# 評価指標や評価の頻度を設定
cfg.evaluation.metric = 'bbox'
cfg.evaluation.interval = 2
cfg.checkpoint_config.interval = 2
# ランダムシードの設定
cfg.seed = 0
set_random_seed(0, deterministic=False)
cfg.gpu_ids = range(1)
# tensorboardも利用できる
cfg.log_config.hooks = [
dict(type='TextLoggerHook'),
dict(type='TensorboardLoggerHook')]
# いい感じに出力できる
# print(f'Config:\n{cfg.pretty_text}')
# ファイルとして保存もできる
cfg.dump('./my_config.py')
保存された./my_config.py
を眺めると、大体どんなことができるか掴めると思います。
3-3. モデルの訓練
ここまでくれば簡単です。
tools
以下にtrain.py
というファイルがあるので、こちらを利用します。
python ./mmdetection/tools/train.py ./my_config.py
学習済みのモデルはConfigで指定したtutorial_exps
に入っています。
学習が完了したら、先ほどと同様の手順で推論を行なってみましょう。
config = './tutorial_exps/my_config.py'
checkpoint = './tutorial_exps/latest.pth'
device='cuda:0'
config = mmcv.Config.fromfile(config)
config.model.pretrained = None
model = build_detector(config.model)
checkpoint = load_checkpoint(model, checkpoint, map_location=device)
model.CLASSES = checkpoint['meta']['CLASSES']
model.cfg = config
model.to(device)
model.eval()
img = 'balloon/val/16335852991_f55de7958d_k.jpg'
result = inference_detector(model, img)
show_result_pyplot(model, img, result)
こんな画像が表示されたら成功です。
きちんと風船が認識されているのではないでしょうか?
3-4. モデルの評価など
先ほどと同様に、configファイルさえ作ってしまえばあとはどうとでもなります。
公式ドキュメントのuseful_toolsにさまざまなツールの使い方が書いてあるので参考にしてください。
さいごに
さて、気づいたでしょうか。
実はモデルの学習を行うまでに自分で編集したファイルは、(データセット整備部分を除けば)Configファイルの生成部分だけです。
データセットの整理とConfigファイルの編集の部分さえなんとかしてしまえば、あとはmmsegmentationなどの他のmmlabが提供するツールも使えるようになるのではないでしょうか?
需要あるかわからないですが、次はConfigファイルを編集してBackboneモデルを載せ替えて訓練する記事なんかも書いてみようと思ってます。