PEFT 文档
IA3
并获得增强的文档体验
开始使用
IA3
IA3 通过三个学习到的向量来乘以模型的激活值(自注意力块和编码器-解码器注意力块中的键和值,以及位置前馈网络的中间激活值)。这种 PEFT 方法引入的可训练参数数量甚至比 LoRA 更少,后者引入的是权重矩阵而非向量。原始模型的参数保持冻结,只更新这些向量。因此,针对新的下游任务进行微调时,它更快、更便宜、更高效。
本指南将向您展示如何使用 IA3 训练一个序列到序列模型,以便根据一些财经新闻来 *生成情感*。
对训练序列到序列模型的一般过程有所了解会非常有帮助,能让您更专注于如何应用 IA3。如果您是新手,我们建议您先阅读 Transformers 文档中的翻译和摘要指南。准备好后,再回来看看在您的训练中加入 PEFT 是多么简单!
数据集
您将使用 financial_phrasebank 数据集的 `sentences_allagree` 子集。该子集包含的财经新闻在情感标签上获得了 100% 的标注员一致性。通过数据集查看器可以更好地了解您将要处理的数据和句子。
使用 load_dataset 函数加载数据集。该数据集子集仅包含训练集,因此使用 `train_test_split` 函数创建一个训练集和验证集。创建一个新的 `text_label` 列,以便更容易理解 `label` 值 `0`、`1` 和 `2` 的含义。
from datasets import load_dataset
ds = load_dataset("financial_phrasebank", "sentences_allagree")
ds = ds["train"].train_test_split(test_size=0.1)
ds["validation"] = ds["test"]
del ds["test"]
classes = 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]
{'sentence': 'It will be operated by Nokia , and supported by its Nokia NetAct network and service management system .',
'label': 1,
'text_label': 'neutral'}
加载一个分词器并创建一个预处理函数,该函数:
- 对输入进行分词、填充和截断至 `max_length`
- 对标签应用相同的分词器,但使用与标签长度对应的较短 `max_length`
- 掩码填充令牌
from transformers import AutoTokenizer
text_column = "sentence"
label_column = "text_label"
max_length = 128
tokenizer = AutoTokenizer.from_pretrained("bigscience/mt0-large")
def preprocess_function(examples):
inputs = examples[text_column]
targets = examples[label_column]
model_inputs = tokenizer(inputs, max_length=max_length, padding="max_length", truncation=True, return_tensors="pt")
labels = tokenizer(targets, max_length=3, padding="max_length", truncation=True, return_tensors="pt")
labels = labels["input_ids"]
labels[labels == tokenizer.pad_token_id] = -100
model_inputs["labels"] = labels
return model_inputs
使用 map 函数将预处理函数应用于整个数据集。
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",
)
创建训练和评估的 `DataLoader`,如果您的数据集样本在 CPU 上,设置 `pin_memory=True` 可以加速训练期间数据到 GPU 的传输。
from torch.utils.data import DataLoader
from transformers import default_data_collator
train_ds = processed_ds["train"]
eval_ds = processed_ds["validation"]
batch_size = 8
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)
模型
现在您可以加载一个预训练模型作为 IA3 的基础模型。本指南使用 bigscience/mt0-large 模型,但您可以使用任何您喜欢的序列到序列模型。
from transformers import AutoModelForSeq2SeqLM
model = AutoModelForSeq2SeqLM.from_pretrained("bigscience/mt0-large")
PEFT 配置和模型
所有的 PEFT 方法都需要一个配置,其中包含并指定了如何应用该 PEFT 方法的所有参数。创建一个 IA3Config,指定任务类型并将推理模式设置为 `False`。您可以在 API 参考中找到该配置的其他参数。
调用 print_trainable_parameters() 方法,比较 PeftModel 的可训练参数数量与基础模型中的参数数量!
配置设置好后,将其与基础模型一起传递给 get_peft_model() 函数,以创建一个可训练的 PeftModel。
from peft import IA3Config, get_peft_model
peft_config = IA3Config(task_type="SEQ_2_SEQ_LM")
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()
"trainable params: 282,624 || all params: 1,229,863,936 || trainable%: 0.022980103060766553"
训练
设置优化器和学习率调度器。
import torch
from transformers import get_linear_schedule_with_warmup
lr = 8e-3
num_epochs = 3
optimizer = torch.optim.AdamW(model.parameters(), lr=lr)
lr_scheduler = get_linear_schedule_with_warmup(
optimizer=optimizer,
num_warmup_steps=0,
num_training_steps=(len(train_dataloader) * num_epochs),
)
将模型移动到 GPU,并创建一个训练循环,报告每个周期的损失和困惑度。
from tqdm import tqdm
device = "cuda"
model = model.to(device)
for epoch in range(num_epochs):
model.train()
total_loss = 0
for step, batch in enumerate(tqdm(train_dataloader)):
batch = {k: v.to(device) for k, v in batch.items()}
outputs = model(**batch)
loss = outputs.loss
total_loss += loss.detach().float()
loss.backward()
optimizer.step()
lr_scheduler.step()
optimizer.zero_grad()
model.eval()
eval_loss = 0
eval_preds = []
for step, batch in enumerate(tqdm(eval_dataloader)):
batch = {k: v.to(device) for k, v in batch.items()}
with torch.no_grad():
outputs = model(**batch)
loss = outputs.loss
eval_loss += loss.detach().float()
eval_preds.extend(
tokenizer.batch_decode(torch.argmax(outputs.logits, -1).detach().cpu().numpy(), skip_special_tokens=True)
)
eval_epoch_loss = eval_loss / len(eval_dataloader)
eval_ppl = torch.exp(eval_epoch_loss)
train_epoch_loss = total_loss / len(train_dataloader)
train_ppl = torch.exp(train_epoch_loss)
print(f"{epoch=}: {train_ppl=} {train_epoch_loss=} {eval_ppl=} {eval_epoch_loss=}")
分享您的模型
训练完成后,您可以使用 `push_to_hub` 方法将模型上传到 Hub。您需要先登录您的 Hugging Face 账户,并在提示时输入您的令牌。
from huggingface_hub import notebook_login
account = <your-hf-account-name>
peft_model_id = f"{account}/mt0-large-ia3"
model.push_to_hub(peft_model_id)
推理
要加载模型进行推理,请使用 from_pretrained() 方法。我们还从数据集中加载一条财经新闻,为其生成情感。
from peft import AutoPeftModelForSeq2SeqLM
model = AutoPeftModelForSeq2SeqLM.from_pretrained("<your-hf-account-name>/mt0-large-ia3").to("cuda")
tokenizer = AutoTokenizer.from_pretrained("bigscience/mt0-large")
i = 15
inputs = tokenizer(ds["validation"][text_column][i], return_tensors="pt")
print(ds["validation"][text_column][i])
"The robust growth was the result of the inclusion of clothing chain Lindex in the Group in December 2007 ."
调用 `generate` 方法来生成预测的情感标签。
with torch.no_grad():
inputs = {k: v.to(device) for k, v in inputs.items()}
outputs = model.generate(input_ids=inputs["input_ids"], max_new_tokens=10)
print(tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True))
['positive']