본문 바로가기
딥러닝관련/Segmentation

MMSegmentation 사용하기 (구성 확인)

by 머리올리자 2022. 3. 3.

따로 정리하지 않았지만 mmsegmentation에서 Pascal VOC 데이터를 이용해 학습을 진행하였다.

 

이로 생긴 checkpoint로 inference 진행 및 mmsegmentation의 구성을 조금 살펴 보려고 한다.

 

MMsegmentation에서는 모델에 대한 정보를 불러올 때 config 파일을 적극 활용한다.

 

https://github.com/open-mmlab/mmsegmentation/tree/master/configs

 

GitHub - open-mmlab/mmsegmentation: OpenMMLab Semantic Segmentation Toolbox and Benchmark.

OpenMMLab Semantic Segmentation Toolbox and Benchmark. - GitHub - open-mmlab/mmsegmentation: OpenMMLab Semantic Segmentation Toolbox and Benchmark.

github.com

위 링크에 가보면 알겠지만 많은 모델들과,

특정 데이터들에 대해서 어떻게 파라미터를 두고 학습시켰는지에 대한 정보가 모두 담겨져 있다.

 

아래는 deeplabv3plus에 대한 모델들 정보 파일들이다.

https://github.com/open-mmlab/mmsegmentation/tree/master/configs/deeplabv3plus

 

 

하나를 열어보자

(deeplabv3plus_r50-d8_512x512_20k_voc12aug.py)

 

보면 위와 같이 특정 파일들을 참고하는 것이 보인다.

_base_ = [
    '../_base_/models/deeplabv3plus_r50-d8.py',
    '../_base_/datasets/pascal_voc12_aug.py', '../_base_/default_runtime.py',
    '../_base_/schedules/schedule_20k.py'
    ]

하나 하나씩 살펴보자.

 

우선 deeplabv3plus_r50-d8.py에 가보면 아래와  같이 되어 있는 것을 확인할 수 있다.

 

한번 쪽 살펴보자.

# https://github.com/open-mmlab/mmsegmentation/blob/master/configs/_base_/models/deeplabv3plus_r50-d8.py

# model settings
norm_cfg = dict(type='SyncBN', requires_grad=True)
model = dict(
    type='EncoderDecoder',
    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='DepthwiseSeparableASPPHead',
        in_channels=2048,
        in_index=3,
        channels=512,
        dilations=(1, 12, 24, 36),
        c1_in_channels=256,
        c1_channels=48,
        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'))

크게는 norm_cfg, model로 나눌 수 있고 더 세부적으로는

 

                                                                                norm_cfg

                                                                                model

                                                                                  - type

                                                                                  - pretrained

                                                                                  - backbone

                                                                                  - decoder_head

                                                                                  - auxiliary_head

                                                                                  - train_cfg

                                                                                  - test_cfg

 

로 나뉜 걸 알 수 있다.

 

대충 모델에 대한 정보 정의라는 걸 알 수 있겠다.

 

다음은 pascal_voc12_aug.py로 가보자

 

또 pascal_voc12.py를 참조한단다..

(타고타고 들어가기....)

# https://github.com/open-mmlab/mmsegmentation/blob/master/configs/_base_/datasets/pascal_voc12_aug.py

_base_ = './pascal_voc12.py'
# dataset settings
data = dict(
    train=dict(
        ann_dir=['SegmentationClass', 'SegmentationClassAug'],
        split=[
            'ImageSets/Segmentation/train.txt',
            'ImageSets/Segmentation/aug.txt'
        ]))

그렇게 한번 가보라는 곳으로 가보자...

 

흠... 아래와 같이 데이터셋에 대한 정보가 있는 것을 알 수 있다.

# https://github.com/open-mmlab/mmsegmentation/blob/master/configs/_base_/datasets/pascal_voc12.py

# dataset settings
dataset_type = 'PascalVOCDataset'
data_root = 'data/VOCdevkit/VOC2012'
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
crop_size = (512, 512)
train_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='LoadAnnotations'),
    dict(type='Resize', img_scale=(2048, 512), ratio_range=(0.5, 2.0)),
    dict(type='RandomCrop', crop_size=crop_size, cat_max_ratio=0.75),
    dict(type='RandomFlip', prob=0.5),
    dict(type='PhotoMetricDistortion'),
    dict(type='Normalize', **img_norm_cfg),
    dict(type='Pad', size=crop_size, pad_val=0, seg_pad_val=255),
    dict(type='DefaultFormatBundle'),
    dict(type='Collect', keys=['img', 'gt_semantic_seg']),
]
test_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(
        type='MultiScaleFlipAug',
        img_scale=(2048, 512),
        # img_ratios=[0.5, 0.75, 1.0, 1.25, 1.5, 1.75],
        flip=False,
        transforms=[
            dict(type='Resize', keep_ratio=True),
            dict(type='RandomFlip'),
            dict(type='Normalize', **img_norm_cfg),
            dict(type='ImageToTensor', keys=['img']),
            dict(type='Collect', keys=['img']),
        ])
]
data = dict(
    samples_per_gpu=4,
    workers_per_gpu=4,
    train=dict(
        type=dataset_type,
        data_root=data_root,
        img_dir='JPEGImages',
        ann_dir='SegmentationClass',
        split='ImageSets/Segmentation/train.txt',
        pipeline=train_pipeline),
    val=dict(
        type=dataset_type,
        data_root=data_root,
        img_dir='JPEGImages',
        ann_dir='SegmentationClass',
        split='ImageSets/Segmentation/val.txt',
        pipeline=test_pipeline),
    test=dict(
        type=dataset_type,
        data_root=data_root,
        img_dir='JPEGImages',
        ann_dir='SegmentationClass',
        split='ImageSets/Segmentation/val.txt',
        pipeline=test_pipeline))

