3. LoRA秩的选择

任务目标

在GLUE基准的MRPC(微软研究释义语料库)文本对匹配任务上,使用BERT-base作为底座模型,分别以LoRA秩 r=1、4、8、16 进行微调,通过验证集准确率与F1分数对比,确定当前任务下的最佳秩配置。

环境与依赖

需要安装以下核心库(Python 3.9+):

pip install transformers==4.40.0 datasets==2.19.0 peft==0.10.0 torch==2.2.0 evaluate==0.4.1

完整实现代码

以下代码完整实现了4种秩配置的训练与评估闭环。使用MRPC数据集的1,000条训练样本和验证集全量(408条)进行快速对比,确保在合理时间内完成实验。

import torch
from datasets import load_dataset
from transformers import (
    AutoTokenizer, AutoModelForSequenceClassification,
    TrainingArguments, Trainer, DataCollatorWithPadding
)
from peft import LoraConfig, get_peft_model, TaskType
import evaluate
import numpy as np

# ========== 1. 加载数据与预处理 ==========
dataset = load_dataset("glue", "mrpc")
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

def preprocess(examples):
    return tokenizer(examples["sentence1"], examples["sentence2"],
                     truncation=True, max_length=128)

# 使用1000条训练样本加速实验
train_data = dataset["train"].select(range(1000)).map(preprocess, batched=True)
eval_data = dataset["validation"].map(preprocess, batched=True)

data_collator = DataCollatorWithPadding(tokenizer=tokenizer)

# ========== 2. 评估指标 ==========
accuracy_metric = evaluate.load("accuracy")
f1_metric = evaluate.load("f1")

def compute_metrics(eval_pred):
    logits, labels = eval_pred
    predictions = np.argmax(logits, axis=-1)
    acc = accuracy_metric.compute(predictions=predictions, references=labels)["accuracy"]
    f1 = f1_metric.compute(predictions=predictions, references=labels)["f1"]
    return {"accuracy": acc, "f1": f1}

# ========== 3. 训练不同秩的LoRA ==========
def train_and_evaluate(r):
    model = AutoModelForSequenceClassification.from_pretrained(
        "bert-base-uncased", num_labels=2
    )
    # 冻结全部基座参数
    for param in model.parameters():
        param.requires_grad = False

    lora_config = LoraConfig(
        task_type=TaskType.SEQ_CLS,
        r=r,
        lora_alpha=2 * r,  # 缩放因子随秩线性调整
        lora_dropout=0.1,
        target_modules=["query", "value"]  # 仅注入Q和V矩阵
    )
    peft_model = get_peft_model(model, lora_config)
    peft_model.print_trainable_parameters()

    training_args = TrainingArguments(
        output_dir=f"./lora_r_{r}",
        learning_rate=3e-4,
        per_device_train_batch_size=32,
        per_device_eval_batch_size=32,
        num_train_epochs=3,
        evaluation_strategy="epoch",
        save_strategy="no",
        logging_dir=f"./logs_r_{r}",
        remove_unused_columns=False,
        report_to=[],
    )

    trainer = Trainer(
        model=peft_model,
        args=training_args,
        train_dataset=train_data,
        eval_dataset=eval_data,
        data_collator=data_collator,
        compute_metrics=compute_metrics,
    )
    trainer.train()
    eval_result = trainer.evaluate()
    return eval_result

# ========== 4. 执行对比实验 ==========
if __name__ == "__main__":
    results = {}
    for r in [1, 4, 8, 16]:
        print(f"\n===== 训练 LoRA r={r} =====")
        result = train_and_evaluate(r)
        results[r] = {
            "accuracy": result["eval_accuracy"],
            "f1": result["eval_f1"]
        }
        print(f"r={r} -> Accuracy: {result['eval_accuracy']:.4f}, F1: {result['eval_f1']:.4f}")

    # 输出汇总
    print("\n===== 结果汇总 =====")
    for r, metrics in results.items():
        print(f"r={r:2d} | Acc={metrics['accuracy']:.4f} | F1={metrics['f1']:.4f}")

    # 确定最佳秩
    best_r = max(results, key=lambda r: results[r]["f1"])
    print(f"\n最佳秩: r={best_r} (基于F1分数)")

运行方式

将上述代码保存为 lora_rank_search.py,在具备GPU(建议显存≥8GB)的环境中执行:

python lora_rank_search.py

首次运行会自动下载BERT-base模型与MRPC数据集。训练4个模型(每个约3分钟,取决于GPU性能),最终在终端输出各秩的验证集指标。

验证方法与判定标准

  • 可训练参数对比:程序会打印每个秩的LoRA可训练参数量。r=1时约0.3M参数,r=16时约1.2M参数,均远小于全量微调的110M参数,验证LoRA的高效性。
  • 性能趋势观察:MRPC验证集上,通常r=8或r=16能取得最佳F1分数(约85-88%),r=1可能欠拟合(F1约80-83%)。若r=4与r=8差距小于0.5%,说明低秩已足够捕获任务特征。
  • 判定最佳秩:以F1分数为主要指标(MRPC类别不平衡),选择F1最高的秩作为最佳配置。若两个秩的F1差异小于0.3%,则选择更小的秩(参数效率更高)。

预期输出示例

===== 结果汇总 =====
r= 1 | Acc=0.7892 | F1=0.8341
r= 4 | Acc=0.8235 | F1=0.8612
r= 8 | Acc=0.8382 | F1=0.8725
r=16 | Acc=0.8407 | F1=0.8749

最佳秩: r=16 (基于F1分数)

以上数值仅为基于模型容量的合理示例,实际结果会因随机种子和训练环境略有波动。核心观察点在于:随着秩增大,性能先快速提升后趋于平缓,r=8与r=16的差距通常小于r=1与r=4的差距。

LoRA秩对MRPC验证集性能的影响 0.80 0.82 0.84 0.86 0.88 r=1 r=4 r=8 r=16 0.834 0.861 0.873 0.875 秩 r → 性能趋于饱和,r=8与r=16差距微小 欠拟合区 性能饱和区

关键结论与使用建议

  • 秩的选择规律:低秩(r=1-4)适合简单任务或数据量小的场景;中等秩(r=8)是多数文本分类任务的稳妥起点;高秩(r=16)仅在任务复杂度高时带来边际收益。
  • 参数效率考量:r=16的可训练参数量约为r=1的16倍,但性能提升通常不超过3-5%。若部署资源紧张,优先选择性能下降在0.5%以内的最小秩。
  • 超参数联动:本实验将 lora_alpha 设为 2*r,保持缩放比例一致。若调整alpha值,最佳秩可能偏移,需重新对比。