系列文章目录
- 【diffusers 进阶之 PEFT 入门(一)】 inject_adapter_in_model 详解
- 【diffusers 进阶之 PEFT 入门(二)】LoraConfig 如何处理 lora_config 参数的?
文章目录
def set_adapter(self, adapter_names: str | list[str]) -> None:
"""Set the active adapter(s).
Additionally, this function will set the specified adapters to trainable (i.e., requires_grad=True). If this is
not desired, use the following code.
```py
>>> for name, param in model_peft.named_parameters():
... if ...: # some check on name (ex. if 'lora' in name)
... param.requires_grad = False
```
Args:
adapter_name (`str` or `List[str]`): Name of the adapter(s) to be activated.
"""
if isinstance(adapter_names, str):
adapter_names = [adapter_names]
# Deactivate grads on the inactive adapter and activate grads on the active adapter
for layer_name in self.adapter_layer_names:
module_dict = getattr(self, layer_name)
for key, layer in module_dict.items():
if key in adapter_names:
# Note: It is possible that not a single layer is called with requires_grad_(True) here. This may
# happen if a completely different adapter layer is being activated.
layer.requires_grad_(True)
else:
layer.requires_grad_(False)
self._active_adapter = adapter_names
getattr
和 self
在 PEFT 中的详细解析
getattr
函数
getattr
是 Python 内置函数,用于获取对象的属性。
基本语法
getattr(object, name[, default])
- object: 要获取属性的对象
- name: 属性名称(字符串)
- default: 可选参数,如果属性不存在则返回此值
在 PEFT 中的应用
module_dict = getattr(self, layer_name)
这行代码的作用是:
- 从
self
对象(即当前类实例)中 - 获取名为
layer_name
的属性 - 将获取到的属性赋值给
module_dict
变量
在 PEFT 的上下文中,这些属性是存储适配器层的字典。
self
在 PEFT 中的含义
self
是 Python 类方法中的第一个参数,表示类的实例本身。
在 PEFT 中的 self
在 set_adapter
方法中,self
指的是 BaseTunerLayer
的实例,它包含:
-
适配器层字典:
- 每个
layer_name
对应一个字典属性 - 这些字典存储了不同名称的适配器层
- 每个
-
适配器层名称列表:
self.adapter_layer_names
存储了所有适配器层的属性名称- 例如,对于 LoRA,可能包含
['lora_A', 'lora_B']
-
活跃适配器记录:
self._active_adapter
记录当前活跃的适配器名称
完整流程解析
让我们详细分析这段代码的执行流程:
for layer_name in self.adapter_layer_names:
module_dict = getattr(self, layer_name)
for key, layer in module_dict.items():
if key in adapter_names:
layer.requires_grad_(True)
else:
layer.requires_grad_(False)
-
遍历适配器层类型:
self.adapter_layer_names
包含所有适配器层类型的名称- 对于 LoRA,这通常是
['lora_A', 'lora_B']
- 对于其他适配器类型,可能有不同的名称
-
获取每种类型的适配器字典:
module_dict = getattr(self, layer_name)
获取特定类型的适配器字典- 例如,
getattr(self, 'lora_A')
返回所有 A 矩阵的字典
-
遍历适配器实例:
for key, layer in module_dict.items()
遍历字典中的所有适配器key
是适配器名称(如 “default”, “adapter1” 等)layer
是实际的适配器层(如 LoRA 的 A 或 B 矩阵)
-
设置梯度状态:
- 如果适配器名称在要激活的列表中,设置
requires_grad=True
- 否则设置
requires_grad=False
- 如果适配器名称在要激活的列表中,设置
具体示例
假设我们有一个 LoRA 模型,其结构如下:
BaseTunerLayer
├── adapter_layer_names = ('lora_A', 'lora_B', 'lora_embedding_A', 'lora_embedding_B')
├── lora_A = {
│ ├── 'default': LinearLayer(...),
│ └── 'adapter1': LinearLayer(...)
│ }
└── lora_B = {
├── 'default': LinearLayer(...),
└── 'adapter1': LinearLayer(...)
}
...
当调用 set_adapter('adapter1')
时:
adapter_names
被设置为['adapter1']
- 遍历
adapter_layer_names
(即['lora_A', 'lora_B']
) - 对于
'lora_A'
:- 获取
self.lora_A
字典 - 将
'default'
对应的层设为不可训练 - 将
'adapter1'
对应的层设为可训练
- 获取
- 对于
'lora_B'
:- 获取
self.lora_B
字典 - 将
'default'
对应的层设为不可训练 - 将
'adapter1'
对应的层设为可训练
- 获取
- 设置
self._active_adapter = ['adapter1']
这种设计使得 PEFT 可以在同一个模型中管理多个适配器,并轻松切换它们的活跃状态。