AI/easyOCR

6. easyOCR 결과 로그 분석.

사리생성 2025. 11. 20. 21:56

 

이 로그는 EasyOCR 파인튜닝(Fine-tuning) 과정이 완료되었음을 보여주지만, 현재 모델은 **심각한 과적합(Overfitting)**과 학습 데이터 부족 문제를 겪고 있습니다.

다음은 결과에 대한 상세 분석과 모델 성능을 개선하기 위한 구체적인 해결 방안입니다.

1. 진단: 심각한 과적합 (Severe Overfitting)

로그에서 가장 치명적인 지표는 '학습 손실(Train Loss)'과 '검증 손실(Valid Loss)'의 격차입니다.

지표 해석
Train Loss 0.00404 모델이 학습 데이터를 거의 완벽하게 암기했습니다.
Valid Loss 1.40425 모델이 새로운 이미지(검증 데이터)에 대해서는 예측을 전혀 못 하고 있습니다.
격차 (Gap) 매우 큼 학습 손실은 바닥인데 검증 손실이 높거나 줄어들지 않는 것은 전형적인 과적합(Overfitting) 현상입니다.

2. 근본 원인: 데이터 부족

  • 데이터셋 크기: 현재 학습에 사용한 이미지가 416장(num samples: 416)에 불과합니다.
  • 배치 크기 (Batch Size): batch_size: 312로 설정되어 있습니다.
  • 문제점: 매 반복(iteration)마다 모델이 전체 데이터의 약 75%를 봅니다. 10,000번의 반복(iteration) 동안 모델은 똑같은 416장의 이미지를 수천 번 반복해서 보게 되었고, 이는 글자를 '학습'하는 것이 아니라 이미지의 픽셀 패턴을 단순히 '암기'하게 만들었습니다. 딥러닝 모델을 효과적으로 미세 조정하려면 보통 수천 장 이상의 이미지가 필요합니다.

3. 예측 오류 분석 (자모 분리 현상)

예측 로그를 보면 한글 자모가 제대로 합쳐지지 않는 문제가 보입니다.

  • 자모 분리(Decomposition) 현상:
    • 정답: 섬유 -> 예측: 성ᆷ유
    • 정답: 중공업 -> 예측: ᄀᆼᆫ고ᅳ억
    • 분석: 모델이 개별 자모(ㄱ, ㄴ, ㅓ, ㅕ)를 인식하긴 하지만, 이를 온전한 글자(음절)로 결합하지 못하고 있습니다. 이는 모델이 다양한 폰트와 스타일을 충분히 보지 못해 결합 규칙을 배우지 못했거나, 정답 라벨(GT)의 유니코드 정규화(NFC) 문제일 가능성이 큽니다.

4. 해결 방안 (권장 사항)

정확도 28.4%를 실제 사용 가능한 수준으로 끌어올리기 위해 다음 조치들이 필요합니다.

A. 데이터셋 늘리기 (가장 중요)

400장의 이미지로는 부족합니다. 두 가지 방법이 있습니다.

  1. 합성 데이터 생성 (추천): TextRecognitionDataGenerator 같은 도구를 사용하여 다양한 폰트와 배경을 가진 한글 텍스트 이미지를 최소 5,000장에서 10,000장 이상 생성하여 학습하세요.
  2. 데이터 증강 (Augmentation): 기존 416장에 회전, 노이즈, 블러, 기울기 변환 등을 강하게 적용하여 데이터 양을 억지로 늘립니다. (하지만 합성 데이터를 만드는 것이 훨씬 효과적입니다.)

B. 유니코드 정규화 (NFC 확인)

학습 데이터의 라벨 파일(txt/csv)이 정규화되어 있는지 확인해야 합니다. 한글은 자모가 분리된 형태(NFD)와 결합된 형태(NFC)가 있습니다.

  • 조치: 학습을 시작하기 전에 파이썬 스크립트를 이용해 모든 라벨을 NFC 포맷으로 변환하세요.

C. 특징 추출기 고정 (Freeze Feature Extraction)

데이터가 매우 적은 상황에서는 VGG 네트워크 전체를 다시 학습시키면 안 됩니다.

  • 조치: 설정(config) 파일에서 freeze_FeatureFxtraction: True로 설정하세요. 이렇게 하면 이미지의 형태를 인식하는 사전 학습된 가중치(korean_g2.pth)를 그대로 유지하면서, 글자 순서를 예측하는 부분만 집중적으로 학습하게 됩니다.

D. 하이퍼파라미터 조정

  • Batch Size: 현재 312는 너무 큽니다. 32 또는 64 정도로 줄이세요.
  • Learning Rate: 미세 조정(Fine-tuning) 시 lr: 1.0은 너무 높을 수 있습니다. 레이어를 고정하지 않을 거라면 0.01이나 0.001 수준으로 낮춰보세요.

 

한글 학습용 합성 데이터를 생성하는 파이썬 스크립트 (TextRecognitionDataGenerator TRDG) 

 

