tsKim
feat: schoolbridge spaces deploy (extract-text endpoint added)
7f105c8

카테고리 분류 모델 — 경이님 작업 가이드

이 문서는 경이님이 작업 내용을 빠르게 이해하고 바로 실행할 수 있도록 작성되었습니다.
코드가 이렇게 짜여졌는지, 무엇을 하는지 중심으로 설명합니다.


전체 구조 한눈에 보기

model/classification/
├── data/
│   ├── notice_sample_v3.csv        ← 경이님이 라벨링한 학습 데이터 (150개)
│   └── split_v1.csv                ← train/val/test 분할 (scripts 실행 후 생성됨)
├── src/
│   ├── predict.py                  ← 백엔드 진입점 (이게 핵심!)
│   ├── classifier_simple.py        ← 베이스라인 모델 (TF-IDF + LogReg)
│   └── classifier_kcelectra.py     ← KcELECTRA 추론 모듈
├── scripts/
│   ├── split_dataset.py            ← 데이터 분할 (딱 한 번만 실행)
│   └── evaluate_compare.py         ← 두 모델 성능 비교
├── notebooks/
│   ├── 01_train_kcelectra.ipynb    ← GPU 학습 (Colab에서 실행)
│   └── 02_evaluate_compare.ipynb   ← 성능 비교 시각화
├── checkpoints/
│   ├── simple_tfidf_logreg.pkl     ← 베이스라인 모델 저장 파일 (학습 후 생성)
│   └── kcelectra-category/         ← KcELECTRA 파인튜닝 결과 (Colab 후 복사)
└── README2.md                      ← 지금 이 파일

파이프라인에서 경이님 역할

전체 가정통신문 분석 시스템에서 경이님 모델은 [4]번 단계를 담당합니다.

[3] 윤정님 모델 (할일 추출)
        ↓
       text: "체험학습 비용 20,000원을 납부해 주세요."
             ↓
[4] 경이님 모델 (카테고리 분류)  ← 여기!
        ↓
    category: "비용"
        ↓
[5] 번역 → [6] 응답 빌드 → [7] TTS

윤정님이 추출한 문장들이 경이님 모델로 들어오고, 경이님 모델이 각 문장을 6개 카테고리 중 하나로 분류합니다.


6가지 카테고리 설명

카테고리 의미 예시
일정 날짜·시간·행사 관련 "운동회는 10월 5일 오전 9시에..."
준비물 챙겨야 할 물건 "도시락과 물을 준비해 주세요."
제출 서류·동의서 제출 "동의서를 담임선생님께 제출해 주세요."
비용 금액·납부 관련 "급식비 65,000원을 납부해 주세요."
건강·안전 건강·안전 지침 "발열 증상 시 등교를 자제해 주세요."
기타 위에 해당 없음 "궁금한 사항은 담임선생님께 문의..."

백엔드 연결 구조 이해하기

백엔드 backend/app/services/classifier.py가 이렇게 호출합니다:

from src.predict import predict_one
result = predict_one("납부할 급식비는 6만 5천원입니다.", model="simple")
# → {"category": "비용", "confidence": 0.87, "model_used": "simple"}

predict.pypredict_one()모든 모델의 단일 창구입니다.
model="simple" → TF-IDF+LogReg 사용
model="kcelectra" → KcELECTRA 파인튜닝 모델 사용
model="auto" → KcELECTRA 체크포인트 있으면 사용, 없으면 simple로 자동 전환


파일별 역할 상세 설명

data/notice_sample_v3.csv

학습 데이터 파일입니다. 컬럼 2개 (text, category).

  • 150개의 문장이 미리 라벨링 되어 있습니다
  • 각 카테고리당 약 20~25개씩 균등하게 구성
  • 더 많은 데이터를 추가할수록 모델 성능이 향상됩니다
    • 형식: 문장,카테고리 (맨 아래에 행 추가)
    • 카테고리는 반드시 일정, 준비물, 제출, 비용, 건강·안전, 기타 중 하나

src/classifier_simple.py — 베이스라인 (TF-IDF + Logistic Regression)

