跳到主要内容

文本摘要

文本摘要(Text Summarization)是将长文本压缩成简短、准确、保留核心信息的过程。在信息爆炸的时代,自动摘要技术可以帮助用户快速获取关键信息,提高信息处理效率。

什么是文本摘要

文本摘要的目标是生成一个简洁的版本,保留原文的主要信息,同时减少冗余。一个好的摘要应该具备以下特点:

简洁性:摘要应该比原文短很多,通常压缩率在 10%-30%。

信息保留:保留原文的核心信息和关键内容。

连贯性:摘要本身应该是通顺、连贯的文本。

准确性:摘要内容应该忠实于原文,不引入错误信息。

摘要的类型

抽取式摘要

抽取式摘要从原文中选择重要的句子或段落,组合成摘要。这种方法不生成新文本,只是筛选和排列原文内容。

优点是实现简单、结果可解释、不会产生事实错误。缺点是摘要可能不够连贯、灵活性较低。

生成式摘要

生成式摘要理解原文内容后,用新的语言重新组织表达。这更接近人类撰写摘要的方式。

优点是摘要更连贯、可以综合多个句子的信息、灵活性高。缺点是实现复杂、可能产生事实错误。

混合式摘要

结合抽取和生成的优点,先抽取重要内容,再进行改写和重组。

抽取式摘要

基于频率的方法

最简单的抽取式摘要方法是基于词频:包含更多高频词的句子通常更重要。

import jieba
from collections import Counter

def extract_summary_by_frequency(text, num_sentences=3):
"""基于词频的抽取式摘要"""
# 分句
sentences = text.split('。')
sentences = [s.strip() for s in sentences if s.strip()]

# 分词并统计词频
words = []
for sentence in sentences:
words.extend(jieba.cut(sentence))

# 过滤停用词
stop_words = {'的', '了', '在', '是', '我', '有', '和', '就', '不', '人', '都', '一', '一个', '上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有', '看', '好', '自己', '这'}
words = [w for w in words if w not in stop_words and len(w) > 1]

word_freq = Counter(words)

# 计算每个句子的得分
sentence_scores = []
for sentence in sentences:
sentence_words = list(jieba.cut(sentence))
sentence_words = [w for w in sentence_words if w not in stop_words and len(w) > 1]
score = sum(word_freq.get(w, 0) for w in sentence_words)
sentence_scores.append((sentence, score))

# 选择得分最高的句子
sentence_scores.sort(key=lambda x: x[1], reverse=True)
summary_sentences = [s[0] for s in sentence_scores[:num_sentences]]

return '。'.join(summary_sentences) + '。'

# 示例
text = """
自然语言处理是人工智能领域中最具挑战性的研究方向之一。
它致力于让计算机能够理解和处理人类语言。
自然语言处理技术广泛应用于机器翻译、情感分析、问答系统等领域。
深度学习的发展极大地推动了自然语言处理的进步。
近年来,预训练语言模型如BERT和GPT取得了巨大成功。
这些模型在多项NLP任务上刷新了最佳成绩。
"""

summary = extract_summary_by_frequency(text, num_sentences=2)
print("摘要:", summary)

TextRank 算法

TextRank 是一种基于图的排序算法,类似于网页排名的 PageRank。它将句子作为图的节点,句子之间的相似度作为边的权重,通过迭代计算每个句子的重要性。

import jieba
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

def text_rank_summary(text, num_sentences=3, damping=0.85, max_iter=100):
"""TextRank 摘要算法"""
# 分句
sentences = text.split('。')
sentences = [s.strip() for s in sentences if s.strip()]

if len(sentences) <= num_sentences:
return text

# 使用 TF-IDF 计算句子相似度
vectorizer = TfidfVectorizer(tokenizer=lambda x: jieba.cut(x))
tfidf_matrix = vectorizer.fit_transform(sentences)

# 计算相似度矩阵
similarity_matrix = cosine_similarity(tfidf_matrix)

# 归一化
for i in range(len(similarity_matrix)):
similarity_matrix[i] /= similarity_matrix[i].sum() if similarity_matrix[i].sum() > 0 else 1

# TextRank 迭代
scores = np.ones(len(sentences)) / len(sentences)

for _ in range(max_iter):
new_scores = np.ones(len(sentences)) * (1 - damping) / len(sentences)
for i in range(len(sentences)):
for j in range(len(sentences)):
if i != j:
new_scores[i] += damping * similarity_matrix[j][i] * scores[j]

if np.abs(new_scores - scores).sum() < 1e-6:
break
scores = new_scores

# 选择得分最高的句子
ranked_indices = np.argsort(scores)[::-1][:num_sentences]
ranked_indices = sorted(ranked_indices) # 按原顺序排列

summary = '。'.join([sentences[i] for i in ranked_indices])
return summary + '。'

