p-tuning Pattern-Exploiting Training(PET)

P-tuning是一种新的模版构建方法,它允许模型自动构建模版,用于提升GPT在NLU任务上的表现,甚至在SuperGLUE基准上超越BERT。这种方法通过优化几个未使用的token,实现了在小样本和有限计算资源下的高效学习,同时展示了GPT具有强大的理解能力。
摘要由CSDN通过智能技术生成

在之前的文章必须要GPT-3吗?不,BERT的MLM模型也能小样本学习中,我们介绍了一种名为Pattern-Exploiting Training(PET) 的方法,它通过人工构建的模版与BERT的MLM模型结合,能够起到非常好的零样本、小样本乃至半监督学习效果,而且该思路比较优雅漂亮,因为它将预训练任务和下游任务统一起来了。然而,人工构建这样的模版有时候也是比较困难的,而且不同的模版效果差别也很大,如果能够通过少量样本来自动构建模版,也是非常有价值的。

最近Arxiv上的论文《GPT Understands, Too》提出了名为P-tuning的方法,成功地实现了模版的自动构建。不仅如此,借助P-tuning,GPT在SuperGLUE上的成绩首次超过了同等级别的BERT模型,这颠覆了一直以来“GPT不擅长NLU”的结论,也是该论文命名的缘由。

论文标题:GPT Understands, Too

论文链接:https://arxiv.org/abs/2103.10385

代码链接:https://github.com/THUDM/P-tuning

什么是模版

所谓PET,主要的思想是借助由自然语言构成的模版(英文常称Pattern或Prompt),将下游任务也转化为一个完形填空任务,这样就可以用BERT的MLM模型来进行预测了。比如下图中通过条件前缀来实现情感分类和主题分类的例子:

▲ 通过特定模版将情感分类转换为MLM任务

当然,这种方案也不是只有MLM模型可行,用GPT这样的单向语言模型(LM)其实也很简单:

▲ 通过特定模版将新闻分类转换为MLM任务

▲ 通过特定模版将新闻分类转换为LM任务

不过由于语言模型是从左往右解码的,因此预测部分只能放在句末了(但还可以往补充前缀说明,只不过预测部分放在最后)。

某种意义上来说,这些模版属于语言模型的“探针”,我们可以通过模版来抽取语言模型的特定知识,从而做到不错的零样本效果,而配合少量标注样本,可以进一步提升效果,这些在必须要GPT-3吗?不,BERT的MLM模型也能小样本学习中已经比较详细讨论过了。

然而,前面已经说了,对于某些任务而言,人工构建模版并不是那么容易的事情,模型的优劣我们也不好把握,而不同模型之间的效果差别可能很大,在这种情况下,人工标注一些样本可能比构建模版还要轻松得多。所以,如何根据已有的标注样本来自动构建模版,便成了一个值得研究的问题了。

P-tuning

P-tuning重新审视了关于模版的定义,放弃了“模版由自然语言构成”这一常规要求,从而将模版的构建转化为连续参数优化问题,虽然简单,但却有效。

模版的反思

首先,我们来想一下“什么是模版”。直观来看,模版就是由自然语言构成的前缀/后缀,通过这些模版我们使得下游任务跟预训练任务一致,这样才能更加充分地利用原始预训练模型,起到更好的零样本、小样本学习效果。

等等,我们真的在乎模版是不是“自然语言”构成的吗?

并不是。本质上来说,我们并不关心模版长什么样,我们只需要知道模版由哪些token组成,该插入到哪里,插入后能不能完成我们的下游任务,输出的候选空间是什么。模版是不是自然语言组成的,对我们根本没影响,“自然语言”的要求,只是为了更好地实现“一致性”,但不是必须的。于是,P-tuning考虑了如下形式的模版:

▲ P-tuning直接使用[unused*]的token来构建模版,不关心模版的自然语言性

这里的[u1]~[u6],代表BERT词表里边的 [unused1]~[unused6],也就是用几个从未见过的token来构成模板,这里的token数目是一个超参数,放在前面还是后面也可以调整。接着,为了让“模版”发挥作用,我们用标注数据来求出这个模板。

如何去优化

这时候,根据标注数据量的多少,我们又分两种情况讨论。

第一种,标注数据比较少。这种情况下,我们固定整个模型的权重,只优化[unused1]~[unused6]这几个token的Embedding,换句话说,其实我们就是要学6个新的Embedding,使得它起到了模版的作用。这样一来,因为模型权重几乎都被固定住了,训练起来很快,而且因为要学习的参数很少,因此哪怕标注样本很少,也能把模版学出来,不容易过拟合。

第二种,标注数据很充足。这时候如果还按照第一种的方案来,就会出现欠拟合的情况,因为只有6个token的可优化参数实在是太少了。因此,我们可以放开所有权重微调,原论文在SuperGLUE上的实验就是这样做的。读者可能会想:这样跟直接加个全连接微调有什么区别?原论文的结果是这样做效果更好,可能还是因为跟预训练任务更一致了吧。

▲ P-tuning在SuperGLUE上的表现

