[竞赛01]2021CCF BDCI新闻摘要自动生成Baseline - 爱码帮™分享编程知识和开发经验
「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」
本文提供竞赛的Baseline,采用hugging face的预训练模型配合pipeline
方法快速得到文本摘要,经过测试\
Rouge_L分数在 0.22158458, 第 8 名
比赛信息
大赛链接:新闻摘要自动生成 Competitions - DataFountain
赛题介绍
赛题背景
随着互联网、社交媒体的迅速发展,各类新闻文章层出不穷,读者在面对海量新闻信息时,难以有效发现哪些是自己感兴趣的新闻内容。为了帮助读者快速了解新闻文章,并找到其感兴趣的新闻内容,本训练赛题旨在研究构建高质量摘要生成模型,通过为新闻文档生成简短摘要,帮助读者快速理解新闻内容。
赛题任务
依据真实的新闻文章,利用机器学习相关技术,建立高效的摘要生成模型,为新闻文档生成相应的内容摘要。
时间安排
本赛题为训练赛,如无特别通知,永久开放
2021年9月27日15:00正式开放线上报名;\
2021年10月11日前上线赛题训练数据开放排名;\
2021年12月06日进行大赛名次及奖品公布。
本赛题为训练赛,不设置奖金。 截至12月6日,排行榜前3名的队伍
将会获得1个CCF会员名额+纪念奖牌
,排行榜前50名的团队
将会获得平台发出的电子证书
。
代码要求
提交要求
参赛者以csv文件格式提交,参赛者以csv结果提交,编码格式为utf8格式。使用“\t”分隔符,submission.csv文件字段如下:
字段名 | 类型 | 取值范围 | 字段解释 |
---|---|---|---|
Index | Int | - | 索引 |
Target | Str | 字符串 | 生成的摘要 |
提交示例
示例如下:
0 | I like it |
---|---|
1 | It is good |
评测标准
本赛题采用ROUGE-L值进行评价,详细评分算法如下:
其中LCS (X, Y)是X和Y的最长公共子序列的长度,m和n分别表示人工标注摘要和机器自动摘要的长度(一般就是所含词的个数),Rlcs 和Plcs 分别表示召回率和准确率,Flcs 表示Rouge-L。
数据说明
数据是以CNN 和Daily Mail的报刊新闻为文章基础的,包含新闻文章和摘要等,该类数据集被广泛应用于摘要生成和阅读理解等应用场景。
数据文件夹包含4个文件,依次为:
文件类别 | 文件名 | 文件内容 |
---|---|---|
训练集 | train.csv | 训练数据集,对应的摘要 |
测试集 | test.csv | 测试数据集,无对应的摘要 |
字段说明 | 字段说明.xlsx | 训练集/测试集字段的具体说明 |
提交样例 | submission.csv | 仅有两个字段Index \t Target |
官方基线
rouge f(ROUGR-L): 0.24
rouge p : 0.34
rouge r : 0.19
Baseline
先安装rouge
和transformers
这两个依赖。
下面展示代码流程:
准备工作
# --------------------------导包--------------------------
import re
import json
import torch
import random
import numpy as np
import pandas as pd
from rouge import Rouge
from tqdm import tqdm
from transformers import pipeline
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
# 方便复现
def set_seed(seed):
torch.manual_seed(seed) # cpu 为CPU设置种子用于生成随机数,以使得结果是确定的
torch.cuda.manual_seed(seed) # gpu 为当前GPU设置随机种子
torch.backends.cudnn.deterministic = True # cudnn
np.random.seed(seed) # numpy
random.seed(seed) # random and transforms
# 评测 rouge_L 分数
def print_rouge_L(output, label):
rouge = Rouge()
rouge_score = rouge.get_scores(output, label)
rouge_L_f1 = 0
rouge_L_p = 0
rouge_L_r = 0
for d in rouge_score:
rouge_L_f1 += d["rouge-l"]["f"]
rouge_L_p += d["rouge-l"]["p"]
rouge_L_r += d["rouge-l"]["r"]
print("rouge_f1:%.2f" % (rouge_L_f1 / len(rouge_score)))
print("rouge_p:%.2f" % (rouge_L_p / len(rouge_score)))
print("rouge_r:%.2f" % (rouge_L_r / len(rouge_score)))
set_seed(0)
数据读取
处理成pandas.DataFrameDataFrame方便操作
# --------------------------读取数据--------------------------
train_path='./CCFNewsSummary/train_dataset.csv' #自定义训练集路径
with open(train_path,'r',encoding='utf-8') as f:
train_data_all=f.readlines()
test_path='./CCFNewsSummary/test_dataset.csv' #自定义测试集路径
with open(test_path,'r',encoding='utf-8') as f:
test_data=f.readlines()
train = pd.DataFrame([],columns=["Index","Text","Abstract"])
test = pd.DataFrame([],columns=["Index","Text"])
for idx,rows in enumerate(train_data_all):
train.loc[idx] = rows.split("\t")
for idx,rows in enumerate(test_data):
test.loc[idx] = rows.split("\t")
加载多语言T5模型
预训练模型下载地址:csebuetnlp/mT5_multilingual_XLSum · Hugging Face
点击 - Files
- 除.gitattributes
、README.md
外全部下载下来,放在同一个文件下。
如下图所示,就可以在本地加载预训练模型
# --------------------------加载【T5】模型--------------------------
WHITESPACE_HANDLER = lambda k: re.sub('\s+', ' ', re.sub('\n+', ' ', k.strip()))
model_name = "./PretrainModel/mT5_multilingual_XLSum"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
样本测试
# --------------------------查看单条样本预测结果-------------------------
i = 0
article_text = train["Text"][i]
article_abstract = train["Abstract"][i]
input_ids = tokenizer(
[WHITESPACE_HANDLER(article_text)],
return_tensors="pt",
padding="max_length",
truncation=True,
max_length=512
)["input_ids"]
output_ids = model.generate(
input_ids=input_ids,
max_length=512,
min_length=int(len(article_text)/32),
no_repeat_ngram_size=3,
num_beams=5
)[0]
summary = tokenizer.decode(
output_ids,
skip_special_tokens=True,
clean_up_tokenization_spaces=False
)
print(f"Generate:\n{summary}")
print(f"Label:\n{article_abstract}")
print_rouge_L(summary,article_abstract)
虽然生成的句子有些奇怪,Rouge_L有0.34,相较榜单上的分数还是不错的
再评测一下10条样本的Rouge_L
# --------------------------预测-------------------------
multi_sample = 10
for idx,article_text in tqdm(enumerate(train["Text"][:multi_sample]),total=multi_sample):
input_ids = tokenizer(
[WHITESPACE_HANDLER(article_text)],
return_tensors="pt",
padding="max_length",
truncation=True,
max_length=512
)["input_ids"]
output_ids = model.generate(
input_ids=input_ids,
max_length=512,
min_length=int(len(article_text)/32),
no_repeat_ngram_size=3,
num_beams=5
)[0]
summary = tokenizer.decode(
output_ids,
skip_special_tokens=True,
clean_up_tokenization_spaces=False
)
train.loc[idx,"summary"] = summary
print_rouge_L(train["summary"][:multi_sample],train["Abstract"][:multi_sample])
rouge_f: 0.22
rouge_p: 0.17
rouge_r: 0.31
多条测试效果还是下来了,10条样本需要4分钟,预估1000测试样本预测下来可能要接近7个小时了。
预测
耗时需要越6-7个小时
# --------------------------预测-------------------------
for idx,article_text in tqdm(enumerate(test["Text"]),total=1000):
input_ids = tokenizer(
[WHITESPACE_HANDLER(article_text)],
return_tensors="pt",
padding="max_length",
truncation=True,
max_length=768
)["input_ids"]
output_ids = model.generate(
input_ids=input_ids,
max_length=512,
min_length=int(len(article_text)/32),
no_repeat_ngram_size=3,
num_beams=5
)[0]
summary = tokenizer.decode(
output_ids,
skip_special_tokens=True,
clean_up_tokenization_spaces=False
)
test.loc[idx,"Text"] = summary
# test[["Index","Text"]].to_csv("T5summit01.csv",index=False,header=False,sep="\t")
榜单效果
作者:ArmorHTK 原文地址:https://juejin.cn/post/7026590075051851789