본문 바로가기

컴린이 탈출기/Vision

공부하며 정리해보는 MMDetection 튜토리얼 🤖 (2) - Model, Runtime Setting (Optimizer, Scheduler 등), Finetuning Models, Weight Initialization

반응형

https://mmdetection.readthedocs.io/en/latest/

 

Welcome to MMDetection’s documentation! — MMDetection 2.15.0 documentation

© Copyright 2018-2021, OpenMMLab Revision 604bfe96.

mmdetection.readthedocs.io

MMDetection 공식 문서를 공부하며 정리한 글입니다!
오역한 부분이나 자연스러운 표현을 위해 의역한 부분이 있을 수 있습니다.
잘못된 내용에 대한 댓글로 부탁드립니다. :)



이전 글

공부하며 정리해보는 MMDetection 튜토리얼 🤖 (1) - Config, Dataset, Data Pipelines

 

Customize Models

MMDet은 기본적으로 모델을 5가지 요소로 구분한다.

◾ Backbone - 피처맵을 추출하기 위한 FCN 네트워크 (ex. ResNet, MobileNet)
◾ neck - backbone과 head 사이를 연결하는 요소 (ex. FPN, PAFPN)
◾ head - 구체적인 태스크를 위한 요소 (ex. bbox prediction, mask prediction)
◾ roi extractor - 피처맵으로부터 RoI 특징을 추출하는 부분 (ex. RoI Align)
◾ loss - loss를 계산하기 위한 head의 구성 요소 (ex. FocalLoss, L1Loss, GHMLoss)

 

Develop new components - Add a new backbone

제공되지 않는 새로운 모델을 추가하는 방법을 알아보자. 이와 유사한 방법으로 Neck, Head, Loss도 추가할 수 있다. (문서 참고)

1. Define a new backbone

다음과 같은 새로운 파일을 만든다. (mmdet/models/backbones/mobilenet.py)

import torch.nn as nn
from ..builder import BACKBONES

@BACKBONES.register_module()
class MobileNet(nn.Module):
	
    def __init__(self, arg1, arg2):
    	pass
        
    def forward(self, x): # should return a tuple
    	pass

2. Import the module

mmdet/models/backbones/__init__.py에 다음과 같은 줄을 추가한다.

from .mobilenet import MobileNet

3. Use the backbone in your config file

model = dict(
    ...
    backbone=dict(
        type='MobileNet',
        arg1=xxx,
        arg2=xxx),
    ...

 

+ model config의 기본 구성은 다음과 같다.

# 1 stage model
model = dict(
	type = 'RetinaNet',
    pretrained='torchvision://resnet50',
    backbone=dict(
        type='ResNet',
        depth=50,
        num_stages=4,
        out_indices=(0, 1, 2, 3),
        frozen_stages=1,
        norm_cfg=dict(type='BN', requires_grad=True),
        norm_eval=True,
        style='pytorch'),
    neck= dict(),
    bbox_head = dict(),
    
    train_cfg = dict(),
    test_cfg = dict()
)

backbone, neck 등 각각의 부분은 위와 같이 여러 아규먼트를 갖고, 이 아규먼트 값을 데이터, 모델링에 맞게 변경해주면 된다.

 

+ 헷갈리는 config들 😨

mmdetection은 두 군데에 모델과 관련한 config들을 가지고 있다.

1) configs/__base__/models

이 config들은 말 그대로 base가 되는 config들로 cascade mask rcnn, faster rcnn 등 각각의 모델을 정의한다. backbone, neck, rpn_head, roi_head 등 모델 정보, train_cfg, test_cfg 등의 정보가 담겨있다.

2) configs/ ...

__base__ 폴더와 같은 레벨에 있는 모델과 같은 이름을 가진 폴더 안에 있는 config이다. 모델 config 외에도 데이터셋, 옵티마이저에 관한 config를 모두 상속받는다. train 코드에서 최종적으로 이 py 파일을 config로 불러와 사용하게 된다.

 

Customize Runtime Settings

Customize optimization settings - Customize optimizer supported by Pytorch

MMDet은 Pytorch에서 지원하는 optimizer는 모두 지원하기 때문에 config 파일의 optimizer 필드만 수정해주면 된다. 만약 ADAM을 쓰고 싶다면 다음과 같이 수정하면 된다.

optimizer = dict(type='Adam', lr=0.0003, weight_decay=0.0001)

 

# Additional settings

Optimizer로 실행할 수 없는 트릭들은 optimizer constructor 혹은 hook을 통해 실행한다. 다음은 학습을 안정화 혹은 가속화시킬 수 있는 몇 가지 일반적인 세팅들이다.

- Use gradient clip to stabilize training

optimizer_config = dict (
	_delete_ = True,
    grad_clip = dict(max_norm=35, norm_type=2))

- Use momentum schedule to accelerate model convergence

lr_config = dict(
    policy='cyclic',
    target_ratio=(10, 1e-4),
    cyclic_times=1,
    step_ratio_up=0.4,
)
momentum_config = dict(
    policy='cyclic',
    target_ratio=(0.85 / 0.95, 1),
    cyclic_times=1,
    step_ratio_up=0.4,
)

 

Customize training schedules

