使用PEFT LoRA进行序列到序列模型微调实战指南

使用PEFT LoRA进行序列到序列模型微调实战指南

peft 🤗 PEFT: State-of-the-art Parameter-Efficient Fine-Tuning. peft 项目地址: https://gitcode.com/gh_mirrors/pe/peft

前言

在自然语言处理领域,序列到序列(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))

总结

通过本教程,我们学习了:

  1. 如何使用PEFT LoRA技术高效微调大型Seq2Seq模型
  2. 金融情感分析任务的数据处理流程
  3. LoRA模型的训练、评估和推理方法
  4. 适配器权重的保存与加载

PEFT LoRA技术显著降低了模型微调的资源需求,同时保持了良好的性能(本示例达到97.35%的准确率),是资源受限环境下微调大型语言模型的理想选择。

peft 🤗 PEFT: State-of-the-art Parameter-Efficient Fine-Tuning. peft 项目地址: https://gitcode.com/gh_mirrors/pe/peft

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

管旭韶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值