
仰止
2022/12/09阅读:233主题:默认主题
mT5 & T5
这次主要介绍T5系列模型,其中mT5可用于中文。由于T5论文极长,所以用了很长时间陆陆续续看完了一遍。不得不说,T5真的是nlper必看的一篇论文,文章中对很多ideas进行了实验,同时也提出了很多具有潜力的研究方向,并且对于一些研究意义不大的方向也做了说明。同时,我们也可以在学习或工作中,使用那些ideas来提分或者保证效果的前提下降低资源消耗。


T5论文地址:
https://arxiv.org/abs/1910.10683
T5代码地址:
https://github.com/google-research/text-to-text-transfer-transformer
T5论文笔记:
https://note.youdao.com/s/Ja81XUtE
mT5论文地址:
https://arxiv.org/pdf/2010.11934.pdf
mT5代码地址:
https://github.com/google-research/multilingual-t5
mT5论文笔记:
https://note.youdao.com/s/MFDCzrMx
T5
T5在后面看的,所以就先从T5说起
(1)模型框架
T5就是一个text-to-text的框架,输入文本输出文本,一般用于处理英文数据。如下图所示:

可以看到T5的输入为一段文本,输出为对应的目标答案。可以发现,T5在输入上做了些改动,将任务名以前缀的方式添加到了输入的text上。因为T5是一个多任务的模型,所以添加任务名的前缀让模型得以自动分辨该样本需要执行的任务,进而输出相符的输出。
当使用T5时需要将数据预处理为它要求的格式
(2)模型任务
英文里叫做objectives,也就是模型怎么进行学习的。以bert为例,bert的学习任务有MLM,也就是对一句话随机mask,这里的MLM的任务就可以称作objective。
在介绍T5的学习任务之前,我们可以先对mask进行一些了解:

如上图所示,mask一般可以分为三种,第一种就是全部可见,也就是没有对句子的token进行mask(当然padding部分肯定是需要mask,上图的mask针对句子token),比如transofrmer的encoder就是这种mask,双向。
第二种就是causal mask(我翻译为因果mask,也可以说上三角/下三角mask,图中为下三角mask),顾名思义,结合了句子的因果关系进行的mask,常用于生成式任务,单向。
第三种就是casual with prefix,unilm使用的应该就是这种mask策略。简单点说,就是对于前缀部分使用双向的encode形式,对于后面部分使用单向的decode的形式。这里的前缀部分就是指输入的句子,具体来说生成模型在得到句子每个字的embedding后,会一个字一个字的生成,此时就全部使用的是causal mask;这里不同,prefix表示会给于模型前面一部分句子的信息,也就是说前面几个字,或者一个小短句是双向的形式,后面才是一个个生成。
T5以bert-base作为baseline实验了很多不同学习任务的效果。这些任务可以分为:span corrupted、deshuffle、prefix等。 如上图所示,一共列举了6种学习任务。其中BERT-style的任务我们已经比较清楚了就不说了,不过,值得注意的是,bert的target为原始text,我之前一直以为是mask的word,因为bert对MLM的解释不就是预测mask的word吗
Prefix language modeling:根据后面给的例子很容易理解。将一个text随机分割为两个部分,前面的部分作为输入,后面的部分作为target。所以这是一个生成式的模型,下面是prefix LM与bert和LM的结构对比:

