AI 모델 평가 입문 — 내 모델이 잘하는지 어떻게 아나?
정확도, BLEU, CER, SDR — 태스크마다 다른 평가 지표와 \"왜 이걸 쓰는지\"
왜 평가가 필요한가
파인튜닝을 했다. trainer.train()이 끝났다. 근데 내 모델이 진짜 잘하는지 어떻게 아나?
"돌려보니까 괜찮아 보이는데?"는 평가가 아니다. 숫자로 측정해야 한다.
핵심 개념: 정답이 있는 테스트 데이터
훈련 데이터: 모델이 학습하는 데 사용 (시험 공부 자료)
테스트 데이터: 모델을 평가하는 데 사용 (시험 문제)
시험 공부 자료(훈련 데이터)로 시험을 보면 당연히 100점이다. 의미 없다. 모델이 처음 보는 데이터로 평가해야 진짜 실력을 알 수 있다.
IMDB 데이터셋이 train 25,000개 + test 25,000개로 나뉜 이유가 이것이다.
from datasets import load_dataset
dataset = load_dataset("imdb")
# dataset["train"] → 25,000개 (훈련용, 모델이 봄)
# dataset["test"] → 25,000개 (평가용, 모델이 안 봄)
태스크별 평가 지표
1. 분류 (감정 분석, 이미지 분류 등) — 정확도(Accuracy)
가장 직관적. 맞은 개수 / 전체 개수.
from evaluate import load
accuracy = load("accuracy")
predictions = [1, 0, 1, 1, 0] # 모델 예측
references = [1, 0, 0, 1, 0] # 정답
result = accuracy.compute(predictions=predictions, references=references)
print(result)
# → {'accuracy': 0.8} (5개 중 4개 맞음 = 80%)
Precision / Recall / F1 — 정확도만으로 부족할 때:
100개 중 긍정 95개, 부정 5개인 데이터에서 "전부 긍정"이라고 찍으면 정확도 95%다. 근데 부정을 하나도 못 찾았다. 이럴 때 F1이 필요.
f1 = load("f1")
result = f1.compute(predictions=predictions, references=references, average="binary")
print(result) # → {'f1': 0.8}
| 지표 | 뭘 측정 | 공식 |
|---|---|---|
| Accuracy | 전체 중 맞은 비율 | 맞은 수 / 전체 |
| Precision | "긍정"이라고 한 것 중 진짜 긍정 | TP / (TP+FP) |
| Recall | 진짜 긍정 중 찾아낸 비율 | TP / (TP+FN) |
| F1 | Precision과 Recall의 조화 평균 | 2×P×R / (P+R) |
2. 텍스트 생성 (번역, 요약 등) — BLEU / ROUGE
생성된 텍스트가 정답과 얼마나 겹치는지 측정.
bleu = load("bleu")
predictions = ["The cat sat on the mat"]
references = [["The cat is on the mat"]] # 정답 (여러 개 가능)
result = bleu.compute(predictions=predictions, references=references)
print(f"BLEU: {result['bleu']:.2f}")
# → BLEU: 0.61 (61% 겹침)
| 지표 | 용도 | 측정 방식 |
|---|---|---|
| BLEU | 번역 | n-gram 겹침 (1~4단어 조합이 얼마나 같은지) |
| ROUGE | 요약 | 정답의 n-gram이 생성에 얼마나 포함되었는지 |
| BERTScore | 범용 | BERT 임베딩으로 의미적 유사도 (단어 겹침이 아닌 의미) |
BLEU 0.0 = 완전 다름, 1.0 = 완전 동일. 실전에서 0.3~0.5면 양호.
3. OCR — CER / WER
글자/단어 단위 오류율. 낮을수록 좋다.
cer = load("cer")
predictions = ["賃料は月額150,000円とする"]
references = ["賃料は月額150,000円とする"]
result = cer.compute(predictions=predictions, references=references)
print(f"CER: {result:.2%}")
# → CER: 0.00% (완벽 일치)
# 오류가 있는 경우
predictions_bad = ["賃料は月額150,000円とすろ"] # る → ろ
result_bad = cer.compute(predictions=predictions_bad, references=references)
print(f"CER: {result_bad:.2%}")
# → CER: 5.88% (17글자 중 1글자 틀림)
| 지표 | 단위 | 계산 |
|---|---|---|
| CER (Character Error Rate) | 글자 | (삽입+삭제+대체) / 정답 글자수 |
| WER (Word Error Rate) | 단어 | (삽입+삭제+대체) / 정답 단어수 |
CER 0% = 완벽. 실전에서 1~5%면 좋은 수준.
4. 음원 분리 — SDR
분리된 소리가 원본과 얼마나 가까운지. 높을수록 좋다.
# pip install mir_eval
import mir_eval
import numpy as np
reference = np.random.randn(44100) # 원본 보컬 (1초)
estimated = reference + 0.1 * np.random.randn(44100) # 분리된 보컬 (약간 노이즈)
sdr, sir, sar, _ = mir_eval.separation.bss_eval_sources(
reference[np.newaxis, :], estimated[np.newaxis, :]
)
print(f"SDR: {sdr[0]:.1f} dB")
# → SDR: 20.0 dB (높을수록 좋음)
| 지표 | 뭘 측정 | 좋은 수준 |
|---|---|---|
| SDR (Signal-to-Distortion Ratio) | 전체 왜곡 | 10+ dB |
| SIR (Signal-to-Interference Ratio) | 다른 소스 섞임 | 15+ dB |
| SAR (Signal-to-Artifacts Ratio) | 인공적 잡음 | 10+ dB |
5. 음성 인식 (STT) — WER
OCR의 WER과 동일. 인식된 텍스트와 정답 텍스트의 단어 오류율.
wer = load("wer")
result = wer.compute(
predictions=["hello how are you"],
references=["hello how old are you"]
)
print(f"WER: {result:.2%}")
# → WER: 20.00% (5단어 중 1단어 차이)
전체 지표 한눈에
| 태스크 | 지표 | 방향 | 코드 |
|---|---|---|---|
| 분류 | Accuracy | 높을수록 ↑ | load("accuracy") |
| 분류 | F1 | 높을수록 ↑ | load("f1") |
| 번역 | BLEU | 높을수록 ↑ | load("bleu") |
| 요약 | ROUGE | 높을수록 ↑ | load("rouge") |
| OCR | CER | 낮을수록 ↓ | load("cer") |
| OCR | WER | 낮을수록 ↓ | load("wer") |
| STT | WER | 낮을수록 ↓ | load("wer") |
| 음원 분리 | SDR | 높을수록 ↑ | mir_eval |
| 의미 유사도 | BERTScore | 높을수록 ↑ | load("bertscore") |
전부 pip install evaluate하면 load("지표명")으로 쓸 수 있다.
파인튜닝 + 평가 = 세트
# 감정 분석 파인튜닝에 평가 추가
from evaluate import load
import numpy as np
accuracy = load("accuracy")
def compute_metrics(eval_pred):
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return accuracy.compute(predictions=predictions, references=labels)
trainer = Trainer(
model=model,
train_dataset=dataset["train"],
eval_dataset=dataset["test"], # ← 테스트 데이터
compute_metrics=compute_metrics, # ← 평가 함수
args=TrainingArguments(
output_dir="./results",
eval_strategy="epoch", # ← 매 에폭마다 평가
)
)
trainer.train()
# 훈련 중 출력:
# Epoch 1: accuracy=0.82
# Epoch 2: accuracy=0.87
# Epoch 3: accuracy=0.89 ← 에폭마다 정확도가 올라가는 걸 볼 수 있다
compute_metrics를 Trainer에 넘기면 훈련 중에 자동으로 평가해준다. 에폭마다 "지금 내 모델이 몇 점인지" 숫자가 나온다.
평가 없이 파인튜닝하면?
과적합(overfitting)을 모른다. 훈련 데이터에서는 99%인데 실제 데이터에서는 50%일 수 있다. 시험 문제를 미리 봤으니 시험은 100점이지만, 실전에서는 못 푸는 것과 같다.
평가는 선택이 아니다. 파인튜닝의 필수 파트다.
핵심 개념
pip install evaluate — HuggingFace 평가 라이브러리 설치
metric = load(\"accuracy\") — 태스크에 맞는 지표 로드
metric.compute(predictions, references) — 예측과 정답 비교 → 숫자 1개
Trainer에 compute_metrics 추가 — 훈련 중 매 에폭마다 자동 평가