왜 TF-IDF인가?

  • TF-IDF는 각 단어가 문서에서 얼마나 중요한지 숫자로 나타냅니다
  • "납부", "입금", "원" 같은 단어가 비용 카테고리에서 많이 나오면 높은 점수를 받음
  • GPU 없이 CPU에서 수십 ms만에 실행 — 백엔드 서버 부담 없음

왜 char_wb n-gram인가?

  • 한국어는 "납부해" "납부하여" "납부하시기" 등 동사 변형이 많음
  • 글자 단위 2~4글자 조합(ngram_range=(2,4))으로 형태소 변형 문제 해결
  • 예: "납부" → "납부", "부하", "부해", "납부하" 등으로 분해해 학습

사용법:

cd model/classification
python src/classifier_simple.py          # 학습 + 저장
python src/classifier_simple.py --eval   # 테스트 평가

src/classifier_kcelectra.py — KcELECTRA 추론 모듈

왜 KcELECTRA인가?

  • 한국어 특화 사전학습 모델 (윤정님 모델과 동일한 backbone!)
  • ELECTRA 구조: BERT보다 학습 효율이 2~3배 좋음
  • koelectra-small: 메모리 사용량 적어 CPU 서버에서도 동작

중요: 이 파일은 추론만 합니다. 학습은 notebooks/01_train_kcelectra.ipynb에서.

학습이 끝나면 checkpoints/kcelectra-category/ 폴더가 생깁니다. 이 폴더가 없으면 is_ready() 함수가 False를 반환하여 simple로 자동 전환됩니다.

src/predict.py — 백엔드 진입점

왜 이 파일이 중요한가?

  • 백엔드가 from src.predict import predict_one으로 이 함수를 호출
  • 내부에서 어떤 모델을 쓸지 결정하는 로직 포함
  • model="auto"로 설정하면 체크포인트 유무에 따라 자동 선택

반환 형식:

{
    "text":       "납부할 급식비는 6만 5천원입니다.",
    "category":   "비용",       # 최종 분류 결과
    "confidence": 0.87,         # 얼마나 확신하는지 (0~1)
    "model_used": "simple",     # 실제 사용된 모델
    "probs": {                  # explain=True일 때만 포함
        "일정": 0.02,
        "비용": 0.87,
        ...
    }
}

scripts/split_dataset.py — 데이터 분할

왜 딱 한 번만 실행해야 하는가?

  • 베이스라인과 KcELECTRA가 완전히 동일한 데이터로 학습/평가해야 공정한 비교 가능
  • 한 번 분할하면 split_v1.csv에 고정 저장
  • 랜덤 시드 42로 고정 → 언제 실행해도 같은 결과
python scripts/split_dataset.py         # 최초 1회 실행
python scripts/split_dataset.py --force # 강제 재생성 (비추천)

분할 비율: Train 80% / Val 10% / Test 10%
Stratified Split: 각 카테고리에서 균등하게 뽑음

scripts/evaluate_compare.py — 성능 비교

두 모델을 같은 test 데이터로 평가하고 결과를 저장합니다.

python scripts/evaluate_compare.py

생성 파일:

  • data/eval_results_simple.json — 베이스라인 상세 결과
  • data/eval_results_kcelectra.json — KcELECTRA 상세 결과
  • data/eval_comparison_summary.csv — 두 모델 비교 요약

실행 순서 (처음부터 전부 하려면)

Step 1. 데이터 분할 (딱 한 번)

cd c:\Users\kysop\Team_Project_Multiculture\multicultural-ai\model\classification
python scripts/split_dataset.py

Step 2. 베이스라인 학습

python src/classifier_simple.py

checkpoints/simple_tfidf_logreg.pkl 파일이 생성됩니다.

Step 3. KcELECTRA 파인튜닝 (Colab GPU 필요)

  1. Google Colab 접속 → 런타임 → 런타임 유형 변경 → GPU
  2. notebooks/01_train_kcelectra.ipynb 업로드
  3. data/notice_sample_v3.csvdata/split_v1.csv 업로드
  4. 모든 셀 순서대로 실행 (~20분)
  5. checkpoints/kcelectra-category/ 폴더 다운로드
  6. 로컬 checkpoints/kcelectra-category/에 붙여넣기

Step 4. 성능 비교

