포스트

[AI 말평 대회] 참여기 #2: 1주차(2) - 평가 지표 정리

[AI 말평 대회] 참여기 #2: 1주차(2) - 평가 지표 정리

AI 말평 대회 참여기 #2: 1주차(2) - 평가 지표 정리

1주차 첫 번째 시간에는 모델 탐색과 대회 이해에 집중했다.
이번 글에서는 가장 먼저 대회 평가 지표를 정리하고,
Exact Match(EM) + BLEURT + BERTScore + ROUGE-1
공식 코드 핵심 부분 및 수식까지 살펴보기로 결정하였다.

대회 공식 평가지표 코드는 GitHub에서 확인 가능하다.
평가 지표 코드 바로가기


1. 대회 평가 흐름 요약

대회에서는 단순 정확도가 아닌 문장 품질과 의미 유사도를 반영한 평가를 진행한다.

  1. 제출 JSON과 정답 JSON의 ID를 매칭
  2. 문제 유형에 따라 다른 지표 사용
    • 선택형/단답형 → Exact Match (EM) / Accuracy
    • 서술형/교정형 → BLEURT + BERTScore + ROUGE-1 평균
  3. 최종 점수 = 유형별 점수의 평균

실제 대회 코드에서는 evaluation_korean_contest_RAG_QA() 함수로
RAG 과제 점수를 계산하며,
정답 문장에서 정답(Answer)이유(Reason)를 분리해 각각 평가한다. (“가 올다.”를 기준으로)


2. 사용된 핵심 지표

이번 대회에서 중요한 지표는 네 가지다.

지표특징장점한계
EM예측과 정답이 완전히 일치 시 1점간단하고 직관적띄어쓰기·표기 차이도 0점
BLEURTBERT 기반 문장 품질 평가의미 유사도 반영, 사람 평가와 유사사전학습 필요, 연산량 큼
BERTScoreBERT 임베딩 기반 의미 유사도의미적 정밀 평가긴 문장 처리 시 느림
ROUGE-11-gram(단어) 중복률 기반 평가직관적, 계산 빠름의미 유사도 반영 못함

2-1. Exact Match (EM)

  • 개념
    예측 문장이 정답 문장과 완전히 동일하면 1점, 아니면 0점
    전체 점수는 샘플별 결과의 평균

  • 수식

\[EM = \frac{1}{N} \sum_{i=1}^{N} \mathbf{1}[\hat{y}_i = y_i]\]
  • 대회 코드 예시
1
2
3
4
5
6
7
8
9
10
11
def calc_exact_match(true_data, pred_data):
    correct = 0
    total = len(true_data)

    for true, pred in zip(true_data, pred_data):
        # 여러 정답이 '#'로 구분될 경우 처리
        acceptable_answers = true.split('#')
        if any(pred.strip() == ans.strip() for ans in acceptable_answers):
            correct += 1

    return correct / total if total > 0 else 0

2-2. BLEURT

  • 개념
    BLEURT(Bilingual Evaluation Understudy with Representations from Transformers)는
    BERT 기반 사전학습 모델로 문장의 자연스러움과 의미 일치도를 평가한다.

  • 수식 표현 (개념적)

\[BLEURT(\hat{y}, y) \approx MLP\big(\cos(\mathbf{h}_{\hat{y}}, \mathbf{h}_{y})\big)\]
  • $\mathbf{h}_{\hat{y}}$: 생성 문장 임베딩
  • $\mathbf{h}_{y}$: 참조 문장 임베딩

  • 대회 코드 예시
1
2
3
4
5
6
7
8
9
10
from bleurt import score

checkpoint = "BLEURT-20"
scorer = score.BleurtScorer(checkpoint)

def calc_bleurt(true_data, pred_data):
    if type(true_data[0]) is list:
        true_data = list(map(lambda x: x[0], true_data))
    scores = scorer.score(references=true_data, candidates=pred_data, batch_size=64)
    return sum(scores) / len(scores)

2-3. BERTScore

  • 개념
    생성 문장과 참조 문장의 의미 유사도를 BERT 임베딩 기반으로 평가한다.
    Precision / Recall / F1 스코어를 제공하며, F1을 최종 점수로 활용.

  • 수식

\[P = \frac{1}{|\hat{y}|} \sum_{x_i \in \hat{y}} \max_{y_j \in y} \cos(\mathbf{h}_{x_i}, \mathbf{h}_{y_j})\] \[R = \frac{1}{|y|} \sum_{y_j \in y} \max_{x_i \in \hat{y}} \cos(\mathbf{h}_{y_j}, \mathbf{h}_{x_i})\] \[F_1 = 2 \cdot \frac{P \cdot R}{P + R}\]
  • 대회 코드 예시
1
2
3
4
5
6
7
8
9
10
11
import evaluate
bert_scorer = evaluate.load('bertscore')
bert_model_type = 'bert-base-multilingual-cased'