可以看到prefix LM就是encoder于LM的结合。以前面一幅图为例,就是对inputs用encoder,然后生成targets的时候用LM。
Deshuffling:以打乱顺序的句子作为输入,原始句子作为输出。单在我看来,一个句子被打乱后能学到啥,语义基本没有,上下文字词的共现频率基本没有,难道靠一个句子打乱为多个不同的输入,但有同样的target,这种学习方式来训练模型?所以,感觉这个方法应该不值得期待。
MASS-style:从上面的表格来看,这个策略应该与bert的差不多,不过全部使用mask来代替,而不用删除或替换
noise replace spans:span mask,inputs:将一个span用一个特殊token(<X>)代替;targets:将输入中未mask的用对应的特殊token代替,mask的部分保持原状,更具体的,对于<X>之前的输入在target中用<X>代替,对于<Y>之前的则用<Y>代替,剩余部分用新的特殊token代替
noise drop tokens:与上面的策略一样,不过删除了需要mask的部分,target也只是需要mask的部分
random span:对这个策略,我貌似没找到直接的说明,多半是我看漏了。大致意思就是不管是否为noise,随机选择一个span的token进行mask
(3)模型训练
T5使用了较多的模型训练策略,主要包括fine-tuning、multi-task、combine,其中combine表示前面两种方式的结合
fine-tuning
T5主要实验了两种微调策略。一个是adapter,一个是gradual unfreezing
其中adapter就是在dense-relu-dense块,相当于给中间的输出做了一个双线性变换,一般后接于transformer中的前面的FFN。使用adapter后,在训练时就只会更新adapter block和LN中的参数,预训练模型原始的参数基本保持不变。adapter的结构特点可以使其匹配任意的网络结构,而不必对网络进行改动
gradual unfreezing就是字面意思,逐层解冻。也就是说,开始阶段,预训练模型的所有参数都是固定的,随着训练的进行,每层参数会逐层进行更新,最后一层优先更新,以此类推。由于T5是一种encoder-decoder的结构,所以在对每层进行解冻时,将encoder和decoder进行同步解冻。实验时,以训练step实现时间的计数,T5将其分成了12份,每次达到指定的step就会解冻一层。
两种策略的实验结果如下: 根据实验结果,从整体来看,微调全部参数的效果最好,gradual unfreezing紧随其后,adapter效果最差。而对于adapter并不是d越大效果越好,而是需要选择合适的d,这个可以实验得到。adapter的优点在于训练参数大大减少,可以很好的提速。
multi-task
多任务就是用多个任务的数据对模型进行训练,注意这里并没有预训练。一般来说多任务模型有两种形式,一种是大一统模型,使用单个模型可以对每种任务都可以得到相应的输出。一种是同时训练多个任务,使之可以生成在每个单一任务上表现良好的单独参数设置,之前提到的centrabert就是用的这类多任务的实现。
进行多任务训练时,每个任务的数据量是否平衡是一个非常重要的点,所以对于多任务模型,没种任务的训练数据占比就是一个可实验的方向。T5一共做了三个实验:
Examples-proportional mixing :
-
按照数据集大小的进行采样,但是数据集中存在大量的无标签数据,会导致每个监督任务都无法得到很好的训练。同时,也存在有些任务的数据量很大,有些的很少,这样也会影响到数量较少的task的训练。 -
该方法用了一个limit来限制最大的数据量,类似于grad clip -
比如从第m个任务中采样样本时有: ,其中 表示数据集, 表示人工设置的数据采样上限
Temperature-scaled mixing:
-
这个方法简单来说就是加了一个温度系数 ,确保模型可以对低资源的任务有足够的训练 -
具体做法是将每个task的混合比率变为 ,然后将所有比率归一化。当 时等价于上面的按数据集大小比例进行采样,随着 的增加,逐渐向等比采样靠拢
Equal mixing:
-
等比采样
T5的实验结果如下:
baseline为预训练+微调,可以看到baseline基本保持了很大的优势,等比采样的效果最差,Examples-proportional mixing效果最好,当 时Temperature-scaled mixing效果变好
实验只中分析到等比采样导致指标下滑严重,多半因为数据量较小的task过拟合,而数据量较多的task没有学习到足够多的数据,抑或是模型没有足够的无标签数据去获得已些通识知识。对于Examples-proportional mixing中 的大小选取并不是一层不变的,需要根据自己的数据集多做几组实验,来确定最合适的值。
combine
这部分的核心思想就是,模型用所有任务的数据进行预训练,然后针对每个任务进行微调,这就与centrabert几乎一致了。这也是被MT-DNN所使用的方法。
对于这部分作者做了三个变量的实验:
-
以 examples-proportional mixture的方式采样数据,并设置 作为数据采样最大值。
以测试在预训练阶段融合无标签数据和有标签数据相比于单纯的无标签数据,是否会带来更多的收益,也就是使模型学到更多的该领域知识
-
针对微调,将需要微调的task数据不加入预训练。类似于机器学习中的leave one out
用来模拟业务场景下,出现新任务时,预训练+微调的效果
-
作者还做了只使用有监督数据进行预训练,来增强对比
实验的结果如下: 根据实验结果,我们可以得到一下结论:
-
使用无监督预训练+微调的方式(baseline),的效果已就是十分不错的 -
对于多任务模型,预训练+微调的方式更好 -
leave-one-out不会对结果产生太差的影响,说明预训练模型是可以用于新任务的,而且在某些数据集下其效果甚至更好 -
有监督的多任务预训练效果一般,但是翻译任务的效果却最佳,表明翻译任务并不依赖与无监督的预训练
直觉上,在无监督预训练的基础上加上有标签的多任务数据,并联合在一起进行预训练应该在这些任务领域都可以超过原有的无监督预训练。可是,实验结果显示只能在部分任务上有所超越,其他任务甚至会下降。
对于这个问题,姑且在这里分析一下自己的理解。一是,整个有监督和无监督结合的预训练是怎么实现的,从我的认知讲,应该是先进行无监督的预训练,然后在根据多任务的数据进行domain预训练,最后才是微调。第一步与普通的预训练没有区别,可以共用,所以导致最后结果下降的原因就在与domain的预训练。一般,对于single task,这种domain都会起到正向的作用,所以问题就出在multi task上,而论文在前面也分析到了multi task的困难在与对每种任务的训练集比例的确定。所以,导致指标下降的主要因素应该就是这个比率问题。
换个角度,我们也可以向论文中提到的方式去理解,无监督预训练和微调可以帮助multi task缓解mix data比率带来的问题
(4)scale
顾名思义,这个部分就是对模型的某个部分进行scale,具体包括bigger model、train more steps、以及集成ensembling。T5做的实验就是,使用现在的4倍的计算资源,并以上面提到的方法进行scale模型,观察模型性能的提高情况。实验如下:

