[MMSeg] 사용하기

반디·2023년 6월 18일
0

개발기

목록 보기
5/16

설치

(GPU 환경)

conda create --name openmmlab python=3.8 -y
conda activate openmmlab

conda install pytorch torchvision -c pytorch

pip install -U openmim
mim install mmengine
mim install "mmcv>=2.0.0"

git clone -b main https://github.com/open-mmlab/mmsegmentation.git #main branch를 HEAD로 clone
cd mmsegmentation
pip install -v -e .
# '-v': 함수 수행 시 발생하는 정보들을 표준 출력으로 내보냄
# '-e': 코드 수정이 가능한 모드로 설치

https://mmsegmentation.readthedocs.io/en/latest/get_started.html

Config 파일 알아보기

MMSeg는 config 파일을 기반으로 실행됩니다. dataset, model, scheduler 등의 정보를 config 파일에 작성하여 실행합니다.

configs-_base_에는 datasets, models, schedules 세 개의 폴더와 default_runtime.py가 있습니다.

  • datasets: 데이터에 따른 pipeline과 dataloader 구성 정보 등
  • models: 모델 구성 정보
  • schedules: optimizer 구성 정보
  • default_runtime.py: 실행 환경에 대한 기본값

_base_의 component들로 구성된 config를 primitive라 하며, 같은 폴더 안의 config 파일들에 대해서는 오직 하나의 primitivie config 파일만 있는 것을 권장합니다.
예를 들어, DeepLabV3의 모델 구조를 변경하여 학습하는 상황을 생각해봅니다.
1. _base_-models-deeplabv3 안에 있는 모델들 중 하나를 선택하여 상속합니다.

_base_ = ../deeplabv3/deeplabv3_r50-d8_4xb2-40k_cityscapes-512x1024.py
  1. 변경할 구조를 덧씌우는 형태로 새로운 config 파일을 작성합니다.
model = dict(
    type='CustomEncoderDecoder',
)
...

_base_-models안에 없는 새로운 모델을 구성할 경우, folder를 새로 만들고 그 안에 configs 파일을 생성합니다.

custom dataset 구성

Step 1. configs-_base_-datasets에서 config 파일 구성
Step 2. mmseg-models-datasets에서 Dataset 모듈 등록 + __init__.py에도 등록

Step 1. configs-_base_-datasets에서 config 파일 구성

구성하고자 하는 형식에 맞추어 train_pipeline, test_pipeline, train_dataloader, val_dataloader, test_dataloader, val_evaluator, test_evalutator를 구성합니다.

ex) (built-in file) cityscapes.py

# dataset settings
dataset_type = 'CityscapesDataset'
data_root = 'data/cityscapes/'
crop_size = (512, 1024)
train_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='LoadAnnotations'),
    dict(
        type='RandomResize',
        scale=(2048, 1024),
        ratio_range=(0.5, 2.0),
        keep_ratio=True),
    dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75),
    dict(type='RandomFlip', prob=0.5),
    dict(type='PhotoMetricDistortion'),
    dict(type='PackSegInputs')
]
test_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='Resize', scale=(2048, 1024), keep_ratio=True),
    # add loading annotation after ``Resize`` because ground truth
    # does not need to do resize data transform
    dict(type='LoadAnnotations'),
    dict(type='PackSegInputs')
]
img_ratios = [0.5, 0.75, 1.0, 1.25, 1.5, 1.75]
tta_pipeline = [
    dict(type='LoadImageFromFile', backend_args=None),
    dict(
        type='TestTimeAug',
        transforms=[
            [
                dict(type='Resize', scale_factor=r, keep_ratio=True)
                for r in img_ratios
            ],
            [
                dict(type='RandomFlip', prob=0., direction='horizontal'),
                dict(type='RandomFlip', prob=1., direction='horizontal')
            ], [dict(type='LoadAnnotations')], [dict(type='PackSegInputs')]
        ])
]
train_dataloader = dict(
    batch_size=2,
    num_workers=2,
    persistent_workers=True,
    sampler=dict(type='InfiniteSampler', shuffle=True),
    dataset=dict(
        type=dataset_type,
        data_root=data_root,
        data_prefix=dict(
            img_path='leftImg8bit/train', seg_map_path='gtFine/train'),
        pipeline=train_pipeline))
val_dataloader = dict(
    batch_size=1,
    num_workers=4,
    persistent_workers=True,
    sampler=dict(type='DefaultSampler', shuffle=False),
    dataset=dict(
        type=dataset_type,
        data_root=data_root,
        data_prefix=dict(
            img_path='leftImg8bit/val', seg_map_path='gtFine/val'),
        pipeline=test_pipeline))
