안녕하세요. 이 글에서는 MMSegmentation의 Config 파일에 대해 알아보겠습니다.
Config 파일이란 MMSegmentation에서 다양한 실험을 수행하기 편리하게 만들어 둔 디자인입니다.
Config 파일 예시
mmsegmentation/configs/pspnet/pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py
_base_ = [
'../_base_/models/pspnet_r50-d8.py', '../_base_/datasets/cityscapes.py',
'../_base_/default_runtime.py', '../_base_/schedules/schedule_40k.py'
]
crop_size = (512, 1024)
data_preprocessor = dict(size=crop_size)
model = dict(data_preprocessor=data_preprocessor)
위와 같이 Config 파일에서는 models, datasets, schedules, default_runtime.py 총 네 개의 구성을 사용합니다.
이전 글에서 mmsegmentation을 설치하셨다면, mmsegmentation 폴더를 확인할 수 있습니다.
mmsegmentation/configs/_base_/datasets
mmsegmentation/configs/_base_/models
mmsegmentation/configs/_base_/schedules
mmsegmentation/configs/_base_/default_runtime.py
해당 경로에는 datasets, models, schedules, default_runtime.py 네 개의 구성이 있습니다. 이것을 원시(primitive) 설정이라고 합니다.
또한 MMCV 연구실은 기존 방법을 상속하는 것을 권장합니다. 예를 들어 DeepLabv3 모델을 사용하고 싶다면, 아래와 같이 config 파일을 상속한 후 설정 파일을 수정하는 것을 권합니다.
만약 새로운 모델을 추가하고 싶다면 configs 하위에 xxxnet 폴더를 만들어 직접 추가해야 합니다. 이 부분은 다음에 다루도록 하겠습니다.
Config 파일의 이름은 정해진 디자인을 따릅니다.
이름의 구성은 algorithm name, model component names, training settings, training dataset information, testing dataset information으로 되어 있습니다.
mmsegmentation/configs/pspnet/pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py
- algorithm name : deeplabv3, pspnet
- model component names : r50-d8
- training settings : 4xb4-ce-linearlr-40k
- training dataset information : cityscapes-512x1024
- testing dataset information (optional)
이를 각각 보자면
r50-d8 : ResNet50 백본 사용, 백본의 출력을 8배 다운샘플링하여 입력으로 사용)
4xb4 : 4 gpus x 4 images per gpu (= gpus x batch per gpu)
ce : CrossEntropy loss
linearlr : Linear learning rate scheduler
40k : train 40k iterations
cityscapes-512x1024 : Cityscapes 데이터셋 사용 입력 사이즈 512x1024
testing dataset information 언급이 없다면, train 데이터셋과 같은 데이터셋으로 테스트되었음을 의미합니다.
Config 파일은 mmsegmentation/configs/pspnet 경로의 pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py 파일을 사용합니다.
mmsegmentation/configs/pspnet/pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py
_base_ = [
'../_base_/models/pspnet_r50-d8.py', '../_base_/datasets/cityscapes.py',
'../_base_/default_runtime.py', '../_base_/schedules/schedule_40k.py'
] # 새로운 설정 파일을 만들기 위해 기존의 기본 설정 파일들을 포함합니다.
crop_size = (512, 1024)
data_preprocessor = dict(size=crop_size)
model = dict(data_preprocessor=data_preprocessor)
이제 각각의 구성 파일을 살펴봅시다.
mmsegmentation/configs/base/models/pspnet_r50-d8.py 파일을 열어보겠습니다.
# 모델 설정
norm_cfg = dict(type='SyncBN', requires_grad=True)
# 세그멘테이션은 일반적으로 SyncBN을 사용합니다.
data_preprocessor = dict(
# 데이터 전처리기의 설정, 일반적으로 이미지 정규화와 augmentation을 포함합니다.
type='SegDataPreProcessor', # 데이터 전처리기의 유형.
mean=[123.675, 116.28, 103.53], # 입력 이미지를 정규화하는 데 사용되는 평균 값.
std=[58.395, 57.12, 57.375], # 입력 이미지를 정규화하는 데 사용되는 표준 편차.
bgr_to_rgb=True, # 이미지를 BGR에서 RGB로 변환할 지 여부.
pad_val=0, # 이미지의 패딩 값.
seg_pad_val=255) # 세그멘테이션 맵의 패딩 값.
model = dict(
type='EncoderDecoder', # 세그멘터의 이름
data_preprocessor=data_preprocessor,
pretrained='open-mmlab://resnet50_v1c', # 로드할 ImageNet 사전 훈련된 백본
backbone=dict(
type='ResNetV1c', # 백본의 유형. 자세한 내용은 mmseg/models/backbones/resnet.py를 참조하십시오.
depth=50, # 백본의 깊이. 보통 50, 101이 사용됩니다.
num_stages=4, # 백본의 스테이지 수.
out_indices=(0, 1, 2, 3), # 각 스테이지에서 생성된 출력 피쳐 맵의 인덱스.
dilations=(1, 1, 2, 4), # 각 레이어의 확장 비율.
strides=(1, 2, 1, 1), # 각 레이어의 스트라이드.
norm_cfg=norm_cfg, # norm 레이어의 구성.
norm_eval=False, # BN의 통계를 얼릴지 여부
style='pytorch', # 백본의 스타일, 'pytorch'는 stride 2 레이어가 3x3 conv에 있음을 의미합니다.
contract_dilation=True), # dilation > 1인 경우 첫 번째 레이어를 contract할 지 여부.
decode_head=dict(
type='PSPHead', # decode head의 유형. 가능한 옵션은 mmseg/models/decode_heads를 참조하십시오.
in_channels=2048, # decode head의 입력 채널.
in_index=3, # 선택할 피쳐 맵의 인덱스.
channels=512, # decode head의 중간 채널.
pool_scales=(1, 2, 3, 6), # PSPHead의 avg pooling 스케일.
dropout_ratio=0.1, # 최종 분류 레이어 전의 드롭아웃 비율.
num_classes=19, # 세그멘테이션 클래스의 수. 일반적으로 cityscapes에는 19개, VOC에는 21개, ADE20k에는 150개가 있습니다.
norm_cfg=norm_cfg, # norm 레이어의 구성.
align_corners=False, # 디코딩 중 리사이즈에 대한 align_corners 인자.
loss_decode=dict( # decode_head의 손실 함수 구성.
type='CrossEntropyLoss', # 세그멘테이션에 사용되는 손실의 유형.
use_sigmoid=False, # 세그멘테이션에 시그모이드 활성화를 사용할 지 여부.
loss_weight=1.0)), # decode_head의 손실 가중치.
auxiliary_head=dict(
type='FCNHead', # 보조 헤드의 유형. 가능한 옵션은 mmseg/models/decode_heads를 참조하십시오.
in_channels=1024, # 보조 헤드의 입력 채널.
in_index=2, # 선택할 피쳐 맵의 인덱스.
channels=256, # 보조 헤드의 중간 채널.
num_convs=1, # FCNHead에서의 conv 수. 일반적으로 보조 헤드에서는 1입니다.
concat_input=False, # 분류 레이어 전에 conv의 출력을 입력과 연결할지 여부.
dropout_ratio=0.1, # 최종 분류 레이어 전의 드롭아웃 비율.
num_classes=19, # 세그멘테이션 클래스의 수. 일반적으로 cityscapes에는 19개, VOC에는 21개, ADE20k에는 150개가 있습니다.
norm_cfg=norm_cfg, # norm 레이어의 구성.
align_corners=False, # 디코딩 중 리사이즈에 대한 align_corners 인자.
loss_decode=dict( # 보조_head의 손실 함수 구성.
type='CrossEntropyLoss', # 세그멘테이션에 사용되는 손실의 유형.
use_sigmoid=False, # 세그멘테이션에 시그모이드 활성화를 사용할 지 여부.
loss_weight=0.4)), # 보조_head의 손실 가중치.
# 모델 훈련 및 테스트 설정
train_cfg=dict(), # 현재는 train_cfg는 그저 플레이스 홀더입니다.
test_cfg=dict(mode='whole')) # 테스트 모드. 'whole' 및 'slide' 옵션이 있습니다. 'whole': 전체 이미지 fully-convolutional test. 'slide': 이미지에 슬라이딩 크롭 윈도우를 적용합니다.
# 데이터셋 설정
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), # 이미지의 종횡비를 유지할지 여부.
# ``Resize`` 이후에 로딩 어노테이션을 추가합니다. 왜냐하면
# ground truth가 resize 데이터 변환을 하지 않기 때문입니다.
dict(type='LoadAnnotations'), # 데이터셋에서 제공하는 시맨틱 세그멘테이션을 로드합니다.
dict(type='PackSegInputs') # 시맨틱 세그멘테이션을 위한 입력 데이터를 패킹합니다.
]
train_dataloader = dict( # 훈련 데이터로더 설정
batch_size=2, # 단일 GPU의 배치 크기
num_workers=2, # 각 단일 GPU에 대해 데이터를 미리 가져오는 워커
persistent_workers=True, # 에폭 종료 후 워커 프로세스를 종료하여 훈련 속도를 가속화할 수 있습니다.
sampler=dict(type='InfiniteSampler', shuffle=True), # 훈련 중에 무작위로 섞습니다.
dataset=dict( # 훈련 데이터셋 설정
type=dataset_type, # 데이터셋 유형, 세부 사항은 mmseg/datasets/를 참조하십시오.
data_root=data_root, # 데이터셋의 루트.
data_prefix=dict(
img_path='leftImg8bit/train', seg_map_path='gtFine/train'), # 훈련 데이터에 대한 접두사.
pipeline=train_pipeline)) # 처리 파이프라인. 이것은 이전에 생성된 train_pipeline로 전달됩니다.
val_dataloader = dict(
batch_size=1, # 단일 GPU의 배치 크기
num_workers=4, # 각 단일 GPU에 대해 데이터를 미리 가져오는 워커
persistent_workers=True, # 에폭 종료 후 워커 프로세스를 종료하여 테스트 속도를 가속화할 수 있습니다.
sampler=dict(type='DefaultSampler', shuffle=False), # 검증 및 테스트 중에는 섞지 않습니다.
dataset=dict( # 테스트 데이터셋 설정
type=dataset_type, # 데이터셋 유형, 세부 사항은 mmseg/datasets/를 참조하십시오.
data_root=data_root, # 데이터셋의 루트.
data_prefix=dict(
img_path='leftImg8bit/val', seg_map_path='gtFine/val'), # 테스트 데이터에 대한 접두사.
pipeline=test_pipeline)) # 처리 파이프라인. 이것은 이전에 생성된 test_pipeline로 전달됩니다.
test_dataloader = val_dataloader
# 정확도를 측정하는 메트릭. 여기서는 IoUMetric을 사용합니다.
val_evaluator = dict(type='IoUMetric', iou_metrics=['mIoU'])
test_evaluator = val_evaluator
# 옵티마이저
optimizer = dict(type='SGD', # 옵티마이저의 유형, 자세한 내용은 https://github.com/open-mmlab/mmengine/blob/main/mmengine/optim/optimizer/default_constructor.py를 참조하십시오.
lr=0.01, # 옵티마이저의 학습률, PyTorch 문서에서 매개변수의 세부 사용법을 확인하십시오.
momentum=0.9, # 모멘텀
weight_decay=0.0005) # SGD의 가중치 감소
optim_wrapper = dict(type='OptimWrapper', # Optimizer wrapper는 매개변수를 업데이트하는 데 공통 인터페이스를 제공합니다.
optimizer=optimizer, # 모델 매개변수를 업데이트하는 데 사용되는 옵티마이저.
clip_grad=None) # ``clip_grad``가 None이 아닌 경우, ``torch.nn.utils.clip_grad``의 인수가 됩니다.
# 학습 정책
param_scheduler = [
dict(
type='PolyLR', # 스케줄러의 정책, Step, CosineAnnealing, Cyclic 등도 지원됩니다. 지원되는 LrUpdater의 세부사항은 https://github.com/open-mmlab/mmengine/blob/main/mmengine/optim/scheduler/lr_scheduler.py를 참조하십시오.
eta_min=1e-4, # 스케줄링 종료시 최소 학습률.
power=0.9, # 다항식 감소의 지수.
begin=0, # 매개변수 업데이트를 시작하는 단계.
end=40000, # 매개변수 업데이트를 중지하는 단계.
by_epoch=False) # 에포크 별로 계산할지 여부.
]
# 40k 반복에 대한 훈련 일정
train_cfg = dict(type='IterBasedTrainLoop', max_iters=40000, val_interval=4000)
val_cfg = dict(type='ValLoop')
test_cfg = dict(type='TestLoop')
# 기본 후크
default_hooks = dict(
timer=dict(type='IterTimerHook'), # 반복 중 소요 시간을 기록합니다.
logger=dict(type='LoggerHook', interval=50, log_metric_by_epoch=False), # ``Runner``의 다른 구성 요소에서 로그를 수집하고 기록합니다.
param_scheduler=dict(type='ParamSchedulerHook'), # optimizer의 일부 하이퍼파라미터를 업데이트합니다. 예: 학습률.
checkpoint=dict(type='CheckpointHook', by_epoch=False, interval=4000), # 일정 간격으로 체크포인트를 저장합니다.
sampler_seed=dict(type='DistSamplerSeedHook')) # 분산 훈련용 데이터 로딩 샘플러입니다.
# 레지스트리의 기본 범위를 mmseg로 설정합니다.
default_scope = 'mmseg'
# 환경
env_cfg = dict(
cudnn_benchmark=True, # cudnn benchmark 활성화
mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), # 다중 프로세스 구성
dist_cfg=dict(backend='nccl'), # 분산 학습 설정
)
log_level = 'INFO' # 로그 레벨 설정
log_processor = dict(by_epoch=False) # 로그 프로세서 설정
load_from = None # 파일에서 체크포인트 로드하지 않음
resume = False # 기존 모델에서 재개할지 여부
MMEngine에서 Config를 확인하기 위해 아래와 같은 코드를 사용할 수 있습니다.
from mmengine.config import Config
cfg = Config.fromfile('configs/pspnet/pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py')
print(cfg.train_dataloader)
위의 코드를 복사하여 임의로 config_test.py를 만들었습니다.
아래는 그 출력창입니다.
{'batch_size': 2,
'num_workers': 2,
'persistent_workers': True,
'sampler': {'type': 'InfiniteSampler', 'shuffle': True},
'dataset': {'type': 'CityscapesDataset',
'data_root': 'data/cityscapes/',
'data_prefix': {'img_path': 'leftImg8bit/train',
'seg_map_path': 'gtFine/train'},
'pipeline': [{'type': 'LoadImageFromFile'},
{'type': 'LoadAnnotations'},
{'type': 'RandomResize',
'scale': (2048, 1024),
'ratio_range': (0.5, 2.0),
'keep_ratio': True},
{'type': 'RandomCrop', 'crop_size': (512, 1024), 'cat_max_ratio': 0.75},
{'type': 'RandomFlip', 'prob': 0.5},
{'type': 'PhotoMetricDistortion'},
{'type': 'PackSegInputs'}]}}
cfg는 mmengine.config.Config의 Instance 입니다. 자세한 내용은 MMEngine 구성 튜토리얼을 참조할 수 있습니다.
또한 cfg의 사용은 mmsegmentation/tools/train.py 경로에서 일부 찾을 수 있습니다.
mmsegmentation/tools/train.py
...
def main():
args = parse_args()
# load config
cfg = Config.fromfile(args.config)
cfg.launcher = args.launcher
if args.cfg_options is not None:
cfg.merge_from_dict(args.cfg_options)
...
Config 파일을 검사하기 위해 아래의 코드를 터미널에서 실행할 수 있다고 합니다.
python tools/misc/print_config.py configs/pspnet/pspnet_r50-d8_4xb2-40k_cityscapes-512x1024.py
이후 추가하겠습니다.