Bootstrap

Prompt-Tuning方法学习


一、背景

  • 语言模型的三个阶段:
    在这里插入图片描述

  • 自从GPT、BERT的相继提出,以Pre-training+Fine-Tuning的模式在诸多自然语言处理(NLP)任务中被广泛使用。即先在Pre-training阶段通过一个模型在大规模无监督语料上训练一个预训练语言模型(Pre-trained Language Model,PLM),然后在Fine-Tuning阶段基于训练好的语言模型在具体的下游任务上进行再次微调(Fine-Tuning),以获得适应下游任务的模型。这种模式在诸多任务表现上超越了传统的监督学习方法,不论在工业生产、科研创新还是竞赛中均作为主流方法。然而,这套模式也存在一些问题。例如:下游任务的目标与预训练的目标差距过大导致提升效果不明显,微调过程中依赖大量监督语料等。

  • 所以一种新的微调范式——Prompt-Tuning被提出,其旨在通过添加模板提示的方法来避免优化过多的参数,从而让语言模型可以在小样本(Few-shot)或零样本(Zero-shot)场景下达到理想效果。

  • Prompt-Tuning可解决以下痛点:

    • 大型模型无法进行Fine-Tuning:例如GPT-3的参数达到1750亿,Fine-Tuning已无法对庞大的模型进行全量参数微调;
    • 降低语义差异(Bridge the gap between Pre-training and Fine-Tuning):预训练主要以Masked Language Model(MLM)为主,微调需要根据下游任务目标重新引入新的训练参数,两阶段的目标通常有较大差异;
    • 避免过拟合(Overfitting of the head):Fine-Tuning阶段在样本量有限的情况容易发生过拟合;

1.1 Pre-training

(1)MLM

  • Masked Language Model,是一种自监督的训练方法,先从大规模无监督语料上通过固定替换策略获得自监督语料,设计预训练目标来训练模型。
  • 替换策略:随机抽取15%的文本,被选中文本中,80%随机挑选一个token并替换为[mask],10%的文本随机挑选一个token替换为其他token,10%的文本保持不变;
  • 训练目标:当模型遇到[mask]token时,根据学习得到上下文语义去预测该位置可能的词,即对整个词表上的分类任务;
    (2)NSP
  • 在BERT原文中,还加入了Next Sentence Prediction任务,主要判断两个句子之间的关系,在NSP中存在三种关系:entailment(isNext)、contradition(isNotNext)、Neutral(中性关系)
  • ALBERT等模型中,由于发现NSP对实验效果没有太多正向影响,因此删除了NSP任务。在后续的预训练语言模型中也纷纷剔除其他预训练目标。Prompt-Tuning技术大多以MLM为切入点。

1.2 Fine-Tuning

对模型全量参数进行微调,需要消耗大量算力,较早提出。

  • 微调的任务目标取决于下游任务的性质:
    • 单句分类(Single-text Classification):长/短文本分类、意图识别、情感分析、关系抽取等
      • 给定一个文本,喂入多层Transfomer中,获得最后一层隐状态向量后,再输入新添加的分类器MLP中进行分类,通过交叉信息熵损失函数训练分类器
    • 文本匹配(Sentence-pair Classification):语义推理、语义蕴含、文本匹配与检索
      • 给定两个文本,用于判断匹配关系,将两个文本拼接后喂入模型,训练策略与单句分类相似
    • 区间预测(Span Text Prediction):抽取式阅读理解、实体抽取、抽取式摘要等
      • 给定一个passage和query,根据query寻找passage中可靠的字序列作为预测。通常需要模型预测区间的起止位置
    • 字符分类(Single-token Classification):序列标注、完形填空、拼写检测等
      • 获得给定文本的隐状态向量后,喂入MLP中,获得每个token对应的预测结果,采用交叉熵损失函数训练
    • 文本生成(Text Generation):生成式摘要、机器翻译、问答等
      • 选择单向预训练语言模型实现文本自回归生成,也有部分研究探索非自回归的双向Transformer进行文本生成任务

1.3 高效微调(SOTA PEFT)

