Search
🔵

bc3__3. [info] title: MMOCR 에서 제공하는 detection 모델을 커스텀 데이터로 학습하기

생성
🚀 prev note
🚀 next note
14 more properties
전체 목차(from1).

들어가며

MMOCR 은 OCR 문제에서 문자 영역을 검출하는 text detection 과 검출된 영역에서 문자를 읽어내는 text recognition 을 각각 다른 모델로 다루는 프레임워크입니다(from1). MMOCR 프레임워크와 소통하기 위해 모든 모델과 모든 데이터는 config 파일을 매개체로 사용합니다(from2). 따라서 config 파일에는 모델과 데이터에 대한 정보가 포함되어 있어야 합니다. MMOCR 프레임워크에게 사용할 모델에 대한 정보를 전달하기 위해 작성된 config 파일은 configs/textdet 디렉토리의 하나의 단어로 이름붙여진 폴더 속에서 _base 로 시작하고 모델에 대한 간단한 정보를 덧붙인 뒤 _fpnc 로 끝나는 이름을 가지고 있음을 알 수 있습니다. MMOCR 프레임워크의 detection 모델을 학습하는 일에 사용할 데이터셋에 대한 정보를 전달하기 위해 작성된 config 파일은 configs/textdet/_base_/datasets 디렉토리에 위치해 있습니다.
이 가이드에서는 커스텀 데이터로 Aihub 에서 제공하는 금융 OCR 데이터셋을 이용합니다. 복잡도를 낮추기 위해 모델은 건드리지 않습니다. 우선 MMOCR 에게 금융 데이터셋을 사용할 수 있도록 도와줘 봅시다. 새롭게 생성할 config 파일은 aihub_finance.py 파일과 dbnet_resnet18_fpnc_3e_aihub_finance.py 파일입니다.
config
상세정보
config
데이터 config
Aihub 금융 데이터셋
configs/textdet/_base_/datasets/aihub_finance.py
모델 config
문자 검출 모델 DBNet(ResNet18 Backbone)
configs/textdet/dbnet/_base_dbnet_resnet18_fpnc.py
데이터 + 모델 config
데이터 config 과 모델 config 를 상속받음
configs/textdet/dbnet/dbnet_resnet18_fpnc_3e_aihub_finance.py

데이터 config 파일 작성

