使用PEFT LoRA进行序列到序列模型微调实战指南
前言
在自然语言处理领域,序列到序列(Seq2Seq)模型是处理文本生成任务的重要工具,如机器翻译、文本摘要等。然而,这些大型模型在微调时需要消耗大量计算资源。PEFT(Parameter-Efficient Fine-Tuning)项目中的LoRA(Low-Rank Adaptation)技术提供了一种高效的解决方案,本教程将详细介绍如何使用PEFT LoRA对Seq2Seq模型进行高效微调。
环境准备与配置
首先需要确保环境已正确配置CUDA和必要的Python库。关键配置包括:
os.environ["TOKENIZERS_PARALLELISM"] = "false" # 禁用tokenizer并行处理以避免冲突
# 模型与训练参数
model_name_or_path = "bigscience/mt0-large" # 使用MT0-large预训练模型
tokenizer_name_or_path = "bigscience/mt0-large"
max_length = 128 # 输入文本最大长度
lr = 1e-3 # 学习率
num_epochs = 3 # 训练轮数
batch_size = 8 # 批大小
LoRA模型配置
LoRA的核心思想是通过低秩分解来减少可训练参数数量,同时保持模型性能:
peft_config = LoraConfig(
task_type=TaskType.SEQ_2_SEQ_LM, # 指定任务类型为序列到序列语言模型
inference_mode=False, # 训练模式
r=8, # 低秩矩阵的秩
lora_alpha=32, # 缩放因子
lora_dropout=0.1 # dropout率
)
# 加载预训练模型并应用LoRA
model = AutoModelForSeq2SeqLM.from_pretrained(model_name_or_path)
model = get_peft_model(model, peft_config)
model.print_trainable_parameters() # 打印可训练参数数量
通过这种方式,我们仅需训练原始模型参数的一小部分(通常<1%),大大降低了计算资源需求。
数据准备与预处理
本示例使用金融情感分析数据集(financial_phrasebank),将句子分类为positive/neutral/negative三类:
dataset = load_dataset("financial_phrasebank", "sentences_allagree")
dataset = dataset["train"].train_test_split(test_size=0.1)
dataset["validation"] = dataset["test"] # 将测试集重命名为验证集
# 将数字标签转换为文本标签
classes = dataset["train"].features["label"].names
dataset = dataset.map(
lambda x: {"text_label": [classes[label] for label in x["label"]]},
batched=True,
num_proc=1,
)
数据预处理函数将文本转换为模型可接受的输入格式:
def preprocess_function(examples):
inputs = examples[text_column]
targets = examples[label_column]
# 对输入文本进行tokenize
model_inputs = tokenizer(inputs, max_length=max_length, padding="max_length",
truncation=True, return_tensors="pt")
# 对标签文本进行tokenize
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 # 忽略pad token的损失计算
model_inputs["labels"] = labels
return model_inputs
训练流程
训练过程采用标准的PyTorch训练循环,但加入了学习率调度:
# 优化器和学习率调度器
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),
)
# 训练循环
for epoch in range(num_epochs):
model.train()
total_loss = 0
for batch in tqdm(train_dataloader):
batch = {k: v.to(device) for k, v in batch.items()}
outputs = model(**batch)
loss = outputs.loss
loss.backward()
optimizer.step()
lr_scheduler.step()
optimizer.zero_grad()
# 验证集评估
model.eval()
eval_loss = 0
eval_preds = []
for batch in tqdm(eval_dataloader):
with torch.no_grad():
outputs = model(**batch)
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)
模型评估与保存
训练完成后,我们评估模型在验证集上的准确率:
correct = 0
total = 0
for pred, true in zip(eval_preds, dataset["validation"]["text_label"]):
if pred.strip() == true.strip():
correct += 1
total += 1
accuracy = correct / total * 100
print(f"{accuracy=} % on the evaluation dataset")
模型保存仅需存储适配器权重,体积非常小(本示例中仅9.2MB):
peft_model_id = f"{model_name_or_path}_{peft_config.peft_type}_{peft_config.task_type}"
model.save_pretrained(peft_model_id) # 保存适配器权重
模型推理
加载和使用训练好的LoRA模型进行推理:
from peft import PeftModel, PeftConfig
# 加载基础模型和适配器
config = PeftConfig.from_pretrained(peft_model_id)
model = AutoModelForSeq2SeqLM.from_pretrained(config.base_model_name_or_path)
model = PeftModel.from_pretrained(model, peft_model_id)
# 示例推理
model.eval()
inputs = tokenizer("Demand for fireplace products was lower than expected", return_tensors="pt")
with torch.no_grad():
outputs = model.generate(input_ids=inputs["input_ids"], max_new_tokens=10)
print(tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True))
总结
通过本教程,我们学习了:
- 如何使用PEFT LoRA技术高效微调大型Seq2Seq模型
- 金融情感分析任务的数据处理流程
- LoRA模型的训练、评估和推理方法
- 适配器权重的保存与加载
PEFT LoRA技术显著降低了模型微调的资源需求,同时保持了良好的性能(本示例达到97.35%的准确率),是资源受限环境下微调大型语言模型的理想选择。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考