【Hugging Face】PEFT 库中的 VeraConfig 常用参数和说明

在 Hugging Face 的 PEFT(Parameter-Efficient Fine-Tuning)库中,VeraConfig 是用于配置 VeRA(Vector-based Random Matrix Adaptation)方法的类。VeRA 是一种高效的参数微调技术,通过使用共享的低秩矩阵对和少量可训练的缩放向量(scaling vectors)来减少微调大型语言模型(LLM)所需的参数量。相比于 LoRA,VeRA 显著减少了可训练参数,同时保持相似的性能,特别适合存储受限或多任务适配的场景。以下是对 VeraConfig 的详细讲解,包括其参数、用法、代码示例和注意事项。


1. VeraConfig 概述

VeRA 的核心思想是使用一组共享的低秩矩阵(A 和 B)作为所有层的适配器基底,并为每个层学习少量的缩放向量(scaling vectors)。这些共享矩阵是固定的(基于随机种子生成),不参与训练,从而大幅减少参数量。VeRA 在生成任务(如因果语言建模)中表现良好,尤其适用于需要高效存储或快速切换任务的场景。

VeRA 的优势

  • 极低参数量:仅训练缩放向量,参数量远少于 LoRA(通常只有 LoRA 的 10%-20%)。
  • 存储效率:可选不保存共享矩阵(通过随机种子重现),进一步减少模型检查点大小。
  • 性能:在 GLUE、E2E 基准测试和指令微调任务中与 LoRA 性能相当。
  • 兼容性:与 Hugging Face 的 Transformers 模型无缝集成。

VeRA 的局限性

  • 依赖随机种子生成共享矩阵,跨设备或 PyTorch 版本的再现性可能受限。
  • 初始化和训练复杂度略高于 LoRA,可能需要更多计算资源。

2. VeraConfig 的主要参数

