合并适配器
适配器库支持通过组合多个已训练适配器的参数来创建新适配器,即将多个现有适配器合并为一个新适配器。这种方法能实现高效的领域、语言和任务迁移。适配器合并是任务算术的一种形式(Ilharco et al., 2023;Zhang et al., 2023),因此可以增强或消除特定技能。消除技能是通过使用负权重实现的。
average_adapter() 方法提供了这种合并功能:
model.add_adapter("bottleneck_1", "seq_bn")
model.add_adapter("bottleneck_2", "seq_bn")
model.add_adapter("bottleneck_3", "seq_bn")
model.average_adapter(adapter_name="avg", adapter_list=["bottleneck_1", "bottleneck_2", "bottleneck_3"], weights=[-1, 1.2, 0.8])
在这个示例中,三个新增的瓶颈适配器参数被合并(权重分别为-1、1.2和0.8)以创建新适配器avg。
请注意,要成功实现此操作,所有被平均的适配器必须使用相同的适配器配置。与输出平均组合块相比,合并适配器参数的优点在于相对于使用单个适配器不会引入任何额外的推理时间。
所有adapter方法都支持线性合并。在线性合并中,训练好的adapter权重会进行线性组合:假设我们有N个adapter,设\(\Phi_i\)为第i个adapter的所有参数,\(\lambda_i\)为对应的权重系数,表示该adapter的加权强度。合并后的adapter参数\(\Phi_{merged}\)计算公式如下:
average_adapter 方法仅合并适配器的权重,但不会创建新的头部。若要平均头部的权重,请使用 average_head 方法。由于头部通常是线性层,average_head 方法采用线性合并方式:
model.add_masked_lm_head("head_1")
model.add_masked_lm_head("head_2")
model.average_head(head_name="avg_head", head_list=["head_1", "head_2"], weights=[0.2, 0.8])
合并LoRA适配器
LoRA引入了\(A\)和\(B\)矩阵,其中\(\Delta W = BA\)。由于B矩阵和A矩阵彼此高度依赖,因此有多种方式可以合并LoRA适配器的权重。您可以通过向average_adapter方法传递combine_strategy参数来选择组合方法:
combine_strategy = "linear": 线性组合(默认)。这是Chronopoulou等人(2023)为LoRA提出的方法。设\(\Phi = \{A, B\}\):\[ \Phi_{merged} = \sum_{i=0}^{N} \lambda_i \Phi_i \]combine_strategy = "lora_linear_only_negate_b"根据Zhang et al. (2023)的研究,该方法仅在权重为负时对B矩阵使用负权重:\[\begin{split} A_{merged} &= \sum_{i=0}^{N} |\lambda_i| A_i\\ B_{merged} &= \sum_{i=0}^{N} \lambda_i B_i \end{split}\]combine_strategy = "lora_delta_w_svd": 该方法合并每个适配器的\(\Delta W_i\),然后执行奇异值分解(SVD)来获取A和B LoRA矩阵:对于每个适配器 i,我们计算:\(\Delta W_i = B_i \cdot A_i\)
\(\Delta W_{new} = \sum_{i=0}^N \lambda_i \cdot W_i\)
对\(\text{SVD}(\Delta W_{new})\)执行奇异值分解(SVD),得到\(A_{new}\)和\(B_{new}\)
lora_delta_w_svd 不被Deberta和GPT-2支持。以下是这些LoRA特定合并策略的示例用法:
model.add_adapter("lora_1", "seq_bn")
model.add_adapter("lora_2", "seq_bn")
model.add_adapter("lora_3", "seq_bn")
model.average_adapter(
adapter_name="lora_avg",
adapter_list=["lora_1", "lora_2", "lora_3"],
weights=[1, -1, 1],
combine_strategy="lora_delta_w_svd",
svd_rank=8
)
# Note that "lora_delta_w_svd" requires the "svd_rank" parameter, which determines the r (rank) of the resulting LoRA adapter after SVD
对于输出和参数平均,默认情况下传递的权重会被归一化。要禁用归一化,请传递normalize_weights=False。
如需更详细的示例和说明,请参阅我们的Task Arithmetic notebook。
合并其他LoRA变体
IA3: LoRA的合并方法同样适用于IA3适配器。
VeRA: 由于VeRA同时包含冻结的LoRA权重矩阵和普通权重矩阵,仅支持线性合并。
提示
添加更多的适配器合并方法非常简单:您只需修改average_adapter方法即可。大多数适配器方法都使用model_mixin.py中仅支持线性合并的默认实现。而像LoRA这样的方法会重写此方法以添加新的合并方式,例如"lora_delta_w_svd",具体可参考lora.py。