Skip to content

LoRA微调

LoRA 英文全称为 Low-Rank Adaptation,中文:“低秩适配器”

秩的概念#

英文 Rank 中文:秩

所谓秩,指的就是一个矩阵真正包含的信息量 有多少。

🙋小红买了 3 个苹果 4 个桃子,花了 18 元,小明买了 2 个苹果 3 个桃子,花了 13 元,请问苹果和桃子各多少钱。

苹果:x
桃子:y
3x + 4y = 18
2x + 3y = 13
6x + 8y = 36
6x + 9y = 39
y = 3

🙋小红买了 3 个苹果 4 个桃子,花了 18 元,小明买了 6 个苹果 8 个桃子,花了 36 元,请问苹果和桃子各多少钱。

3x + 4y = 18
6x + 8y = 36

上面的式子中,虽然有两个式子,但是第二个式子没有带来额外的信息。

例如:

A=[0000]A = \begin{bmatrix} 0 & 0 \\ 0 & 0 \end{bmatrix}

秩为 0,因为这个矩阵没有任何的信息。

A=[1001]A = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}

秩为 2,矩阵的两行提供了两条有效的信息。

A=[1224]A = \begin{bmatrix} 1 & 2 \\ 2 & 4 \end{bmatrix}

秩为 1,虽然矩阵有两行,但是两行是倍数关系(是线性相关的),只包含一条有效信息。

秩:矩阵中有效信息的数量。

LoRA原理#

假设大模型原始权重矩阵(W)为:

W=[1.02.03.04.05.06.07.08.09.010.011.012.013.014.015.016.017.018.019.020.0]W = \begin{bmatrix} 1.0 & 2.0 & 3.0 & 4.0 \\ 5.0 & 6.0 & 7.0 & 8.0 \\ 9.0 & 10.0 & 11.0 & 12.0 \\ 13.0 & 14.0 & 15.0 & 16.0 \\ 17.0 & 18.0 & 19.0 & 20.0 \\ \end{bmatrix}

全量微调需要更新全部 5 x 4 = 20 个参数。假设微调后的参数为:

W=[1.412.443.474.505.937.08.079.1410.4511.5612.6713.7814.9716.1217.2718.4219.4920.6821.8723.06]W' = \begin{bmatrix} 1.41 & 2.44 & 3.47 & 4.50 \\ 5.93 & 7.0 & 8.07 & 9.14 \\ 10.45 & 11.56 & 12.67 & 13.78 \\ 14.97 & 16.12 & 17.27 & 18.42 \\ 19.49 & 20.68 & 21.87 & 23.06 \\ \end{bmatrix}

也就是说,微调后的矩阵可以看作是 一个原始矩阵 加上 一个增量矩阵,如下:

W=W+ΔW=[1.02.03.04.05.06.07.08.09.010.011.012.013.014.015.016.017.018.019.020.0]+[0.410.440.470.500.931.001.071.141.451.561.671.781.972.122.272.422.492.682.873.06]W' = W + \Delta W = \begin{bmatrix} 1.0 & 2.0 & 3.0 & 4.0 \\ 5.0 & 6.0 & 7.0 & 8.0 \\ 9.0 & 10.0 & 11.0 & 12.0 \\ 13.0 & 14.0 & 15.0 & 16.0 \\ 17.0 & 18.0 & 19.0 & 20.0 \\ \end{bmatrix} + \begin{bmatrix} 0.41 & 0.44 & 0.47 & 0.50 \\ 0.93 & 1.00 & 1.07 & 1.14 \\ 1.45 & 1.56 & 1.67 & 1.78 \\ 1.97 & 2.12 & 2.27 & 2.42 \\ 2.49 & 2.68 & 2.87 & 3.06 \\ \end{bmatrix}

到目前为止,增量矩阵就是微调的参数数量,一共 20 个。(全量微调)

换成 LoRA 微调。

先对这个增量矩阵进行低秩分解:

ΔW=AB\Delta W = A \cdot B

A 和 B 是什么呢?也是拆分出来的两个矩阵:

ΔW=AB=[0.10.20.30.40.50.60.70.80.91.0][1.11.21.31.41.51.61.71.8]\Delta W = A \cdot B = \begin{bmatrix} 0.1 & 0.2 \\ 0.3 & 0.4 \\ 0.5 & 0.6 \\ 0.7 & 0.8 \\ 0.9 & 1.0 \\ \end{bmatrix} \cdot \begin{bmatrix} 1.1 & 1.2 & 1.3 & 1.4 \\ 1.5 & 1.6 & 1.7 & 1.8 \\ \end{bmatrix}

🤔为什么 增量矩阵 可以拆解成 A·B 呢?