此外,在上面的例子中,目标token如“很”、“体育”是认为选定的,那么它们可不可以也用[unused*]的token代替呢?答案是可以,但也分两种情况考虑:1、在标注数据比较少的时候,人工来选定适当的目标token效果往往更好些;2、在标注数据很充足的情况下,目标token用[unused*]效果更好些,因为这时候模型的优化空间更大一些。

增强相关性

在原论文中,P-tuning并不是随机初始化几个新token然后直接训练的,而是通过一个小型的LSTM模型把这几个Embedding算出来,并且将这个LSTM模型设为可学习的。这样多绕了一步有什么好处呢?原论文大概的意思是:LSTM出现的token表示相关性更强,某种程度上来说更像“自然语言”(因为自然语言的token之间不是独立的),此外还能防止局部最优。我在Github上进一步向作者确认了一下(参考这里),效果上的差别是通过LSTM多绕一步的方法可以使得模型收敛更快、效果更优。

然而,这样多了一个LSTM,总感觉有些别扭,而且实现上也略微有点麻烦。按照作者的意思,LSTM是为了帮助模版的几个token(某种程度上)更贴近自然语言,但这并不一定要用LSTM生成,而且就算用LSTM生成也不一定达到这一点。笔者认为,更自然的方法是在训练下游任务的时候,不仅仅预测下游任务的目标token(前面例子中的“很”、“新闻”),还应该同时做其他token的预测。

比如,如果是MLM模型,那么也随机mask掉其他的一些token来预测;如果是LM模型,则预测完整的序列,而不单单是目标词。这样做的理由是:因为我们的MLM/LM都是经过自然语言预训练的,所以我们(迷之自信地)认为能够很好完成重构的序列必然也是接近于自然语言的,因此这样增加训练目标,也能起到让模型更贴近自然语言的效果。经过笔者的测试,加上这样辅助目标,相比单纯优化下游任务的目标,确实提升了效果。

实验与效果

所谓“talk is cheap, show me the code”,又到了喜闻乐见的实验时间了。这里分享一下P-tuning的实验结果,其中还包括笔者对P-tuning的实现思路,以及笔者在中文任务上的实验结果。

停止的梯度

怎么实现上述的P-tuning算法比较好呢?如果是放开所有权重训练,那自然是简单的,跟普通的BERT微调没有什么区别。关键是在小样本场景下,如何实现“只优化几个token”呢?

当然,实现的方法也不少,比如为那几个要优化的token重新构建一个Embedding层,然后拼接到BERT的Embedding层中,然后训练的时候只放开新Embedding层的权重。但这样写对原来模型的改动还是蛮大的,最好的方法是尽可能少改动代码,让使用者几乎无感。为此,笔者构思了一种用stop_gradient简单修改Embedding层的方案,大体上是将Embedding层修改如下:

class PtuningEmbedding(Embedding):
    """新定义Embedding层,只优化部分Token
    """
    def call(self, inputs, mode='embedding'):
        embeddings = self.embeddings
        embeddings_sg = K.stop_gradient(embeddings)
        mask = np.zeros((K.int_shape(embeddings)[0], 1))
        mask[1:9] += 1  # 只优化id为1~8的token
        self.embeddings = embeddings * mask + embeddings_sg * (1 - mask)
        return super(PtuningEmbedding, self).call(inputs, mode)

变量经过stop_gradient算子后,在反向传播的时候梯度为0,但是前向传播不变,因此在上述代码中,前向传播的结果不会有变化,但是反向传播求梯度的时候,梯度不为0的token由mask变量控制,其余token的梯度都为零,因此就实现了只更新部分token。

完整代码可见:

https://github.com/bojone/P-tuning

对了,原论文也开源了代码:

https://github.com/THUDM/P-tuning

测试与效果

前面已经分享了原作者在SuperGLUE上的实验结果,显示出如果配合P-tuning,那么:1)GPT、BERT的效果相比直接finetune都有所提升;2)GPT的效果还能超过了BERT。这表明GPT不仅有NLG的能力,也有NLU能力,可谓是把GPT的潜能充分“压榨”出来了,当然BERT配合P-tuning也有提升,说明P-tuning对语言模型潜能的释放是较为通用的。

原论文的实验比较丰富,建议读者仔细阅读原论文,相信会收获颇多。特别指出的是原论文的Table 2最后一列,当预训练模型足够大的时候,我们的设备可能无法finetune整个模型,而P-tuning可以选择只优化几个Token的参数,因为优化所需要的显存和算力都会大大减少,所以P-tuning实则上给了我们一种在有限算力下调用大型预训练模型的思路。

▲ P-tuning在各个体量的语言模型下的效果

当然,笔者一直以来的观点是“没有在中文上测试过的算法是没有灵魂的”,因此笔者也在中文任务上简单测试了,测试任务跟必须要GPT-3吗?不,BERT的MLM模型也能小样本学习一致,都是情感分类的小样本学习,测试模型包括BERT和GPT,两者的候选模版分别如下图:

▲ 笔者在中文情感分类上使用的“BERT+P-tuning”模版

▲ 笔者在中文情感分类上使用的“BERT+P-tuning”模版