可以看到作者一共做了7组实验,baseline使用的是bert-base参数量级的模型,(不是单纯的bert-base,而是参数量与bert-base差不多的一个encoder-decoder模型)
对于bigger model则使用了bert-large量级的参数量
train more step就是简单的增加训练步数,不过,对于增加训练步数有利有弊,需要多做几组实验,逐次增加步数,防止过拟合的出现
对于模型集成,作者对4个单独的预训练+微调模型得到的output_encode取平均,然后再送入softmax层;同时,作者也进行了另一个"cheaper"的实验,四个模型共用一个ptm,但是进行4次ft,这种方法并没有使用baseline的4倍的计算资源
从实验结果,我们也可以看到,对模型进行“放大”后,模型在各个任务上的指标都有所提高,所以对于NLP来说,真的只要模型够大,就可以提高更多的效果吗?
现在的工业界,以小爱语音助手为例,其整套逻辑真的十分庞大,各个垂域,歌中规则,各个词表,以及一些大模型,光是每月消耗的存储和计算资源就超过了百万元。对于一些bad case,也是人为的去加规则拒召之类的解决方法,别看小爱现在表现的又那么点智能,但是背后给我的感觉就真的是一个十分“庞大”、“臃肿”的系统。在我看来,这远远不是AI该有的表现,或者可能只是一种最为简单的AI,真正的AI应该更加“智能”,而不是更多“人工”,不过,这也有很长的路要走,还是很期待看到真正的智能生活的。
(5)T5实验图
下面给张T5的实验图,真的是排面

(6)T5的使用
一般情况下,可以直接根据T5的源码来使用T5,考虑到很多人一般不会去用源码,所以transformers将T5也进行了集成。对于transformers真的是有利有弊,可以大大将低人工智能的门槛,但是,也同样让人容易忽视一个模型背后的逻辑和代码,成为一个“调包侠”。
from transformers import AutoTokenizer, AutoModelWithLMHead
tokenizer = AutoTokenizer.from_pretrained("t5-base")#这里也可以换成其他的如:t5-samll、t5-large
model = AutoModelWithLMHead.from_pretrained("t5-base")
text = ['Hello world!', 'Hello python!']
inputs = tokenizer(text, return_tensors='pt', padding=True)
output = model.encoder(input_ids=inputs['input_ids'], attention_mask=inputs['attention_mask'], return_dict=True)
last_layer_output = output.last_hidden_state
output = torch.mean(last_layer_output, dim=1)#对seq_len维取平均
mT5
可以看到T5是没有使用中文的,所以如果想在中文上使用T5就需要重新训练模型,而当数据量较少时,也达不到T5该有的效果,但是数据量多了训练成本就增加了。为了解决T5语言方面的问题,mT5就出现了,mT5适用于多种语言,其中就包括中文。
(1)实验
mT5的模型结构基本与T5相同。突然发现T5好像并没有给模型的结构图,只是不断在说明是一个encoder-decoder结构的模型,可能其模型的结构就是一个最简单的transformer结构吧
mT5主要是针对多语言模型进行了一些实验,也就是说其对比的模型基本都是多语言的模型,如下:

