LoRA 系列常见面试题篇
整理自:AiGC面试宝典 Just do it! 2024年05月19日 21:22---
一、LoRA 篇
1.1 什么是 LoRA?
- 介绍:固定大模型,增加低秩分解的矩阵来适配下游任务,从而以极小的参数量来实现大模型的间接训练。
📝通俗解释:LoRA就像给汽车加装一个可拆卸的智能导航系统。汽车本身(预训练模型)不需要改动,只需要加一个小的配件(低秩矩阵)来适应不同的目的地(下游任务)。这样既保留了汽车原有的性能,又能精准到达新目的地。
1.2 LoRA 的思路是什么?
在原模型旁边增加一个旁路,通过低秩分解(先降维再升维)来模拟参数的更新量:
- 训练时:原模型固定,只训练降维矩阵 A 和升维矩阵 B;
- 推理时:可将 BA 加到原参数上,不引入额外的推理延迟;
- 初始化:A 采用高斯分布初始化,B 初始化为全 0,保证训练开始时旁路为 0 矩阵;
可插拔式的切换任务,当前任务 $W_0 + B_1A_1$,将 LoRA 部分减掉,换成 $B_2A_2$,即可实现任务切换。
[图表描述] 图片展示了 LoRA 的重参数化结构图(Figure 1)。
- 左侧蓝色方块代表预训练权重(Pretrained Weights),维度为 $W \in \mathbb{R}^{d \times d}$。
- 右侧橙色部分代表低秩分解的旁路矩阵。上方倒梯形代表矩阵 B(初始化为 $B=0$),下方正梯形代表矩阵 A(初始化为 $A = \mathcal{N}(0, \sigma^2)$)。中间连接处的维度标记为 $r$(rank)。
- 底部输入向量 $x$(维度 $d$)同时进入左侧预训练权重和右侧旁路。
- 右侧旁路的计算过程是先乘以 A 再乘以 B。
- 最后,左侧预训练权重的输出与右侧旁路的输出相加,得到最终输出 $h$。
Figure 1: Our reparametrization. We only train $A$ and $B$.
📝通俗解释:想象一下,原模型是一个已经训练好的厨师(预训练模型),现在要让他学会做新菜(下游任务)。传统方法需要重新训练整个厨师,而LoRA方法只是给他一本小册子(矩阵A和B)来记录新菜的独特配方。这样厨师还是那个厨师,但有了小册子的帮助,就能做出新菜了。
秩的选取:对于一般的任务,rank=1,2,4,8足矣,而对于一些领域差距比较大的任务可能需要更大的rank。
1.3 LoRA 的特点是什么?
- 将 BA 加到 W 上可以消除推理延迟;
- 可以通过可插拔的形式切换到不同的任务;
- 设计的比较好,简单且效果好。
📝通俗解释:LoRA的三大优点是:①不增加推理时间(相当于直接换掉厨师的配方本);②可以随时切换任务(像换不同的菜谱);③实现简单效果好(就像小册子虽然薄但很实用)。
1.4 简单描述一下 LoRA?
LoRA 的实现思想很简单,就是冻结一个预训练模型的矩阵参数,并选择用 A 和 B 矩阵来替代,在下游任务时只更新 A 和 B。
📝通俗解释:LoRA的核心思想就是"冻结主干,训练分支"。就像一棵大树的枝叶(预训练参数)不动,只在树干上嫁接几个新枝条(A和B矩阵)来适应新环境。
1.5 解释一下 LoRA 微调的原理和计算流程?
语言模型针对特定任务微调之后,权重矩阵通常具有很低的本征秩。
研究人员认为参数更新量即便投影到较小的子空间中,也不会影响学习的有效性。因此,提出固定预训练模型参数不变,在原本权重矩阵旁路添加低秩矩阵的乘积作为可训练参数,用以模拟参数的变化量。
具体来说,假设预训练权重为 $W_0$,可训练参数为 $\Delta W = BA$。初始化时矩阵 A 通过高斯函数初始化,矩阵 B 为零初始化,使得训练开始之前旁路对原模型不造成影响,即参数改变量为 0。对于该权重的输入 $x$ 来说,输出为下式:
$$ h = W_0x + \Delta Wx = W_0x + BAx $$
LoRA 方法的计算流程如图所示:
(图表描述:左侧展示了Transformer模型结构,包含前馈网络、线性变换 $W^d$、自注意力机制以及下方的三个线性变换 $W^q, W^k, W^v$。右侧放大了其中一个线性变换模块(如 $W^v$),展示了LoRA的具体实现:原始预训练参数 $W^v$ 保持不变(冻结),旁边并联了一个低秩分解结构,由矩阵 $B=0$ 和矩阵 $A=\mathcal{N}(0, \sigma^2)$ 组成,两者的输出相加后融入主路径。)
📝通俗解释:LoRA的原理基于一个关键发现——模型微调后的参数变化量往往是"低秩"的,就像一个高维向量其实可以用很少的几个关键特征表示。LoRA用两个小矩阵A和B的乘积来模拟这个变化,矩阵A负责降维,矩阵B负责升维,中间这个瓶颈维度就是rank。这样用一个"中间窄两头宽"的结构,就能近似表达任意的参数变化。
二、LoRA 变体篇
2.1 QLoRA 篇
2.1.1 QLoRA 的思路是怎么样的?
- 使用一种新颖的高精度技术将预训练模型量化为 4 bit;
- 然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。
📝通俗解释:QLoRA可以理解为"压缩版LoRA"。它先把预训练模型压缩成4位精度(像把高清电影压缩成低分辨率),大幅减少内存占用,然后在这个压缩模型上再用LoRA方法进行微调。这样即使只有一块普通显卡,也能微调大模型。
2.1.2 QLoRA 的特点是什么?
使用 QLoRA 微调模型,可以显著降低对于显存的要求。同时,模型训练的速度会慢于 LoRA。
📝通俗解释:QLoRA的优点是省显存(可以在消费级显卡上微调大模型),代价是训练速度变慢(因为需要频繁地在压缩和完整精度之间转换)。
2.1.3 QLoRA 相比 LoRA 做了哪些改进?
QLoRA(Quantized LoRA)是在 LoRA(Low-Rank Adaptation)的基础上进行的改进,旨在进一步减少微调大语言模型时的内存占用,同时保持或仅轻微牺牲性能。以下是 QLoRA 相比 LoRA 所做的主要改进:
4-bit NormalFloat(NF4):QLoRA 引入了一种新的数据类型,即 4-bit NormalFloat,这是一种理论上最优的数据类型,特别适用于正态分布的权重。这种数据类型通过确保每个量化箱有相同数量的值来避免量化误差,对于异常值的处理有好处。
双重量化(Double Quantization):QLoRA 采用了双重量化技术,即对量化常数进行量化,以进一步减少内存占用。这种方法通过量化第一层量化的常数作为输入,进行第二次量化,从而减少了量化常数本身的内存占用。
分页优化器 (Paged Optimizers):QLoRA 使用 NVIDIA 的统一内存特性,通过自动在 CPU 和 GPU 之间进行页面到页面的传输,来管理梯度更新时可能出现的内存峰值。这种方法允许在 GPU 内存不足时,将优化器状态自动转移到 CPU RAM,然后在需要时再将其移回 GPU 内存。
内存使用效率:QLoRA 通过上述技术显著降低了微调 65B 参数模型所需的平均内存需求,从需要超过 780GB 的 GPU 内存降低到小于 48GB,而不会降低运行时间或预测性能。
性能保持:QLoRA 在减少内存需求的同时,能够保持与 fp16 微调基线相当的性能。这使得最大的公开可用模型能够在单个 GPU 上进行微调,大大提高了 LLM 微调的可访问性。
📝通俗解释:QLoRA的三大技术创新:①NF4数据类型——就像用更高效的编码方式来存储数据;②双重量化——相当于对数据进行二次压缩;③分页优化器——像电脑的虚拟内存一样,当GPU内存不够时自动借用CPU内存。这些技术组合起来,使得在只有48GB显存的显卡上微调650亿参数的大模型成为可能。
2.2 AdaLoRA 篇
2.2.1 AdaLoRA 的思路是怎么样的?
AdaLoRA 是对 LoRA 的一种改进,它根据重要性评分动态分配参数预算给权重矩阵,将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
📝通俗解释:AdaLoRA就像一个智能的预算分配员。它会评估模型中每个部分的重要性——重要的部分多分配资源(高rank),不重要的部分少分配资源(低rank)。这样既能保证关键信息被充分学习,又能节省计算资源避免过拟合。
2.3 LongLoRA 篇
2.3.1 为什么需要 LongLoRA?
问题一:用较长的上下文长度训练 LLM 的计算成本很高,需要大量的训练时间和 GPU 资源。
📝通俗解释:比如上下文长度8192的训练,计算量是2048的16倍,成本呈平方级增长。
问题二:LoRA 训练长语境模型既不够有效,也不够高效。
LoRA 利用低秩矩阵来修改自我注意区块中的线性投影层,这种方法通常很有效,并能减少可训练参数的数量。然而,使用 LoRA 训练长语境模型既不够有效,也不够高效。
就有效性而言,如表所示,普通的低秩适应在长语境扩展中会导致较高的复杂度。将等级提高到更高的值,例如 rank = 256,并不能缓解这一问题。
| Method | Full FT | LoRA (rank) 8 | 16 | 32 | 64 | 128 | 256 | LoRA (rank = 8) + Norm | + Norm + Embed |
|---|---|---|---|---|---|---|---|---|---|
| PPL | 8.08 | 11.44 | 11.82 | 11.92 | 11.96 | 11.97 | 11.98 | 10.49 | 8.12 |
在效率方面,无论是否采用 LoRA,计算成本都会随着上下文规模的扩大而急剧增加,这主要是由标准的 self-attention 机制造成的(Vaswani 等人,2017年)。如图1所示,即使采用 LoRA,当上下文窗口扩大时,标准 LLaMA2 模型的训练时间也会大幅增加。
[图表描述] 图片包含三个并排的折线图,横轴均为 Context (8192, 16364, 32768, 65536)。
Perplexity (左图):纵轴为 2.4 到 3.9。Full FT (蓝色线) 和 LongLoRA (黄色线) 的困惑度较低且平稳(约 2.5-2.7),而 LoRA (橙色线) 随着 Context 增加困惑度显著上升,最高达 3.73。
GPU memory (中图):纵轴为 GB (20-80)。Full FT (蓝色线) 显存占用最高,在 65536 处标记为 OOM (Out Of Memory)。LoRA (橙色线) 显存占用次之。LongLoRA (黄色线) 显存占用最低。
Training hours (右图):纵轴为 hours (0-90)。Full FT (蓝色线) 训练时间最长,在 32768 后急剧上升并在 65536 处标记为 OOM。LoRA (橙色线) 训练时间次之。LongLoRA (黄色线) 训练时间最短。
Figure 1: LongLoRA closes the accuracy gap that between conventional LoRA and full fine-tuning, while still maintaining up to 1.8× lower memory cost than full fine-tuning. Furthermore, LongLoRA improves the training speed of LoRA by up to 1.8× with S²-Attn.
📝通俗解释:LongLoRA解决的是"长文本"问题。标准的LoRA在处理长文本时效果不好(困惑度升高),而且计算量大。LongLoRA通过两个核心技术——shift short attention和改进的LoRA配置——在保持接近全参数微调效果的同时,大幅降低内存和训练时间。
2.3.2 LongLoRA 思路是什么?
LongLoRA 从两个方面加快了 LLM 的上下文扩展:
思路一:shift short attention
虽然在推理过程中需要密集的全局注意力,但通过 sparse local attention 可以有效地对模型进行微调。LongLoRA 使用的 shift short attention($S^2$-Attn)可以有效地实现上下文扩展,从而节省大量计算量,其性能与使用 vanilla attention 进行微调的效果类似。特别是,在训练中只需两行代码即可实现,而在推理中则是可选的。
LongLoRA 发现在可训练嵌入和规范化的前提下,用于上下文扩展的 LoRA 运行良好。LongLoRA 在从 7B/13B 到 70B 的 LLaMA2 模型的各种任务上都取得了很好的实证结果。LongLoRA 采用 LLaMA2 7B 从 4k 上下文到 100k,或 LLaMA2 70B 到 32k,在一台 8 * A100 机器上实现。LongLoRA 扩展了模型的上下文,同时保留了它们的原始架构,并与大多数现有技术兼容,如 FlashAttention-2。此外,为了使 LongLoRA 实用化,还收集了一个数据集 LongQA,用于监督微调。
📝通俗解释:LongLoRA的核心思路是"训练时稀疏,推理时密集"。训练时使用shift short attention(把注意力分散到不同组),大幅减少计算量;推理时再用完整的注意力。这样既能达到长文本处理的效果,又不会增加推理时间。
2.3.3 介绍一下 shift short attention?
![图表描述:图片展示了 $S^2$-Attn 的示意图。左侧流程图分为三步:Step 1 Split(将注意力头分为两半),Step 2 Shift(将第二部分按半组大小移位),Step 3 Group(分组)。右侧展示了 Attention w/o shift 和 Attention w shift 的注意力矩阵热力图对比,显示了移位操作如何改变注意力模式。]
Figure 3: Illustration of $S^2$-Attn. It involves three steps. First, it splits features along the head dimension into two chunks. Second, tokens in one of the chunks are shifted by half of the group size. Third, we split tokens into groups and reshape them into batch dimensions. Attention only computes in each group in ours while the information flows between groups via shifting.
shift short attention 包含三个步骤:
- 首先,它将特征沿头部维度分成两块;
- 其次,将其中一个块中的标记移动到组大小的一半;
- 第三,将标记分成若干组,并将其重塑为批次维度。
在 LongLoRA 方法中,注意力只在每个组中进行计算,而标准自我注意力则在所有标记之间进行计算。组与组之间的信息流动是通过移位实现的。
📝通俗解释:shift short attention的工作方式类似于"错位分组"。想象把一段文字分成若干小组,每组独立做注意力计算,但相邻组之间通过"错位"来交换信息。这样既保留了局部信息,又让远距离的信息能够流动起来,而计算量却大大减少。
三、LoRA 的矩阵怎么初始化?为什么要初始化为全0?
矩阵 B 被初始化为 0,而矩阵 A 正常高斯初始化。
- 如果 B,A 全都初始化为 0,那么缺点与深度网络全 0 初始化一样,很容易导致梯度消失(因为此时初始所有神经元的功能都是等价的)。
- 如果 B,A 全部高斯初始化,那么在网络训练刚开始就会有概率得到一个过大的偏移值 $\Delta W$ 从而引入太多噪声,导致难以收敛。
因此,一部分初始为 0,一部分正常初始化是为了在训练开始时维持网络的原有输出(初始偏移为 0),但同时也保证在真正开始学习后能够更好的收敛。
📝通俗解释:LoRA矩阵初始化的策略其实很巧妙——让B=0(零矩阵),A=高斯分布。这样在训练开始时,BA=0,输出完全等于原始模型的输出,网络行为不会突变。随着训练进行,A开始学习有意义的特征,B逐渐获得非零值,模型就能平稳地从原始状态过渡到微调状态。
四、LoRA 权重是否可以合入原模型?
可以,将训练好的低秩矩阵(B*A)+原模型权重合并(相加),计算出新的权重。
📝通俗解释:可以把LoRA想象成贴纸,合并权重就是把贴纸撕下来直接贴到原始模型上,变成模型的一部分。这样推理时就不需要额外的LoRA计算了。
五、ChatGLM-6B LoRA 后的权重多大?
rank 8,target_module 为 query_key_value 条件下,大约 15M。
📝通俗解释:ChatGLM-6B使用LoRA微调后,额外参数量只有约15MB,非常轻量。相比之下原始模型有6B参数,LoRA只增加了0.25%的参数量。
六、LoRA 微调优点是什么?
- 一个中心模型服务多个下游任务,节省参数存储量;
- 推理阶段不引入额外计算量;
- 与其它参数高效微调方法正交,可有效组合;
- 训练任务比较稳定,效果比较好;
- LoRA 几乎不添加任何推理延迟,因为适配器权重可以与基本模型合并;
- 效果好,可插拔,不引入额外的推理延时。
📝通俗解释:LoRA的六大优点:①一个模型服务多个任务(像万能钥匙);②推理不增加计算量(不耽误速度);③可以和其他方法叠加使用(兼容性好);④训练稳定不容易出错;⑤效果接近全参数微调;⑥可以随时插拔切换任务。
七、LoRA 微调方法为啥能加速训练?
- 只更新了部分参数:比如 LoRA 原论文就选择只更新 Self Attention 的参数,实际使用时我们还可以选择只更新部分层的参数;
- 减少了通信时间:由于更新的参数量变少了,所以(尤其是多卡训练时)要传输的数据量也变少了,从而减少了传输时间;
- 采用了各种低精度加速技术,如 FP16、FP8 或者 INT8 量化等。
这三部分原因确实能加快训练速度,然而它们并不是 LoRA 所独有的,事实上几乎所有参数高效方法都具有这些特点。LoRA 的优点是它的低秩分解很直观,在不少场景下跟全量微调的效果一致,以及在预测阶段不增加推理成本。
📝通俗解释:LoRA加速训练的三个原因:①只更新少量参数(相当于只培训少数员工而不是整个公司);②减少多卡通信(像减少开会人数);③支持低精度计算(像用简化版表格)。但LoRA真正的优势是在保持效果的同时不增加推理成本,这是其他方法做不到的。
八、如何在已有 LoRA 模型上继续训练?
理解此问题的情形是:已有的 LoRA 模型只训练了一部分数据,要训练另一部分数据的话,是在这个 LoRA 上继续训练呢,还是跟 base 模型合并后再套一层 LoRA,或者从头开始训练一个 LoRA?
我认为把之前的 LoRA 跟 base model 合并后,继续训练就可以,为了保留之前的知识和能力,训练新的 LoRA 时,加入一些之前的训练数据是需要的。另外,每次都重头来成本高。
📝通俗解释:继续训练的推荐做法是:先把之前的LoRA合并回基础模型,然后用合并后的模型作为起点,继续训练新的LoRA。这样既能保留之前学到的知识,又不需要从头开始。同时建议在新训练数据中混入部分旧数据,防止灾难性遗忘。
九、LoRA 缺点是什么?
缺点很明显,参与训练的模型参数量不多,也就百万到千万级别的参数量,所以效果比全量微调差很多。可能在扩散模型上感知没那么强,但在 LLM 上,个人感觉表现还是差距挺大的。
📝通俗解释:LoRA的主要缺点是"容量有限"。就像让一个只读过几页书的人去回答各种问题,能力有限。在大语言模型上,由于参数量相对较少,效果和全参数微调相比还是有明显差距的。
十、LoRA 这种微调方法和全参数比起有什么劣势吗?
如果有足够计算资源以及有 10k 以上数据,我还是建议全参数微调。LoRA 的一个初衷就是为了解决计算资源不够的情况下微调,只引入了少量参数,就可以在消费级 GPU 上训练。但 LoRA 的问题在于它不能节省训练时间,相比于全量微调,它要训练更久,同时因为可训练参数量很小,在同样大量数据训练下,比不过全量微调。
| Model | Training data | others | rewrite | classification | generation | summarization | extract | open qa | brainstorming | closed qa | macro ave |
|---|---|---|---|---|---|---|---|---|---|---|---|
| LLaMA-7B+ LoRA | 0.6M | 0.358 | 0.719 | 0.695 | 0.816 | 0.65 | 0.448 | 0.315 | 0.793 | 0.51 | 0.589 |
| LLaMA-7B+ LoRA | 2M | 0.364 | 0.795 | 0.676 | 0.854 | 0.617 | 0.472 | 0.369 | 0.808 | 0.531 | 0.61 |
| LLaMA-7B+ LoRA | 4M | 0.341 | 0.821 | 0.677 | 0.847 | 0.645 | 0.467 | 0.374 | 0.806 | 0.639 | 0.624 |
| LLaMA-13B+ LoRA | 2M | 0.422 | 0.810 | 0.696 | 0.837 | 0.700 | 0.537 | 0.435 | 0.823 | 0.577 | 0.648 |
| LLaMA-7B+ FT | 0.6M | 0.438 | 0.869 | 0.698 | 0.917 | 0.701 | 0.592 | 0.477 | 0.870 | 0.606 | 0.686 |
| LLaMA-7B+ FT | 2M | 0.399 | 0.871 | 0.775 | 0.920 | 0.734 | 0.603 | 0.555 | 0.900 | 0.633 | 0.710 |
| LLaMA-7B + FT(2M) + LoRA | math0.25M | 0.560 | 0.863 | 0.758 | 0.915 | 0.754 | 0.651 | 0.518 | 0.886 | 0.656 | 0.729 |
| LLaMA-7B + FT(2M) + FT | math0.25M | 0.586 | 0.887 | 0.763 | 0.955 | 0.749 | 0.658 | 0.523 | 0.872 | 0.652 | 0.738 |
📝通俗解释:从表格数据可以看出,LoRA和全参数微调(FT)的差距还是比较明显的。例如在相同2M数据下,LoRA得分0.61,FT得分0.71,相差10个百分点。但如果数据量少(0.6M)且没有足够GPU,全参数微调可能无法进行,此时LoRA是更好的选择。最佳方案是先全参数微调再用LoRA(如表格最后两行),可以取得最好效果。
十一、LoRA 应该作用于 Transformer 的哪个参数矩阵?
| # of Trainable Parameters = 18M | |||||||
|---|---|---|---|---|---|---|---|
| Weight Type | $W_q$ | $W_k$ | $W_v$ | $W_o$ | $W_q, W_k$ | $W_q, W_v$ | $W_q, W_k, W_v, W_o$ |
| Rank $r$ | 8 | 8 | 8 | 8 | 4 | 4 | 2 |
| WikiSQL ($\pm 0.5%$) | 70.4 | 70.0 | 73.0 | 73.2 | 71.4 | 73.7 | 73.7 |
| MultiNLI ($\pm 0.1%$) | 91.0 | 90.8 | 91.0 | 91.3 | 91.3 | 91.3 | 91.7 |
从上图我们可以看到:
- 将所有微调参数都放到 attention 的某一个参数矩阵的效果并不好,将可微调参数平均分配到 $W_q$ 和 $W_k$ 的效果最好;
- 即使是秩仅取 4 也能在 $\Delta W$ 中获得足够的信息。
因此在实际操作中,应当将可微调参数分配到多种类型权重矩阵中,而不应该用更大的秩单独微调某种类型的权重矩阵。
📝通俗解释:实验证明,LoRA应该"雨露均沾"而不是"集中一处"。把参数分散到多个矩阵(如同时作用于Wq和Wv)比把全部参数集中在一个矩阵上效果更好。即使rank很小(如4),只要分布合理,也能学到足够的信息。
十二、LoRA 微调参数量怎么确定?
LoRA 模型中可训练参数的结果数量取决于低秩更新矩阵的大小,其主要由秩 r 和原始权重矩阵的形状确定。实际使用过程中,通过选择不同的 lora_target 决定训练的参数量。
以 LLaMa 为例:
--lora_target q_proj,k_proj,v_proj,o_proj,gate_proj,up_proj,down_proj📝通俗解释:LoRA的参数量由两个因素决定:①rank值(r),决定中间层维度;②目标矩阵的数量(lora_target),决定在哪些层添加LoRA。rank越大、目标层越多,参数量就越大。
十三、Rank 如何选取?
Rank 的取值作者对比了 1-64,效果上 Rank 在 4-8 之间最好,再高并没有效果提升。不过论文的实验是面向下游单一监督任务的,因此在指令微调上根据指令分布的广度,Rank 选择还是需要在 8 以上的取值进行测试。
📝通俗解释:Rank的选取建议:一般任务用4-8即可,如果任务比较复杂或领域差异大,可以适当提高到16-32,但不必太高,因为效果提升不明显。
十四、Alpha 参数如何选取?
Alpha 其实是个缩放参数,本质和 learning rate 相同,所以为了简化我默认让 alpha=rank,只调整 lr,这样可以简化超参。
📝通俗解释:Alpha是LoRA影响力的缩放因子。可以把它理解为"LoRA的权重",alpha越大,LoRA对模型的影响越大。简化做法是让alpha等于rank,只调学习率就够了。
十五、LoRA 高效微调如何避免过拟合?
减小 r 或增加数据集大小可以帮助减少过拟合。还可以尝试增加优化器的权重衰减率或 LoRA 层的 dropout 值。
📝通俗解释:防止LoRA过拟合的方法:①减小rank(让模型容量变小);②增加数据量;③加大权重衰减(让参数不要变化太大);④增加dropout(随机丢弃一些LoRA的输出)。
十六、微调大模型时,优化器如何?
除了 Adam 和 AdamW,其他优化器如 Sophia 也值得研究,它使用梯度曲率而非方差进行归一化,可能提高训练效率和模型性能。
📝通俗解释:优化器选择建议:默认用AdamW就够了,这是最稳定的选择。如果想尝试新东西,可以试试Sophia等新型优化器,可能训练更快。
十七、哪些因素会影响内存使用?
内存使用受到模型大小、批量大小、LoRA 参数数量以及数据集特性的影响。例如,使用较短的训练序列可以节省内存。
📝通俗解释:影响显存的主要因素:①模型越大显存越高;②batch size越大显存越高;③LoRA的rank和目标层数越多显存越高;④序列长度越长显存越高(尤其是平方级增长)。
十八、LoRA 权重是否可以合并?
可以将多套 LoRA 权重合并。训练中保持 LoRA 权重独立,并在前向传播时添加,训练后可以合并权重以简化操作。
📝通俗解释:多套LoRA可以合并。想象一下,你有一个基础模型和多个LoRA(分别擅长不同任务),可以先把它们都合并成一个"全能模型",推理时就不需要来回切换了。
十九、是否可以逐层调整 LoRA 的最优 rank?
理论上,可以为不同层选择不同的 LoRA rank,类似于为不同层设定不同学习率,但由于增加了调优复杂性,实际中很少执行。
📝通俗解释:理论上可以给不同层设置不同的rank(比如重要的层用rank: 16,不重要的层用rank: 2),但实际操作中太麻烦,一般不推荐这样做。
二十、LoRA 微调有哪些超参数需要注意?
LoRA (Low-Rank Adaptation) 微调时,主要涉及以下几个超参数需要注意:
秩 (Rank):这是 LoRA 中最重要的参数之一,它决定了 LoRA 矩阵的秩或维度,直接影响模型的复杂度和容量。较高的 r 值意味着更强的表达能力,但可能导致过拟合;较低的 r 值可以减少过拟合,但可能降低表达能力。实验中建议的 r 值通常为 1、2、4、8 或 64,其中 4 或 8 在大多数情况下效果最好。
缩放因子 (Alpha):LoRA 引入了一个额外的缩放系数 alpha,用于在前向传播过程中将 LoRA 权重应用于预训练模型中。这个系数与秩参数 rank 一起使用,如下所示:$scaling = \alpha / rank$。LoRA 权重的值越大,其影响就越大。在实践中,将 alpha 设置为 rank 的两倍是一种常见的做法。
权重衰减 (Weight Decay):在使用 AdamW 或 SGD 等优化器时,可以通过增加权重衰减率来帮助防止过拟合,特别是在选择较大的 r 值时。
学习率 (Learning Rate):学习率是微调过程中的关键超参数,需要根据模型和数据集的具体情况进行调整。
优化器选择:LoRA 微调可以使用不同的优化器,如 SGD、Adam 或 AdamW。优化器的选择会影响内存占用和训练效率。
迭代次数 (Epochs):微调时的迭代次数也是需要考虑的超参数。过多的迭代可能导致过拟合,而迭代次数不足可能导致模型未能充分学习。
批次大小 (Batchsize):批次大小会影响内存使用和训练速度,需要根据可用的硬件资源进行调整。
数据集大小和质量:虽然不是传统意义上的超参数,但数据集的大小和质量对 LoRA 微调的效果有重要影响。高质量的数据集可以帮助模型更好地适应新任务。
📝通俗解释:LoRA最重要的四个超参数:①rank(决定LoRA的容量,一般4-8);②alpha(决定LoRA的影响力,一般设为rank的2倍);③学习率(决定训练速度,常用1e-4到5e-5);④权重衰减(防止过拟合,常用0.01-0.1)。其他参数如batch size、epoch根据实际情况调整。
实践篇
1. LoRA 微调计算可训练参数的比例 如何确定?
可以通过 numel 方法获取张量中参数的数量和 requires_grad 方法获取模型张量是否进行梯度计算来计算可训练参数的比例:
# 打印可训练参数
def print_trainable_params(model: torch.nn.Module) -> None:
trainable_params, all_param = 0, 0
for param in model.parameters():
num_params = param.numel()
# if using DS Zero 3 and the weights are initialized empty
if num_params == 0 and hasattr(param, "ds_numel"):
num_params = param.ds_numel
all_param += num_params
if param.requires_grad:
trainable_params += num_params
print("trainable params: {:d} || all params: {:d} || trainable%: {:.4f}".format(
trainable_params, all_param, 100 * trainable_params / all_param))>>>
trainable params: 62586880 || all params: 13078451200 || trainable: 0.4785📝通俗解释:这个代码用来计算LoRA可训练参数占总参数的比例。从例子可以看出,LoRA只用了0.48%的参数量(大约6000万可训练参数 vs 130亿总参数),这就是LoRA如此高效的原因。
2. LoRA 微调结果如何保存?
LoRA 微调的结果通常保存为两个部分:
- LoRA 权重文件:包含矩阵 A 和 B 的参数,通常保存为
.safetensors或.pt格式; - 配置文件:包含 LoRA 的配置信息(如 rank、alpha、target_modules 等),通常保存为
adapter_config.json。
保存时可以使用 peft 库提供的 PeftModel.save_pretrained() 方法,加载时使用 PeftModel.from_pretrained() 方法。
📝通俗解释:LoRA保存就像保存游戏的存档。权重文件是"游戏进度"(A和B矩阵的参数),配置文件是"存档说明"(怎么使用这些参数)。需要保存这两个文件才能完整恢复LoRA的微调结果。
整理完成