以下是 VeraConfig 中常用的参数及其说明(基于 PEFT 文档和代码):

  • peft_type(默认:"VERA"

    • 指定 PEFT 方法类型,固定为 "VERA"
    • 通常无需手动设置,由类自动处理。
  • task_type(可选,字符串或 peft.utils.peft_types.TaskType

    • 指定任务类型,帮助 PEFT 确定模型结构和用途。常见选项包括:
      • "SEQ_CLS":序列分类(如情感分析)。
      • "TOKEN_CLS":token 分类(如 NER)。
      • "CAUSAL_LM":因果语言模型(如 GPT)。
      • "SEQ_2_SEQ_LM":序列到序列模型(如 T5)。
    • 推荐明确指定,例如生成任务使用 "CAUSAL_LM"
  • r(整数,默认:256)

    • 指定低秩矩阵的秩(rank),控制适配器的表达能力。
    • 典型值:128 到 512。较高的秩增加表达能力,但也增加缩放向量的参数量。
    • 参数量计算:r * num_layers * 2(每个层有两个缩放向量:一个用于 A,一个用于 B)。
  • target_modules(列表或字符串,可选)

    • 指定应用 VeRA 的模型模块(通常是 Transformer 的注意力层或前馈层)。
    • 常见值:
      • ["q_proj", "v_proj"]:对注意力层的 query 和 value 投影应用 VeRA。
      • ["q_proj", "k_proj", "v_proj", "o_proj"]:更广泛的注意力模块。
    • 必须根据模型结构明确指定(例如,LLaMA 使用 ["q_proj", "v_proj"])。
  • projection_prng_key(整数,默认:0)

    • 指定生成共享低秩矩阵 A 和 B 的随机种子。
    • 确保一致的矩阵初始化,但跨设备或 PyTorch 版本的再现性可能不完全保证。
  • save_projection(布尔值,默认:True)

    • 是否在保存模型时存储共享低秩矩阵 A 和 B。
    • True:保存矩阵,确保跨设备完全再现性(检查点稍大)。
    • False:不保存矩阵,依赖 projection_prng_key 重现,显著减少检查点大小(例如,从 MB 级降到 KB 级),但再现性可能受限。
  • vera_dropout(浮点数,默认:0.0)

    • 缩放向量的 Dropout 概率,用于正则化。
    • 典型值:0.0 到 0.1。推荐从 0.0 开始,若过拟合再增加。
  • d_initial(浮点数,默认:0.1)

    • 缩放向量的初始值,用于初始化缩放参数。
    • 典型值:0.01 到 0.1。较小的值确保初始行为接近原始模型。
  • fan_in_fan_out(布尔值,默认:False)

    • 是否适配特定模型的权重矩阵布局(fan-in/fan-out)。通常针对非标准 Transformer 架构。
  • bias(字符串,默认:"none"

    • 指定是否为适配器添加偏置(bias)。选项:
      • "none":无偏置。
      • "all":为所有适配器层添加偏置。
      • "vera_only":仅为 VeRA 层添加偏置。
    • 推荐保持默认值 "none",除非任务需要额外的表达能力。
  • modules_to_save(列表,可选)

    • 指定需要全量微调的模块(不使用 VeRA)。例如,分类头或语言模型头。
    • 示例:["lm_head"]["classifier"]
  • init_weights(布尔值或字符串,默认:True)

    • 指定缩放向量的初始化方式:
      • True:使用默认初始化(基于 d_initial)。
      • "gaussian":使用高斯分布初始化(不推荐,可能不稳定)。
    • 推荐使用默认值 True
  • layers_to_transform(列表或整数,可选)

    • 指定应用 VeRA 的 Transformer 层索引。
    • 示例:[0, 1, 2]10(仅前 10 层)。
    • 默认:所有层。
  • layers_pattern(字符串或列表,可选)

    • 指定匹配层名称的模式,用于非标准模型。
    • 示例:"blocks"["layer", "h"]

3. 使用 VeraConfig 的基本流程

以下是一个使用 VeraConfig 微调 GPT-2 模型(用于因果语言建模任务)的完整示例:

步骤 1:安装和导入库
pip install peft transformers torch datasets
from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments
from peft import VeraConfig, get_peft_model
from datasets import load_dataset
步骤 2:加载模型和数据集
# 加载预训练模型和分词器
model_name = "gpt2"
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token  # 为 GPT-2 设置 pad token

# 加载数据集(以 wikitext 为例)
dataset = load_dataset("wikitext", "wikitext-2-raw-v1")

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

tokenized_dataset = dataset.map(tokenize_function, batched=True)
步骤 3:配置 VeraConfig
# 配置 VeRA
vera_config = VeraConfig(
    task_type="CAUSAL_LM",           # 因果语言模型任务
    r=128,                           # 低秩矩阵的秩
    target_modules=["c_attn"],       # 应用 VeRA 的模块(GPT-2 的注意力层)
    projection_prng_key=0,           # 随机种子
    save_projection=False,           # 不保存共享矩阵,减少检查点大小
    vera_dropout=0.0,                # Dropout 概率
    d_initial=0.1,                   # 缩放向量初始值
    modules_to_save=["lm_head"]      # 全量微调语言模型头
)

# 将 VeRA 应用到模型
peft_model = get_peft_model(model, vera_config)

# 查看可训练参数
peft_model.print_trainable_parameters()

输出示例:

trainable params: 49,152 || all params: 124,747,008 || trainable%: 0.039

这表明只有约 0.039% 的参数需要训练(缩放向量 + 语言模型头参数),远少于 LoRA。

步骤 4:训练模型
# 配置训练参数
training_args = TrainingArguments(
    output_dir="./results",
    evaluation_strategy="epoch",
    learning_rate=1e-3,                     # VeRA 通常需要较高学习率
    per_device_train_batch_size=8,
    per_device_eval_batch_size=8,
    num_train_epochs=3,
    weight_decay=0.01,
)

# 初始化 Trainer
trainer = Trainer(
    model=peft_model,
    args=training_args,
    train_dataset=tokenized_dataset["train"].select(range(1000)),  # 选取子集以加速示例
    eval_dataset=tokenized_dataset["validation"].select(range(200)),
)

# 开始训练
trainer.train()
步骤 5:保存和加载 VeRA 模型
# 保存 VeRA 参数
peft_model.save_pretrained("./vera_model")

# 加载 VeRA 模型
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained(model_name)
loaded_model = PeftModel.from_pretrained(base_model, "./vera_model")
步骤 6:推理
# 准备输入
inputs = tokenizer("Once upon a time", return_tensors="pt").to("cuda")

# 推理
loaded_model.eval()
outputs = loaded_model.generate(**inputs, max_length=50)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

4. VeraConfig 的优化建议

  • 选择 r

    • r=128r=256 开始实验。较高的秩(如 512)增加表达能力,但参数量略增。
    • 参数量与 r 和层数成正比:r * num_layers * 2
  • 配置 target_modules

    • 推荐从 ["q_proj", "v_proj"] 开始,仅调整注意力层的 query 和 value,参数量最小。
    • 如果性能不足,扩展到 ["q_proj", "k_proj", "v_proj", "o_proj"]
    • 使用 model.named_modules() 检查模型结构,确认模块名称。
  • 设置 save_projection

    • 设置 save_projection=False 以最小化检查点大小(例如,几十 KB),适合多任务存储。
    • 如果需要跨设备完全再现性,设置为 True(检查点大小增加到 MB 级)。
  • 调整 projection_prng_key

    • 默认值 0 通常足够。更改种子可能影响初始化矩阵,需实验验证。
    • 记录种子值以确保实验可重复。
  • 学习率

    • VeRA 通常需要较高的学习率(如 1e-3 或 5e-4),因为只优化少量缩放向量。
    • 使用学习率调度器(如线性衰减)以提高稳定性。
  • 任务类型

    • 确保 task_type 匹配模型类型,例如 GPT 使用 "CAUSAL_LM",T5 使用 "SEQ_2_SEQ_LM"
  • 内存优化

    • VeRA 参数量极小,但基模型可能需要量化以进一步节省内存:
      from transformers import BitsAndBytesConfig
      quantization_config = BitsAndBytesConfig(load_in_4bit=True)
      model = AutoModelForCausalLM.from_pretrained(model_name, quantization_config=quantization_config)
      
  • Dropout

    • 保持 vera_dropout=0.0 除非观察到过拟合。增加到 0.05 或 0.1 以增强正则化。

5. VeRA vs. 其他 PEFT 方法

  • VeRA vs. LoRA

    • 参数量:VeRA 参数量远少于 LoRA(仅缩放向量 vs. 低秩矩阵)。
    • 存储:VeRA 可不保存共享矩阵,检查点更小(KB 级 vs. MB 级)。
    • 性能:VeRA 在生成任务中与 LoRA 性能相当,但 LoRA 更通用。
    • 适用场景:VeRA 适合存储受限或多任务场景;LoRA 适合需要高表达能力的任务。
  • VeRA vs. Prompt Tuning

    • 结构:VeRA 调整模型内部权重,Prompt Tuning 添加输入提示。
    • 参数量:VeRA 参数量通常更少(缩放向量 vs. 嵌入矩阵)。
    • 适用场景:VeRA 更适合生成任务,Prompt Tuning 更适合快速实验。
  • VeRA vs. IA3

    • 结构:VeRA 使用共享低秩矩阵和缩放向量,IAPent Tuning**:
    • 结构:VeRA 使用共享低秩矩阵和缩放向量,IA3 使用一维缩放向量。
    • 参数量:VeRA 参数量略多于 IA3(因共享矩阵的秩),但表达能力更强。
    • 适用场景:VeRA 更适合生成任务,IA3 更高效但表达能力有限。
  • VeRA vs. LoftQ

    • 结构:VeRA 使用共享矩阵,LoftQ 结合量化初始化 LoRA 权重。
    • 参数量:VeRA 参数量少于 LoftQ(缩放向量 vs. 低秩矩阵)。
    • 适用场景:VeRA 更适合存储受限场景,LoftQ 更适合量化微调。

6. 常见问题与解答

  • Q1:如何确定 target_modules

    • 使用 model.named_modules() 查看模型层结构,找到注意力(q_proj, v_proj)或前馈层的名称。
    • 参考模型文档或 PEFT 默认值(例如,LLaMA 的 q_proj, v_proj)。
  • Q2:save_projection=False 是否安全?

    • 如果目标设备和 PyTorch 版本一致,save_projection=False 是安全的,可显著减少检查点大小。
    • 如果需要跨设备部署,推荐 save_projection=True 以确保再现性。
  • Q3:VeRA 是否支持所有模型?

    • 支持所有 Hugging Face Transformers 模型,但最适合生成模型(如 GPT、LLaMA、Falcon)。
    • 对于分类模型(如 BERT),效果可能不如 LoRA。
  • Q4:性能不佳如何优化?

    • 增加 r(如从 128 到 256 或 512)。
    • 扩展 target_modules(如添加 k_proj, o_proj)。
    • 调整学习率(尝试 5e-4 到 2e-3)。
    • 检查数据集质量或增加训练轮次。
    • 尝试 LoRA 或 LoftQ 以比较性能。
  • Q5:VeRA 的参数量如何计算?

    • 每个层的参数量为 r * 2(两个缩放向量)。
    • 总参数量 = r * num_layers * 2
    • 示例:GPT-2(12 层,r=128):128 * 12 * 2 = 3,072 参数。

7. 进阶用法

  • 多任务 VeRA

    • 为不同任务创建多个 VeRA 适配器:
      vera_config_task1 = VeraConfig(
          task_type="CAUSAL_LM",
          r=128,
          target_modules=["c_attn"],
          save_projection=False
      )
      vera_config_task2 = VeraConfig(
          task_type="CAUSAL_LM",
          r=256,
          target_modules=["c_attn"],
          save_projection=True
      )
      
      peft_model = get_peft_model(model, vera_config_task1, adapter_name="task1")
      peft_model.add_adapter("task2", vera_config_task2)
      peft_model.set_adapter("task1")  # 切换适配器
      
  • 合并 VeRA 权重

    • 消除推理时的适配器延迟:
      peft_model.merge_and_unload()
      
  • 保存到 Hugging Face Hub

    peft_model.push_to_hub("your-username/vera-model")
    
  • 结合量化

    • 为大型模型启用 4-bit 量化以节省内存:
      from transformers import BitsAndBytesConfig
      quantization_config = BitsAndBytesConfig(load_in_4bit=True)
      model = AutoModelForCausalLM.from_pretrained(model_name, quantization_config=quantization_config)
      peft_model = get_peft_model(model, vera_config)
      

8. 进一步资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

彬彬侠

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

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

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

打赏作者

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

抵扣说明:

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

余额充值