ROUGE 스코어 이해하기

ROUGE 스코어 이해하기

  • Recall-Oriented : 재현율에 중점을 둔
  • Understudy : 인간을 대신하여
  • for Gisting Evaluation : 핵심 추출 평가

개발 목적: 

ROUGE는 원래 텍스트 요약을 평가하기 위해 개발 (Lin, 2004)


요약 평가

추론 - 정답 비교 평가 기준 : 정답에 담겨있는 핵심이 얼마나 잘 추론되었는가 (정답 얼마나 잘 맞췄나)


ROUGE 사용의 한계

핵심을 빠뜨리지 않기 위해, 요약을 하지 않는다면? (출력 MAX_Length를 정한다)


ROUGE 의 발전

  • 초기에는 재현율만을 평가했으나, 이후로 정밀도, f1 스코어까지 확장되었다.
  • ROUGE-L, ROUGE-S, ROUGE-SU 등 다양한 측정 방식으로 확장되었다.

결론: 

ROUGE는 요약 모델 평가에 가장 적합하고 널리 사용되지만, 다른 NLP 작업에도 사용할 수 있다. 다만 그 한계를 인식하고, 필요에 따라 다른 평가 지표와 함께 사용하는 것이 좋다. 최근에는 BERTScore, MoverScore 같은 의미적 유사성을 더 잘 포착하는 지표들도 있다.



실습

!pip install konlpy

from collections import Counter
from konlpy.tag import Okt
from nltk.util import ngrams


토큰화, n-gram화, 토큰의 빈도
def tokenize_korean(text):
    """한국어 텍스트를 토큰화합니다."""
    okt = Okt()
    return okt.morphs(text)  # 형태소 단위로 토큰화

def get_ngrams(tokens, n):
    """토큰에서 n-gram을 생성합니다."""
    return list(ngrams(tokens, n))

def count_ngrams(ngram_list):
    """n-gram의 빈도를 계산합니다."""
    return Counter(ngram_list)


reference=결과, candidate= 정답
reference = "인공지능 기술은 우리의 일상 생활을 변화시키고 있습니다."
candidate = "인공지능 기술이 우리 생활을 크게 변화시키고 있다."

# 토큰화
ref_tokens = tokenize_korean(reference)
cand_tokens = tokenize_korean(candidate)

# bi-gram 생성
ref_ngrams = get_ngrams(ref_tokens, 2)
cand_ngrams = get_ngrams(cand_tokens, 2)

# n-gram 빈도 계산
ref_count = count_ngrams(ref_ngrams)
cand_count = count_ngrams(cand_ngrams)


정답 기준으로 정답과 결과의 count를 비교하여, 작은 값을 가져온다.
정답: 2, 결과: 1 -> 1개 맞춤
정답: 2, 결과: 3 -> 2개 맞춤
# 일치하는 n-gram 계산
matches = 0
for ngram in cand_count:
    m = min(cand_count[ngram], ref_count.get(ngram, 0))
    print(m)

    matches += m


# @title 정답
def rouge_n(reference, candidate, n):
    """ROUGE-N 점수를 계산합니다.

    Args:
        reference: 참조 텍스트 (문자열)
        candidate: 후보 텍스트 (문자열)
        n: n-gram의 크기 (1 또는 2)

    Returns:
        precision, recall, f1 점수를 포함하는 튜플
    """
    # 토큰화
    ref_tokens = tokenize_korean(reference)
    cand_tokens = tokenize_korean(candidate)

    # n-gram 생성
    ref_ngrams = get_ngrams(ref_tokens, n)
    cand_ngrams = get_ngrams(cand_tokens, n)

    # n-gram 빈도 계산
    ref_count = count_ngrams(ref_ngrams)
    cand_count = count_ngrams(cand_ngrams)

    # 일치하는 n-gram 계산
    matches = 0
    for ngram in cand_count:
        matches += min(cand_count[ngram], ref_count.get(ngram, 0))

    # 정밀도, 재현율, F1 점수 계산
    precision = matches / max(sum(cand_count.values()), 1)
    recall = matches / max(sum(ref_count.values()), 1)

    if precision + recall == 0:
        f1 = 0
    else:
        f1 = 2 * precision * recall / (precision + recall)

    return precision, recall, f1

def rouge_1(reference, candidate):
    """ROUGE-1 점수를 계산합니다."""
    return rouge_n(reference, candidate, 1)

def rouge_2(reference, candidate):
    """ROUGE-2 점수를 계산합니다."""
    return rouge_n(reference, candidate, 2)



댓글 쓰기

다음 이전