PEFT原理及代码

一.soft-prompt

训练大型预训练语言模型非常耗时且计算密集。随着模型规模的不断扩大,研究者们越来越关注更有效的训练方法,如提示(Prompt)。提示通过在输入中添加描述任务的文本提示,甚至通过提供任务示例,来为特定下游任务准备冻结的预训练模型。通过使用提示,您可以避免为每个下游任务训练一个单独的模型,而是通过同一个冻结的预训练模型来完成多个任务。这比为每个任务训练一个单独的模型要高效得多,因为您只需要训练和存储一个较小的提示参数集,而不是训练整个模型的参数。

提示方法可以分为两类:

  • 硬提示:手动创建的带有离散输入标记的文本提示。缺点是创建一个好的提示需要付出很多努力。
  • 软提示:与可以针对数据集优化的输入嵌入连接的可学习张量。缺点是软提示不是人类可读的,因为这些“虚拟标记”没有与真实单词的嵌入对应。

本概念指南简要概述了 PEFT(Prompt Engineering and Fine-Tuning)中包含的软提示方法:提示调优、前缀调优、P调优和多任务提示调优。

# pip install -q peft transformers datasets

from datasets import load_dataset

ds = load_dataset("ought/raft", "twitter_complaints")

classes = [k.replace("_", " ") for k in ds["train"].features["Label"].names]
ds = ds.map(
    lambda x: {"text_label": [classes[label] for label in x["Label"]]},
    batched=True,
    num_proc=1,
)
# ds["train"][0]
# {"Tweet text": "@HMRCcustomers No this is my first job", "ID": 0, "Label": 2, "text_label": "no complaint"}

数据集: 

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bigscience/bloomz-560m")
if tokenizer.pad_token_id is None:
    tokenizer.pad_token_id = tokenizer.eos_token_id
target_max_length = max([len(tokenizer(class_label)["input_ids"]) for class_label in classes])
print(target_max_length)

import torch

max_length = 64

def preprocess_function(examples, text_column="Tweet text", label_column="text_label"):
    batch_size = len(examples[text_column])
    inputs = [f"{text_column} : {x} Label : " for x in examples[text_column]]
    targets = [str(x) for x in examples[label_column]]
    model_inputs = tokenizer(inputs)
    labels = tokenizer(targets)
    classes = [k.replace("_", " ") for k in ds["train"].features["Label"].names]
    for i in range(batch_size):
        sample_input_ids = model_inputs["input_ids"][i]
        label_input_ids = labels["input_ids"][i]
        model_inputs["input_ids"][i] = [tokenizer.pad_token_id] * (
            max_length - len(sample_input_ids)
        ) + sample_input_ids
        model_inputs["attention_mask"][i] = [0] * (max_length - len(sample_input_ids)) + model_inputs[
            "attention_mask"
        ][i]
        labels["input_ids"][i] = [-100] * (max_length - len(label_input_ids)) + label_input_ids
        model_inputs["input_ids"][i] = torch.tensor(model_inputs["input_ids"][i][:max_length])
        model_inputs["attention_mask"][i] = torch.tensor(model_inputs["attention_mask"][i][:max_length])
        labels["input_ids"][i] = torch.tensor(labels["input_ids"][i][:max_length])
    model_inputs["labels"] = labels["input_ids"]
    return model_inputs

processed_ds = ds.map(
    preprocess_function,
    batched=True,
    num_proc=1,
    remove_columns=ds["train"].column_names,
    load_from_cache_file=False,
    desc="Running tokenizer on dataset",
)
from torch.utils.data import DataLoader
from transformers import default_data_collator

train_ds = processed_ds["train"]
eval_ds = processed_ds["test"]

batch_size = 16

train_dataloader = DataLoader(train_ds, shuffle=True, collate_fn=default_data_collator, batch_size=batch_size, pin_memory=True)
eval_dataloader = DataLoader(eval_ds, collate_fn=default_data_collator, batch_size=batch_size, pin_memory=True)

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("bigscience/bloomz-560m")

1.p-tune 

P调优(P-Tuning)是一种为自然语言理解(NLU)任务和所有语言模型设计的方法,它是软提示方法的另一种变体。P调优通过添加一个可训练的嵌入张量来优化提示,以找到更好的提示,并使用提示编码器(例如双向长短期记忆网络 LSTM)来优化提示参数。与前缀调优不同,P调优的特点是:

  • 提示令牌可以插入到输入序列的任何位置,而不仅仅是输入的开头。
  • 提示令牌只添加到输入中,而不是添加到模型的每一层。
  • 引入锚令牌(anchor tokens)可以改善性能,因为锚令牌能够表示输入序列中某一组件的特征。

研究结果表明,P调优比手动设计提示更高效,并且使得像 GPT 这样的模型能够在自然语言理解任务上与 BERT 等模型相竞争。

 P-tuning 添加了一个可训练的嵌入张量,其中提示标记可以添加到输入序列中的任何位置。创建一个 PromptEncoderConfig,其中包含任务类型、要添加和学习的虚拟令牌数量以及用于学习提示参数的编码器的隐藏大小

from peft import PromptEncoderConfig, get_peft_model

peft_config = PromptEncoderConfig(task_type="CAUSAL_LM", num_virtual_tokens=20, encoder_hidden_size=128)
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()
"trainable params: 300,288 || all params: 559,514,880 || trainable%: 0.05366935013417338"

PromptEncoderConfig

class peft.PromptEncoderConfig:
    peft_type: Union = None
    auto_mapping: Optional = None
    base_model_name_or_path: Optional = None
    revision: Optional = None
    task_type: Union = None
    inference_mode: bool = False
    num_virtual_tokens: int = None
    token_dim: int = None
    num_transformer_submodules: Optional = None
    num_attention_heads: Optional = None
    num_layers: Optional = None
    encoder_reparameterization_type: Union = <PromptEncoderReparameterizationType.MLP: 'MLP'>
    encoder_hidden_size: int = None
    encoder_num_layers: int = 2
    encoder_dropout: float = 0.0

参数说明

  • encoder_reparameterization_type:指定要使用的重新参数化类型。
  • encoder_hidden_size:提示编码器的隐藏层大小。
  • encoder_num_layers:提示编码器的层数。
  • encoder_dropout:提示编码器的丢弃概率。
  • 这是用于存储 PromptEncoder 配置

PromptEncoder

class peft.PromptEncoder:
    config: PromptEncoderConfig

参数说明

  • config:提示编码器的配置。
  • 提示编码器网络用于生成 P-tuning 的虚拟令牌嵌入。

示例代码

from peft import PromptEncoder, PromptEncoderConfig

config = PromptEncoderConfig(
    peft_type="P_TUNING",
    task_type="SEQ_2_SEQ_LM",
    num_virtual_tokens=20,
    token_dim=768,
    num_transformer_submodules=1,
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值