PEFT FRoD 实战指南:基于 Transformers Trainer 的文本与图像分类微调
2026/9/20 8:06:20 网站建设 项目流程

PEFT FRoD 实战指南:基于 Transformers Trainer 的文本与图像分类微调

【免费下载链接】peft🤗 PEFT: State-of-the-art Parameter-Efficient Fine-Tuning.项目地址: https://gitcode.com/gh_mirrors/pe/peft

FRoD(Full-Rank Efficient Fine-Tuning with Rotational Degrees,全秩旋转自由度高效微调)是 PEFT 库中一类以"共享全秩基 + 稀疏可学习旋转自由度"为核心的新型参数高效微调方法。本文以 examples/frod_finetuning/README.md 为骨架,结合 FRoD 源码 与 单元测试,完整讲解如何在 TransformersTrainer下用两个开箱即用的脚本完成文本分类(BERT + GLUE SST-2)与图像分类(CLIP ViT + Stanford Cars)微调,并深入剖析FrodConfig每个配置项、三段式学习率设计以及投影张量共享与保存的底层机制。读完本文,你将能独立复现这两个示例、按需调整FrodConfig参数,并把 FRoD 迁移到自己的模型与数据集上。

FRoD 是什么:全秩更新与稀疏旋转的平衡

FRoD 论文提出的核心思路是:适配器更新不再被限制在低秩子空间中,而是通过"固定的投影张量 + 可训练系数"来表达全秩更新。从 tuners/frod/layer.py 的实现可以清晰看到它的数学形式:

S = S_sparse.to_dense() L = torch.diag_embed(lambda_l) frod_weight = U @ (S + L) @ V.T

其中:

  • VU是由基础模型权重推导出的固定投影张量(不可训练,仅参与前向);
  • L是对角系数矩阵,对应可训练参数frod_lambda_l
  • S是稀疏旋转矩阵,只保留非对角位置上按sparse_rate随机采样的一小部分可训练条目,对应参数frod_lambda_s_values

由于对角系数覆盖了所有输出维度,FRoD 在每个被适配的线性层内可以表达全秩更新,同时训练参数量却很小——这正是"在低秩更新过于受限时"的一种替代方案。相比 LoRA,FRoD 的代价是:注入适配器时需要基于基础权重执行矩阵分解来构建投影张量,因此初始化更慢、对模型层的支持面更窄(目前仅支持nn.Lineartransformers.pytorch_utils.Conv1D)。

环境准备:安装示例依赖

两个示例脚本的外部依赖集中在 examples/frod_finetuning/requirements.txt 中:

peft transformers accelerate>=1.0.0 datasets numpy Pillow

安装依赖后即可直接运行任一脚本:

pip install -r examples/frod_finetuning/requirements.txt python examples/frod_finetuning/frod_text_classification.py python examples/frod_finetuning/frod_image_classification.py

两个脚本都只依赖标准组件(datasets加载数据、TransformersTrainer训练、PEFTget_peft_model注入适配器),没有额外框架要求。

文本分类示例:BERT + GLUE SST-2

frod_text_classification.py 在google-bert/bert-base-uncased上以nyu-mll/glue数据集的sst2配置做二分类微调。

参数定义与默认值

脚本通过HfArgumentParser同时解析自定义的FrodTextArguments与 Transformers 的FrodTextTrainingArguments,核心参数如下:

参数默认值说明
model_name_or_pathgoogle-bert/bert-base-uncased序列分类基础模型
dataset_namenyu-mll/glue数据集名或本地数据集路径
task_namesst2数据集配置名(GLUE 子任务)
target_modules["query", "value"]替换为 FRoD 适配器的模块名
sparse_rate0.02稀疏 FRoD 矩阵中参与训练的非对角条目占比
frod_dropout0.0FRoD 适配器分支前应用的 dropout 概率
frod_lambda_l_lr2e-2可训练对角系数frod_lambda_l的学习率
frod_lambda_s_lr2e-3可训练稀疏系数frod_lambda_s_values的学习率
classifier_lr1e-2分类头学习率
runtime_offload_base_weightFalse激活的 FRoD 路径不需要基础权重时,将其保持在 CPU 上

训练参数中值得注意的默认设置:learning_rate=2e-2per_device_train_batch_size=32num_train_epochs=1eval_strategy="epoch"load_best_model_at_end=Truemetric_for_best_model="accuracy"

三段式学习率:FRoD 示例的关键设计

README 明确指出:两个脚本都为FRoD 对角系数、FRoD 稀疏系数、分类头分别设置了独立学习率。代码通过自定义 AdamW 参数分组实现:

optimizer = torch.optim.AdamW( [ { "params": [p for n, p in model.named_parameters() if "frod_lambda_l" in n], "lr": frod_args.frod_lambda_l_lr, }, { "params": [p for n, p in model.named_parameters() if "frod_lambda_s_values" in n], "lr": frod_args.frod_lambda_s_lr, }, {"params": [p for n, p in model.named_parameters() if "classifier" in n], "lr": frod_args.classifier_lr}, ] )

