MMDetection は、インスタンスのセグメンテーション タスク用に RTMDet モデルを微調整します。

序文

  • 前回のブログでは、MMdetectionフレームワークはターゲット検出タスクに適しているだけでなく、インスタンスのセグメンテーション タスクも実行できます。
  • ただし、MMdetectionフレームワークの公式プロジェクトのインスタンス セグメンテーション タスクに関するチュートリアル ファイルは、フレームワークのバージョンの更新により、実際の動作中にエラーが報告されるため、この記事は主に、フレームワークの新しいバージョンのインスタンス セグメンテーションに関するチュートリアルですcannot import name 'build_dataset' from 'mmdet.datasets'。フレームワーク
  • 公式データセットのデータ量がballoon少なすぎるため、ここではkaggleプラットフォーム上のMotorcycle Night Rideデータセットを使用します。データアドレス
  • 次のコードはすべて、環境kaggleプラットフォーム上で実行されます。GPUP100

環境構成

import IPython.display as display

!pip install openmim
!mim install mmengine==0.7.2
!pip install -q /kaggle/input/frozen-packages-mmdetection/mmcv-2.0.1-cp310-cp310-linux_x86_64.whl

!rm -rf mmdetection
!git clone https://github.com/open-mmlab/mmdetection.git
!git clone https://github.com/open-mmlab/mmyolo.git
%cd mmdetection

!mkdir ./data
%pip install -e .

!pip install wandb
display.clear_output()
  • wandbトレーニング プロセスを視覚化するためにプラットフォームを使用しているため、wandb最初にプラットフォームにログインする必要もあります。
import wandb
wandb.login()

事前トレーニングされたモデルの推論

  • まず、微調整が必​​要なRTMDet-lモデルの重みをダウンロードし、テスト画像上で推論を実行します。ちなみに、環境が完成しているかどうかを確認することもできます。
  • モデル番号については、configs/rtmdetプロジェクト ファイルの下にあります。Readme.mdただし、ドキュメントには と の 2 つのテーブルがあることObject Detection注意してくださいInstance Segmentation。これはインスタンスのセグメンテーション タスクであるため、`Instance Segmentation` テーブルでモデル モデルを検索する必要があります。
    ここに画像の説明を挿入
!mkdir ./checkpoints
!mim download mmdet --config rtmdet-ins_l_8xb32-300e_coco --dest ./checkpoints
  • テスト画像のモデル推論
import mmcv
import mmengine
from mmdet.apis import init_detector, inference_detector
from mmdet.utils import register_all_modules

config_file = 'configs/rtmdet/rtmdet-ins_l_8xb32-300e_coco.py'

checkpoint_file = 'checkpoints/rtmdet-ins_l_8xb32-300e_coco_20221124_103237-78d1d652.pth'

register_all_modules()

model = init_detector(config_file, checkpoint_file, device='cuda:0')

image = mmcv.imread('demo/demo.jpg',channel_order='rgb')
result = inference_detector(model, image)

from mmdet.registry import VISUALIZERS
visualizer = VISUALIZERS.build(model.cfg.visualizer)
visualizer.dataset_meta = model.dataset_meta

visualizer.add_datasample('result',image,data_sample=result,draw_gt = None,wait_time=0,)

display.clear_output()
visualizer.show()

画像の説明を追加してください

データの探索と視覚化

  • データセットの名前が長すぎるため、画像フォルダーとアノテーション ファイルをここのプロジェクト フォルダー内のdataサブフォルダーにコピーします。
import os
import shutil

def copy_files(src_folder, dest_folder):
    # 确保目标文件夹存在
    os.makedirs(dest_folder, exist_ok=True)

    # 遍历源文件夹中的所有内容
    for root, _, files in os.walk(src_folder):
        for file in files:
            # 拼接源文件的完整路径
            src_file_path = os.path.join(root, file)

            # 拼接目标文件的完整路径
            dest_file_path = os.path.join(dest_folder, os.path.relpath(src_file_path, src_folder))

            # 确保目标文件的文件夹存在
            os.makedirs(os.path.dirname(dest_file_path), exist_ok=True)

            # 复制文件
            shutil.copy(src_file_path, dest_file_path)

source_folder = '/kaggle/input/motorcycle-night-ride-semantic-segmentation/www.acmeai.tech ODataset 1 - Motorcycle Night Ride Dataset'
destination_folder = './data'
copy_files(source_folder, destination_folder)
  • データの視覚化。視覚化されたグラフがデータセットにすでに提供されているため、元のグラフと注釈付きのグラフを一緒に比較します。
import mmcv
import matplotlib.pyplot as plt

img_og = mmcv.imread('data/images/Screenshot (446).png')
img_fuse = mmcv.imread('data/images/Screenshot (446).png___fuse.png')

fig, axes = plt.subplots(1, 2, figsize=(15, 10))
axes[0].imshow(mmcv.bgr2rgb(img_og))
axes[0].set_title('Original Image')
axes[0].axis('off')

