마지막으로, EasyOCR에서 사용자 모델을 사용할 수 있는 방법을 기술하기에 앞서, 학습에 필요한 학습데이터 생성, 변환 및 미세조정(Fine-tune) 학습 등에 대한 내용은 이전 포스트를 참고하기 바란다.
[Development/OCR] - EasyOCR 사용자 모델 학습하기 (1) - 시작하기 전에
[Development/OCR] - EasyOCR 사용자 모델 학습하기 (2) - 학습데이터 생성
[Development/OCR] - EasyOCR 사용자 모델 학습하기 (3) - 학습데이터 변환
[Development/OCR] - EasyOCR 사용자 모델 학습하기 (4) - 모델 학습
4. 모델 사용하기
이제 EasyOCR에서 학습한 모델을 사용해 문자를 인식해 보자.
4.1 프로젝트 설치 및 개발환경 구축
먼저 다음 명령 구문을 통해 EasyOCR 프로젝트 소스코드를 내려받고, 프로젝트에서 요구하는 환경을 구축한다.
# 소스코드 내려받기
$ git clone https://github.com/JaidedAI/EasyOCR.git
# 개발환경 구축 (가상환경 내에서 실행)
(venv) $ pip install -r requirements.txt
4.2 사용자 모델 사용 환경 구성
이제 사용자 모델을 사용하기 위해 필요한 파일들을 생성한다.
단, 여기서는 사용자 모델 파일의 이름을 'custom'으로 정하고 진행하는 것으로 한다.
(꼭 'custom'이 아니어도 된다. 하지만 사용자 학습 모델과 모듈 및 설정파일의 이름은 반드시 통일시켜야 한다)
4.2.1 사용자 모델 디렉토리 생성 및 사용자 모델 파일 이동
EasyOCR 모듈에서 사용하게 될 사용자 모델과 모델의 네트워크 모듈 파일 및 관련 설정 파일을 저장할 디렉토리를 생성하고 사용자 모델을 복사한다. 해당 디렉토리의 구조는 다음과 같다.
# 사용자 모델 설정 파일 위치
EasyOCR/user_network
├── custom.py # 사용자 학습 모델 네트워크 모듈
└── custom.yaml # 사용자 학습 모델 설정 파일
# 사용자 모델 저장 위치
EasyOCR/model
└── custom.pth # 사용자 학습 모델
사용자 학습 모델은 이전 포스트에서 학습한 학습 결과 중 원하는 모델 파일(.pth)을 선택, 복사해서 파일명을 'custom.pth'로 바꾸면 된다.
4.2.2 'custom.yaml' 파일 생성
학습한 모델의 학습 시 사용한 파라미터와 EasyOCR 모듈 사용 시 필요한 파라미터 정보들을 담은 설정 파일이다. 이전 포스트에서 진행해왔던 방법 그대로 따라 했다면 아래와 똑같이 생성하면 된다. (또는 아래 첨부파일을 내려받아 사용하면 된다)
# english (None-VGG-BiLSTM-CTC)
imgH: 32
lang_list: ['en']
network_params:
input_channel: 1
output_channel: 512
hidden_size: 256
character_list: "0123456789abcdefghijklmnopqrstuvwxyz"
모델의 네트워크 구조를 변경하지 않았다면 다른 내용은 특별히 알 필요가 없고, 사용자가 원하는 학습데이터, 클래스 등을 사용했을 때 필요한 파라미터 정보들에 대해서만 살짝 언급하고 넘어가겠다.
- lang_list: 학습한 언어의 ISO-639 기반 언어코드를 리스트 형태로 기입한다. (단, 여러 언어를 학습하고 언어 리스트를 여러 개 넣을 수 있으나, 내 짧은 소견으로는 추천하지 않는다)
- character_list: 학습데이터의 클래스로, 우린 deep-text-recognition-benchmark 프로젝트의 기본 설정을 이용했기 때문에 위와 같이 작성했고, EasyOCR 프로젝트의 'EasyOCR/easyocr/config.py' 파일을 보면 다양한 클래스 설정을 확인할 수 있으니 참고하기 바란다. (또, 어떤 언어의 클래스든 일반적으로 숫자와 영문(대소문자)은 포함해서 구성하는 것을 추천한다)
4.2.3 'custom.py' 파일 생성
사용자 모델의 네트워크 구조를 정의하는 모듈 파일로, 우리는 EasyOCR 모듈에서 사용하는 'None-VGG-BiLSTM-CTC' 구조를 사용했기 때문에 EasyOCR 프로젝트에서 제공하는 파일을 이용해 다음과 같이 구성하면 된다. 앞서 'custom.yaml' 파일을 그대로 사용했던 것처럼 이 'custom.py' 파일도 아래 내용을 그대로 사용하면 된다. (또는 아래 첨부파일을 내려받아 사용하면 된다)
import torch.nn as nn
class Model(nn.Module):
def __init__(self, input_channel, output_channel, hidden_size, num_class):
super(Model, self).__init__()
""" FeatureExtraction """
self.FeatureExtraction = VGG_FeatureExtractor(input_channel, output_channel)
self.FeatureExtraction_output = output_channel
self.AdaptiveAvgPool = nn.AdaptiveAvgPool2d((None, 1))
""" Sequence modeling"""
self.SequenceModeling = nn.Sequential(
BidirectionalLSTM(self.FeatureExtraction_output, hidden_size, hidden_size),
BidirectionalLSTM(hidden_size, hidden_size, hidden_size))
self.SequenceModeling_output = hidden_size
""" Prediction """
self.Prediction = nn.Linear(self.SequenceModeling_output, num_class)
def forward(self, input, text):
""" Feature extraction stage """
visual_feature = self.FeatureExtraction(input)
visual_feature = self.AdaptiveAvgPool(visual_feature.permute(0, 3, 1, 2))
visual_feature = visual_feature.squeeze(3)
""" Sequence modeling stage """
contextual_feature = self.SequenceModeling(visual_feature)
""" Prediction stage """
prediction = self.Prediction(contextual_feature.contiguous())
return prediction
class BidirectionalLSTM(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(BidirectionalLSTM, self).__init__()
self.rnn = nn.LSTM(input_size, hidden_size, bidirectional=True, batch_first=True)
self.linear = nn.Linear(hidden_size * 2, output_size)
def forward(self, input):
"""
input : visual feature [batch_size x T x input_size]
output : contextual feature [batch_size x T x output_size]
"""
try: # multi gpu needs this
self.rnn.flatten_parameters()
except: # quantization doesn't work with this
pass
recurrent, _ = self.rnn(input) # batch_size x T x input_size -> batch_size x T x (2*hidden_size)
output = self.linear(recurrent) # batch_size x T x output_size
return output
class VGG_FeatureExtractor(nn.Module):
def __init__(self, input_channel, output_channel=256):
super(VGG_FeatureExtractor, self).__init__()
self.output_channel = [int(output_channel / 8), int(output_channel / 4),
int(output_channel / 2), output_channel]
self.ConvNet = nn.Sequential(
nn.Conv2d(input_channel, self.output_channel[0], 3, 1, 1), nn.ReLU(True),
nn.MaxPool2d(2, 2),
nn.Conv2d(self.output_channel[0], self.output_channel[1], 3, 1, 1), nn.ReLU(True),
nn.MaxPool2d(2, 2),
nn.Conv2d(self.output_channel[1], self.output_channel[2], 3, 1, 1), nn.ReLU(True),
nn.Conv2d(self.output_channel[2], self.output_channel[2], 3, 1, 1), nn.ReLU(True),
nn.MaxPool2d((2, 1), (2, 1)),
nn.Conv2d(self.output_channel[2], self.output_channel[3], 3, 1, 1, bias=False),
nn.BatchNorm2d(self.output_channel[3]), nn.ReLU(True),
nn.Conv2d(self.output_channel[3], self.output_channel[3], 3, 1, 1, bias=False),
nn.BatchNorm2d(self.output_channel[3]), nn.ReLU(True),
nn.MaxPool2d((2, 1), (2, 1)),
nn.Conv2d(self.output_channel[3], self.output_channel[3], 2, 1, 0), nn.ReLU(True))
def forward(self, input):
return self.ConvNet(input)
참고로, 모델의 네트워크 구조를 바꿔서 학습하고 사용하고자 한다면, deep-text-recognition-benchmark 프로젝트의 'deep-text-recognition-benchmark/model.py' 파일과 'deep-text-recognition-benchmark/modules/' 안의 파일들을 참고해서 본 'custom.py' 파일을 구성하면 된다.
이렇게 사용자 모델을 사용할 환경 구성은 모두 마쳤다.
4.3 EasyOCR 실행 파라미터
이제 EasyOCR 모듈을 실행하는 명령 구문에서 지원하는 파라미터 중 사용할만한 파라미터에 대해 알아보겠다.
참고로, 괄호 안의 내용은 파라미터의 값 형식을 뜻하며, 음영으로 표시한 파라미터를 사용하게 될 것이다.
- lang_list: (list) 언어코드(ISO-639 기준) 리스트
- gpu: (bool) GPU 사용여부 (default: True)
- model_storage_directory: (string) 사용 모델 저장 위치 (default: './model/') - EasyOCR 프로젝트에서 제공하는 모델의 다운로드 경로이거나, recog_network에서 설정한 이름으로 된 사용자 모델(.pth)을 저장하는 경로
- download_enabled: (bool) HTTP를 통해 EasyOCR 프로젝트에서 모델 데이터를 다운로드할 수 있도록 하는 설정 (default: True)
- recog_network: (string) 사용자 모델, 모듈, 설정 파일의 이름 (default: 'standard') - 'standard'일 경우 EasyOCR 프로젝트에서 기본으로 제공하는 모델을 사용
- user_network: (string) 사용자 모델 저장 위치 (default: './user_network') - 사용자 모델을 사용하고자 할 경우 이 경로에 recog_network에서 설정한 이름으로 된 모듈(.py), 설정(.yaml) 파일이 위치
4.4 실행 테스트
이제 다음과 같이 코드를 작성하고, 실행해 보자. (또는 아래 첨부파일을 내려받아 사용하면 된다)
from easyocr.easyocr import *
# GPU 설정
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1'
def get_files(path):
file_list = []
files = [f for f in os.listdir(path) if not f.startswith('.')] # skip hidden file
files.sort()
abspath = os.path.abspath(path)
for file in files:
file_path = os.path.join(abspath, file)
file_list.append(file_path)
return file_list, len(file_list)
if __name__ == '__main__':
# # Using default model
# reader = Reader(['en'], gpu=True)
# Using custom model
reader = Reader(['en'], gpu=True,
model_storage_directory='model',
user_network_directory='user_network',
recog_network='custom')
files, count = get_files('demo_image')
for idx, file in enumerate(files):
filename = os.path.basename(file)
result = reader.readtext(file)
# ./easyocr/utils.py 733 lines
# result[0]: bbox
# result[1]: string
# result[2]: confidence
for (bbox, string, confidence) in result:
print("filename: '%s', confidence: %.4f, string: '%s'" % (filename, confidence, string))
# print('bbox: ', bbox)
실행하는 방법은 위 코드를 PyCharm과 같은 통합IDE 환경에서 실행해도 되고, 아래 명령 구문처럼 콘솔에서 실행해도 된다.
# EasyOCR 사용자 모델 사용해 실행하기
(venv) $ python3 run.py
실행 결과는 다음과 같다. (참고로 테스트한 이미지는 이전 포스트에서 사용한 데모 이미지를 사용했다)
5. 결론
위 결과만 보면 매우 만족스럽지 못하다. 사실 충분한 학습시간과 학습에 필요한 충분한 학습데이터, 미세조정(Fine-tune)을 위한 다양한 설정 등 무엇 하나 제대로 준비하지 않은 채로, 빠르게 본 과정을 기록하기 위해 진행해 왔기 때문이다.
이제 만족할만한 충분한 성능을 갖는 모델을 만들어 내는 것은 각자의 몫으로 남기고, EasyOCR 사용자 모델 학습 및 사용하기에 대한 포스트는 여기까지 하겠다.
기회가 된다면, 한글 학습데이터를 생성하고 사용하는 과정을 포스팅하도록 하겠다.
아래는 한글 학습데이터를 생성, 학습 및 테스트하는 과정을 작성한 포스트이다.
[Development/OCR] - EasyOCR 사용자 모델 학습하기 (6) - 한글 학습데이터 생성, 학습 및 테스트
'Development > OCR' 카테고리의 다른 글
EasyOCR 사용자 모델 학습하기 (6) - 한글 학습데이터 생성, 학습 및 테스트 (147) | 2021.06.15 |
---|---|
EasyOCR 사용자 모델 학습하기 (4) - 모델 학습 (22) | 2021.05.25 |
EasyOCR 사용자 모델 학습하기 (3) - 학습데이터 변환 (3) | 2021.05.22 |
EasyOCR 사용자 모델 학습하기 (2) - 학습데이터 생성 (0) | 2021.05.22 |
EasyOCR 사용자 모델 학습하기 (1) - 시작하기 전에 (0) | 2021.05.22 |