分组依据来自 layer.py 中定义的两个可训练参数容器:frod_lambda_l(对角系数)与frod_lambda_s_values(稀疏 COO 值)。在文本示例中,对角系数学习率(2e-2)比稀疏系数(2e-3)高一个数量级;分类头同样使用独立学习率。参数名匹配采用子串匹配("frod_lambda_l" in n),注意frod_lambda_s_values不包含frod_lambda_l子串,因此两组互不干扰。

训练完成后将optimizers=(optimizer, None)传入Trainer,即完全接管优化器而不用 Transformers 默认调度器。

FRoD 注入与训练流程

peft_config = FrodConfig( task_type=TaskType.SEQ_CLS, target_modules=frod_args.target_modules, modules_to_save=["classifier"], frod_dropout=frod_args.frod_dropout, sparse_rate=frod_args.sparse_rate, runtime_offload_base_weight=frod_args.runtime_offload_base_weight, ) model = get_peft_model(model, peft_config) model.print_trainable_parameters()

modules_to_save=["classifier"]表示分类头随机初始化、需要可训练并保存进最终 checkpoint;frod_dropout=0.0的设定是刻意的——在这些示例中,稀疏旋转参数化本身就是主要正则化手段,因此不再叠加 dropout。

随后是标准的Trainer流程:预处理(tokenizer +DataCollatorWithPadding)、compute_metrics计算准确率、trainer.train()trainer.evaluate(),最后model.save_pretrained(training_args.output_dir)保存适配器。

图像分类示例:CLIP ViT + Stanford Cars

frod_image_classification.py 在openai/clip-vit-base-patch32上微调tanganke/stanford_cars数据集的训练/测试 parquet 分片。

数据加载的两种方式

脚本用load_dataset("parquet", data_files=data_files)加载数据。未指定data_dir时,直接读取 Hub 上的 parquet 分片:

data_files = { "train": [ "hf://datasets/tanganke/stanford_cars/data/train-00000-of-00002.parquet", "hf://datasets/tanganke/stanford_cars/data/train-00001-of-00002.parquet", ], "test": [ "hf://datasets/tanganke/stanford_cars/data/test-00000-of-00002.parquet", "hf://datasets/tanganke/stanford_cars/data/test-00001-of-00002.parquet", ], }

指定本地data_dir时改用本地文件路径({data_dir}/data/train-*.parquet),便于在无外网环境下使用数据集镜像。

图像专用配置差异

图像脚本与文本脚本的差异点:

  • target_modules覆盖注意力与 MLP 六类投影:["q_proj", "k_proj", "v_proj", "out_proj", "fc1", "fc2"]
  • sparse_rate=0.01(文本为 0.02);
  • 三段学习率整体下调:frod_lambda_l_lr=5e-4frod_lambda_s_lr=5e-5classifier_lr=1e-4
  • 新增projection_prng_key=3:用于稀疏 FRoD 投影掩码(COO 结构)的随机种子;
  • 训练参数使用lr_scheduler_type="constant"remove_unused_columns=False(因为with_transform需要保留原始图像列)。

标签信息从数据集的 label 特征中提取id2label/label2id映射,并以num_labels=len(label_names)ignore_mismatched_sizes=True重建 CLIP 的分类头。FrodConfig无需task_type(模型自带分类头),但同样通过modules_to_save=["classifier"]保留分类头可训练。

图像预处理通过dataset.with_transform(transform)完成:批量转 RGB、经AutoImageProcessor得到pixel_values,并辅以自定义collate_fn堆叠张量。

FrodConfig 配置项全解

FrodConfig定义在 tuners/frod/config.py,继承自PeftConfig。除上文已述参数外,其余配置项如下:

参数默认值说明
projection_prng_key0初始化稀疏 FRoD COO 结构(非对角位置采样)时使用的随机种子
save_projectionTrue是否把 FRoD 投影张量保存进 state dict。True增大 checkpoint 体积,但保证加载不依赖投影再生细节;False减小体积,加载时由基础权重 +projection_prng_key重建投影
fan_in_fan_outFalse若被替换层以(fan_in, fan_out)存储权重(如 GPT-2 的Conv1D)需设为True。源码 model.py 会根据目标层类型自动纠正该设置并给出警告
bias"none"可选"none"/"all"/"frod_only"。设为非"none"时对应偏置会参与训练,注意此时即使停用适配器,模型输出也不再与基础模型完全一致
init_weightsTrue是否用默认初始化初始化 FRoD 层。False时稀疏系数以std=0.1的正态分布初始化、对角系数叠加0.1尺度噪声(见 layer.py),仅在明确知道后果时修改
layers_to_transformNone只变换指定索引的层;传整数则只变换该层
layers_patternNone配合layers_to_transform指定模型nn.ModuleList的名称(常见为"layers""h")。源码会校验:指定了layers_pattern而未指定layers_to_transform时直接抛错
regularization_alpha1e-3从基础权重构建共享基时加入的小正数,用于稳定同类相关层的矩阵求逆(ridge 项)
progressbarTrue构建 FRoD 投影时是否显示进度条。投影初始化需要对每个目标模块类别执行矩阵分解,大模型上较慢,可设False关闭

