用于序列分类的 P-tuning
译者:片刻小哥哥
项目地址:https://huggingface.apachecn.org/docs/peft/task_guides/ptuning-seq-classification
原始地址:https://huggingface.co/docs/peft/task_guides/ptuning-seq-classification
为下游任务微调大型语言模型具有挑战性,因为它们有太多参数。要解决此问题,您可以使用 提示 在不完全微调模型的情况下将模型引导至特定的下游任务。通常,这些提示是手工制作的,这可能不切实际,因为您需要非常大的验证集才能找到最佳提示。 P调 是一种在连续空间中自动搜索和优化更好提示的方法。
💡阅读 GPT 也能理解 了解有关 p 调整的更多信息。
本指南将向您展示如何训练
roberta-large
模型(但您也可以使用任何 GPT、OPT 或 BLOOM 模型),并在
mrpc
配置的
胶水
基准。
在开始之前,请确保已安装所有必需的库:
!pip install -q peft transformers datasets evaluate
设置
首先,导入 🤗 Transformers 以创建基本模型,🤗 Datasets 来加载数据集,🤗 Evaluate 来加载评估指标,🤗 PEFT 来创建 PeftModel 并设置 p-tuning 的配置。
定义模型、数据集和一些基本训练超参数:
from transformers import (
AutoModelForSequenceClassification,
AutoTokenizer,
DataCollatorWithPadding,
TrainingArguments,
Trainer,
)
from peft import (
get_peft_config,
get_peft_model,
get_peft_model_state_dict,
set_peft_model_state_dict,
PeftType,
PromptEncoderConfig,
)
from datasets import load_dataset
import evaluate
import torch
model_name_or_path = "roberta-large"
task = "mrpc"
num_epochs = 20
lr = 1e-3
batch_size = 32
加载数据集和指标
接下来,加载
mrpc
配置 - 根据语义是否等价标记的句子对语料库 - 来自
胶水
基准:
dataset = load_dataset("glue", task)
dataset["train"][0]
{
"sentence1": 'Amrozi accused his brother , whom he called " the witness " , of deliberately distorting his evidence .',
"sentence2": 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .',
"label": 1,
"idx": 0,
}
从🤗评估中,加载用于评估模型性能的指标。评估模块返回与该特定任务相关的准确性和 F1 分数。
metric = evaluate.load("glue", task)
现在您可以使用
公制
编写一个计算准确度和 F1 分数的函数。这
计算指标
函数根据模型预测和标签计算分数:
import numpy as np
def compute\_metrics(eval\_pred):
predictions, labels = eval_pred
predictions = np.argmax(predictions, axis=1)
return metric.compute(predictions=predictions, references=labels)
预处理数据集
初始化标记生成器并配置要使用的填充标记。如果您使用 GPT、OPT 或 BLOOM 模型,则应该设置
填充侧
向左转;否则它将被设置在右侧。对句子对进行分词并将其截断至最大长度。
if any(k in model_name_or_path for k in ("gpt", "opt", "bloom")):
padding_side = "left"
else:
padding_side = "right"
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, padding_side=padding_side)
if getattr(tokenizer, "pad\_token\_id") is None:
tokenizer.pad_token_id = tokenizer.eos_token_id
def tokenize\_function(examples):
# max\_length=None => use the model max length (it's actually the default)
outputs = tokenizer(examples["sentence1"], examples["sentence2"], truncation=True, max_length=None)
return outputs
使用
地图
来应用
标记化函数
到数据集,并删除未处理的列,因为模型不需要这些列。您还应该重命名
标签
列至
标签
因为这是 🤗 Transformers 库中模型标签的预期名称。
tokenized_datasets = dataset.map(
tokenize_function,
batched=True,
remove_columns=["idx", "sentence1", "sentence2"],
)
tokenized_datasets = tokenized_datasets.rename_column("label", "labels")
创建一个整理器函数 DataCollatorWithPadding 将批次中的示例填充到 ‘最长’ 批次中的顺序:
data_collator = DataCollatorWithPadding(tokenizer=tokenizer, padding="longest")
火车
P-tuning 使用提示编码器来优化提示参数,因此您需要初始化 PromptEncoderConfig 有几个参数:
任务类型
:您正在训练的任务类型,在本例中是序列分类或SEQ_CLS
num_virtual_tokens
:要使用的虚拟令牌的数量,或者换句话说,提示编码器隐藏大小
:用于优化提示参数的编码器的隐藏大小
peft_config = PromptEncoderConfig(task_type="SEQ\_CLS", num_virtual_tokens=20, encoder_hidden_size=128)
创建基地
“罗伯塔·大号”
模型来自
AutoModelForSequenceClassification
,然后包装基础模型并
peft_config
和
get_peft_model()
创建一个
PeftModel
。如果您想知道与所有模型参数的训练相比,您实际训练了多少参数,您可以使用以下命令打印出来
print_trainable_parameters()
:
model = AutoModelForSequenceClassification.from_pretrained(model_name_or_path, return_dict=True)
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()
"trainable params: 1351938 || all params: 355662082 || trainable%: 0.38011867680626127"
从 🤗 Transformers 库中,设置 TrainingArguments 包含要将模型保存到的位置、训练超参数、如何评估模型以及何时保存检查点的类:
training_args = TrainingArguments(
output_dir="your-name/roberta-large-peft-p-tuning",
learning_rate=1e-3,
per_device_train_batch_size=32,
per_device_eval_batch_size=32,
num_train_epochs=2,
weight_decay=0.01,
evaluation_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
)
然后通过模型, 《训练论据》 、数据集、分词器、数据整理器和评估函数 Trainer 课程,它将为您处理整个培训循环。准备好后,请致电 火车 开始训练!
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["test"],
tokenizer=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics,
)
trainer.train()
分享模型
如果您愿意,您可以在 Hub 上存储和共享您的模型。登录您的 Hugging Face 帐户并在出现提示时输入您的令牌:
from huggingface_hub import notebook_login
notebook_login()
使用以下命令将模型上传到 Hub 上的特定模型存储库 push_to_hub 功能:
model.push_to_hub("your-name/roberta-large-peft-p-tuning", use_auth_token=True)
推理
模型上传到 Hub 后,任何人都可以轻松使用它进行推理。加载配置和模型:
import torch
from peft import PeftModel, PeftConfig
from transformers import AutoModelForSequenceClassification, AutoTokenizer
peft_model_id = "smangrul/roberta-large-peft-p-tuning"
config = PeftConfig.from_pretrained(peft_model_id)
inference_model = AutoModelForSequenceClassification.from_pretrained(config.base_model_name_or_path)
tokenizer = AutoTokenizer.from_pretrained(config.base_model_name_or_path)
model = PeftModel.from_pretrained(inference_model, peft_model_id)
获取一些文本并将其标记化:
classes = ["not equivalent", "equivalent"]
sentence1 = "Coast redwood trees are the tallest trees on the planet and can grow over 300 feet tall."
sentence2 = "The coast redwood trees, which can attain a height of over 300 feet, are the tallest trees on earth."
inputs = tokenizer(sentence1, sentence2, truncation=True, padding="longest", return_tensors="pt")
将输入传递给模型以对句子进行分类:
with torch.no_grad():
outputs = model(**inputs).logits
print(outputs)
paraphrased_text = torch.softmax(outputs, dim=1).tolist()[0]
for i in range(len(classes)):
print(f"{classes[i]}: {int(round(paraphrased\_text[i] \* 100))}%")
"not equivalent: 4%"
"equivalent: 96%"