澜舟科技为有兴趣入门 NLP 技术的开发者提供各种学习资源指引
自动文摘的目的是通过对原文本进行压缩、提炼,为用户供简明扼要的文字描述。自动文摘是一个信息压缩过程,将输入的一篇或多篇文档内容总结为一段简要描述。该过程中不可避免会有信息损失,但是要求保留尽可能多的重要信息。自动文摘也是自然语言生成领域中的一个重要任务。本文中,我们以文本摘要任务为例,展示孟子预训练模型在下游任务上微调的流程。整体流程可以分为4部分:
下面通过中文科学文献数据(CSL)文本摘要数据进行演示。
数据下载地址: https://github.com/CLUEbenchmark/CLGE
本文完整示例代码地址: https://github.com/Langboat/Mengzi/blob/main/examples/Mengzi_summary.ipynb
CSL数据以json的形式存储,我们可以通过定义read_json函数读取数据文件,将数据加载进内存。
def read_json(input_file: str) -> list:with open(input_file, 'r') as f:lines = f.readlines()return list(map(json.loads, tqdm(lines, desc='Reading...')))train = read_json("csl/v1/train.json")dev = read_json("csl/v1/dev.json")
数据集的具体信息如下:
数据划分 | 数据量 |
---|---|
训练集 | 2500 |
测试集 | 500 |
每个训练样本的原始格式如下:
{'id': 2364,'title': '基于语义规则的Web服务发现方法','abst': '语义Web服务发现问题研究的核心内容是服务描述与对应的服务发现方法。服务描述分为服务请求描述与服务发布描述,但目前的服务发现方法,并未将请求描述与发布描述分开,以比对服务请求描述与服务发布描述中对应部分作为匹配依据,导致服务请求描述构建困难以及发现结果不够理想。提出以语义规则刻画服务请求描述,以本体构建服务发布描述,进行有效的以语义规则驱动的Web服务发现。对语义规则添加影响因子使得服务匹配精度可以通过匹配度来度量,并按照给定的调节系数来决定最终匹配是否成功。最后以OWL-STCV2测试服务集合进行了对比实验,证实该方法有效地提高了查全率与查准率高,特别是Top-k查准率。'}
数据预处理的目的是将原始数据处理为模型可以接受的输入形式,相当于在原始数据和模型输入之间建立管道。
模型输入,可接受的字段为 input_ids、labels,其中 input_ids 为输入文本的 tokenized 表示,可以直接通过 transformers 提供的 Tokenizer
进行转换;labels 为模型期望输出文本的tokenized 表示。
通过定义 DataCollatorForSeq2Seq
数据预处理类,并将其传递给模型完成上述流程。详情见代码。
训练模型前需要指定模型训练的超参数,包括训练的轮数、学习率和学习率管理策略等等。
这一点可以通过实例化 TrainingArguments
类来实现,接着将其传递给 Trainer 来传入这些超参数;然后通过 huggingface 定义的 trainer.train()
方法来进行训练,训练完成后通过 trainer.save_model()
方法来保存最佳模型。
Mengzi_tokenizer = T5Tokenizer.from_pretrained(model_path)Mengzi_model = T5ForConditionalGeneration.from_pretrained(model_path)trainer = Trainer(tokenizer=Mengzi_tokenizer,model=Mengzi_model,args=training_args,data_collator=collator,train_dataset=trainset,eval_dataset=devset)trainer.train()trainer.save_model("test/best")
最佳模型保存在了 test/best
位置,我们可以加载最佳模型并利用其进行摘要生成。
下面是我们利用模型进行推理的一种实现方式,将希望简化的文本 tokenized 后传入模型,得到经过 tokenizer 解码后即可获得摘要后的文本。当然,读者也可以利用自己熟悉的方式进行生成。
def predict(sources, batch_size=8):_model = model.eval() #将模型转换为预测模式,使模型内部的dropout失效。kwargs = {"num_beams": 4}outputs = []for start in tqdm(range(0, len(sources), batch_size)):batch = sources[start:start+batch_size]input_tensor = tokenizer(batch, return_tensors="pt", truncation=True, padding=True, max_length=512).input_ids.cuda()outputs.extend(model.generate(input_ids=input_tensor, **kwargs))return tokenizer.batch_decode(outputs, skip_special_tokens=True)
采用自动文摘任务上常用的自动评测指标 Rouge-1, Rouge-2, Rouge-L 对生成文本的质量进行评测。
def rouge_score(candidate, reference):text1 = " ".join(list(candidate))text2 = " ".join(list(reference))score = rouge.get_scores(text1, text2)print(score)return scoredef compute_rouge(preds, refs):r1=[]r2=[]R_L=[]for pred, ref in zip(preds, refs):score = rouge_score(pred, ref)r1.append(scores[0]["rouge-1"]["f"])r2.append(scores[0]["rouge-2"]["f"])R_L.append(scores[0]["rouge-l"]["f"])return sum(r1)/len(r1), sum(r2)/len(r2), sum(R_L)/len(R_L)R_1, R_2, R_L = compute_rouge(generations, titles)