Skip to main content

텍스트 요약 (Text Summarization)

텍스트 요약은 긴 문서의 핵심 내용을 짧게 압축하는 태스크입니다. 뉴스 기사 요약, 회의록 정리, 논문 초록 생성, 대화 요약 등 정보 과부하 시대에 필수적인 기능입니다. 이 문서에서는 추출(Extractive) 요약과 생성(Abstractive) 요약 두 가지 접근법을 모두 실습합니다.

학습 목표

이 문서를 완료하면 다음을 수행할 수 있습니다.
  • Extractive 요약과 Abstractive 요약의 차이를 설명할 수 있습니다
  • TextRank 알고리즘으로 추출 요약을 구현할 수 있습니다
  • BART/T5 모델로 생성 요약을 수행할 수 있습니다
  • ROUGE 지표로 요약 품질을 평가할 수 있습니다

요약 방식 비교

항목Extractive (추출형)Abstractive (생성형)
방식원문에서 중요 문장 선택새로운 문장 생성
장점사실 왜곡 적음, 구현 간단자연스러운 요약, 재구성 가능
단점어색한 문장 연결환각(Hallucination) 위험
대표 방법TextRank, BERT-extBART, T5, Pegasus
학습 필요비지도 학습 가능대규모 학습 데이터 필요

실습 1: TextRank 추출 요약

1

TextRank 알고리즘 이해

TextRank는 Google의 PageRank를 텍스트에 적용한 알고리즘입니다. 학습 데이터 없이 비지도 방식으로 중요 문장을 추출합니다.동작 원리:
  1. 문서를 문장 단위로 분할합니다
  2. 각 문장을 벡터로 표현합니다 (TF-IDF 또는 문장 임베딩)
  3. 문장 간 유사도로 그래프를 구성합니다
  4. PageRank 알고리즘으로 각 문장의 중요도를 계산합니다
  5. 중요도가 높은 문장을 선택합니다
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

def textrank_summarize(text, num_sentences=3):
    """TextRank 기반 추출 요약"""
    # 1. 문장 분할
    sentences = text.split(". ")
    sentences = [s.strip() for s in sentences if len(s.strip()) > 10]

    if len(sentences) <= num_sentences:
        return ". ".join(sentences)

    # 2. TF-IDF 벡터화
    vectorizer = TfidfVectorizer()
    tfidf_matrix = vectorizer.fit_transform(sentences)

    # 3. 문장 간 유사도 행렬 (그래프의 간선 가중치)
    similarity_matrix = cosine_similarity(tfidf_matrix)

    # 4. PageRank 계산
    scores = np.ones(len(sentences)) / len(sentences)
    damping = 0.85  # 감쇠 계수

    for _ in range(30):  # 반복 수렴
        new_scores = (1 - damping) / len(sentences)
        for i in range(len(sentences)):
            weighted_sum = 0
            for j in range(len(sentences)):
                if i != j and similarity_matrix[i][j] > 0:
                    degree = similarity_matrix[j].sum() - similarity_matrix[j][j]
                    if degree > 0:
                        weighted_sum += (
                            similarity_matrix[i][j] / degree * scores[j]
                        )
            new_scores_i = (1 - damping) / len(sentences) + damping * weighted_sum
            scores[i] = new_scores_i

    # 5. 상위 문장 선택 (원문 순서 유지)
    ranked_indices = np.argsort(scores)[::-1][:num_sentences]
    ranked_indices = sorted(ranked_indices)

    summary = ". ".join([sentences[i] for i in ranked_indices])
    return summary + "."
2

한국어 TextRank 실습

한국어에서는 문장 분할과 토큰화에 주의가 필요합니다.
# 한국어 텍스트 예시
article = """
인공지능(AI) 기술이 의료 분야에서 혁신을 이끌고 있다.
특히 의료 영상 분석에서 딥러닝 모델의 정확도가 전문의 수준에 도달했다.
폐 CT 영상에서 폐암을 조기 발견하는 AI 모델은 방사선과 의사의 진단 정확도와
유사한 수준을 보여주고 있다.
그러나 AI 진단의 신뢰성과 설명 가능성에 대한 우려도 존재한다.
환자의 개인정보 보호와 의료 AI의 윤리적 사용에 대한 가이드라인이 필요하다.
전문가들은 AI가 의사를 대체하는 것이 아니라 보조하는 도구로 활용되어야 한다고 강조한다.
향후 AI 기술의 발전과 함께 의료 분야의 디지털 전환이 가속화될 것으로 전망된다.
""".strip()

summary = textrank_summarize(article, num_sentences=3)
print("요약 결과:")
print(summary)
문장 임베딩 활용: TF-IDF 대신 Sentence-BERT 같은 문장 임베딩을 사용하면 의미적 유사도를 더 정확하게 계산할 수 있습니다. 이는 의미 유사도 페이지에서 다룹니다.
3

