公開日:2022年10月27日
最終更新日:2022年11月24日
はじめに
前回「MMOCR==0.6.2」を使って日本語の学習を行いました。touch-sp.hatenablog.com
今回は「MMOCR==1.0.0rc2」を使ってみたいと思います。
PC環境
前回と一緒です。Windows 11 CUDA 11.6.2 Python 3.10.8
Python環境構築
pip install torch==1.12.1 torchvision==0.13.1 --extra-index-url https://download.pytorch.org/whl/cu116 pip install openmim==0.3.2 pip install mmengine==0.2.0 pip install mmcv==2.0.0rc1 -f https://download.openmmlab.com/mmcv/dist/cu116/torch1.12.0/index.html pip install mmdet==3.0.0rc2 pip install mmocr==1.0.0rc2 pip install openpyxl==3.0.10 pip install trdg==1.8.0
モデルによっては以下が必要になります。
pip install albumentations==1.3.0
「mmocr==1.0.0rc3」も試しましたが問題なく動きました。
「mmcv==2.0.0rc2」にすると動きませんでした。
学習データの作成
前回同様「TextRecognitionDataGenerator」を使わせて頂きました。前回と異なる点は「TextRecognitionDataGenerator」が出力するtextファイルをjsonファイルに変更する必要があることです。以下のスクリプトで変換が可能です。import argparse import json parser = argparse.ArgumentParser() parser.add_argument('--input', type=str, help='text file') parser.add_argument('--output', type = str, help='json file') args = parser.parse_args() input_fname = args.input output_fname = args.output with open(input_fname, 'r', encoding='utf-8') as f: lines = f.readlines() lines = [x.strip() for x in lines] data_list = [] for line in lines: img_path, text = line.split(' ') data = { 'img_path': img_path, 'instances':[{'text':text}] } data_list.append(data) result = { 'metainfo':{ 'dataset_type':'TextRecogDataset', 'task_name':'textrecog' }, 'data_list':data_list } with open(output_fname, 'w', encoding='utf-8') as f: json.dump(result, f, indent=2, ensure_ascii=False)
Configファイルを作成する
train = dict( type='OCRDataset', data_prefix=dict(img_path='mnt/ramdisk/max/90kDICT32px'), ann_file='train_labels.json', test_mode=False, pipeline=None) test = dict( type='OCRDataset', data_prefix=dict(img_path='mnt/ramdisk/max/90kDICT32px'), ann_file='test_labels.json', test_mode=True, pipeline=None) default_scope = 'mmocr' env_cfg = dict( cudnn_benchmark=True, mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), dist_cfg=dict(backend='nccl')) randomness = dict(seed=None) default_hooks = dict( timer=dict(type='IterTimerHook'), logger=dict(type='LoggerHook', interval=100), param_scheduler=dict(type='ParamSchedulerHook'), checkpoint=dict(type='CheckpointHook', interval=1), sampler_seed=dict(type='DistSamplerSeedHook'), sync_buffer=dict(type='SyncBuffersHook'), visualization=dict( type='VisualizationHook', interval=1, enable=False, show=False, draw_gt=False, draw_pred=False)) log_level = 'INFO' log_processor = dict(type='LogProcessor', window_size=10, by_epoch=True) load_from = None resume = False val_evaluator = dict( type='Evaluator', metrics=[ dict( type='WordMetric', mode=['exact', 'ignore_case', 'ignore_case_symbol']), dict(type='CharMetric') ]) test_evaluator = dict( type='Evaluator', metrics=[ dict( type='WordMetric', mode=['exact', 'ignore_case', 'ignore_case_symbol']), dict(type='CharMetric') ]) vis_backends = [dict(type='LocalVisBackend')] visualizer = dict( type='TextRecogLocalVisualizer', name='visualizer', vis_backends=[dict(type='LocalVisBackend')]) optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='Adam', lr=0.0003)) train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=5, val_interval=1) val_cfg = dict(type='ValLoop') test_cfg = dict(type='TestLoop') param_scheduler = [dict(type='MultiStepLR', milestones=[3, 4], end=5)] file_client_args = dict(backend='disk') dictionary = dict( type='Dictionary', dict_file= 'd:/python/preocrenv/lib/site-packages/mmocr/.mim/configs/textrecog/satrn/../../../dicts/english_digits_symbols.txt', with_padding=True, with_unknown=True, same_start_end=True, with_start=True, with_end=True) model = dict( type='SATRN', backbone=dict(type='ShallowCNN', input_channels=3, hidden_dim=512), encoder=dict( type='SATRNEncoder', n_layers=12, n_head=8, d_k=64, d_v=64, d_model=512, n_position=100, d_inner=2048, dropout=0.1), decoder=dict( type='NRTRDecoder', n_layers=6, d_embedding=512, n_head=8, d_model=512, d_inner=2048, d_k=64, d_v=64, module_loss=dict( type='CEModuleLoss', flatten=True, ignore_first_char=True), dictionary=dict( type='Dictionary', dict_file= 'd:/python/preocrenv/lib/site-packages/mmocr/.mim/configs/textrecog/satrn/../../../dicts/english_digits_symbols.txt', with_padding=True, with_unknown=True, same_start_end=True, with_start=True, with_end=True), max_seq_len=25, postprocessor=dict(type='AttentionPostprocessor')), data_preprocessor=dict( type='TextRecogDataPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375])) train_pipeline = [ dict( type='LoadImageFromFile', file_client_args=dict(backend='disk'), ignore_empty=True, min_size=2), dict(type='LoadOCRAnnotations', with_text=True), dict(type='Resize', scale=(100, 32), keep_ratio=False), dict( type='PackTextRecogInputs', meta_keys=('img_path', 'ori_shape', 'img_shape', 'valid_ratio')) ] test_pipeline = [ dict(type='LoadImageFromFile', file_client_args=dict(backend='disk')), dict(type='Resize', scale=(100, 32), keep_ratio=False), dict(type='LoadOCRAnnotations', with_text=True), dict( type='PackTextRecogInputs', meta_keys=('img_path', 'ori_shape', 'img_shape', 'valid_ratio')) ] train_dataset = dict( type='ConcatDataset', datasets=[train], pipeline=[ dict( type='LoadImageFromFile', file_client_args=dict(backend='disk'), ignore_empty=True, min_size=2), dict(type='LoadOCRAnnotations', with_text=True), dict(type='Resize', scale=(100, 32), keep_ratio=False), dict( type='PackTextRecogInputs', meta_keys=('img_path', 'ori_shape', 'img_shape', 'valid_ratio')) ]) test_dataset = dict( type='ConcatDataset', datasets=[test], pipeline=[ dict(type='LoadImageFromFile', file_client_args=dict(backend='disk')), dict(type='Resize', scale=(100, 32), keep_ratio=False), dict(type='LoadOCRAnnotations', with_text=True), dict( type='PackTextRecogInputs', meta_keys=('img_path', 'ori_shape', 'img_shape', 'valid_ratio')) ]) train_dataloader = dict( batch_size=128, num_workers=24, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), dataset=train_dataset) test_dataloader = dict( batch_size=1, num_workers=4, persistent_workers=True, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=test_dataset) val_dataloader = dict( batch_size=1, num_workers=4, persistent_workers=True, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False), dataset=test_dataset) auto_scale_lr = dict(base_batch_size=512)
学習用ファイルを実行する
import os from mmengine.config import Config from mmengine.registry import RUNNERS from mmengine.runner import Runner def main(): cfg = Config.fromfile('satrn_japanese_cfg.py') os.makedirs('satrn_output', exist_ok=True) #### ## modify configuration file #### # Set output dir cfg.work_dir = 'satrn_output' # Path to dictionary file cfg.dictionary.dict_file = 'dicts.txt' cfg.model.decoder.dictionary = cfg.dictionary # Path to annotation file and image folder cfg.train.data_prefix.img_path = 'train' cfg.train.ann_file = 'train_labels.json' cfg.train_dataset.datasets = [cfg.train] cfg.train_dataloader.dataset = cfg.train_dataset cfg.test.data_prefix.img_path = 'test' cfg.test.ann_file = 'test_labels.json' cfg.test_dataset.datasets = [cfg.test] cfg.test_dataloader.dataset = cfg.test_dataset cfg.val_dataloader.dataset = cfg.test_dataset # Modify cuda setting cfg.gpu_ids = range(1) cfg.device = 'cuda' # Others cfg.train_dataloader.batch_size = 32 cfg.train_dataloader.num_workers = 8 cfg.model.decoder.max_seq_len = 35 cfg.train_cfg.max_epochs = 1 # default 5 # Build the runner from config if 'runner_type' not in cfg: # build the default runner runner = Runner.from_cfg(cfg) else: # build customized runner from the registry # if 'runner_type' is set in the cfg runner = RUNNERS.build(cfg) # Start training runner.train() if __name__ == '__main__': main()
補足①
上記のConfigファイルを見ると画像を(100, 32)にリサイズしています。dict(type='Resize', scale=(100, 32), keep_ratio=False),
scale=(200, 32)に変更するとmodel.encoder.n_positionも200に変更する必要があります。
補足②
新しい記事も書いています。そちらも読んでみて下さい。touch-sp.hatenablog.com
その他
スクリプトはGitHubで公開しています。github.com