1. 使用Hugging Face PEFT库对进行LoRA微调

任务目标

本案例将加载预训练的 模型,使用 Hugging Face PEFT 库为其注入 LoRA 适配器,在一个小型文本数据集上完成微调,并通过困惑度(Perplexity)指标验证微调前后模型性能的变化。

环境依赖

需要安装以下 Python 包:

pip install transformers datasets peft accelerate torch

完整实现代码

import math
import torch
from datasets import load_dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForLanguageModeling, Trainer, TrainingArguments
from peft import LoraConfig, get_peft_model, TaskType

# 1. 加载模型与分词器
model_name = ""
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_ = tokenizer.eos_
model = AutoModelForCausalLM.from_pretrained(model_name)

# 2. 配置 LoRA
lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=8,
    lora_alpha=32,
    lora_dropout=0.1,
    target_modules=["c_attn"],  #  的注意力层模块
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()  # 应显示仅约 0.1% 参数可训练

# 3. 加载小型数据集(使用 WikiText-2 的 1% 子集)
dataset = load_dataset("wikitext", "wikitext-2-raw-v1", split="train[:1%]")
dataset = dataset.filter(lambda x: len(x["text"]) > 50)  # 过滤过短样本

# 4. 数据预处理
def tokenize_function(examples):
    return tokenizer(examples["text"], truncation=True, max_length=128)

tokenized_dataset = dataset.map(tokenize_function, batched=True, remove_columns=["text"])
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)

# 5. 微调前评估(困惑度)
def compute_perplexity(model, dataset):
    model.eval()
    total_loss = 0.0
    count = 0
    with torch.no_grad():
        for batch in torch.utils.data.DataLoader(dataset.select(range(50)), batch_size=4, collate_fn=data_collator):
            input_ids = batch["input_ids"].to(model.device)
            attention_mask = batch["attention_mask"].to(model.device)
            labels = batch["labels"].to(model.device)
            outputs = model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)
            total_loss += outputs.loss.item() * input_ids.size(0)
            count += input_ids.size(0)
    avg_loss = total_loss / count
    return math.exp(avg_loss)

# 将模型移至 GPU(如可用)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

# 微调前困惑度
ppl_before = compute_perplexity(model, tokenized_dataset)
print(f"微调前困惑度: {ppl_before:.2f}")

# 6. 配置训练参数并微调
training_args = TrainingArguments(
    output_dir="./-lora-finetuned",
    per_device_train_batch_size=4,
    num_train_epochs=3,
    logging_steps=50,
    save_strategy="no",
    report_to=[],
    disable_tqdm=False,
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset,
    data_collator=data_collator,
)

trainer.train()

# 7. 微调后评估
ppl_after = compute_perplexity(model, tokenized_dataset)
print(f"微调后困惑度: {ppl_after:.2f}")
print(f"困惑度下降幅度: {ppl_before - ppl_after:.2f}")

# 8. 保存 LoRA 适配器
model.save_pretrained("./-lora-adapter")

运行方式

将上述代码保存为 finetune__lora.py,在终端执行:

python finetune__lora.py

验证方法与判定标准

  • 参数效率验证:运行代码时,model.print_trainable_parameters() 应输出可训练参数占比约为 0.1%(约 0.3M 参数),证明 LoRA 仅微调少量参数。
  • 训练收敛验证:训练日志中的 loss 应随步数增加呈下降趋势。
  • 效果验证:程序最终打印的微调后困惑度应明显低于微调前困惑度(例如从约 30 降至 20 以下),且困惑度下降幅度为正值,即证明 LoRA 微调有效提升了模型对训练数据分布的拟合能力。

预期输出示例

trainable params: 294,912 || all params: 125,619,456 || trainable%: 0.2347
微调前困惑度: 32.45
...
微调后困惑度: 18.72
困惑度下降幅度: 13.73

以上数值仅为基于代码逻辑的示例,实际结果会因随机种子和数据集采样而略有不同。