聊聊LoRA及其target_module配置

理论简述

聊聊LoRA及其target_module配置

上图为 LoRA 的实现原理,其实现流程为:

  1. 在原始预训练语言模型旁边增加一个旁路,做降维再升维的操作来模拟内在秩;
  2. 用随机高斯分布初始化 A,用零矩阵初始化B,训练时固定预训练模型的参数,只训练矩阵 A 与矩阵 B ;
  3. 训练完成后,将 B 矩阵与 A 矩阵相乘后合并预训练模型参数作为微调后的模型参数。

矩阵A的维度是;矩阵B的维度是,且

细节事项

  1. 对哪些参数微调?对于transformer结构来说,LoRA一般只对每层的Self-Attention的部分做微调,其中主要是四个映射层参数做微调;而transformer模型自身有多个权重参数矩阵包括 Attention 模块里用于计算 query, key, value 的 Wq,Wk,Wv 以及多头 attention 的 Wo,以及 MLP 层的权重矩阵。
  2. Rank(r) 的选取:Rank 的取值作者对比了 1-64,效果上 Rank 在 4-8 之间最好,再高并没有效果提升。不过论文的实验是面向下游单一监督任务的,因此在指令微调上根据指令分布的广度,Rank选择还是需要在 8 以上的取值进行测试。
  3. alpha 参数选取:alpha 其实是个缩放参数,训练后权重 merge 时的比例为 alpha/r
  4. 初始化:矩阵A是 Uniform 初始化,B 是零初始化,这样最初的 lora 权重为 0,所以 lora 参数是从头学起,并没有那么容易收敛。

对应在transformer模型中的结构:

聊聊LoRA及其target_module配置

其对应的计算公式可以理解为:

结合模型源码的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 微调细节

在消费级GPU调试LLM的三种方法:梯度检查点,LoRA和量化

LLM微调知多少(2)——LoRA及QLoRA微调技术实战


原文始发于微信公众号(阿郎小哥的随笔驿站):聊聊LoRA及其target_module配置

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/244156.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!