문서는 일상과 산업 전반에서 중요한 역할을 합니다. 특히 금융, 의료, 보험, 물류 등 다양한 도메인에서 생성되는 문서들은 구조적이지 않고 형식도 천차만별입니다. 이번 프로젝트의 목표는 주어진 문서 이미지의 타입을 17개의 클래스 중 하나로 분류하는 모델을 개발하는 것이었습니다.
우리는 다양한 형태의 문서를 이미지로 받아 분류하는 태스크를 수행하기 위해 CV 기반의 이미지 분류 모델을 활용했고, 단일 모델뿐 아니라 Two-Stage 모델 구조도 실험하며 성능 개선을 시도했습니다.
GPU: NVIDIA RTX 3090
CUDA: 12.2
Python 주요 라이브러리:
torch, torchvision, timm
albumentations, scikit-learn
학습 데이터: 총 1,570장의 문서 이미지
테스트 데이터: 총 3,140장
라벨은 총 17개의 클래스로 구성되어 있으며, meta.csv와 train.csv를 통해 정제된 매핑 정보 제공
특정 클래스 간 혼동 발생 : 입·퇴원확인서(3)와 외래진료증명서(7) 이력서(13)는 다양한 양식으로 인해 모델이 혼란스러워함 (일부 클래스(자동차 계기판, 자동차 등록판)은 다른 문서들과 시각적 이질성이 큼)
Label 오류가 있거나 명확하지 않은 라벨링 일부 수정
이미지 크기 및 포맷 통일
클래스 불균형을 고려해 일부 클래스 oversampling
Albumentations 라이브러리로 16종 이상의 Offline Augmentation 수행
RandomRotate90, Flip, GridDistortion, Perspective 등 다양한 시각적 왜곡 부여
train_transform = A.Compose([
A.RandomRotate90(),
A.Resize(height=img_size, width=img_size),
A.Flip(),
A.GaussNoise(p=0.3),
...
A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
ToTensorV2(),
])
model = timm.create_model(model_name, pretrained=True, num_classes=17).to(device)
다양한 input size 실험, 모델별 파라미터 크기 고려
a = train.target.value_counts().sort_index().reset_index()
a = a['count'].apply(lambda x: round(max(a['count'])/x, 5)).tolist()
a[3] *= 1.3
a[7] *= 1.3
스케줄러 실험
다양한 learning rate scheduler 사용:
LambdaLR (학습률 감소)
CosineAnnealingWarmRestarts (warm restart 전략)
Two-Stage 모델 전략 (by 김태한)
Stage 1: 문서 vs 자동차 계기판/번호판 분리
목적: 문서와 비문서(class 2, 16) 간의 시각적 차이를 먼저 분리하여 전체 정확도 상승 기대
전체 학습은 Fine-tuning 및 Classifier만 학습하는 Transfer Learning 두 방식으로 모두 수행
EarlyStopping 및 Scheduler 연동해 과적합 방지
이번 프로젝트는 단순한 이미지 분류 문제가 아닌, 비정형 문서 이미지의 시각적 다양성을 이해하고 모델링에 반영하는 것이 중요했습니다. 단일 모델로 해결되지 않는 혼동 클래스는 오히려 두 단계로 나누어 설계하거나, 클래스 기반 Loss 조정을 통해 해결할 수 있다는 점을 경험적으로 알 수 있었고, 이 과정을 통해 CV 분야에서의 실제 분류 전략을 깊이 있게 학습할 수 있었습니다.
또한 팀원 간의 적극적인 토의와 실험 결과 공유는 모델 선택과 학습 전략 결정에 중요한 역할을 했습니다. 다양한 모델 실험을 통해 우리 팀만의 최적 모델 조합을 찾을 수 있었고, 그 결과로 7위라는 유의미한 순위를 달성할 수 있었습니다.