这其实就是低秩分解的思想,指的是 矩阵里的信息往往是不均匀分布的,很多维度是冗余的,只需要抓住主要方向就够了

因此在线性代数的矩阵乘法中,存在这么一个基础结论:

对于任意秩为 r 的矩阵:

MRm×nM \in \mathbb{R}^{m \times n}

矩阵 M 是一个大小为 m 行 n 列的实数矩阵。

M:表示一个矩阵的名字(矩阵通常用大写字母表示);

:表示“属于”;

:表示“实数集合”,所有实数的集合;

ℝ^{m × n}:表示所有 m 行 n 列的实数矩阵 组成的集合。

总是存在两个矩阵:

ARm×rBRr×nA \in \mathbb{R}^{m \times r} \\ B \in \mathbb{R}^{r \times n}

这就使得:

M=ABM = A \cdot B

这个结论是线性代数中“秩分解”(Rank factorization)的经典定理。

一个“秩分解”的详细例子,假设有这么一个矩阵:

M=[24612]M = \begin{bmatrix} 2 & 4 \\ 6 & 12 \end{bmatrix}

🤔 先思考这个矩阵的秩是多少?

秩为 1,代表着这是一个低秩,因此可以进行一个低秩分解。秩越低,信息量就越少。

于是我们就可以将它分解为:

M=[13][24]=[24612]M = \begin{bmatrix} 1 \\ 3 \end{bmatrix} \cdot \begin{bmatrix} 2 & 4 \\ \end{bmatrix} = \begin{bmatrix} 2 & 4 \\ 6 & 12 \end{bmatrix}

可以看到,在上面的示例中,一个秩为 1 的 2x2 矩阵就可以拆成一个 2x1 和 1x2 的矩阵乘积。

好了,回到我们刚才增量所拆解出来的矩阵 A 和 B 这里。拆解出 A 和 B 两个新的矩阵后,接下来我们就可以针对 A 和 B 两个矩阵来做训练:

可以看到,通过 LoRA 微调,调参对象从 \(\Delta W\) 的 20 个参数下降到 A·B 的 18 个参数。

🙋这没下降多少啊?

在实际的模型中,参数量往往是 数十亿,而通过 LoRA 只需训练原始参数总量的 0.01%~3% 的新增参数模块,就能获得接近全量微调的效果。

举个例子,假设你用的是一个 7B (70亿)参数的大模型:

因此参数量变为了原来的:

LoRA 可训练参数原始参数总量0.01%3%\frac{\text{LoRA 可训练参数}}{\text{原始参数总量}} \approx 0.01\% \sim 3\%

总结 LoRA 优点:

  1. 参数少:它只微调原始参数的 1% 甚至更少

    • 在 GPT-3 或类似大模型上,LoRA(如 r = 8)时可训练参数量仅为全量微调的 0.01% - 0.1%,但在多个自然语言任务(如问答、摘要)中,其性能已能达到全量微调的 95%~99%。

    • 在 GLUE 基准测试中(使用 BERT),LoRA 设置 r = 16 时,仅使用约 0.1% 的参数,就能在多个子任务上达到与全量微调相近的表现,平均仅低 0.5–1 分。

      TIP

      以上数据均来自原始论文《LoRA: Low-Rank Adaptation of Large Language Models》

  2. 速度快:训练和部署都比全量微调省时省力。

  3. 模块化:训练好的 LoRA 插件可以随时加载或者卸载,不影响原始模型,特别适合多任务场景。可扩展性以及灵活性比较高。

微调实战?#

🙋是否可以实战大模型微调?

目前为止,微调大模型高度依赖 Python 环境。

  1. **主流工具和框架依赖 Python:**像 Hugging Face Transformers、PEFT、PyTorch Lightning、TensorFlow、DeepSpeed、Axolotl 等主流微调工具,都是基于 Python 构建的。它们提供了训练循环、优化器、数据加载器、分布式训练等关键能力,而这些功能的 API 和调用方式基本都依赖 Python。
  2. **数据准备环节使用 Python 工具链:**微调之前的数据处理(如格式转换、清洗、tokenize、构造 prompt 等),普遍使用如 pandasjsondatasets 等 Python 库来完成。
  3. **训练环境配置依赖命令行 + Python:**微调通常需要在具备 GPU 的环境中完成(无论是本地还是云端),这些环境的配置如 CUDA 驱动安装、依赖管理(conda、pip)、模型下载和运行,也大多围绕 Python 生态展开。
  4. **模型理解和调试文档以 Python 为主:**无论是 Hugging Face 的官方文档,还是 GitHub 上的开源实现、论文配套代码,几乎都是 Python 编写的,理解其结构也离不开对 Python 的基本掌握。