def calc_bertscore(true_data, pred_data):
    if type(true_data[0]) is list:
        true_data = list(map(lambda x: x[0], true_data))
    scores = bert_scorer.compute(predictions=pred_data,
                                 references=true_data,
                                 model_type=bert_model_type)
    return sum(scores['f1']) / len(scores['f1'])

2-4. ROUGE-1

  • 개념
    ROUGE(Recall-Oriented Understudy for Gisting Evaluation)는
    n-gram 기반 중복률을 계산해 문장 유사도를 평가한다.
    그중 ROUGE-1은 1-gram(단어 단위) 일치율만 계산한다.

  • 수식

\[ROUGE\text{-}1 = \frac{|\text{생성 문장 단어} \cap \text{참조 문장 단어}|}{|\text{참조 문장 단어}|}\]
  • 대회 코드 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from rouge_metric import Rouge

def calc_ROUGE_1(true, pred):
    rouge_evaluator = Rouge(
        metrics=["rouge-n", "rouge-l"],
        max_n=2,
        limit_length=True,
        length_limit=1000,
        length_limit_type="words",
        use_tokenizer=True,
        apply_avg=True,
        apply_best=False,
        alpha=0.5,  # F1 score
        weight_factor=1.0,
    )
    scores = rouge_evaluator.get_scores(pred, true)
    return scores['rouge-1']['f']

2-5. ROUGE 계열 확장

ROUGE-“1” 이라는 이름에서 알 수 있듯이 ROUGE에는 여러 버전이 존재한다. ROUGE와 관련된 추가 함수에 대해 공부한 내용도 이곳에 정리하고자 한다.

1. ROUGE-N

  • 개념: n-gram 단위 일치율
  • 예시:
    • ROUGE-1 → 단어 단위
    • ROUGE-2 → 2-gram (연속 2단어)
    • ROUGE-3 → 3-gram
  • 수식
\[ROUGE\text{-}N = \frac{\sum_{g \in Ref} \min(Cand(g), Ref(g))}{\sum_{g \in Ref} Ref(g)}\]

2 ROUGE-L (Longest Common Subsequence)

  • 개념: 두 문장의 최장 공통 부분 수열(LCS) 기반
  • 장점: 단어 순서를 고려하면서도 일부 건너뛰기 허용
  • 활용: 요약, 서술형 생성 품질 평가 가능

3. ROUGE-W (Weighted LCS)

  • 개념: LCS 기반이지만 연속된 일치 구간에 가중치 부여
  • 활용: 자연스러운 연속 생성 평가 가능

3. 평가 함수 구조

대회 평가 핵심 함수는 evaluation_korean_contest_RAG_QA()로,
정답과 예측 데이터를 받아 정확도 + 생성 품질을 모두 측정한다. 코드가 굉장히 길기에 중요한 실행 과정만 요약해 보았다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def evaluation_korean_contest_RAG_QA(true_data, pred_data):
    scores = {
        "exact_match": 0,
        "rouge_1": 0,
        "bertscore": 0,
        "bleurt": 0,
        "descriptive_avg": 0,
        "final_score": 0
    }

    # 1. 정답/예측에서 답변과 이유를 분리
    # 2. Exact Match로 선택형 채점
    # 3. ROUGE-1, BERTScore, BLEURT 평균으로 서술형 채점
    # 4. 최종 점수 = (Exact Match + 서술형 평균) / 2

    return scores

4. 최종 점수 계산과 전략적 시사점

4-1. 최종 점수 계산

  1. Descriptive Average (서술형 품질 평균)
\[descriptive\_avg = \frac{BLEURT + BERTScore + ROUGE1}{3}\]
  1. Final Score (최종 점수)
\[final\_score = \frac{EM + descriptive\_avg}{2}\]
  • EM의 비중이 절반을 차지하므로, EM 확보가 성적에 가장 중요할 것 같다.

4-2. EM 확보 전략

  • EM은 정답 문장의 앞부분(“…이/가 옳다” 직전) 기준으로 채점
  • 따라서 다음이 중요:
    1. 정답 문장 앞부분을 정확히 재현
    2. “이/가 옳다” 형식 준수
  • BLEURT/BERTScore/ROUGE로 문장 품질을 높이는 것도 중요하지만,
    EM을 확보하지 못하면 최종 점수가 크게 낮아질 것이다.

5. 오늘 정리한 핵심

  1. EM(Exact Match) → 예측과 정답이 완전히 같을 때만 1점
  2. BLEURT → 의미 중심 문장 품질 평가, 사람 평가와 유사
  3. BERTScore → 임베딩 기반 의미 유사도, F1 스코어 활용
  4. ROUGE-1 → 단어 단위 일치율 기반, 빠르고 직관적
  5. 최종 점수 계산식 → EM과 Descriptive Avg의 평균으로 산출

결론: EM 확보가 최우선, 품질 지표는 이를 뒷받침하는 역할

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.