nlp实战--t5微调--文本摘要

t5--文本摘要

  • T5(Text-to-Text Transfer Transformer)模型将翻译、分类、回归、摘要生成等任务都统一转成Text-to-Text任务,从而使得这些任务在训练(pre-train和fine-tune)时能够使用相同的目标函数,在测试时也能使用相同的解码过程。

  • T5模型在NLU和NLG上都具有出色表现,能够完成翻译任务、文本分类、阅读理解、摘要生成任务等多种下游任务。

  • 然而,T5刚出来的时候,我们可能没有什么存在感,原因很简单:没有中文版T5可用。

    • 不过Google后面放出了多国语言版的T5(mT5),里边包含了中文语言。

  • 论文链接:mT5: A massively multilingual pre-trained text-to-text transformer Hugging face链接:https://huggingface.co/collections/google/mt5-release-65005f1a520f8d7b4d039509 另外,国内还有一些公司,利用T5模型使用了大量中文数据进行训练。

    • 孟子T5预训练生成模型与T5结构相同,但是不包含下游任务,需要在特定任务上 Finetune 后使用。孟子T5预训练生成模型-中文-base

    • iic在mt5模型基础上使用了大量中文数据进行训练,并引入了零样本分类增强的技术。全任务零样本学习-mT5分类增强版-中文-base

在这里插入图片描述

Encoder-Decoder结构

  • 如下图所示,目前基于Transformer的模型架构主要有Encoder-Decoder结构(传统的Transformer结构)、Language model结构 (GPT的结构)和Prefix LM结构(UniLM的结构)。

  • Encoder-Decoder结构:Seq2Seq常用模型,编码器输入中可以看到序列中包括自己的全部字符,解码器的输出只能看到当前字符及之前的字符;

  • LM模型:Encoder-Decoder中的Decoder部分,单向结构,每次只能看到当前及之前的部分;基于前缀的语言模型Prefix LM:前面一部分文本可以看到前缀部分所有内容,后面剩下的内容只能看到自己及之前的内容。

在这里插入图片描述

SentencePiece

  • 把一个句子看作一个整体,再拆成片段,而没有保留天然的词语的概念。

  • SentencePiece不将空格视为分隔符,而是将字符串作为其原始格式的输入,使用BPE或ULM作为其分词器来构建词汇表。

相对位置编码 不同于RNN、CNN等模型,对于Transformer模型来说,位置编码的加入是必不可少的,因为纯粹的Attention模块是无法捕捉输入顺序的,即无法区分不同位置的Token。为此我们大体有两个选择:

1、将位置信息融入到输入中,这构成了绝对位置编码的一般做法; 2、微调一下Attention结构,使得它有能力分辨不同位置的Token,这构成了相对位置编码的一般做法。 <!--Transformer中有两种常用的位置编码,分别为绝对位置编码和相对位置编码。-->

在这里插入图片描述

  • 我们可以使用一个阈值k,例如k=2,当超过这个特定的阈值(就是下图中红色背景的部分)

  • 即其他的position_embedding距离自身超过2个位置,那么这些位置的position_embedding就和距离最近的position_embedding值一样。例如下图中x1的w3和w4就会变成w2,其他同理。

    在这里插入图片描述

T5模型中的位置编码

我们先看下苏神博客中的内容,分析下T5模型中相对位置编码公式的由来:

  • T5采用了一个长距离不敏感的相对位置编码,这一设计是考虑到远距离的单词依赖往往比较稀疏且不精细,因此我们需要对周围单词的位置做精确的区分,而远距离单词的位置变化则相对缓慢。

  • 如下图所示,T5模型对相对位置进行了一个“分桶”处理,将原始的relative position当成一个个小方块放置在顺序排列的桶中,最后用方块所属的桶号来代替相对距离:

    • 在T5中num_buckets=32,max_distance=128源码中将num_buckets/2的距离定义为近的分割线(对于双向attention是8,对单向attention是16)

    • 低于这个数值的距离被认为是近的,高于这个数值的距离被认为是远的。

    • 这个设计的思路其实也很直观,就是比较邻近的位置(0-7),我们需要比较得精细一些,所以给它们都分配一个独立的位置编码,至于稍远的位置(比如8~11),我们不用区分得太清楚,所以它们可以共用一个位置编码。距离越远,共用的范围就可以越大,直到达到指定范围再clip。