# 示例
text = """
自然语言处理是人工智能的重要分支。
它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。
自然语言处理是一门融语言学、计算机科学、数学于一体的科学。
在自然语言处理领域,深度学习技术取得了显著进展。
循环神经网络、Transformer等模型被广泛应用。
预训练语言模型如BERT、GPT等成为主流技术。
这些模型通过大规模无监督学习获得语言知识。
"""

summary = text_rank_summary(text, num_sentences=3)
print("摘要:", summary)

使用预训练模型进行抽取式摘要

from transformers import pipeline

# 加载摘要模型
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")

# 英文摘要示例
text = """
Natural language processing (NLP) is a subfield of linguistics, computer science,
and artificial intelligence concerned with the interactions between computers and
human language, in particular how to program computers to process and analyze
large amounts of natural language data. The result is a computer capable of
understanding the contents of documents, including the contextual nuances of
the language within them. The technology can then accurately extract information
and insights contained in the documents as well as categorize and organize the
documents themselves.
"""

summary = summarizer(text, max_length=50, min_length=25, do_sample=False)
print(f"原文: {text[:100]}...")
print(f"摘要: {summary[0]['summary_text']}")

生成式摘要

使用 Seq2Seq 模型

生成式摘要通常使用 Seq2Seq 架构,编码器编码原文,解码器生成摘要。

from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
import torch

def generate_summary(text, model_name="google/pegasus-xsum", max_length=100):
"""使用预训练模型生成摘要"""
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)

# 分词
inputs = tokenizer(
text,
max_length=1024,
truncation=True,
return_tensors="pt"
)

# 生成摘要
summary_ids = model.generate(
inputs["input_ids"],
max_length=max_length,
min_length=30,
num_beams=4,
early_stopping=True,
no_repeat_ngram_size=3
)

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

# 示例
text = """
人工智能正在改变各行各业。在医疗领域,AI辅助诊断系统可以帮助医生更准确地识别疾病。
在金融领域,算法交易和风险评估模型提高了效率。在教育领域,个性化学习系统根据学生特点定制教学内容。
然而,AI的发展也带来了挑战,包括就业影响、数据隐私和伦理问题。
如何在推动技术进步的同时解决这些问题,是社会需要共同面对的课题。
"""

summary = generate_summary(text)
print(f"原文: {text[:100]}...")
print(f"摘要: {summary}")

使用中文摘要模型

from transformers import BertTokenizer, BertForConditionalGeneration

def chinese_summary(text, model_name="fnlp/bart-base-chinese"):
"""中文文本摘要"""
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertForConditionalGeneration.from_pretrained(model_name)

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

summary_ids = model.generate(
inputs["input_ids"],
max_length=128,
min_length=20,
num_beams=4,
early_stopping=True
)

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

# 示例
text = """
深度学习是机器学习的一个子领域,它使用多层神经网络来学习数据的表示。
深度学习在图像识别、语音识别、自然语言处理等领域取得了突破性进展。
卷积神经网络在图像处理方面表现出色,循环神经网络则擅长处理序列数据。
Transformer架构的出现进一步推动了深度学习在NLP领域的发展。
"""

summary = chinese_summary(text)
print(f"摘要: {summary}")

使用大语言模型

大语言模型在生成式摘要方面表现出色,能够生成流畅、连贯的摘要。

from transformers import AutoModelForCausalLM, AutoTokenizer

def llm_summary(text, model_name="Qwen/Qwen2-1.5B-Instruct", max_new_tokens=200):
"""使用大语言模型生成摘要"""
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)

# 构建提示
prompt = f"请为以下文本生成一个简洁的摘要,保留关键信息:\n\n{text}\n\n摘要:"

inputs = tokenizer(prompt, return_tensors="pt")

outputs = model.generate(
inputs["input_ids"],
max_new_tokens=max_new_tokens,
temperature=0.7,
top_p=0.9,
do_sample=True
)

response = tokenizer.decode(outputs[0], skip_special_tokens=True)
summary = response.split("摘要:")[-1].strip()

return summary

# 示例
text = """
量子计算是一种利用量子力学原理进行信息处理的技术。
与经典计算机使用比特(0或1)不同,量子计算机使用量子比特,可以同时处于0和1的叠加态。
这种特性使得量子计算机在处理某些特定问题时具有指数级的速度优势。
目前,量子计算仍处于早期发展阶段,但在密码学、药物研发、金融建模等领域展现出巨大潜力。
"""

summary = llm_summary(text)
print(f"摘要: {summary}")

微调摘要模型

当预训练模型不能很好地处理特定领域文本时,可以进行微调。

准备数据

from datasets import load_dataset
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, DataCollatorForSeq2Seq
from transformers import Seq2SeqTrainingArguments, Seq2SeqTrainer
import evaluate

