理论简述

上图为 LoRA 的实现原理,其实现流程为:
-
在原始预训练语言模型旁边增加一个旁路,做降维再升维的操作来模拟内在秩; -
用随机高斯分布初始化 A,用零矩阵初始化B,训练时固定预训练模型的参数,只训练矩阵 A 与矩阵 B ; -
训练完成后,将 B 矩阵与 A 矩阵相乘后合并预训练模型参数作为微调后的模型参数。
矩阵A的维度是;矩阵B的维度是,且 。
细节事项
-
对哪些参数微调?对于transformer结构来说,LoRA一般只对每层的Self-Attention的部分做微调,其中主要是四个映射层参数做微调;而transformer模型自身有多个权重参数矩阵包括 Attention 模块里用于计算 query, key, value 的 Wq,Wk,Wv 以及多头 attention 的 Wo,以及 MLP 层的权重矩阵。 -
Rank(r) 的选取:Rank 的取值作者对比了 1-64,效果上 Rank 在 4-8 之间最好,再高并没有效果提升。不过论文的实验是面向下游单一监督任务的,因此在指令微调上根据指令分布的广度,Rank选择还是需要在 8 以上的取值进行测试。 -
alpha 参数选取:alpha 其实是个缩放参数,训练后权重 merge 时的比例为 alpha/r -
初始化:矩阵A是 Uniform 初始化,B 是零初始化,这样最初的 lora 权重为 0,所以 lora 参数是从头学起,并没有那么容易收敛。
对应在transformer模型中的结构:

其对应的计算公式可以理解为:
结合模型源码的LoRA
HF的库中已经封装好了LoRA相关的实现,其中LoraConfig类用于配置如上所述的各个配置项,其中,对于第一个事项,对应的LoraConfig类的字段是target_module
;那么这个字段的取值该如何分析?
以ChatGLM与Llama2为例,首先是ChatGLM,其对应可用于LoRA的参数是:
# 计算qkv,共享参数矩阵
self.query_key_value = nn.Linear(config.hidden_size, self.qkv_hidden_size,
bias=config.add_bias_linear or config.add_qkv_bias,
device=device, **_config_to_kwargs(config)
)
# selfattention output
self.dense = nn.Linear(self.projection_size, config.hidden_size, bias=config.add_bias_linear,
device=device, **_config_to_kwargs(config)
)
# Project to 4h. If using swiglu double the output width, see https://arxiv.org/pdf/2002.05202.pdf
self.dense_h_to_4h = nn.Linear(
config.hidden_size,
config.ffn_hidden_size * 2,
bias=self.add_bias,
device=device,
**_config_to_kwargs(config)
)
# Project back to h.
self.dense_4h_to_h = nn.Linear(
config.ffn_hidden_size,
config.hidden_size,
bias=self.add_bias,
device=device,
**_config_to_kwargs(config)
)
总结如下:
lora_module_name = "query_key_value,dense_h_to_4h,dense_4h_to_h,dense"
Llama2,其对应可用于LoRA的参数是:
# q,k,v,o参数计算
self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=config.attention_bias)
self.k_proj = nn.Linear(self.hidden_size, self.num_key_value_heads * self.head_dim, bias=config.attention_bias)
self.v_proj = nn.Linear(self.hidden_size, self.num_key_value_heads * self.head_dim, bias=config.attention_bias)
self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=config.attention_bias)
# FFN层计算
self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
lora_module_name = "q_proj,k_proj,v_proj,o_proj,gate_proj,up_proj,down_proj"
HF上,LoraConfig类target_module
的配置要根据具体的LLM模型源码中的关键字来设置,才能准确的对模型参数进行微调。
参考
推荐阅读LoRA理论及实战相关文章。
原文始发于微信公众号(阿郎小哥的随笔驿站):聊聊LoRA及其target_module配置
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/244156.html