axes[1].imshow(mmcv.bgr2rgb(img_fuse))
axes[1].set_title('mask Image')
axes[1].axis('off')
plt.show()

画像の説明を追加してください

  • pycocotoolsライブラリを使用してアノテーションファイルを読み込み、カテゴリ情報を出力します
from pycocotools.coco import COCO

# 初始化COCO对象
coco = COCO('data/COCO_motorcycle (pixel).json')

# 获取所有的类别标签和对应的类别ID
categories = coco.loadCats(coco.getCatIds())
category_id_to_name = {
    
    cat['id']: cat['name'] for cat in categories}

display.clear_output()
# 打印所有类别ID和对应的类别名称
for category_id, category_name in category_id_to_name.items():
    print(f"Category ID: {
      
      category_id}, Category Name: {
      
      category_name}")
  • 出力:
Category ID: 1329681, Category Name: Rider
Category ID: 1323885, Category Name: My bike
Category ID: 1323884, Category Name: Moveable
Category ID: 1323882, Category Name: Lane Mark
Category ID: 1323881, Category Name: Road
Category ID: 1323880, Category Name: Undrivable
  • 合計 6 つのカテゴリがあることがわかります。つまり、ライダー、マイバイク、移動可能、レーンマーク、道路、運転不能です。

設定ファイルを変更する

  • 構成ファイルの詳細な説明については、ブログで MMDetection フレームワークのトレーニングとテストおよびMMSegmentation を使用したMask2Formerモデルの微調整のプロセス全体に関する詳細な手順を説明しています。
  • 主な変更は、トレーニング前のウェイト パス、画像パス、アノテーション ファイル パス、、、batch_size学習epochs率スケーリング、カテゴリの数、マルチカードからシングルカードへ (SyncBN --> BN)、カテゴリのラベルとパレット
  • カテゴリ番号とカテゴリ ラベルとパレットの 2 つのパラメータに十分注意してください。そうでないと、エラーが報告されます。class EpochBasedTrainLoop in mmengine/runner/loops.py: class CocoDataset in mmdet/datasets/coco.py: need at least one array to concatenateこの種のエラーは非常によく発生します。カテゴリ番号とラベルの情報が正しいかどうかを確認する必要があります。
from mmengine import Config
cfg = Config.fromfile('./configs/rtmdet/rtmdet-ins_l_8xb32-300e_coco.py')
from mmengine.runner import set_random_seed

cfg.load_from = 'checkpoints/rtmdet-ins_l_8xb32-300e_coco_20221124_103237-78d1d652.pth'

cfg.work_dir = './work_dir'

cfg.max_epochs = 100
cfg.stage2_num_epochs = 7
cfg.train_dataloader.batch_size = 4
cfg.train_dataloader.num_workers = 2

scale_factor = cfg.train_dataloader.batch_size / (8 * 32)

cfg.base_lr *= scale_factor
cfg.optim_wrapper.optimizer.lr = cfg.base_lr

# cfg.model.backbone.frozen_stages = 4
cfg.model.bbox_head.num_classes = 6

# 单卡训练时,需要把 SyncBN 改成 BN
cfg.norm_cfg = dict(type='BN', requires_grad=True)

cfg.metainfo = {
    
    
    'classes': ('Rider', 'My bike', 'Moveable', 'Lane Mark', 'Road', 'Undrivable', ),
    'palette': [
        (141, 211, 197),(255, 255, 179),(190, 186, 219),(245, 132, 109),(127, 179, 209),(251, 180, 97),
    ]
}

cfg.data_root = './data'

cfg.train_dataloader.dataset.ann_file = 'COCO_motorcycle (pixel).json'
cfg.train_dataloader.dataset.data_root = cfg.data_root
cfg.train_dataloader.dataset.data_prefix.img = 'images/'
cfg.train_dataloader.dataset.metainfo = cfg.metainfo


cfg.val_dataloader.dataset.ann_file = 'COCO_motorcycle (pixel).json'
cfg.val_dataloader.dataset.data_root = cfg.data_root
cfg.val_dataloader.dataset.data_prefix.img = 'images/'
cfg.val_dataloader.dataset.metainfo = cfg.metainfo


cfg.test_dataloader = cfg.val_dataloader

cfg.val_evaluator.ann_file = cfg.data_root+'/'+'COCO_motorcycle (pixel).json'
cfg.val_evaluator.metric = ['segm']

cfg.test_evaluator = cfg.val_evaluator

cfg.default_hooks.checkpoint = dict(type='CheckpointHook', interval=10, max_keep_ckpts=2, save_best='auto')
cfg.default_hooks.logger.interval = 20

cfg.custom_hooks[1].switch_epoch = 300 - cfg.stage2_num_epochs

cfg.train_cfg.max_epochs = cfg.max_epochs
cfg.train_cfg.val_begin = 20
cfg.train_cfg.val_interval = 2
cfg.train_cfg.dynamic_intervals = [(300 - cfg.stage2_num_epochs, 1)]