▲ 笔者在中文情感分类上使用的“GPT+P-tuning”模版

注意,对于LM模型,前缀的引入非常重要,只引入后缀时效果会明显变差;而对于MLM模型,前缀的效果通常也优于后缀。总的效果如下表:

小样本直接微调半监督学习零样本无监督小样本半监督验证集测试集验证集测试集小样本直接微调88.93%89.34%VAT半监督学习89.83%90.37%PET零样本85.17%84.27%PET无监督88.05%87.53%PET小样本89.29%89.18%PET半监督90.09%89.76%BERT + P-tuning89.81%89.75%GPT + P-tuning89.30%88.51%

其中“小样本”只用到了“少量标注样本”,“无监督”则用到了“大量无标注样本”,“半监督”则用到了“少量标注样本+大量无标注样本”,“P-tuning”都是小样本,PET的几个任务报告的是最优的人工模版的结果,其实还有更差的人工模版。从小样本角度来看,P-tuning确实取得了最优的小样本学习效果;从模版构建的角度来看,P-tuning确实也比人工构建的模版要好得多;从模型角度看,P-tuning确实可以将GPT的分类性能发挥到跟BERT相近,从而揭示了GPT也有很强的NLU能力的事实。

进一步理解

这一节将会介绍笔者对P-tuning的进一步思考,以求从多个维度来理解P-tuning。

离散 vs 连续

在P-tuning之前,也已经有一些在做模版的自动构建,如《How Can We Know What Language Models Know?》《AutoPrompt: Eliciting Knowledge from Language Models with Automatically Generated Prompts》等,但它们搜索的都是在离散空间下搜索的自然语言模版,所以效果有所限制,并没有取得特别突出的结果。

相反,P-tuning放弃了“模版由自然语言构成”这一要求,从而将其变成了可以简单梯度下降求解的连续参数问题,效果还更好。同时,这一改动意味着P-tuning突出了模版的本质——即模版的关键在于它是怎么用的,不在于它由什么构成——给人一种去芜存菁、眼前一亮额的感觉,确实值得点赞。

注:经读者提醒,年初有一篇论文《Prefix-Tuning: Optimizing Continuous Prompts for Generation》提出的Prefix-Tuning方法其实已经相当接近P-tuning,两者都设计了非自然语言的模版,只不过Prefix-Tuning主要关心NLG的应用而P-tuning更加关心NLU的应用。

Adapter

我们还可以从Adapter的角度来理解P-tuning。BERT出来后不久,Google在论文《Parameter-Efficient Transfer Learning for NLP》中提出了一种名为Adapter的微调方式,它并不是直接微调整个模型,而是固定住BERT原始权重,然后在BERT的基础上添加一些残差模块,只优化这些残差模块,由于残差模块的参数更少,因此微调成本更低。Adapter的思路实际上来源于CV的《Learning multiple visual domains with residual adapters》,不过这两年似乎很少看到了,也许是因为它虽然提高了训练速度,但是预测速度却降低了,精度往往还有所损失。

在P-tuning中,如果我们不将新插入的token视为“模版”,是将它视为模型的一部分,那么实际上P-tuning也是一种类似Adapter的做法,同样是固定原模型的权重,然后插入一些新的可优化参数,同样是只优化这些新参数,只不过这时候新参数插入的是Embedding层。因此,从这个角度看,P-tuning与Adapter有颇多异曲同工之处。

为什么有效

然后,还有一个值得思考的问题:为什么P-tuning会更好? 比如全量数据下,大家都是放开所有权重,P-tuning的方法依然比直接finetune要好,为啥呢?

事实上,提出这个问题的读者,应该是对BERT加个全连接层的直接finetune做法“习以为常”了。很明显,不管是PET还是P-tuning,它们其实都更接近预训练任务,而加个全连接层的做法,其实还没那么接近预训练任务,所以某种程度上来说,P-tuning有效更加“显然”,反而是加个全连接层微调为什么会有效才是值得疑问的。

去年有篇论文《A Mathematical Exploration of Why Language Models Help Solve Downstream Tasks》试图回答这个问题,大致的论证顺序是:

1.预训练模型是某种语言模型任务;

2.下游任务可以表示为该种语言模型的某个特殊情形;

3.当输出空间有限的时候,它又近似于加一个全连接层;

4.所以加一个全连接层微调是有效的。

可以看到,该论文的假设主要是第2点,其实就是直接假设了下游任务可以表达为类似PET的形式,然后才去证明的。所以这进一步说明了,PET、P-tuning等才是更自然的使用预训练模型的方式,加全连接直接finetune的做法其实只是它们的推论罢了,也就是说,PET、P-tuning才是返璞归真、回归本质的方案,所以它们更有效。

简单的总结

本文介绍了P-tuning,它是一种模版的自动构建方法,而通过模版我们可以从语言模型中抽取知识,完成零样本、小样本等学习任务,并且效果往往还更好。借助P-tuning,GPT也能实现优秀的NLU效果,在SuperGLUE上的表现甚至超过了BERT。除此之外,P-tuning还一种在有限算力下调用大型预训练模型的有效方案

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值