此外sparse_rate必须位于[0, 1]区间,否则__post_init__会抛出ValueError(见 config.py)。

使用本地镜像:断网环境的完整用法

README 特别给出了图像模型/数据集使用本地镜像的 CLI 方式:

python examples/frod_finetuning/frod_image_classification.py \ --model_name_or_path /path/to/local/clip-vit-model \ --data_dir /path/to/local/stanford_cars \ --output_dir clip-vit-local-frod-stanford-cars

文本脚本同样可以传--model_name_or_path指向本地模型、--dataset_name指向本地数据集路径。所有 CLI 参数均来自上述 dataclass 字段,可按需覆盖任意默认值。

原理深挖:共享投影、稀疏旋转与 checkpoint 策略

投影张量按"类别"共享

FRoD 的V/U投影并非每个被替换层一份,而是按模块类别共享:同一 transformer 中承担相同角色的模块(如所有 attention 的q_proj)共享同一组投影缓冲。模型源码 model.py 中的_category_from_key负责从模块路径推断类别,例如encoder.layer.0.attention.self.query归入self_queryvision_model.encoder.layers.0.self_attn.q_proj归入self_attn_q_proj,而 BERT 的 attention 输出层attention.output.dense被归一化为attention_output以避免与 MLP 的output.dense冲突。

投影构建流程(_init_frod_projections,model.py)为:收集所有目标模块权重 → 按层索引与类别分组 → 对每个类别调用_projection_from_weights做 QR/SVD 分解与特征分解得到共享基V→ 用projection_prng_key种子随机采样非对角 COO 位置生成frod_s_indices。类别的层数、维度信息会显示在 tqdm 进度条(desc="FRoD hierarchical joint decomposition")中。

前向计算与内存优化

FrodLayer.forward 的逻辑是:FRoD 直接重建"适配后的权重"参与计算,因此单个激活适配器且无随机 dropout 时,基础层前向可以整体跳过(skip_base_layer),只走投影 + 稀疏矩阵乘路径。这也解释了runtime_offload_base_weight=True的意义——当激活的 FRoD 路径不需要基础权重时,把目标基础权重留在 CPU,从而降低 GPU 显存占用。该特性是 opt-in(默认False),因为通常的 PEFT 约定是模型移动或前向之后所有基础参数都留在加速器上。源码 layer.py 中_offload_base_weight_to_cpu实现了显存的按需搬移,且卸载(unload)时会确保基础权重回到适配器所在设备。

save_projection 与多适配器约束

save_projection=False时,checkpoint 只保存对角/稀疏系数,投影张量在加载时根据基础权重与固定种子重新生成,因此 checkpoint 体积更小;但默认save_projection=True,以换取加载过程与"再生细节"完全解耦。加载逻辑(model.py)会校验:配置要求加载投影而 state dict 中没有投影时报错,反之给出警告。此外,多适配器场景下所有适配器的projection_prng_key必须一致、save_projectionruntime_offload_base_weight也必须统一(见 model.py)。

可训练参数规模

可训练参数只有两类:对角系数frod_lambda_l(长度等于输出维度)与稀疏系数frod_lambda_s_values(长度等于 COO 非零元数量,由sparse_rate决定)。model.print_trainable_parameters()会直接打印可训练参数量与占比,用于确认稀疏率设定是否符合预期。

测试验证与进一步探索

仓库为 FRoD 提供了专门的测试文件 tests/test_frod.py,覆盖了多适配器保存/加载(含save_projection=False)、共享投影缓冲、PRNG 种子一致性等关键行为;tests/regression/test_state_dict.py 与 tests/test_custom_models.py 也包含 FRoD 相关回归用例。官方 API 文档见 docs/source/package_reference/frod.md,其中包含更简短的 Quickstart 代码片段(runtime_offload_base_weight=True示例)。

FRoD 的模块映射表定义在 src/peft/utils/constants.py,默认沿用 VeRA 的映射并为 ViT 补充了["query", "value"],可据此快速了解 FRoD 在各类 Transformers 模型上的默认目标模块。

结语

通过本文,你已掌握 PEFT FRoD 的两套开箱即用示例(文本与图像分类)、FrodConfig全参数语义、三段式学习率设计动机,以及共享投影/稀疏旋转的底层原理。下一步建议:先跑通文本示例并观察print_trainable_parameters的输出,再尝试调整sparse_rate观察精度与参数量权衡;在显存受限时开启runtime_offload_base_weight=True,在部署时按需设置save_projection平衡 checkpoint 体积与加载可靠性。

【免费下载链接】peft🤗 PEFT: State-of-the-art Parameter-Efficient Fine-Tuning.项目地址: https://gitcode.com/gh_mirrors/pe/peft

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询