State-of-the-art Parameter-Efficient Fine-Tuning (PEFT) methods

  • 对部分参数微调:PEFT技术旨在通过最小化微调参数的数量和计算复杂度,来提高预训练模型在新任务上的性能,从而缓解大型预训练模型的训练成本。
  • 代表性技术:LoRA、AdaLoRA、Prefix Tuning、Prefix Tuning、Prompt Tuning、P-Tuning等
  • Hugging Face的PEFT库:https://github.com/huggingface/peft

1.4 基于强化学习的进阶微调方法(RLHF)

  • 由微软DeepSpeedChat库进行维护:https://github.com/opendilab/awesome-RLHF

二、Prompt-Tuning技术

2.1 发展历程

在这里插入图片描述

2.2 Prompt模板构建方式

  • Prompt的本质是对下游任务的指令/提示,是一种对预训练任务的复用,可以作为一种信息增强。最初的Prompt旨在设计Template和Verbalizer,即Pattern-Verbalizer Pair来解决基于预训练模型的小样本文本分类。然而NLP领域涉及到很多复杂任务,如抽取、问答、翻译等,并不是简单的PVP可以解决,所以Prompt需要升华到一种更加通用的范式。

  • 关于构建PVP的方式,学术界有以下成熟的构建方法:
    在这里插入图片描述

  • 离散模板通常不稳定,且无法参与模型的训练环节,容易陷入局部最优;

  • 连续提示模板,将模板转换为可优化的连续向量,在模型增大时可以达到fine-Tuning的效果
    在这里插入图片描述

三、基于连续提示的Prompt Tuning

基于连续提示的Prompt Tuning,就是在Prompt中插入一段可以Tuning的Prompt token

Prefix-Tuning:《Prefix-Tuning:Optimizing Continuous Prompts for Generation》

  • 早期提出的针对大模型的少量参数微调的方法

  • 核心点:

    • 冻结预训练模型参数
    • 在每层加入一个小的可训练的连续向量前缀(prefix)
    • 对不同任务保存不同的前缀,微调成本较小
      在这里插入图片描述
  • 细节:

    • 作者发现直接更新多个虚拟token的参数效果很不稳定,因此在prefix层加了MLP,分解成了更小的Embedding层 * 更大的MLP层。原始的Embedding层参数是n_prefix * emb_dim, 调整后变为n_prefix * n_hidden + n_hidden * emb_dim。

    • prefix长度:默认的prefix长度为10,作者在不同任务上进行了微调,最优参数如下。整体上Prompt部分的参数量都在原模型的~0.1%
      在这里插入图片描述

    • 位置:作者还对比了把prefix放在不同位置,prefix的效果比infix效果更好
      在这里插入图片描述

    • Huggingface peft 关于prefix-Tuning核心代码

class PrefixEncoder(torch.nn.Module):
   
        if self.prefix_projection and not config.inference_mode:
            # Use a two-layer MLP to encode the prefix
            self.embedding = torch.nn.Embedding(num_virtual_tokens, token_dim)
            self.transform = torch.nn.Sequential(
                torch.nn.Linear(token_dim, encoder_hidden_size),
                torch.nn.Tanh(),
                torch.nn.Linear(encoder_hidden_size, num_layers * 2 * token_dim),
            )
        else:
            self.embedding = torch.nn.Embedding(num_virtual_tokens, num_layers * 2 * token_dim)

    def forward(self, prefix: torch.Tensor):
        if self.prefix_projection:
            prefix_tokens = self.embedding(prefix)
            past_key_values = self.transform(prefix_tokens)
        else:
            past_key_values = self.embedding(prefix)
        return past_key_values