# 加载数据集
dataset = load_dataset("cnn_dailymail", "3.0.0")

# 查看数据
print(dataset["train"][0])

# 加载分词器和模型
model_name = "google-t5/t5-small"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)

# 预处理函数
def preprocess_function(examples):
inputs = ["summarize: " + doc for doc in examples["article"]]
model_inputs = tokenizer(
inputs,
max_length=512,
truncation=True,
padding="max_length"
)

labels = tokenizer(
examples["highlights"],
max_length=128,
truncation=True,
padding="max_length"
)

model_inputs["labels"] = labels["input_ids"]
return model_inputs

# 预处理数据集
tokenized_dataset = dataset.map(
preprocess_function,
batched=True,
remove_columns=dataset["train"].column_names
)

# 数据整理器
data_collator = DataCollatorForSeq2Seq(tokenizer, model=model)

训练配置

# 加载评估指标
rouge = evaluate.load("rouge")

def compute_metrics(eval_pred):
predictions, labels = eval_pred

# 解码
decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True)
labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)

# 计算 ROUGE 分数
result = rouge.compute(
predictions=decoded_preds,
references=decoded_labels,
use_stemmer=True
)

# 计算生成长度
prediction_lens = [np.count_nonzero(pred != tokenizer.pad_token_id) for pred in predictions]
result["gen_len"] = np.mean(prediction_lens)

return {k: round(v, 4) for k, v in result.items()}

# 训练参数
training_args = Seq2SeqTrainingArguments(
output_dir="./summarization_model",
evaluation_strategy="epoch",
learning_rate=2e-5,
per_device_train_batch_size=8,
per_device_eval_batch_size=8,
weight_decay=0.01,
save_total_limit=3,
num_train_epochs=3,
predict_with_generate=True,
fp16=True,
push_to_hub=False
)

# 创建训练器
trainer = Seq2SeqTrainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset["train"].select(range(1000)), # 使用部分数据
eval_dataset=tokenized_dataset["validation"].select(range(100)),
tokenizer=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics
)

# 开始训练
trainer.train()

摘要质量评估

ROUGE 指标

ROUGE(Recall-Oriented Understudy for Gisting Evaluation)是评估摘要最常用的指标。

import evaluate

rouge = evaluate.load("rouge")

# 示例
predictions = ["人工智能正在改变各个行业,包括医疗、金融和教育领域。"]
references = ["AI技术在医疗、金融和教育等多个行业产生了重大影响。"]

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

print("ROUGE 评估结果:")
for key, value in results.items():
print(f" {key}: {value:.4f}")

ROUGE 指标说明:

  • ROUGE-1:基于单词的匹配
  • ROUGE-2:基于二元组的匹配
  • ROUGE-L:基于最长公共子序列的匹配
  • ROUGE-S:基于跳跃二元组的匹配

其他评估方法

from nltk.translate.bleu_score import sentence_bleu

def evaluate_summary(generated, reference):
"""多维度评估摘要"""
results = {}

# BLEU 分数
generated_tokens = generated.split()
reference_tokens = [reference.split()]
results["bleu"] = sentence_bleu(reference_tokens, generated_tokens)

# 长度比例
results["length_ratio"] = len(generated_tokens) / len(reference_tokens[0])

# 重叠度
generated_set = set(generated_tokens)
reference_set = set(reference_tokens[0])
overlap = len(generated_set & reference_set)
results["overlap_ratio"] = overlap / len(reference_set) if reference_set else 0

return results

# 示例
generated = "人工智能在医疗、金融和教育领域产生重大影响"
reference = "AI技术在医疗、金融和教育等多个行业产生了重大影响"

results = evaluate_summary(generated, reference)
for key, value in results.items():
print(f"{key}: {value:.4f}")

摘要生成策略

控制摘要长度

def summarize_with_length_control(text, model, tokenizer, target_length="short"):
"""控制摘要长度"""
length_map = {
"short": {"max_length": 50, "min_length": 20},
"medium": {"max_length": 100, "min_length": 50},
"long": {"max_length": 200, "min_length": 100}
}

length_params = length_map.get(target_length, length_map["medium"])

inputs = tokenizer(text, return_tensors="pt", max_length=1024, truncation=True)

summary_ids = model.generate(
inputs["input_ids"],
max_length=length_params["max_length"],
min_length=length_params["min_length"],
num_beams=4,
early_stopping=True
)

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

多样性摘要

def diverse_summaries(text, model, tokenizer, num_summaries=3):
"""生成多个不同的摘要"""
inputs = tokenizer(text, return_tensors="pt", max_length=1024, truncation=True)