대충 살펴보면 크게

 

                                                                           어떤 데이터?

                                                                           데이터 경로?

                                                                           normalization 값?

                                                                           crop 값?

                                                                           train pipeline

                                                                           test pipline

                                                                           data에 대한 정보

 

 

데이터에 대해서 어떻게 학습하고 테스트할 것인지, 데이터를 어떻게 처리할 것인지에 대한 내용으로 보인다.

 

다음은 default_runtime.py으로 가보자

 

오.. 다른 것보다 짧다...

 

꼭 필요한 거 몇개 보면

보면 얼마마다 log를 보여줄 것인지(interval)

어디서 weight를 load할 것인지(load_from)

학습을 다시 시작하는 것인지(resume_from)

 

등으로 볼 수 있겠다.

 

# https://github.com/open-mmlab/mmsegmentation/blob/master/configs/_base_/default_runtime.py

# yapf:disable
log_config = dict(
    interval=50,
    hooks=[
        dict(type='TextLoggerHook', by_epoch=False),
        # dict(type='TensorboardLoggerHook')
    ])
# yapf:enable
dist_params = dict(backend='nccl')
log_level = 'INFO'
load_from = None
resume_from = None
workflow = [('train', 1)]
cudnn_benchmark = True

 

 

마지막으로 ../_base_/schedules/schedule_20k.py로 가보자

 

흠.. 학습에 대한 정보가 전체적으로 나와있는 듯 하다.

 

optimizer라던지, learning rate라던지, runner, checkpoint라던지, evaluation이라던지 등등...

# https://github.com/open-mmlab/mmsegmentation/blob/master/configs/_base_/schedules/schedule_20k.py
  
# optimizer
optimizer = dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0005)
optimizer_config = dict()
# learning policy
lr_config = dict(policy='poly', power=0.9, min_lr=1e-4, by_epoch=False)
# runtime settings
runner = dict(type='IterBasedRunner', max_iters=20000)
checkpoint_config = dict(by_epoch=False, interval=2000)
evaluation = dict(interval=2000, metric='mIoU', pre_eval=True)

 

Inference 코드를 실행할 때(training 할 때도 그러겠지만) 위와 같이 config파일들을 불러와 결합하여 실험을 진행한다.

 

cfg = mmcv.Config.fromfile(args.config)

코드 상에 있는 내용을 dictionary의 key, value 처럼 출력해보면

 

아래와 같은 정보가 출력된 것을 확인할 수 있다.

 

 

