Spaces:
Sleeping
Sleeping
| # 모델 A — 추출 파이프라인 (A단계: 이진 분류 + B단계: 카테고리 분류) | |
| **담당: 윤정** · `model/extraction/` · KoELECTRA fine-tuned | |
| --- | |
| ## 한 줄 요약 | |
| > 가정통신문 원문 텍스트를 넣으면, 학부모가 실행해야 할 **후보 문장 리스트**가 나옵니다 (B단계 입력용). | |
| --- | |
| ## 2단계 구조 | |
| ```text | |
| ┌──────────────────────────────────────────────────────────────┐ | |
| │ 가정통신문 원문 텍스트 (OCR 출력) │ | |
| └─────────────────────────┬────────────────────────────────────┘ | |
| │ | |
| ┌─────────────────▼──────────────────┐ | |
| │ A단계 — 윤정 담당 │ | |
| │ file/predict.py │ | |
| │ │ | |
| │ ① split_sentences() │ | |
| │ 줄바꿈 복원 + 문장 분리 │ | |
| │ (헤더·OCR 노이즈 조기 차단) │ | |
| │ │ | |
| │ ② is_likely_todo() │ | |
| │ 정규식 1차 필터 │ | |
| │ → KoELECTRA 이진 분류 │ | |
| │ 0: 노이즈 1: 할 일·중요 일정 │ | |
| │ │ | |
| │ ③ extract_due_date() │ | |
| │ extract_amount() │ | |
| │ extract_action_hint() │ | |
| │ 정규식으로 날짜·금액·행동 추출 │ | |
| └─────────────────┬──────────────────┘ | |
| │ | |
| list[dict] — B단계 입력 스키마 | |
| {"text", "source", "due_date", | |
| "amount", "confidence", "action_hint"} | |
| │ | |
| ┌─────────────────▼──────────────────┐ | |
| │ B단계 — 경이 담당 │ | |
| │ KoELECTRA 5-class 카테고리 분류 │ | |
| │ (제출·준비물·건강·안전·비용·일정·기타) │ | |
| └────────────────────────────────────┘ | |
| ``` | |
| --- | |
| ## 기술 스택 | |
| | | | | |
| | --- | --- | | |
| | A단계 모델 | KoELECTRA-small-v3 이진 분류 (`checkpoints/koelectra-binary/`) | | |
| | B단계 모델 | KoELECTRA-base-v3 5-class · `yunjeong116/koelectra-extractor` | | |
| | 날짜 / 금액 | 정규식 (regex) | | |
| | 실행 환경 | CPU / GPU 자동 선택 | | |
| | 의존성 | `torch` · `transformers` · `huggingface_hub` · `sklearn` | | |
| > **이전 → 현재:** Llama-3-Korean 8B (Colab T4, 4-bit 양자화) → KoELECTRA 하이브리드 | |
| > 추론 속도 ↑, 서버 배포 용이성 ↑ | |
| --- | |
| ## 카테고리 & 중요도 (B단계) | |
| | 카테고리 | 설명 | 기본 점수 | | |
| | --- | --- | --- | | |
| | `제출` | 서류 · 동의서 · 과제 | **1.00** | | |
| | `준비물` | 지참물 안내 | 0.85 | | |
| | `건강·안전` | 건강 · 안전 사항 | 0.80 | | |
| | `비용` | 금액 포함 항목 (정규식) | 0.75 | | |
| | `일정` | 행사 · 일정 안내 | 0.70 | | |
| | `기타` | 위 외 항목 | 0.50 | | |
| 긴급 키워드(`반드시`, `마감`, `즉시` 등) 포함 시 +0.05 / due_date 있을 시 +0.05 | |
| --- | |
| ## 모델 성능 (B단계 카테고리 분류기) | |
| ### v2 재학습 결과 (2026-04-28 · 15 epoch · cosine LR · WeightedCrossEntropy) | |
| ```text | |
| precision recall f1-score support | |
| 일정 1.0000 1.0000 1.0000 4 | |
| 준비물 1.0000 0.5000 0.6667 4 | |
| 제출 0.8000 1.0000 0.8889 4 | |
| 건강·안전 0.8571 0.8571 0.8571 7 | |
| 기타 0.5000 1.0000 0.6667 1 | |
| accuracy 0.8500 20 | |
| macro avg 0.8314 0.8714 0.8159 20 | |
| weighted avg 0.8850 0.8500 0.8444 20 | |
| ``` | |
| ### v1 → v2 비교 | |
| | 지표 | v1 (10 epoch) | v2 (15 epoch) | 변화 | | |
| | ------ | -------------- | -------------- | ------ | | |
| | **accuracy** | 0.7500 | **0.8500** | +0.10 ✅ | | |
| | **macro F1** | 0.5988 | **0.8159** | +0.22 ✅ | | |
| | 기타 F1 | 0.0000 | **0.6667** | 완전 회복 ✅ | | |
| > MVP 목표 (accuracy ≥ 0.80, macro F1 ≥ 0.75) 달성 | |
| > 학습 파라미터: `num_train_epochs=15`, `lr=2e-5`, `scheduler=cosine`, `warmup_ratio=0.1`, `WeightedCrossEntropy(balanced)` | |
| --- | |
| ## 버그 수정 이력 (2026-04-27) | |
| | # | 현상 | 원인 | 수정 | | |
| | --- | ------ | ------ | ------ | | |
| | Bug 1 | 인사말이 TODO로 잡힘 | `NON_TODO_PATTERNS`에 `안녕하세요` 미포함 | 패턴 3개 추가 | | |
| | Bug 2 | NLLB 첫 번역 문장 어색 | 제목 줄이 인사말과 합쳐져 번역 전달 | `_HEADER_ONLY` 필터 추가 | | |
| | Bug 3 | `원→won` 오탐 | `원하시는`, `원인` 등 substring 매칭 | `MONEY_PATTERN`에 숫자 선행 조건 강제 | | |
| --- | |
| ## 파일 구성 | |
| ```text | |
| model/extraction/ | |
| ├── fill_original2.py ← notices_original2.jsonl 자동 채우기 스크립트 | |
| ├── file/ | |
| │ ├── predict.py ← A단계 메인 파이프라인 (백엔드 진입점) | |
| │ ├── evaluate_model.py ← Base vs Fine-tuned 성능 비교 (강사 제출용) | |
| │ ├── preprocess_txt_to_jsonl.py ← PDF txt → JSONL 변환 (문장 단위, 라벨링용) | |
| │ └── txt_to_jsonl.py ← PDF txt → JSONL 변환 (문서 단위) | |
| ├── data/ | |
| │ ├── notices_labeled_v2.jsonl ← 학습 라벨 데이터 (100문장, is_todo + original_id) | |
| │ ├── notices_original2.jsonl ← 원문 27장 + category/keywords/importance 자동 채우기 | |
| │ ├── notices_original2.csv ← CSV 버전 | |
| │ └── galsan_txt/ ← 갈산초 가정통신문 txt 원본 (~100건) | |
| ├── checkpoints/ | |
| │ └── koelectra-extractor/ ← B단계 5-class 카테고리 분류 체크포인트 (Hub 백업) | |
| ├── docs/ | |
| │ ├── devlog-2026-04-27.md ← Bug 수정 3종 + 학습 파라미터 개선 | |
| │ ├── devlog-2026-04-28.md ← notices_original2.jsonl 자동 채우기 작업 | |
| │ └── devlog-2026-04-28-v2.md ← v2 재학습 결과 (accuracy 0.85 달성) | |
| └── x/ ← 구버전 보관 (Llama Few-shot + 구 predict.py) | |
| ├── MODEL.py | |
| ├── predict.py | |
| ├── notices_labeled_v2.csv | |
| └── extracted_results.json | |
| ``` | |
| --- | |
| ## A단계 출력 예시 (`file/predict.py`) | |
| B단계(경이 모델) 입력 스키마: | |
| ```json | |
| [ | |
| { | |
| "text": "개인용 이어폰(3.5mm) 4월 20일까지 준비해 주세요.", | |
| "source": "sample.txt", | |
| "due_date": "2026-04-20", | |
| "amount": null, | |
| "confidence": 0.9312, | |
| "action_hint": "준비" | |
| }, | |
| { | |
| "text": "구입비는 5,000원 이내의 잔돈으로 준비합니다.", | |
| "source": "sample.txt", | |
| "due_date": null, | |
| "amount": 5000, | |
| "confidence": 0.8741, | |
| "action_hint": "준비" | |
| } | |
| ] | |
| ``` | |
| --- | |
| ## 실행 | |
| ### A단계 추출 (직접 테스트) | |
| ```bash | |
| pip install torch transformers | |
| python model/extraction/file/predict.py | |
| ``` | |
| ### 모델 성능 평가 (Base vs Fine-tuned 비교) | |
| ```bash | |
| pip install scikit-learn pandas | |
| python model/extraction/file/evaluate_model.py | |
| # 테스트 데이터 직접 지정 시: | |
| python model/extraction/file/evaluate_model.py --test_data data/test_data.jsonl | |
| ``` | |
| ### txt → JSONL 변환 (데이터 전처리) | |
| ```bash | |
| # 문서 단위 (notices_original2.jsonl 스키마) | |
| python model/extraction/file/txt_to_jsonl.py \ | |
| --input data/galsan_txt/*.txt \ | |
| --output data/notices_original2.jsonl \ | |
| --source_type 초등학교 | |
| # 문장 단위 (학습 라벨링용) | |
| python model/extraction/file/preprocess_txt_to_jsonl.py \ | |
| --input_dir data/galsan_txt \ | |
| --output data/notices_labeled.jsonl | |
| ``` | |
| ### notices_original2.jsonl 자동 채우기 | |
| ```bash | |
| python model/extraction/fill_original2.py | |
| ``` | |
| 멱등성 보장 — 재실행 시 항상 재계산하여 덮어씀. | |
| --- | |
| ## 백엔드 연동 | |
| ```python | |
| from model.extraction.file.predict import predict | |
| # A단계: 후보 문장 추출 → B단계 입력 | |
| candidates = predict(notice_text, source="파일명.pdf") | |
| # [{"text", "source", "due_date", "amount", "confidence", "action_hint"}, ...] | |
| ``` | |
| 모델은 첫 호출 시 로컬 체크포인트(`checkpoints/koelectra-binary/`)를 우선 로드하고, | |
| 없으면 HuggingFace Hub(`yunjeong116/koelectra-extractor`)에서 자동 다운로드합니다. | |
| --- | |
| ## 데이터 구성 | |
| | 파일 | 내용 | 건수 | | |
| | ------ | ------ | ------ | | |
| | `notices_labeled_v2.jsonl` | 문장 단위 라벨 (is_todo + category + original_id) | 100문장 (N01~N19) | | |
| | `notices_original2.jsonl` | 원문 문서 단위 + category/keywords/importance | 27건 | | |
| | `galsan_txt/` | 갈산초 가정통신문 원본 txt | ~100건 | | |
| > `notices_labeled_v2.jsonl`의 `original_id` 필드로 원문(`notices_original2.jsonl`)과 연결 가능. | |
| > N16~N19(알림장 4건)는 27장 원문 미포함 → `original_id: null`. | |
| --- | |
| ## 잔존 한계 및 향후 작업 | |
| | 항목 | 내용 | | |
| | ------ | ------ | | |
| | 준비물 recall 0.50 | 4개 중 2개 오분류. 데이터 추가 시 개선 여지 있음 | | |
| | 기타 support=1 | 검증셋 샘플 1개 → F1 신뢰도 낮음. 가상 데이터 증강 필요 | | |
| | 전체 샘플 100개 | 데이터 절대량 부족. 가상 데이터 추가 후 3차 학습 예정 (목표: 준비물·기타 F1 ≥ 0.70) | | |
| | Binary 체크포인트 | `checkpoints/koelectra-binary/` 미배포 상태 — Colab 재학습 후 교체 필요 | | |