데이터셋에 대한 정보를 MMOCR 프레임워크에 전달하는 방법을 명세한 aihub_finance.py config 파일을 작성할 차례입니다. 앞선 튜토리얼(from2)에서 사용했던 뼈대를 먼저 가져왔습니다. 그런데 각각이 무슨 역할을 하는 것인지 모르기 때문에 채워 넣을 수가 없겠네요.
aihubfinance_det_data_root = '' aihubfinance_det_train = dict( type='', data_root=aihubfinance_det_data_root, ann_file='', data_prefix=dict(img_path=''), filter_cfg=dict(filter_empty_gt=True, min_size=32), pipeline=None) aihubfinance_det_test = dict( type='', data_root=aihubfinance_det_data_root, ann_file='', data_prefix=dict(img_path=''), test_mode=True, pipeline=None)
Bash
복사
configs/textdet/_base_/datasets/aihub_finance.py
aihub_finance… 가 아니라 aihubfinance… 라고 변수명을 붙여준 것은 MMOCR 프레임워크의 이름 컨벤션 때문입니다(참고1).
이 config 파일은 detection 모델에 사용되는 데이터를 적절히 포장하기 위한 용도로 사용되므로 이를 이해하려면 어노테이션파일의 형태를 먼저 이해할 필요가 있습니다. MMOCR 은 text detection 과 text recognition 을 분리해서 관리하는 프레임워크라고 했었는데요(from1), 우리는 text detection 모델을 학습하기 위해 고군분투 중이라는 사실을 잊지 말아야 합니다. 그럼 비어있는 필드들을 하나씩 채워 보도록 합시다.
아래는 MMOCR 에서 요구하는 표준 어노테이션 포맷입니다. MMOCR 표준 어노테이션 포맷에서 Text detection 학습을 위한 어노테이션 파일은 dataset_typeTextDetDataset 이고 task_nametextdet 임을 명시하고 있습니다. 튜토리얼에서는 text detection 모델 학습을 위한 MMOCR 표준을 준수한 어노테이션 파일은 아래와 같은 형태로 생겼다고 소개하고 있습니다(참고2).
코드(참고2)
{ "metainfo": { "dataset_type": "TextDetDataset", "task_name": "textdet", "category": [{"id": 0, "name": "text"}] }, "data_list": [ { "img_path": "test_img.jpg", "height": 640, "width": 640, "instances": [ { "polygon": [0, 0, 0, 10, 10, 20, 20, 0], "bbox": [0, 0, 10, 20], "bbox_label": 0, "ignore": false, }, ], //... } ] }
JSON
복사
모델을 학습시키려면 위와 같은 형태의 어노테이션 파일을 파이썬 객체 모델에 담을 수 있어야 합니다. 위와 같은 형태의 어노테이션 파일을 담아낼 수 있는 파이썬 클래스는 OCRDataset 입니다(from3). 만약 text detection 모델 학습을 위한 MMOCR 의 표준 포맷을 사용하지 않는다면, 당연히 OCRDataset 대신 다른 클래스를 구현해서 사용하면 됩니다.
하지만 Aihub 에서 다운로드받은 금융 OCR 데이터의 레이블 포맷은 MMOCR 표준 포맷과 사뭇 다른 모습입니다. 우리는 다른 글에서 이 서드파티 포맷을 MMOCR 표준 포맷으로 변환하는 방법에 대해 다룰 것입니다. 지금은 그 과정들을 모두 거쳐 Aihub 금융 데이터가 MMOCR 표준 detection 포맷에 맞게 만들어졌음을 상정합니다.
Aihub 금융 OCR 데이터의 레이블 예시 보기
aihublogistics_det_train = dict( type='OCRDataset') aihublogistics_det_test = dict( type='OCRDataset')
Python
복사
configs/textdet/_base_/datasets/aihub_finance.py
data_root 는 위 어노테이션파일이 위치한 디렉토리의 경로입니다. 제 경우 data/det/aihub_finance 디렉토리에 두 개의 어노테이션 파일(instance_test.json, instance_training.json)을 만들 생각이므로 아래와 같이 설정합니다.
aihubfinance_det_data_root = 'data/det/aihub_finance' aihubfinance_det_train = dict( type='OCRDataset', data_root=aihubfinance_det_data_root, ann_file='instances_training.json') aihubfinance_det_test = dict( type='OCRDataset' data_root=aihubfinance_det_data_root, ann_file='instances_test.json')
JavaScript
복사
configs/textdet/_base_/datasets/aihub_finance.py
어노테이션 파일에서 우리가 또 주목해야 하는 것은 이미지파일의 경로(img_path)입니다. 어노테이션 파일의 img_path 는 레이블링 작업을 수행했던 컴퓨터에서 상대 경로로 작성되었기 때문에 내 환경에 맞게 변환시킬 필요가 있습니다. Aihub 금융 데이터의 경우에는 데이터가 아래와 같은 구조로 배치될 예정입니다.
data/det/aihub_finance |-- imgs | |-- test | | `-- img.jpg | `-- train | `-- img.jpg |-- instances_test.json `-- instances_train.json
Plain Text
복사
그리고 어노테이션 파일의 img_path 는 아래와 같은 형태로 작성될 예정입니다.
"img_path": "img.jpg"
JSON
복사
그렇다면 test 디렉토리가 data_root 를 기준으로 어디에 위치해 있는지만 알려주면 되겠네요. 정답은 data_rootimgs 디렉토리입니다. 이 정보를 data_prefix 에 아래와 같이 할당합니다.
aihubfinance_det_data_root = 'data/det/aihub_finance' aihubfinance_det_train = dict( type='OCRDataset', data_root=aihubfinance_det_data_root, ann_file='instances_train.json', data_prefix=dict(img_path='imgs/train')) aihubfinance_det_test = dict( type='OCRDataset', data_root=aihubfinance_det_data_root, ann_file='instances_test.json', data_prefix=dict(img_path='imgs/test'))
Python
복사
configs/textdet/_base_/datasets/aihub_finance.py
테스트모드 여부(test_mode)의 동작 여부를 구체적으로는 알 수 없지만 테스트 데이터의 경우 True 를 설정하도록 합니다. 파이프라인(pipeline)과 필터링 설정(filter_cfg)도 지금 다루지 않습니다. 그럼 이제 아래와 같은 형태가 됩니다.
aihubfinance_det_data_root = 'data/det/aihub_finance' aihubfinance_det_train = dict( type='OCRDataset', data_root=aihubfinance_det_data_root, ann_file='instances_train.json', data_prefix=dict(img_path='imgs/train'), pipeline=None) aihubfinance_det_test = dict( type='OCRDataset', data_root=aihubfinance_det_data_root, ann_file='instances_test.json', data_prefix=dict(img_path='imgs/test'), test_mode=True, pipeline=None)
Python
복사
configs/textdet/_base_/datasets/aihub_finance.py

데이터 + 모델 config 파일 작성

최종 config 파일을 만들어 봅시다.
_base_ = [ '_base_dbnet_resnet18_fpnc.py', '../_base_/datasets/aihub_finance.py', '../_base_/default_runtime.py', '../_base_/schedules/schedule_sgd_base.py', ]
Python
복사
configs/textdet/dbnet/dbnet_resnet18_fpnc_3e_aihub_finance.py
모델의 구조에 대한 정보를 담은 config 파일인 configs/textdet/dbnet/_base_dbnet_resnet18_fpnc.py 과 데이터에 대한 정보를 담은 configs/textdet/_base_/datasets/aihub_finance.py config 파일을 불러옵니다. 스케줄러에 대한 내용을 담고 있는 config 파일인 schedule_sgd_base.py 과 detection 을 수행하는 것과 관련된 기본적인 정보들을 담고 있는 config 파일인 default_runtime.py 도 상속합니다.
train_pipeline = [ dict( type='LoadImageFromFile', file_client_args=_base_.file_client_args, color_type='color_ignore_orientation'), dict( type='LoadOCRAnnotations', with_polygon=True, with_bbox=True, with_label=True, ), dict( type='TorchVisionWrapper', op='ColorJitter', brightness=32.0 / 255, saturation=0.5), dict( type='ImgAugWrapper', args=[['Fliplr', 0.5], dict(cls='Affine', rotate=[-10, 10]), ['Resize', [0.5, 3.0]]]), dict(type='RandomCrop', min_side_ratio=0.1), dict(type='Resize', scale=(640, 640), keep_ratio=True), dict(type='Pad', size=(640, 640)), dict( type='PackTextDetInputs', meta_keys=('img_path', 'ori_shape', 'img_shape')) ] test_pipeline = [ dict( type='LoadImageFromFile', file_client_args=_base_.file_client_args, color_type='color_ignore_orientation'), dict(type='Resize', scale=(1333, 736), keep_ratio=True), dict( type='LoadOCRAnnotations', with_polygon=True, with_bbox=True, with_label=True, ), dict( type='PackTextDetInputs', meta_keys=('img_path', 'ori_shape', 'img_shape', 'scale_factor')) ]
Python
복사
configs/textdet/dbnet/dbnet_resnet18_fpnc_3e_aihub_finance.py
데이터를 로드할 때 사용되는 파이프라인입니다. 어떤 augmentation 을 수행할지에 대한 정보가 여기에 포함됩니다. LoadImageFromFile, LoadOCRAnnotations 과 같은 클래스들이 어떤 역할을 수행하는지는 공식 문서를 참고하세요. 지금 중요한 점은, configs/textdet/dbnet/_base_dbnet_resnet18_fpnc.py config 파일에서 상속받은 train_pipeline, test_pipeline 이 Aihub 금융 OCR 데이터에 적절하지 않기 때문에 이 값을 새로운 augmentation 의 목록을 담은 리스트로 덮어썼다는 사실입니다.
load_from = None # dataset settings train_list = [_base_.aihubfinance_textdet_train] val_list = [_base_.aihubfinance_textdet_test] test_list = [_base_.aihubfinance_textdet_test] train_dataloader = dict( batch_size=32, num_workers=8, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), dataset=dict( type='ConcatDataset', datasets=train_list, pipeline=train_pipeline)) auto_scale_lr = dict(base_batch_size=32) val_dataloader = dict( batch_size=32, num_workers=8, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='ConcatDataset', datasets=val_list, pipeline=test_pipeline)) val_evaluator = dict( type='MultiDatasetsEvaluator', metrics=dict(type='HmeanIOUMetric'), dataset_prefixes=['AihubFinance', 'IC15']) test_dataloader = dict( batch_size=1, num_workers=4, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=False), dataset=dict( type='ConcatDataset', datasets=test_list, pipeline=test_pipeline)) test_evaluator = dict( type='MultiDatasetsEvaluator', metrics=dict(type='HmeanIOUMetric'), dataset_prefixes=['AihubFinance10of100', 'AihubFinance100of100', 'IC15'])
Python
복사
configs/textdet/dbnet/dbnet_resnet18_fpnc_3e_aihub_finance.py
dataloaderevaluation 각각의 데이터 분할(train, val, test) 에 맞는 데이터와 파이프라인을 전달합니다. 파이프라인이 어떤 원리로 작동하는지는 공식 문서의 ‘Data Transforms’ 관련 내용을 확인해 보세요.
# Save checkpoints every 1 epochs default_hooks = dict( logger=dict(type='LoggerHook', interval=5), checkpoint=dict(type='CheckpointHook', interval=1)) # Set the maximum number of epochs to 3, and validate the model every 1 epochs train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=3, val_interval=1)
Python
복사
configs/textdet/dbnet/dbnet_resnet18_fpnc_3e_aihub_finance.py
Aihub 금융 OCR 데이터셋은 총 5만장의 이미지로 구성되어 입니다. 데이터가 많으니 3~10 에폭정도면 충분하겠네요. 여기서는 3으로 지정합니다. val_evaluator 이 실행되는 간격인 val_interval 의 값이 1이므로, 각 에폭이 종료될 때마다 test_pipeline 을 통과한 val_list 데이터로 평가할 것입니다. 모델 가중치(checkpoint)는 매 에폭을 마칠 때마다 저장됩니다.

모델 학습

학습 커맨드는 언제나 간단합니다.
python3 -m tools.train \ configs/textdet/dbnet/dbnet_resnet18_fpnc_3e_aihub_finance.py
Bash
복사
단일 GPU 학습: python3 -m tools.train {config_file_path}
tools/dist_train.sh \ configs/textdet/dbnet/dbnet_resnet18_fpnc_3e_aihub_finance.py 2
Bash
복사
멀티(2) GPU 학습: tools/dist_train.sh {config_file_path} {n_gpu}
parse me : 언젠가 이 글에 쓰이면 좋을 것 같은 재료들.
1.
from : 과거의 어떤 생각이 이 생각을 만들었는가?
1.
2.
4.
supplementary : 어떤 새로운 생각이 이 문서에 작성된 생각을 뒷받침하는가?
2.
opposite : 어떤 새로운 생각이 이 문서에 작성된 생각과 대조되는가?
1.
None
to : 이 문서에 작성된 생각이 어떤 생각으로 발전되고 이어지는가?
참고 : 레퍼런스