Prompt Tuning:《The Power of Scale for Parameter-Efficient Prompt Tuning》

  • 相当于Prefix Tuning的简化版本,无需增加模型参数,而是在已有参数中,选择一部分参数作为可学习参数;

  • 在规模非常大的模型微调效果好,参数达到100亿时和全量微调效果一致;

  • 对比Prefix-Tunning,Prompt Tuning只对输入层(Embedding)进行微调,而Prefix是对虚拟Token对应的上游layer全部进行微调。因此Prompt-Tunning的微调参数量级要更小(10倍以上),且不需要修改原始模型结构;

  • 消融实验

    1. Prompt长度:固定其他参数,作者尝试了{1,5,20,100,150}, 当模型规模到百亿后,只要Prompt长度大于1,更长的Prompt并不能带来效果提升;
    2. Prompt初始化::作者尝试了随机uniform初始化,用标签文本空间初始化,和用Top5K高频词采样初始化,在10^8规模,标签词初始化效果最好。不过到百亿规模后,初始化带来的影响就会消失;
    3. 可解释性:作者使用cosine距离来搜索Prompt embedding对应的Top5近邻。embedding的近邻出现语义相似的cluster,例如{ Technology / technology / Technologies/ technological / technologies }, 说明连续Prompt实际可能是相关离散Prompt词的聚合语义
      在这里插入图片描述
  • Huggingface peft 关于Prompt Tuning核心代码
    class PromptEmbedding(torch.nn.Module):

 def forward(self, indices):
        # Just get embeddings
        Prompt_embeddings = self.embedding(indices)
        return Prompt_embeddings

P-Tuning v1:《GPT Understands, Too》

  • 背景

    • GPT3能够在few-shot甚至是zero-shot情况下获得较好的效果。其主要依赖于提出的新的微调范式(Prompt-based和in-context learning)。这表明,即便是单向模型,如果使用合适的人工构建的Prompt模板也是可以达到很好的自然语言理解目的;
    • 先前工作(包括chengdanqi的LM-BFF)致力于解决离散提示模板(discrete Prompt temporary)的自动生成问题,然而作者认为,神经网络是连续的,离散的Prompt会导致局部最优。
    • 同时作者发现,Prompt模板发生细微的改变,都会对最终的结果产生戏剧性的变化。
  • 核心点

    • Prompt模板的构建:在离散的Prompt模板上对部分token替换为可在连续空间微调的pseudo token,使用双向LSTM+2层MLP来对Prompt进行表征 ;
    • 离散和连续的token混合时,发现显式地插入一些anchor(领域有关的离散token)可以有助于Prompt模板的优化;
  • 方法
    在这里插入图片描述

  • 在一般场景下,给定一个token序列,通过随机MASK若干个token,并进行自监督训练,预测MASK部分的词;在预测阶段(例如分类),则输入的是整个文本序列,预测[CLS]对应的类别。

  • 如果在Prompt-based场景下,则通常将下游任务转化为Mask Language Model任务,此时不需要引入额外的参数,但需要明确一个Prompt模板。作者认为一个模板T可以表示为一个token序列:
    在这里插入图片描述

  • 传统的使用离散的Prompt方法是直接将模板T的每个token映射为对应的embedding,然后喂入BERT中参与微调。而在P-Tuning中,将模板中的P映射为一个可训练的参数h(如上图所示),此时这部分的token则称为pseudo token(soft-Prompt)。在优化过程中,认为这部分pseudo token也存在序列关系,因此使用双向LSTM对模板T中的pseudo token序列进行表征,则可以使用梯度下降法更新连续的参数。
    在这里插入图片描述

  • 缺陷

    • 在一些复杂的自然语言理解任务(NLU)效果差,如序列标注
    • 预训练模型的参数量对效果有影响,仅在10B规模表现良好,在稍小规模模型(330M和2B)上表现不佳
  • Huggingface peft 关于P Tuning的核心代码
    class PromptEncoder(torch.nn.Module):

 def forward(self, indices):
        input_embeds = self.embedding(indices)
        if self.encoder_type == PromptEncoderReparameterizationType.LSTM:
            output_embeds = self.mlp_head(self.lstm_head(input_embeds)[0])
        elif self.encoder_type == PromptEncoderReparameterizationType.MLP:
            output_embeds = self.mlp_head(input_embeds)
        else:
            raise ValueError("Prompt encoder type not recognized. Please use one of MLP (recommended) or LSTM.")

        return output_embeds

