P-tuning|自动构建模板

转载https://www.sohu.com/a/460275238_500659

为什么 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 才是返璞归真、回归本质的方案,所以它们更有效。

Pattern-Exploiting Training(PET)

它通过人工构建的模版与 BERT 的 MLM 模型结合,能够起到非常好的零样本、小样本乃至半监督学习效果,而且该思路比较优雅漂亮,因为它将预训练任务和下游任务统一起来了。然而,人工构建这样的模版有时候也是比较困难的,而且不同的模版效果差别也很大,如果能够通过少量样本来自动构建模版,也是非常有价值的。

PET,主要的思想是借助由自然语言构成的模版(英文常称 Pattern 或 Prompt),将下游任务也转化为一个完形填空任务,这样就可以用 BERT 的 MLM 模型来进行预测了。

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

eg:通过特定模版将情感分类转换为MLM任务
在这里插入图片描述
eg:通过特定模版将新闻分类转换为MLM任务
在这里插入图片描述
这些模版属于语言模型的“探针”,我们可以通过模版来抽取语言模型的特定知识,从而做到不错的零样本效果,而配合少量标注样本,可以进一步提升效果。

如何根据已有的标注样本来自动构建模版,便成了一个值得研究的问题了。

P-tuning

P-tuning 的方法,成功地实现了模版的自动构建。

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

模版的关键在于它是怎么用的,不在于它由什么构成
我们并不关心模版长什么样,我们只需要知道模版由哪些 token 组成,该插入到哪里,插入后能不能完成我们的下游任务,输出的候选空间是什么。模版是不是自然语言组成的,对我们根本没影响,“自然语言”的要求,只是为了更好地实现“一致性”,但不是必须的。于是,P-tuning 考虑了如下形式的模版:(下面是新闻报道。中国女排再夺冠!)
在这里插入图片描述
P-tuning直接使用[unused*]的token来构建模版,不关心模版的自然语言性。
这里的 [u1]~[u6],代表 BERT 词表里边的 [unused1]~[unused6],也就是用几个从未见过的 token 来构成模板,这里的 token 数目是一个超参数,放在前面还是后面也可以调整。接着,为了让“模版”发挥作用,我们用标注数据来求出这个模板。

注意,对于 LM 模型,前缀的引入非常重要,只引入后缀时效果会明显变差;而对于 MLM 模型,前缀的效果通常也优于后缀。
由于LM语言模型是从左往右解码的,因此预测部分只能放在句末了(但还可以往补充前缀说明,只不过预测部分放在最后)
在这里插入图片描述

如何去优化

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

  • 第一种,标注数据比较少。这种情况下,我们固定整个模型的权重,只优化 [unused1]~[unused6] 这几个 token 的 Embedding,换句话说,其实我们就是要学 6 个新的Embedding,使得它起到了模版的作用。这样一来,因为模型权重几乎都被固定住了,训练起来很快,而且因为要学习的参数很少,因此哪怕标注样本很少,也能把模版学出来,不容易过拟合。
  • 第二种,标注数据很充足。这时候如果还按照第一种的方案来,就会出现欠拟合的情况,因为只有 6 个 token的可优化参数实在是太少了。因此,我们可以放开所有权重微调。

1、在标注数据比较少的时候,人工来选定适当的目标 token 效果往往更好些;2、在标注数据很充足的情况下,目标 token 用 [unused*] 效果更好些,因为这时候模型的优化空间更大一些。

增强相关性

在原论文中,P-tuning 并不是随机初始化几个新 token 然后直接训练的,而是通过一个小型的 LSTM 模型把这几个 Embedding 算出来,并且将这个 LSTM 模型设为可学习的。

这样多绕了一步有什么好处呢?原论文大概的意思是: LSTM 出现的 token 表示相关性更强,某种程度上来说更像“自然语言”(因为自然语言的 token 之间不是独立的),此外还能防止局部最优。

通过 LSTM 多绕一步的方法可以使得模型收敛更快、效果更优。

LSTM 是为了帮助模版的几个 token(某种程度上)更贴近自然语言,但这并不一定要用 LSTM 生成,而且就算用 LSTM 生成也不一定达到这一点。

笔者认为,更自然的方法是在训练下游任务的时候,不仅仅预测下游任务的目标 token(前面例子中的“很”、“新闻”), 还应该同时做其他 token 的预测。

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

实现

怎么实现上述的 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

效果

好!

当预训练模型足够大的时候,我们的设备可能无法 finetune 整个模型,而 P-tuning 可以选择只优化几个 Token 的参数,因为优化所需要的显存和算力都会大大减少, 所以 P-tuning 实则上给了我们一种在有限算力下调用大型预训练模型的思路。

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 有颇多异曲同工之处。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值