learning scheduler의 디폴트 세팅은 MMCV에서 StepLRHook이라 불리는 1x schedule의 step learning rate이다. MMDet은 CosineAnnealing이나 Poly schedule과 같은 많은 lr schedule을 제공한다.

# Poly
lr_config = dict(policy='poly', power=0.9, min_lr=1e-4, by_epoch=False)

# CosineAnnealing
lr_config = dict(
    policy='CosineAnnealing',
    warmup='linear',
    warmup_iters=1000,
    warmup_ratio=1.0 / 10,
    min_lr_ratio=1e-5)

 

Customize workflow

Workflow는 동작 순서와 epoch을 명시하는 (phase, epochs) 리스트로 디폴트는 다음과 같다.

workflow = [('train',1)]

 

Valid set에 대해서 loss나 accuracy 등을 체크하고 싶은 경우에는 다음과 같이 workflow를 설정하면 된다.

workflow = [('train', 1), ('val', 1)]

 

Customize hooks

Training pipeline과 Hook

# Use hooks implemented in MMCV

MMCV에서 실행 가능한 hook은 config를 수정해 곧바로 사용할 수 있다.

custom_hooks = [dict(type='NumClassCheckHook')]

custom_hooks를 통해 등록되지 않아도 되는 log_config / checkpoint_config / evaluation / lr_config / optimizer_config / momentum_config과 같은 hook도 있다.

 

Finetuning Models

이번 튜토리얼에서는 Model Zoo가 제공하는 모델들을 사용하는 방법을 알아보자.

새로운 데이터셋에 모델을 finetuning 하는 방법에는 두 가지 단계가 있다.

1. 새로운 데이터셋 커스터마이징
2. config 수정 

이번 튜토리얼에서는 2번에 대해 주요하게 다뤄볼 예정이다.

 

Inherit base configs

Config를 작성할 때의 부담이나 에러를 줄이기 위해서는 MMDet이 지원하는 config들을 상속받는 것이 좋다. 예를 들어 Mask RCNN을 finetuning 할 때 새로운 config는 __base__/models/mask_rcnn_r50_fpn.py 를 상속받아 기본 모델 구조를 세우는 것이 좋다. Cityscape 데이터셋을 이용할 때는 __base__/datasets/cityscapes_instance.py를, runtime setting config를 작성할 때는  __base__/default_runtime.py 을 상속받는 것이 좋다. 이러한 config들은 configs 디렉토리에 위치한다.

Modify head

새로운 데이터셋의 class 개수에 맞게 새로운 config의 head 부분을 수정해주어야 한다. roi_head의 num_classes만을 수정하게 되면, final prediction head를 제외한 대부분의 부분에서 pretrained 웨이트가 재사용된다.

Modify dataset

사용자는 데이터셋을 준비하고 그에 대한 config를 작성해야 한다. 현재 MMDet은 VOC, WIDER FACE, COCO, Cityscapes 데이터셋을 지원한다.

Modify training schedule

finetuning 시의 하이퍼파라미터는 디폴트 schedule로부터 다양해질 수 있다. 보통 작은 learning rate와 적은 training epoch을 요구한다.

Use pre-trained model

Pre-trained 모델을 사용하기 위해서는 새로운 config의 load_from 필드에 pre-trained 모델의 링크를 추가해줘야 한다.

 

Weight initialization

학습 시 적절한 initialization 전략은 학습 속도를 높이거나 혹은 좋은 성능을 얻게 해 준다. MMCV는 nn.Conv2d에 쓰이는 몇몇 일반적인 init 모듈을 제공한다. MMdet에서는 주로 init_cfg를 통해 모델 initialization을 한다. 사용자들은 다음 두 단계를 따라 모델을 초기화할 수 있다.

1. 모델을 위한 init_cfg 혹은 model_cfg의 요소를 정의한다.
2.일반적으로 모델을 빌드하되, model.init_weights() 메서드를 실행시킨다.

MMDet에서의 고급 initialization workflow는 다음과 같다:model_cfg(init_cfg) → build_from_cfg → model → init_weight() → initialize(self, self.init_cfg) → children's init_weight()

 

Initialize parameters

mmcv.runner.BaseModule 혹은 mmdet.models로부터 새로운 모델을 상속받아 예를 들어보자.

import torch.nn as nn
from mmcv.runner import BaseModule

class FooModel(BaseModule)
	def __init__(self,
                 arg1,
                 arg2,
                 init_cfg=None):
    	super(FooModel, self).__init__(init_cfg)

 

# Initialize model by using init_cfg directly in code

import torch.nn as nn
from mmcv.runner import BaseModule
# or directly inherit mmdet models

class FooModel(BaseModule)
	def __init__(self,
                arg1,
                arg2,
                init_cfg=XXX):
		super(FooModel, self).__init__(init_cfg)
	    ...

# Initialize model by using init_cfg directly in mmcv.Sequential or mmcv.ModuleList code

from mmcv.runner import BaseModule, ModuleList

class FooModel(BaseModule)
	def __init__(self,
            	arg1,
            	arg2,
            	init_cfg=None):
		super(FooModel, self).__init__(init_cfg)
    	...
    	self.conv1 = ModuleList(init_cfg=XXX)

# Initialize model by using init_cfg in config file

model = dict(
	...
	model = dict(
    	type='FooModel',
    	arg1=XXX,
    	arg2=XXX,
    	init_cfg=XXX),
        ...
반응형