# cfg.train_dataloader.dataset = dict(dict(type='RepeatDataset',times=5,dataset = cfg.train_dataloader.dataset))

cfg.param_scheduler[0].end = 100

cfg.param_scheduler[1].eta_min = cfg.base_lr * 0.05
cfg.param_scheduler[1].begin = cfg.max_epochs // 2
cfg.param_scheduler[1].end = cfg.max_epochs
cfg.param_scheduler[1].T_max = cfg.max_epochs //2

set_random_seed(0, deterministic=False)

cfg.visualizer.vis_backends.append({
    
    "type":'WandbVisBackend'})

#------------------------------------------------------
config=f'./configs/rtmdet/rtmdet-ins_l_1xb4-100e_motorcycle.py'
with open(config, 'w') as f:
    f.write(cfg.pretty_text)
  • トレーニングを開始する
!python tools/train.py {
    
    config}
  • モデルの最高のパフォーマンスを示すインジケーターの値を表示します
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.561
 Average Precision  (AP) @[ IoU=0.50      | area=   all | maxDets=100 ] = 0.758
 Average Precision  (AP) @[ IoU=0.75      | area=   all | maxDets=100 ] = 0.614
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.017
 Average Precision  (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.195
 Average Precision  (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.633
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=  1 ] = 0.543
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets= 10 ] = 0.645
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=   all | maxDets=100 ] = 0.649
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.036
 Average Recall     (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.246
 Average Recall     (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.721
07/23 19:31:52 - mmengine - INFO - segm_mAP_copypaste: 0.561 0.758 0.614 0.017 0.195 0.633
07/23 19:31:52 - mmengine - INFO - Epoch(val) [98][40/40]    coco/segm_mAP: 0.5610  coco/segm_mAP_50: 0.7580  coco/segm_mAP_75: 0.6140  coco/segm_mAP_s: 0.0170  coco/segm_mAP_m: 0.1950  coco/segm_mAP_l: 0.6330  data_time: 0.0491  time: 3.1246

トレーニングプロセスを視覚化する

  • プラットフォームにログインして、wandbトレーニングプロセス中のインジケーターの変化を確認できます。

ここに画像の説明を挿入
ここに画像の説明を挿入

  • segm_mAPまだ値が上がっているのがわかりますが、今回は時間の関係で100本しか走れepochませんでしたが、実際に試してみるなら300本も走ってみるとさらに効果が期待できます。

テスト画像の推論

  • トレーニングが完了したら、最高のパフォーマンスのモデルをロードし、テスト画像で推論を実行します。
from mmengine.visualization import Visualizer
import mmcv
from mmdet.apis import init_detector, inference_detector
import glob

img = mmcv.imread('data/images/Screenshot (446).png',channel_order='rgb')

checkpoint_file = glob.glob('./work_dir/best_coco_segm_mAP*.pth')[0]

model = init_detector(cfg, checkpoint_file, device='cuda:0')

new_result = inference_detector(model, img)

visualizer_now = Visualizer.get_current_instance()

visualizer_now.dataset_meta = model.dataset_meta

visualizer_now.add_datasample('new_result', img, data_sample=new_result, draw_gt=False, wait_time=0, out_file=None, pred_score_thr=0.5)

visualizer_now.show()

画像の説明を追加してください

トラブルシューティング

  • 公式がいくつかの非常に一般的な問題のトラブルシューティングに関する文書を作成しました。アドレスをここに載せておきます。
  • 実行中に遭遇した最も頻繁なエラーは、valueerror-need-at-least-one-array-to-concatenate上記の公式トラブルシューティングマニュアルにも説明されています。カテゴリ、タグ、パレットの数を確認するため、確認しましたがそのような問題はなく、最終的に別の要因でこのエラーが発生する可能性があることがわかりました
  • フレームワークのアップデートにより、ラベルとパレット書き方が変わりました。間違った書き方は次のとおりです。
cfg.metainfo = {
    
    
    'CLASSES': ('Rider', 'My bike', 'Moveable', 'Lane Mark', 'Road', 'Undrivable', ),
    'PALETTE': [
        (141, 211, 197),(255, 255, 179),(190, 186, 219),(245, 132, 109),(127, 179, 209),(251, 180, 97),
    ]
}
  • 大文字CLASSESの と はPALETTE新しいバージョンでは適用されなくなりました。小文字に変更したい場合は保存されません。
cfg.metainfo = {
    
    
    'classes': ('Rider', 'My bike', 'Moveable', 'Lane Mark', 'Road', 'Undrivable', ),
    'palette': [
        (141, 211, 197),(255, 255, 179),(190, 186, 219),(245, 132, 109),(127, 179, 209),(251, 180, 97),
    ]
}

おすすめ

転載: blog.csdn.net/qq_20144897/article/details/131887980