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하지만 문서에는 두 개의 테이블이 있고 Object Detection인스턴스 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
  • Rider, My bike, Moveable, Lane Mark, Road, Undivable 총 6개의 카테고리가 있음을 알 수 있습니다.

구성 파일 수정

  • 구성 파일에 대한 자세한 설명은 블로그에서 MMDetection 프레임워크를 교육 및 테스트 하고 MMSegmentation을 사용하여 Mask2Former 모델을 미세 조정하는 전체 프로세스에 대한 자세한 지침을 제공 합니다 .
  • 주요 수정은 사전 훈련 가중치 경로, 이미지 경로, 주석 파일 경로, batch_size학습 epochs속도 스케일링,범주의 수, 다중 카드에서 단일 카드로(SyncBN --> BN),범주 레이블 및 팔레트
  • 범주 번호와 범주 레이블 및 팔레트의 두 가지 매개 변수에 주의를 기울이십시오. 그렇지 않으면 오류가 보고됩니다 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),
    ]
}
  • 대문자 CLASSESPALETTE새 버전에서는 더 이상 적용되지 않으며 소문자로 변경하면 저장되지 않습니다.
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