LoRA 数学原理:低秩分解

02-PEFT原理 核心≈ 25 分钟 #LoRA#低秩分解#公式 reviewed
我的状态:

前置知识点

一句话定义

LoRA(Low-Rank Adaptation)假设微调时的权重更新量 ΔW 是低秩的,于是用两个小矩阵 B·A 的乘积来表示它,只训练 B 与 A,从而把可训练参数压缩千倍以上。

为什么重要

LoRA 是当前微调的事实标准:显存占用降一个数量级、训练后可合并回原权重实现零推理延迟、一个基座可挂多个任务适配器。理解它的数学原理,才能正确设置 rank 与 alpha(kp-006),才能解释为什么它常常能逼近全参微调的效果。

前置知识

kp-004 的显存账;线性代数基础:矩阵乘法、矩阵的秩(rank)的含义。

核心概念

  • 权重更新量 ΔW:微调前后权重之差,W₀ + ΔW 才是「理想的微调后权重」。
  • 低秩假设:ΔW 的信息量远小于它的表观尺寸,可以被分解为两个瘦长矩阵的乘积。
  • 秩 r(rank):LoRA 的核心容量旋钮,控制 ΔW 的表达能力。
  • 缩放因子 α/r:LoRA 分支输出的放大系数,控制新分支对原模型行为的扰动幅度。

原理与机制

对原权重矩阵 W₀ ∈ R^(d×k),LoRA 把更新量约束为低秩分解:

ΔW = B·A, B ∈ R^(d×r), A ∈ R^(r×k), r ≪ min(d,k)

前向计算改为:

h = W0x + (α/r)·B(Ax)

初始化是关键设计:A 用高斯噪声初始化,B 初始化为全零,因此训练起点处 B·A = 0,模型行为与原模型完全一致,训练从「零扰动」平滑开始。

参数量对比:全量 ΔW 有 d×k 个参数,LoRA 只有 r×(d+k) 个。以 4096×4096 的注意力投影矩阵、r=16 为例:全量 16.7M 参数,LoRA 仅 0.13M,压缩约 128 倍;对一个 7B 模型整体开启 LoRA 后可训练参数通常只有 10-40M(0.1%-0.6%)。

为什么低秩有效:Aghajanyan et al. 2020 发现预训练模型在下游适配时,所需的「内在维度(intrinsic dimension)」远小于参数总量——权重空间虽然巨大,但有效更新集中在一个低维子空间里。LoRA 是这一观察的工程化兑现。注意推理时可以把 BA 合并回 W₀:W′ = W₀ + (α/r)BA,得到与原模型同构的网络,因此没有额外延迟(见 kp-009)。

图示

        d
   ┌─────────┐        B (d×r)   A (r×k)
 W₀│         │   ΔW =  ┌──┐ × ┌───────┐
   │  稠密大  │         │瘦 │   │ 瘦长  │
   │  矩阵    │         └──┘   └───────┘
   └─────────┘        r≪d,k → 参数量 r(d+k) ≪ dk
        k

直观类比

与其重画一幅 4096×4096 的巨画(全参 ΔW),不如承认「改动其实是几十种基本笔画的组合」,只学这 r 种笔画的配方(A)和它们的混色比例(B)。r 越大配方越丰富,但调色成本也越高。

实例或案例

同一个 7B 模型、同一份 2000 条客服数据:r=8 训练后格式遵从率 89%,r=32 达到 94%,r=128 反而降到 91% 且训练时间翻倍——低秩假设意味着 r 不必贪大,过大反而引入过拟合与不稳定(经验规律见 kp-006)。

操作步骤

用 HuggingFace PEFT 三行注入 LoRA:

from peft import LoraConfig, get_peft_model
config = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05,
                    target_modules=["q_proj", "v_proj"])
model = get_peft_model(model, config)
model.print_trainable_parameters()
# 输出示例: trainable params: 8,388,608 || all params: 7,000,000,000 || 0.12%

保存时 model.save_pretrained("out") 只写出十几 MB 的 adapter 文件,而非整个模型。

排错清单

  • 训练后行为完全没变:检查 target_modules 是否命中了真实层名(不同模型叫 q_proj/k_proj/query 等不同名字),打印 trainable params 确认非零。
  • loss 下降但输出乱码:alpha/r 设得过大造成输出幅值爆炸,或与 BF16 精度问题叠加,见 kp-018。
  • 显存没有明显下降:确认优化器只作用于 LoRA 参数(PEFT 自动处理),不要手动把全模型参数加入 optimizer。

常见误区

  • B、A 都随机初始化:会导致训练起点 ΔW≠0,模型开局即被破坏;必须 A 随机、B 置零。
  • 把 alpha 当成学习率:alpha 只缩放该分支的输出幅值,与优化器学习率是两回事,但二者共同决定有效步长。
  • 认为 LoRA 一定更慢:训练计算量略增(多一条 BA 分支),但显存大幅下降常换来更大批量,总吞吐可能反超全参。

与其他知识点的关系

rank/alpha 怎么选见 kp-006;QLoRA 在此之上叠加 4-bit 量化见 kp-007;合并与多适配器服务见 kp-009。

延伸阅读

Hu et al. 2021《LoRA: Low-Rank Adaptation of Large Language Models》;Aghajanyan et al. 2020《Intrinsic Dimensionality Explains the Effectiveness of Language Model Fine-Tuning》。

自测题

  1. 为什么 B 初始化为零而 A 随机?

答:保证训练起点 BA=0,即 ΔW=0,模型行为与预训练基座完全一致,扰动从零平滑增长;若两者都随机,起点就是一个随机扰动,容易破坏模型。

  1. r=16 时,一个 4096×11008 的 FFN 投影矩阵的 LoRA 参数量是多少?

答:r×(d+k) = 16×(4096+11008) = 241,664 个参数,而全量更新为约 4500 万个。

  1. LoRA 为什么推理时零额外延迟?

答:因为 BA 可以离线合并进 W₀(W′=W₀+α/r·BA),合并后网络结构与原模型完全相同。

相关知识点

来源

  • Hu et al. 2021《LoRA: Low-Rank Adaptation of Large Language Models》

基于模型知识整理,建议按需核对原文。