KoBART 기반 Abstractive 요약

Abstractive 요약은 Sequence-to-Sequence 모델이 원문을 읽고 새로운 요약문을 생성합니다.
pip install transformers torch
from transformers import PreTrainedTokenizerFast, BartForConditionalGeneration

# KoBART 모델 로딩
model_name = "digit82/kobart-summarization"
tokenizer = PreTrainedTokenizerFast.from_pretrained(model_name)
model = BartForConditionalGeneration.from_pretrained(model_name)

def abstractive_summarize(text, max_length=128, min_length=32):
    """KoBART 기반 생성 요약"""
    inputs = tokenizer(
        text,
        return_tensors="pt",
        max_length=1024,
        truncation=True,
    )

    summary_ids = model.generate(
        inputs["input_ids"],
        max_length=max_length,
        min_length=min_length,
        num_beams=4,
        length_penalty=2.0,      # 긴 요약 선호
        no_repeat_ngram_size=3,   # 3-gram 반복 방지
        early_stopping=True,
    )

    summary = tokenizer.decode(
        summary_ids[0],
        skip_special_tokens=True,
    )
    return summary

# 요약 실행
summary = abstractive_summarize(article)
print("생성 요약:")
print(summary)
4

T5 기반 요약 (대안)

T5는 “모든 NLP 태스크를 텍스트-투-텍스트로” 통합한 모델입니다.
from transformers import T5ForConditionalGeneration, T5Tokenizer

model_name = "paust/pko-t5-base"
tokenizer = T5Tokenizer.from_pretrained(model_name)
model = T5ForConditionalGeneration.from_pretrained(model_name)

def t5_summarize(text, max_length=128):
    """T5 기반 생성 요약"""
    # T5는 태스크를 접두어로 지정
    input_text = f"summarize: {text}"

    inputs = tokenizer(
        input_text,
        return_tensors="pt",
        max_length=512,
        truncation=True,
    )

    outputs = model.generate(
        **inputs,
        max_length=max_length,
        num_beams=4,
        early_stopping=True,
    )

    return tokenizer.decode(outputs[0], skip_special_tokens=True)

print(t5_summarize(article))
5

ROUGE 평가

ROUGE(Recall-Oriented Understudy for Gisting Evaluation)는 요약 품질의 표준 평가 지표입니다.
import evaluate

rouge = evaluate.load("rouge")

# 예측 요약과 참조 요약
predictions = [summary]
references = ["AI 기술이 의료 영상 분석에서 혁신을 이끌고 있으나, "
               "신뢰성과 윤리적 사용에 대한 가이드라인이 필요하다."]

results = rouge.compute(
    predictions=predictions,
    references=references,
)

print(f"ROUGE-1: {results['rouge1']:.4f}")  # 유니그램 겹침
print(f"ROUGE-2: {results['rouge2']:.4f}")  # 바이그램 겹침
print(f"ROUGE-L: {results['rougeL']:.4f}")  # 최장 공통 부분 수열
지표계산 방식의미
ROUGE-1유니그램 겹침 비율단어 수준 유사도
ROUGE-2바이그램 겹침 비율구문 수준 유사도
ROUGE-L최장 공통 부분 수열 (LCS)문장 구조 유사도
ROUGE-Lsum문장 단위 LCS 평균다중 문장 요약

생성 파라미터 가이드

요약 생성 시 디코딩 파라미터가 결과 품질에 큰 영향을 미칩니다.
파라미터역할권장 값
num_beams빔 서치 빔 수4~6
length_penalty길이 페널티 (>1: 긴 출력 선호)1.0~2.0
no_repeat_ngram_size반복 방지 N-gram 크기3
min_length최소 출력 길이원문의 10~20%
max_length최대 출력 길이원문의 20~40%
early_stoppingEOS 토큰 생성 시 조기 종료True
no_repeat_ngram_size를 설정하세요 (3 권장). length_penalty를 낮추면 (0.5~1.0) 더 압축적인 요약이 생성됩니다. 모델이 충분히 학습되지 않았을 수 있으므로, 더 큰 모델이나 요약 전용 Fine-tuned 모델을 시도하세요.
한국어 전용 모델(KoBART, pko-t5)을 사용하세요. 다국어 모델(mBART, mT5)은 한국어 생성 품질이 전용 모델보다 낮을 수 있습니다. num_beams를 높이면 문법적 품질이 개선됩니다.
ROUGE는 n-gram 겹침 기반 지표이므로, 의미는 같지만 다른 표현을 사용하면 점수가 낮게 나올 수 있습니다. BERTScore나 인간 평가를 보조 지표로 사용하세요. Abstractive 요약에서는 ROUGE-L이 ROUGE-2보다 더 적합한 지표입니다.

다음 문서