系列文章目录
- 【diffusers 进阶之 PEFT 入门(一)】 inject_adapter_in_model 详解
- 本文重点介绍 LoraConfig
以 ominicontrol 中的 lora 设置为例:
{‘r’: 4, ‘lora_alpha’: 4, ‘init_lora_weights’: ‘gaussian’,
‘target_modules’:
‘(.x_embedder|.(?<!single_)transformer_blocks\.[0-9]+\.norm1\.linear|.(?<!single_)transformer_blocks\.[0-9]+\.attn\.to_k|.(?<!single_)transformer_blocks\.[0-9]+\.attn\.to_q|.(?<!single_)transformer_blocks\.[0-9]+\.attn\.to_v|.(?<!single_)transformer_blocks\.[0-9]+\.attn\.to_out\.0|.*(?<!single_)transformer_blocks\.[0-9]+\.ff\.net\.2|.*single_transformer_blocks\.[0-9]+\.norm\.linear|.*single_transformer_blocks\.[0-9]+\.proj_mlp|.*single_transformer_blocks\.[0-9]+\.proj_out|.*single_transformer_blocks\.[0-9]+\.attn.to_k|.*single_transformer_blocks\.[0-9]+\.attn.to_q|.*single_transformer_blocks\.[0-9]+\.attn.to_v|.*single_transformer_blocks\.[0-9]+\.attn.to_out)’}
LoraConfig 如何处理 **lora_config 参数
当调用 self.transformer.add_adapter(LoraConfig(**lora_config))
时,**lora_config
会将字典中的键值对作为参数传递给 LoraConfig
类的构造函数。下面我详细解释这个过程:
参数解析过程
-
字典解包:
**lora_config
将字典解包为关键字参数- 例如
{'r': 4, 'lora_alpha': 4, ...}
变成r=4, lora_alpha=4, ...
-
参数初始化:
LoraConfig
类接收这些参数并设置相应的属性- 对于您提供的配置,主要设置了以下属性:
r=4
:LoRA 的秩lora_alpha=4
:LoRA 的缩放因子init_lora_weights='gaussian'
:使用高斯分布初始化权重target_modules=...
:复杂的正则表达式,指定要应用 LoRA 的模块
-
__post_init__
处理:- 初始化后,
__post_init__
方法会执行额外的验证和处理 - 设置
peft_type = PeftType.LORA
- 处理
target_modules
(如果是列表,转换为集合) - 验证参数组合的有效性
- 初始化后,
正则表达式处理
对于您提供的复杂正则表达式 target_modules
,处理流程如下:
-
正则表达式保存:
- 配置对象保存这个正则表达式字符串
- 不会在配置阶段解析或匹配模块
-
后续模块匹配:
- 当
add_adapter
方法执行时,PEFT 库会遍历模型的所有模块 - 使用正则表达式匹配每个模块的名称
- 对于匹配的模块,应用 LoRA 适配器
- 当
特殊处理
-
高斯初始化:
- 由于设置了
init_lora_weights='gaussian'
,LoRA 权重将使用高斯分布初始化 - 这会在
LoraLayer
类的update_layer
方法中处理
- 由于设置了
-
参数验证:
- 代码中有多处验证逻辑,确保参数组合有效
- 例如,检查
layers_to_transform
和target_modules
的兼容性
-
警告处理:
- 某些参数组合会触发警告而非错误
- 例如,当
init_lora_weights
不是 ‘loftq’ 但提供了loftq_config
时
实际应用流程
当执行 add_adapter
时,完整流程是:
- 创建
LoraConfig
实例并初始化所有参数 - 调用
__post_init__
进行验证和处理 - 将配置传递给
BaseTuner
的子类(如LoraModel
) LoraModel
遍历模型的所有模块,使用正则表达式匹配模块名称- 对匹配的模块,创建并注入 LoRA 适配器层
- 根据
init_lora_weights
参数初始化 LoRA 权重(在该例子中是高斯初始化)
这种设计允许用户通过简单的配置字典灵活地控制 LoRA 适配器的行为,而不需要直接修改模型代码。