test_dataloader = val_dataloader

val_evaluator = dict(type='IoUMetric', iou_metrics=['mIoU'])
test_evaluator = val_evaluator

Step 2-1. mmseg-datasets에서 Dataset 모듈 등록
ex) cityscapes.py

# Copyright (c) OpenMMLab. All rights reserved.
from mmseg.registry import DATASETS
from .basesegdataset import BaseSegDataset


@DATASETS.register_module()
class CityscapesDataset(BaseSegDataset):
    """Cityscapes dataset.

    The ``img_suffix`` is fixed to '_leftImg8bit.png' and ``seg_map_suffix`` is
    fixed to '_gtFine_labelTrainIds.png' for Cityscapes dataset.
    """
    METAINFO = dict(
        classes=('road', 'sidewalk', 'building', 'wall', 'fence', 'pole',
                 'traffic light', 'traffic sign', 'vegetation', 'terrain',
                 'sky', 'person', 'rider', 'car', 'truck', 'bus', 'train',
                 'motorcycle', 'bicycle'),
        palette=[[128, 64, 128], [244, 35, 232], [70, 70, 70], [102, 102, 156],
                 [190, 153, 153], [153, 153, 153], [250, 170,
                                                    30], [220, 220, 0],
                 [107, 142, 35], [152, 251, 152], [70, 130, 180],
                 [220, 20, 60], [255, 0, 0], [0, 0, 142], [0, 0, 70],
                 [0, 60, 100], [0, 80, 100], [0, 0, 230], [119, 11, 32]])

    def __init__(self,
                 img_suffix='_leftImg8bit.png',
                 seg_map_suffix='_gtFine_labelTrainIds.png',
                 **kwargs) -> None:
        super().__init__(
            img_suffix=img_suffix, seg_map_suffix=seg_map_suffix, **kwargs)

Step 2-2. __init__.py에도 등록

# Copyright (c) OpenMMLab. All rights reserved.
# yapf: disable
from .cityscapes import CityscapesDataset

# yapf: enable
__all__ = ['CityscapesDataset']

custom model 구성

configs-_base_-models에서 model에 대한 configuration 파일을 구성합니다.

data preprocessor, segmentor, backbone, decode_head 등을 설정할 수 있습니다.

ex) (built-in file)

# model settings
norm_cfg = dict(type='SyncBN', requires_grad=True)
data_preprocessor = dict(
    type='SegDataPreProcessor',
    mean=[123.675, 116.28, 103.53],
    std=[58.395, 57.12, 57.375],
    bgr_to_rgb=True,
    pad_val=0,
    seg_pad_val=255)
model = dict(
    type='EncoderDecoder',
    data_preprocessor=data_preprocessor,
    pretrained='open-mmlab://resnet50_v1c',
    backbone=dict(
        type='ResNetV1c',
        depth=50,
        num_stages=4,
        out_indices=(0, 1, 2, 3),
        dilations=(1, 1, 2, 4),
        strides=(1, 2, 1, 1),
        norm_cfg=norm_cfg,
        norm_eval=False,
        style='pytorch',
        contract_dilation=True),
    decode_head=dict(
        type='ANNHead',
        in_channels=[1024, 2048],
        in_index=[2, 3],
        channels=512,
        project_channels=256,
        query_scales=(1, ),
        key_pool_scales=(1, 3, 6, 8),
        dropout_ratio=0.1,
        num_classes=19,
        norm_cfg=norm_cfg,
        align_corners=False,
        loss_decode=dict(
            type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0)),
    auxiliary_head=dict(
        type='FCNHead',
        in_channels=1024,
        in_index=2,
        channels=256,
        num_convs=1,
        concat_input=False,
        dropout_ratio=0.1,
        num_classes=19,
        norm_cfg=norm_cfg,
        align_corners=False,
        loss_decode=dict(
            type='CrossEntropyLoss', use_sigmoid=False, loss_weight=0.4)),
    # model training and testing settings
    train_cfg=dict(),
    test_cfg=dict(mode='whole'))

custom backbones, decode_heads, losses, necks, segmentors

mmseg-models 하위의 backbones, decode_heads, losses, necks, segmentors 폴더에서 새로운 구조를 등록할 수 있습니다. 단, 새로운 구조를 만들고 나서 반드시 각 폴더의 __init__.py에 등록을 해주어야 합니다.

profile
꾸준히!

0개의 댓글