norm_cfg {'type': 'SyncBN', 'requires_grad': True}
model {'type': 'EncoderDecoder', 'pretrained': 'open-mmlab://resnet50_v1c', 'backbone': {'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': {'type': 'SyncBN', 'requires_grad': True}, 'norm_eval': False, 'style': 'pytorch', 'contract_dilation': True}, 'decode_head': {'type': 'DepthwiseSeparableASPPHead', 'in_channels': 2048, 'in_index': 3, 'channels': 512, 'dilations': (1, 12, 24, 36), 'c1_in_channels': 256, 'c1_channels': 48, 'dropout_ratio': 0.1, 'num_classes': 21, 'norm_cfg': {'type': 'SyncBN', 'requires_grad': True}, 'align_corners': False, 'loss_decode': {'type': 'CrossEntropyLoss', 'use_sigmoid': False, 'loss_weight': 1.0}}, 'auxiliary_head': {'type': 'FCNHead', 'in_channels': 1024, 'in_index': 2, 'channels': 256, 'num_convs': 1, 'concat_input': False, 'dropout_ratio': 0.1, 'num_classes': 21, 'norm_cfg': {'type': 'SyncBN', 'requires_grad': True}, 'align_corners': False, 'loss_decode': {'type': 'CrossEntropyLoss', 'use_sigmoid': False, 'loss_weight': 0.4}}, 'train_cfg': {}, 'test_cfg': {'mode': 'whole'}}
dataset_type PascalVOCDataset
data_root data/VOCdevkit/VOC2012
img_norm_cfg {'mean': [123.675, 116.28, 103.53], 'std': [58.395, 57.12, 57.375], 'to_rgb': True}
crop_size (512, 512)
train_pipeline [{'type': 'LoadImageFromFile'}, {'type': 'LoadAnnotations'}, {'type': 'Resize', 'img_scale': (2048, 512), 'ratio_range': (0.5, 2.0)}, {'type': 'RandomCrop', 'crop_size': (512, 512), 'cat_max_ratio': 0.75}, {'type': 'RandomFlip', 'prob': 0.5}, {'type': 'PhotoMetricDistortion'}, {'type': 'Normalize', 'mean': [123.675, 116.28, 103.53], 'std': [58.395, 57.12, 57.375], 'to_rgb': True}, {'type': 'Pad', 'size': (512, 512), 'pad_val': 0, 'seg_pad_val': 255}, {'type': 'DefaultFormatBundle'}, {'type': 'Collect', 'keys': ['img', 'gt_semantic_seg']}]
test_pipeline [{'type': 'LoadImageFromFile'}, {'type': 'MultiScaleFlipAug', 'img_scale': (2048, 512), 'flip': False, 'transforms': [{'type': 'Resize', 'keep_ratio': True}, {'type': 'RandomFlip'}, {'type': 'Normalize', 'mean': [123.675, 116.28, 103.53], 'std': [58.395, 57.12, 57.375], 'to_rgb': True}, {'type': 'ImageToTensor', 'keys': ['img']}, {'type': 'Collect', 'keys': ['img']}]}]
data {'samples_per_gpu': 4, 'workers_per_gpu': 2, 'train': {'type': 'PascalVOCDataset', 'data_root': 'data/VOCdevkit/VOC2012', 'img_dir': 'JPEGImages', 'ann_dir': ['SegmentationClass', 'SegmentationClassAug'], 'split': ['ImageSets/Segmentation/train.txt', 'ImageSets/Segmentation/aug.txt'], 'pipeline': [{'type': 'LoadImageFromFile'}, {'type': 'LoadAnnotations'}, {'type': 'Resize', 'img_scale': (2048, 512), 'ratio_range': (0.5, 2.0)}, {'type': 'RandomCrop', 'crop_size': (512, 512), 'cat_max_ratio': 0.75}, {'type': 'RandomFlip', 'prob': 0.5}, {'type': 'PhotoMetricDistortion'}, {'type': 'Normalize', 'mean': [123.675, 116.28, 103.53], 'std': [58.395, 57.12, 57.375], 'to_rgb': True}, {'type': 'Pad', 'size': (512, 512), 'pad_val': 0, 'seg_pad_val': 255}, {'type': 'DefaultFormatBundle'}, {'type': 'Collect', 'keys': ['img', 'gt_semantic_seg']}]}, 'val': {'type': 'PascalVOCDataset', 'data_root': 'data/VOCdevkit/VOC2012', 'img_dir': 'JPEGImages', 'ann_dir': 'SegmentationClass', 'split': 'ImageSets/Segmentation/val.txt', 'pipeline': [{'type': 'LoadImageFromFile'}, {'type': 'MultiScaleFlipAug', 'img_scale': (2048, 512), 'flip': False, 'transforms': [{'type': 'Resize', 'keep_ratio': True}, {'type': 'RandomFlip'}, {'type': 'Normalize', 'mean': [123.675, 116.28, 103.53], 'std': [58.395, 57.12, 57.375], 'to_rgb': True}, {'type': 'ImageToTensor', 'keys': ['img']}, {'type': 'Collect', 'keys': ['img']}]}]}, 'test': {'type': 'PascalVOCDataset', 'data_root': 'data/VOCdevkit/VOC2012', 'img_dir': 'JPEGImages', 'ann_dir': 'SegmentationClass', 'split': 'ImageSets/Segmentation/val.txt', 'pipeline': [{'type': 'LoadImageFromFile'}, {'type': 'MultiScaleFlipAug', 'img_scale': (2048, 512), 'flip': False, 'transforms': [{'type': 'Resize', 'keep_ratio': True}, {'type': 'RandomFlip'}, {'type': 'Normalize', 'mean': [123.675, 116.28, 103.53], 'std': [58.395, 57.12, 57.375], 'to_rgb': True}, {'type': 'ImageToTensor', 'keys': ['img']}, {'type': 'Collect', 'keys': ['img']}]}]}}
log_config {'interval': 1, 'hooks': [{'type': 'TextLoggerHook', 'by_epoch': False}]}
dist_params {'backend': 'nccl'}
log_level INFO
load_from None
resume_from None
workflow [('train', 1)]
cudnn_benchmark True
optimizer {'type': 'SGD', 'lr': 0.01, 'momentum': 0.9, 'weight_decay': 0.0005}
optimizer_config {}
lr_config {'policy': 'poly', 'power': 0.9, 'min_lr': 0.0001, 'by_epoch': False}
runner {'type': 'IterBasedRunner', 'max_iters': 20000}
checkpoint_config {'by_epoch': False, 'interval': 500}
evaluation {'interval': 500, 'metric': 'mIoU', 'pre_eval': True}