python scripts/evaluate_compare.py

Step 5. 시각화 확인

Jupyter에서 notebooks/02_evaluate_compare.ipynb 열어서 실행.


평가 지표 설명

Macro F1 (메인 지표)

  • 6개 카테고리 각각의 F1을 구한 뒤 평균
  • 클래스 불균형에 강함 (특정 클래스가 많아도 편향 없음)
  • 0.8 이상이면 좋은 성능

F1 Score = 2 × (Precision × Recall) / (Precision + Recall)

  • Precision (정밀도): "비용이라고 예측한 것 중 실제로 비용인 비율"
  • Recall (재현율): "실제 비용인 것 중 비용이라고 맞춘 비율"
  • F1은 이 둘의 균형

Confusion Matrix

행 = 실제 카테고리, 열 = 예측 카테고리
대각선이 클수록 좋음 (맞게 분류한 것들)


KcELECTRA 채택 기준

Simple 대비 Macro F1이 5% 이상 향상되면 KcELECTRA 채택

  • ΔF1 ≥ +0.05 → KcELECTRA 채택, predict_one에서 model="kcelectra"로 변경
  • ΔF1 < 0.05 → Simple 유지 (안정성 우선)
  • Simple은 항상 fallback으로 유지

자주 묻는 질문

Q. 베이스라인 학습이 안 되고 파일을 못 찾는다고 에러가 난다면?
cd model/classification 후 실행하세요. 경로 기준이 model/classification/입니다.

Q. 데이터를 더 추가하고 싶은데 어떻게 하나요?
data/notice_sample_v3.csv 맨 아래에 문장,카테고리 형식으로 행 추가.
단, split_v1.csv가 없는 상태라면 추가 후 split_dataset.py 실행.
이미 split_v1.csv가 있다면 --force로 재분할.

Q. KcELECTRA 학습이 CUDA OOM 에러가 난다면?
01_train_kcelectra.ipynbBATCH_SIZE = 168로 줄이세요.

Q. predict_one이 항상 "기타"만 반환한다면?
→ 베이스라인 모델(pkl 파일)이 없는 것. python src/classifier_simple.py 먼저 실행.

##4월30일##작업 완료 — feature/kyeongyi-classification 브랜치 model/classification/ 폴더에 다음 구조가 완성됐습니다:

model/classification/ ├── data/ │ ├── notice_sample_v3.csv ← 새로 만든 학습 데이터 (150개, 6카테고리 균등) │ ├── notices_labeled_v2.csv ← 기존 라벨 데이터 복원 (병합 학습에 사용) │ └── notices_labeled_v2.jsonl ← 기존 원본 데이터 복원 ├── src/ │ ├── predict.py ← 백엔드 진입점 (predict_one 함수) │ ├── classifier_simple.py ← 베이스라인: TF-IDF + LogReg (CPU) │ └── classifier_kcelectra.py ← KcELECTRA 추론 모듈 ├── scripts/ │ ├── split_dataset.py ← 데이터 공정 분할 (딱 한 번 실행) │ └── evaluate_compare.py ← 두 모델 성능 비교 ├── notebooks/ │ ├── 01_train_kcelectra.ipynb ← GPU 학습 (Colab T4, ~20분) │ └── 02_evaluate_compare.ipynb ← 성능 비교 시각화 ├── checkpoints/ ← 학습 후 모델 파일 저장 위치 ├── docs/ │ └── devlog_2026-04-30.md ← 오늘 개발일지 └── README2.md ← 상세 가이드

지금 바로 실행할 순서:

python scripts/split_dataset.py → 데이터 분할 python src/classifier_simple.py → 베이스라인 학습 Colab에서 notebooks/01_train_kcelectra.ipynb → KcELECTRA 파인튜닝 (GPU) python scripts/evaluate_compare.py → 두 모델 성능 비교 notebooks/02_evaluate_compare.ipynb → 시각화 차트 생성 (발표 근거 자료) 백엔드가 호출하는 predict_one() 인터페이스는 기존과 완전히 호환되며, model="simple" / "kcelectra" / "auto" 세 가지 모드를 지원합니다. 자세한 설명은 README2.md와 devlog_2026-04-30.md를 참고.