python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install numpy pillow opencv-python tqdm wikipedia requests diffimg arabic-reshaper beautifulsoup4
pip install trdg --no-deps
pip install python-bidi

 

 

generate_data.py

import os
import random
import requests
from tqdm import tqdm
from PIL import Image, ImageFont # ImageFont 추가

# ==========================================
# [긴급 패치] Pillow 10.0.0+ 호환성 해결 코드
# getsize 함수가 없으면 새로 만들어줍니다.
# ==========================================
if not hasattr(ImageFont.FreeTypeFont, 'getsize'):
    def getsize(self, text, direction=None, features=None):
        bbox = self.getbbox(text, direction=direction, features=features)
        if bbox is None:
            return (0, 0)
        return (bbox[2] - bbox[0], bbox[3] - bbox[1])
    
    ImageFont.FreeTypeFont.getsize = getsize
# ==========================================

from trdg.generators import GeneratorFromStrings

# --- 설정 ---
OUTPUT_DIR = "korean_synthetic_data_pixelated" 
WORD_FILE = "keywords.txt"                   
COUNT = 1000                                 
FONT_PATH = "NanumGothic.ttf"                
PIXEL_SIZE = 6                               

# 1. 저장 디렉토리 생성
if not os.path.exists(OUTPUT_DIR):
    os.makedirs(OUTPUT_DIR)

# 2. 한글 폰트 다운로드 (나눔고딕)
if not os.path.exists(FONT_PATH):
    print(f"폰트 다운로드 중... ({FONT_PATH})")
    url = "https://github.com/google/fonts/raw/main/ofl/nanumgothic/NanumGothic-Regular.ttf"
    response = requests.get(url)
    with open(FONT_PATH, "wb") as f:
        f.write(response.content)
    print("폰트 다운로드 완료!")

# 3. 외부 파일에서 단어 목록 읽어오기
base_words = []
if os.path.exists(WORD_FILE):
    with open(WORD_FILE, "r", encoding="utf-8") as f:
        base_words = [line.strip() for line in f if line.strip()]
    print(f"'{WORD_FILE}'에서 {len(base_words)}개의 단어를 로드했습니다.")
else:
    print(f"경고: '{WORD_FILE}' 파일이 없습니다. 기본 예시 단어를 사용합니다.")
    base_words = ["기본단어", "테스트", "데이터", "생성", "오류"]

def generate_random_text():
    if not base_words:
        return "데이터없음"
    return " ".join(random.sample(base_words, k=random.randint(1, 3)))

# 생성할 텍스트 리스트 만들기
generated_strings = [generate_random_text() for _ in range(COUNT)]

# 4. 이미지 생성기 초기화
generator = GeneratorFromStrings(
    generated_strings,
    blur=1,
    random_blur=True,
    count=COUNT,
    fonts=[FONT_PATH],
    language="ko",
    size=64,
    skewing_angle=2,
    random_skew=True,
    background_type=1
)

# 5. 이미지 생성 및 라벨 파일(gt.txt) 작성
label_file_path = os.path.join(OUTPUT_DIR, "gt.txt")

print(f"픽셀화된 이미지 {COUNT}장 생성을 시작합니다...")

with open(label_file_path, "w", encoding="utf-8") as f:
    for i, (img, lbl) in enumerate(tqdm(generator)):
        # --- 픽셀화 효과 적용 ---
        if PIXEL_SIZE > 1:
            img_small = img.resize(
                (max(1, img.width // PIXEL_SIZE), max(1, img.height // PIXEL_SIZE)),
                resample=Image.BILINEAR
            )
            img_pixelated = img_small.resize(
                img.size,
                resample=Image.NEAREST
            )
        else:
            img_pixelated = img
        # ---------------------

        # 이미지 파일명
        filename = f"syn_pixel_{i:05d}.jpg"
        filepath = os.path.join(OUTPUT_DIR, filename)
        
        # 저장
        img_pixelated.save(filepath)
        
        # 라벨 파일에 기록
        f.write(f"{filename}\t{lbl}\n")

print(f"\n생성 완료! 픽셀화된 데이터 위치: {OUTPUT_DIR}")
print(f"라벨 파일 위치: {label_file_path}")

 

keywords.txt

공업
농업

 

❯ python3 generate_data.py
Missing modules for handwritten text generation.
'keywords.txt'에서 2772개의 단어를 로드했습니다.
픽셀화된 이미지 3000장 생성을 시작합니다...
3000it [00:10, 275.84it/s]

생성 완료! 픽셀화된 데이터 위치: korean_synthetic_data_pixelated
라벨 파일 위치: korean_synthetic_data_pixelated/gt.txt

 

'AI > easyOCR' 카테고리의 다른 글

5. EasyOCR github trainer  (0) 2025.11.17
4. EasyOCR github  (1) 2025.11.15
3. EasyOCR 옵션.  (1) 2025.11.15
2. EasyOCR 단점.  (0) 2025.11.15
1. EasyOCR 시작하기.  (0) 2025.11.15