P-Tuning v2:《P-Tuning v2: Prompt Tuning Can Be Comparable to Fine-Tuning Universally Across Scales and Tasks》

  • 背景
    • Prompt Tuning是之前其他论文提出的一种方法,通过冻结语言模型仅去调整连续Prompts,在参数量超过10B的模型上,效果追上了fine-tune,但是在normal-sized模型上表现不好,并且无法解决序列标注任务。针对这两个问题,作者提出了P-Tuning v2。
  • 核心
    • 在原始P-Tuning基础上,提出deep Prompt Tuning,对pseudo token采用更深的表征,该方法可以视为Prefix-Tuning的拓展版本(Prefix-Tuning本身用于生成任务,作者将其拓展为NLU任务);
  • 方法
    • 先前的P-Tuning用了一层BiLSTM来表征pseudo token,显然是推理能力不足的原因之一,因此该部分提出Deep Prompt Tuning,采用 Prefix-Tuning 的做法,在输入前面的每层加入可微调的参数,如下图:
      • P-Tuning V2相比P-Tuning,区别在于:
        1. 去掉重参数化的编码器:对pseudo token,不再使用BiLSTM或MLP进行表征,且不再替换pre-trained model word embedding,取而代之的是直接对pseudo token对应的深层模型的参数进行微调;
        2. 可选的多任务学习:对于pseudo token的continous Prompt,随机初始化比较难以优化,因此采用multi-task方法,可以通过增加额外的任务数据或者无标注数据来缓解
        3. 回归传统的 CLS 和 token label classifier:P-Tuning V2无需verbalizer,而完全变为生成模型,可以在[CLS]部分输出sentence-level class,以及每个token位置上输出token-level class。主要是为了解决一些没有语义的标签的问题

在这里插入图片描述

  • 实验效果
    • P-Tuning V2 在不同规模的预训练模型上都能取得媲美 fine-Tuning 的表现,同时也能在一些比较难的 NLU 任务上取得更好的效果,未来研究的一个很强的 baseline。

在这里插入图片描述

四、Q&A

  1. 离散Prompt是什么?和连续Prompt的区别是什么?
  • 离散的Prompt
    • 离散的Prompt是通过人工手动构建或者通过规则生成的模板,可解释性比较强
    • 离散模板通常不稳定,且无法参与模型的训练环节,容易陷入局部最优
  • 连续的Prompt
    • 连续的Prompt是向量化的提示词,可以通过模型的反向传播进行优化
    • 连续提示模板,将模板转换为可优化的连续向量,在模型增大时可以达到fine-Tuning的效果
  1. 论文中第一页指出,离散Prompt在很多情况下效果不好,为什么?
  • 形式固定,设计麻烦,不参与模型训练,容易陷入局部最优
  • 人类理解的好的提示模板,可能不是机器理解的好的模板
  • 作者发现,Prompt模板发生细微的改变,都会对最终的结果产生戏剧性的变化。

在这里插入图片描述

  1. 论文中第二页指出,对于中等大小的模型,Prompt微调的效果比普通微调的效果差,为什么?
  • Prompt微调仅调整1%的参数,理论上效果不如全量微调
  • 较小的模型相比于大模型,参数较少,表达能力较弱,微调效果应该更不如全量微调。大模型的Prompt微调效果接近于fine-Tuning,应该是由于模型本身的泛化能力很强,稍作引导就可以达到很好的效果
  1. 论文中第二页指出,Prompt微调缺乏通用性是指?
  • 主要是指在100亿以下模型和NLU任务上表现逊色
  1. PTuning-v2的原理是什么?相比P-Tuning、prefix-Tuning和soft Prompt的优缺点是什么?
  • 简单来说,PTuning-v2是在prefix Tuning基础上的升级
    • 不再使用重参数化编码器对Prompts进行表征
    • 使用多任务学习的方式共享Prompt参数,更好的进行初始化
  • 优点
    • 适用于中等模型
    • 适用于NLU任务
  • 基于soft Prompt微调的方法均存在以下局限性:
    • 可解释性差
    • 收敛更慢:用少量参数撬动更大的模型,需要更复杂的空间搜索
  1. 论文中第五页指出,PTuning-v2是多层连续Prompts是指什么意思?可以在不同的层给出Prompts?还可以按升序和降序增加Prompts?
  • Deep Prompt Tuning,将soft Prompt加入到模型的每一层
  • 论文中实验了加入Prompt的层数对结果的影响,越靠近输出层效果越好(左)

在这里插入图片描述

;