数据集和大模型选择

大模型t5---孟子t5模型---中文微调模型---text to text

数据集----nlpcc_2017----新闻数据集

总共5000条数据集---取4900--训练集----100--测试集

通过自定义的Dataloader类进行数据传递,同时添加一个collate-fn函数,可以对batch里的content和label进行tokenizer处理,

通过Dataloader类--在dataloader按照batch进行取数据的时候, 是取出大小等同于batch size的index列表; 然后将列表列表中的index输入到dataset的getitem()函数中,取出该index对应的数据;

collate-fn函数就是手动将抽取出的样本堆叠起来的函数

可以看到, 假设的dataset返回两个数据项: x和y. 那么, 传入collate_fn的参数定义为data, 则其shape为(batch_size, 2,…),可以自定义取出一个batch数据的格式. 该函数的输出就是对dataloader进行遍历, 取出一个batch的数据

(1)--lambda函数
info = args.info    # info是已经定义过的
loader = Dataloader(collate_fn=lambda x: collate_fn(x, info))
(2)--创建可被调用的类
class collater():
    def __init__(self, *params):
        self. params = params
    
    def __call__(self, data):
        '''在这里重写collate_fn函数'''
#
collate_fn = collater(*params)
loader = Dataloader(collate_fn=collate_fn)

在这里通过collate-fn来传递tokenizer--

inputs = tokenizer(contents, max_length=384, truncation=True, return_tensors='pt', padding=True)

contents--数据

truncation--超出最大序列长度进行截断

算法构建

构建MengZiT5Model()

首先要对输入的inputs和labels进行处理,mask取为实际上有的序列中有的token,表示为1,因为同一个batch里的数据要等长。损失函数用的是常规的交叉熵loss,进行5个epochs的训练后得到

class MengZiT5Model(nn.Module):
    def __init__(self):
        super().__init__()
        # 加载预训练模型
        self.model = T5ForConditionalGeneration.from_pretrained(model_dir)
​
    def forward(self, inputs, labels=None):
        # 1、encoder的input_ids和attention_mask
        input_ids = inputs['input_ids']
        attention_mask = inputs['attention_mask']
        #print(attention_mask)
        if labels is not None:
            #2、decoder 的labels
            train_labels = labels['input_ids'].contiguous()
            train_labels_mask = labels['attention_mask']
            #3、decoder 的input_ids和attention_mask
            decoder_input_ids = train_labels.new_zeros(train_labels.shape)
            decoder_input_ids[..., 1:] = train_labels[..., :-1].clone()
​
            decoder_attention_mask = train_labels_mask.new_zeros(train_labels_mask.shape)
            decoder_attention_mask[..., 1:] = train_labels_mask[..., :-1].clone()
            decoder_attention_mask[..., 0] = 1
            #4、送入模型进行预测
            outputs = self.model(input_ids=input_ids
                                 , attention_mask=attention_mask
                                 , decoder_input_ids=decoder_input_ids
                                 , decoder_attention_mask=decoder_attention_mask
                                 , labels=train_labels)
            print(outputs.keys())
            #5、返回训练时候的Loss值
            #print(outputs.keys())
            return outputs.loss
        else:
            #模型生成
            summary_ids = self.model.generate(input_ids
                                              , num_beams=4 # 束搜索法
                                              , no_repeat_ngram_size=2 # 确保不重复
                                              , min_length=10 # 长度限制
                                              , max_length=64
                                              , early_stopping=True)
            #将id转换为输出 summary_ids.shape = [bs, length]
            outputs = tokenizer.batch_decode(summary_ids, skip_special_tokens=True)
            return outputs
结果评测

通过rouge库对得到的摘要进行评测。

得到的rouge均在0.7左右。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值