summaries = []
for i in range(num_summaries):
summary_ids = model.generate(
inputs["input_ids"],
max_length=100,
min_length=30,
num_beams=4,
temperature=0.8 + i * 0.1, # 不同的温度产生不同结果
do_sample=True,
top_k=50,
early_stopping=True
)
summary = tokenizer.decode(summary_ids[0], skip_special_tokens=True)
summaries.append(summary)

return summaries

实际应用案例

新闻摘要系统

from transformers import pipeline

class NewsSummarizer:
"""新闻摘要系统"""

def __init__(self, model_name="facebook/bart-large-cnn"):
self.summarizer = pipeline("summarization", model=model_name)

def summarize(self, article, max_length=130, min_length=30):
"""生成新闻摘要"""
# 预处理
article = article.replace('\n', ' ').strip()

# 生成摘要
summary = self.summarizer(
article,
max_length=max_length,
min_length=min_length,
do_sample=False
)

return summary[0]['summary_text']

def batch_summarize(self, articles, batch_size=8):
"""批量摘要"""
summaries = []

for i in range(0, len(articles), batch_size):
batch = articles[i:i+batch_size]
results = self.summarizer(
batch,
max_length=130,
min_length=30,
do_sample=False
)
summaries.extend([r['summary_text'] for r in results])

return summaries

# 使用示例
summarizer = NewsSummarizer()

article = """
The tech industry saw significant changes in 2024. Major companies announced layoffs
as they restructured their operations to focus on artificial intelligence. Meanwhile,
startups in the AI sector continued to attract substantial funding. The rise of
generative AI tools transformed how businesses approach content creation and
software development. Experts predict that AI will continue to reshape the job
market in the coming years, creating new roles while making others obsolete.
"""

summary = summarizer.summarize(article)
print(f"摘要: {summary}")

文档摘要 API

from fastapi import FastAPI
from pydantic import BaseModel
from transformers import pipeline

app = FastAPI()

# 加载模型
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")

class SummarizeRequest(BaseModel):
text: str
max_length: int = 130
min_length: int = 30

@app.post("/summarize")
async def summarize_text(request: SummarizeRequest):
"""摘要 API"""
result = summarizer(
request.text,
max_length=request.max_length,
min_length=request.min_length,
do_sample=False
)

return {
"original_text": request.text[:100] + "...",
"summary": result[0]['summary_text']
}

# 运行: uvicorn app:app --reload

摘要系统的挑战

处理长文档

def summarize_long_document(text, model, tokenizer, chunk_size=1024, overlap=100):
"""处理长文档的摘要"""
# 分块
chunks = []
for i in range(0, len(text), chunk_size - overlap):
chunk = text[i:i + chunk_size]
if chunk:
chunks.append(chunk)

# 对每个块生成摘要
chunk_summaries = []
for chunk in chunks:
inputs = tokenizer(chunk, return_tensors="pt", truncation=True, max_length=chunk_size)
summary_ids = model.generate(inputs["input_ids"], max_length=150, min_length=30)
summary = tokenizer.decode(summary_ids[0], skip_special_tokens=True)
chunk_summaries.append(summary)

# 合并块摘要,生成最终摘要
combined = " ".join(chunk_summaries)

inputs = tokenizer(combined, return_tensors="pt", truncation=True, max_length=chunk_size)
summary_ids = model.generate(inputs["input_ids"], max_length=200, min_length=50)
final_summary = tokenizer.decode(summary_ids[0], skip_special_tokens=True)

return final_summary

事实一致性

生成式摘要可能产生与原文不符的内容,这是需要特别注意的问题。

def check_factual_consistency(summary, source, model, tokenizer):
"""检查摘要与原文的事实一致性"""
# 使用问答模型检查关键事实
qa_pipeline = pipeline("question-answering", model="deepset/roberta-base-squad2")

# 提取摘要中的关键实体
# 这里简化处理,实际应用中可以使用 NER
key_phrases = summary.split('。')[0].split(',')

consistency_scores = []
for phrase in key_phrases:
question = f"Is '{phrase.strip()}' mentioned or supported in the source?"
result = qa_pipeline(question=question, context=source)
consistency_scores.append(result['score'])

avg_score = sum(consistency_scores) / len(consistency_scores) if consistency_scores else 0
return avg_score

总结

文本摘要是 NLP 的核心应用之一,本章介绍了:

  • 摘要类型:抽取式、生成式、混合式
  • 抽取式方法:基于频率、TextRank 算法
  • 生成式方法:Seq2Seq 模型、大语言模型
  • 模型微调:在特定领域数据上优化
  • 评估方法:ROUGE 指标
  • 实际应用:新闻摘要、文档摘要 API
  • 挑战与解决:长文档处理、事实一致性

文本摘要技术在新闻媒体、学术研究、企业文档管理等领域有广泛应用。随着大语言模型的发展,摘要质量不断提升,但事实一致性和领域适应性仍是需要关注的问题。