在做实验时mT5同样面临着数据采样的问题,对每种语言数据的采样比率怎么控制?对于数据量较少的语言,mT5按照 的数学方法进行采样,其中 表示预训练期间从给定语言中采样文本的概率, 表示该语言的数据量, 是一个超参数,用来对该语言数据量的控制。根据作者给出的,使用mbert时 ,使用XLM-R时 ,使用MMNMT时 。最后,作者得到当 时,mT5的表现最好。
这里简要介绍一下上面提到的各种多语言模型:
-
mBERT -
BERT的多语言版本 -
与BERT的不同在于其训练集为104种语言的wikipedia
-
-
XLM -
以BERT为基础,增加了跨语言的预训练目标
-
-
XLM-R -
以roberta为基础 -
使用的训练集来源与XLM不同,同时,为了提高预训练数据集的质量,使用通过wikipedia训练的n-gram LM对数据进行了过滤
-
-
mBART -
一种多语言的encoder-decoder模型 -
结合了span mask和sentence shuffle两种训练目标
-
-
MARGE -
encoder-decoder模型 -
通过检索其他语言的文本来重建一个语言的文本
-
mT5的实验结果如下:

作者的实验包括三个变量:
-
zero-shot:只在英文数据上进行微调 -
translate-train:增加英文到其他语言的机器翻译 -
inlanguage multitask:在目标数据上训练所有的目标语言
实验结果如下: 结果表示,随着模型变大,这些变量对模型的影响逐渐减小
mT5使用逆方根形式的学习率策略, , 表示当前训练的step, 表示warm-up steps,在预训练阶段不使用dropout,使用自监督的目标, 的token被mask,平均 noise span length为3
在微调阶段使用的是常数学习率0.001,dropout取的0.1,对大多数任务使用的batch-size为 ,对少量任务使用的是 ,每200个steps存储一次ckpt
作者也将mT5与T5的效果在sQuAD数据集上进行了对比: 可以看到mT5在指标上没有下降太多
(2)模型的问题及解决
作者也提到了mT5出现的问题,他发现模型在生成结果时,可能会出现一些糟糕的预测,作者称其为"accidental translation"。更具体的,模型的微调阶段在输入非英文时,会输出部分英文,作者对其的解释是,模型在微调时,并未观察到过该非英文文本,随着only-english微调的进行,模型分配给non-english token的可能性越来越低,最终达到输出英语成为最优解的程度
作者的做法是,在微调时混合无监督多语言预训练任务。对此,作者对预训练的数据集进行了些取调整:
-
去掉target文本中的non-mask span -
降低数据采样时的 ,从0.3到0.1。这会产生近乎均匀的语言分布,让模型不会偏向某些语言
最后的实验效果如下: 其中,蓝色表示修改过的,可以看到不合法的输出降低了很多
(3)模型的使用
这里也顺便给出mT5的调用方式,依旧使用transformers。其实需要改的只有T5调用方式的MODEL_NAME
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
#https://huggingface.co/google/mt5-base
tokenizer = AutoTokenizer.from_pretrained("google/mt5-base")
model = AutoModelForSeq2SeqLM.from_pretrained("google/mt5-base")
首先回顾一下T5,这个模型需要将输入文本表示成规定的输入格式(加上任务前缀),然后输出对应任务所需要的答案。当生成式任务使用这种形式时,我们可以很容易理解,但是,当一些判别式任务使用的时候就需要想一想了。如分类任务输出的是对应的类别名,情感分析则是输出对应的情绪(如:positive or negative),也就是说它将判别任务当成生成任务在做,这也是T5比较出名的地方,这种做法可以人每种任务使用相同的训练目标,进而使得一组超参数可以对任何的下游任务进行微调。
T5使用的是"span-corruption"的mask方式,也就是遮住输入的一些连续的span,使用一个符号<X>代替这个span,target就是重构出这些被mask的span。这种与wwm是不一样的,wwm是对一个span中每个mask的word都使用<m>来代替,并且其target应该与bert是一样的,也就是原始句子。
T5的训练方式结合了微调的形式和多任务的训练方式,即在无监督预训练的基础上增加了特定domain的task data
mT5其实就是一个多语言版的T5,其中很多东西与T5都是相同或相似的
不得不说,T5确实做了很多实验,也确定了很多可以提分的思路,看完之后确实可以学习到不少
作者介绍
