DoRA:权重分解低秩自适应——用幅度与方向解耦提升 LoRA 学习能力 | 阅读笔记
笔记日期: 2026-05-22 笔记作者: Zhongzhu Zhou 所读论文: DoRA: Weight-Decomposed Low-Rank Adaptation 论文作者: Shih-Yang Liu, Chien-Yi Wang, Hongxu Yin, Pavlo Molchanov, Yu-Chiang Frank Wang, Kwang-Ting Cheng, Min-Hung Chen(NVIDIA & HKUST) arXiv: 2402.09353v6,2024-07-09 收录状态: ICML 2024 Oral,PMLR 235
一句话总结
LoRA 和全量微调(FT)之间的准确率差距,不是因为参数量不够,而是因为 LoRA 的更新结构有根本性的缺陷——它把权重的「幅度变化」和「方向变化」硬耦合在一起,而 FT 可以灵活地只改一个。DoRA 把每个权重矩阵拆成幅度向量和方向矩阵,分别训练,用 LoRA 只负责方向部分,用一个廉价的标量向量负责幅度,从而让 LoRA 的学习模式在统计上贴近 FT,并在所有测试模型和任务上一致地超过 LoRA。
1. 前置知识
这一节是写给做过 transformer 训练、但没深入读过 LoRA / weight normalization 原论文的同学。重点要理解三件事:LoRA 的数学结构、权重归一化的分解形式、以及「学习模式」的定义方式。
1.1 全量微调和它的代价
给定一个在大规模语料上预训练好的语言模型 (参数量 ),全量微调(Full Fine-Tuning, FT)直接把所有参数当作可训练变量:
对于一个 7B 参数模型:
- 参数本身:7B × 4 bytes(float32)= 28 GB
- Adam 优化器状态(一阶矩 + 二阶矩):额外 56 GB
- 激活值(反向传播用):依序列长度,通常 20–60 GB
合计:100–150 GB 以上。单块 80 GB A100 直接吃不下。这就是 PEFT(参数高效微调)出现的动机。
1.2 PEFT 的三大流派
适配器(Adapter-based):在 transformer 块内的固定位置插入一个小模块(一般是小 MLP:压缩→非线性→扩展),只训练这些模块。缺点是串行插入会增加推理延迟。
软提示(Prompt-based / Prefix-tuning):在输入序列前面或每层的 key-value 上拼一些可训练的”软 token”,backbone 完全冻结,只训练这些向量。缺点是对初始化敏感、通常比适配器差。
低秩更新(LoRA 家族):把权重矩阵的增量 限制为低秩矩阵乘积 ,训练完之后把 合并为一个稠密矩阵,推理时零额外开销。这是目前最主流的方案,DoRA 属于这个流派。
1.3 LoRA 的数学
对预训练权重 ,LoRA 把权重更新限制为:
W' = W_0 + \Delta W = W_0 + BA \tag{1}
其中 ,,。
初始化: 用 Kaiming 均匀分布初始化, 初始化为全零矩阵。所以训练开始时 ,模型从预训练点出发,和 FT 起点相同。
参数量估算:4096×4096 的注意力矩阵, 的 LoRA 用 个参数,相比 参数,节省了约 128 倍。
推理合并:训练后只需做一次 ,存储这个稠密矩阵, 和 可以丢弃。推理开销和原始模型完全相同。
LoRA 的隐含假设:权重更新 的「内在秩」很低。换句话说,模型从预训练到下游任务只需要做一个低维子空间里的变动。这个假设在很多任务上大致成立,但并不总是最优。
1.4 权重归一化(Weight Normalization)
权重归一化(Salimans & Kingma, NeurIPS 2016)是 DoRA 的数学前身。它把一个权重向量 重参数化为:
\mathbf{w} = g \cdot \frac{\mathbf{v}}{\|\mathbf{v}\|} \tag{2}
其中 是标量幅度, 是方向向量(不要求单位长度,训练时自由更新,归一化只在最终合并到 时发生)。
为什么这样做有用:梯度协方差矩阵更接近单位矩阵,SGD/Adam 收敛更快。直觉上,把幅度和方向分开优化,可以避免”想缩放方向但同时被迫缩放幅度”的耦合问题。
推广到矩阵:对 ,把每一列 ()分别做归一化,得到列方向归一化:
W = \mathbf{m} \cdot \frac{V}{\|V\|_c} \tag{3}
其中 是每列的 范数组成的行向量(幅度向量), 是方向矩阵, 表示对每列做 归一化的操作(即每列除以自己的 范数)。
DoRA 用这个分解方式分析 LoRA 和 FT 的差异,并基于分析结果设计方法。
1.5 「学习模式」的定义
DoRA 引入了一个诊断工具——权重分解分析(Weight Decomposition Analysis)。
对于一个经过微调的模型,拿某一层权重 (训练步 时的值)和预训练权重 做分解,然后计算:
幅度差 :
\Delta M^t = \frac{1}{k} \sum_{n=1}^k \left|m_n^t - m_n^0\right| \tag{4}
方向差 :
\Delta D^t = \frac{1}{k} \sum_{n=1}^k \left(1 - \cos(V_n^t, W_0^n)\right) \tag{5}
其中 是 第 列的 范数, 是 第 列的方向(归一化后), 是 第 列(方向参考点)。
把 在不同训练步和不同层上画散点图,就可以直观看到”这个方法在微调时优先改方向还是优先改幅度”。
2. 核心发现:LoRA 的学习模式和 FT 结构不同
2.1 散点图的关键发现
用一个 VL-BART 模型在四个图文任务上做对比(固定 case study):
-
FT(全量微调):散点图呈负相关。大的方向改变伴随着小的幅度改变,反之亦然。方向和幅度之间的 Pearson 相关系数 = −0.62。
-
LoRA:散点图呈正相关。方向改变和幅度改变总是同步增减,斜率固定为正。Pearson 相关 = +0.83。这说明 LoRA 做不到「大幅度调整方向而不改变幅度」,也做不到「大幅缩放但保持方向」——两者总是耦合在一起。
-
DoRA(本文方法):散点图回到负相关,接近 FT 的模式。Pearson 相关 = −0.31。
图一:FT / LoRA / DoRA 的学习模式对比示意
graph TD
subgraph FT_box["全量微调 (FT)"]
f1["相关系数 = −0.62"]
f2["大 ΔD 时 → 小 ΔM\n大 ΔM 时 → 小 ΔD"]
f3["模型可以「只改方向」\n也可以「只改幅度」"]
f1 --> f2
f2 --> f3
end
subgraph LoRA_box["LoRA"]
l1["相关系数 = +0.83"]
l2["ΔD 和 ΔM 总是成比例增减"]
l3["缺乏精细控制:\n想改方向,幅度也跟着变"]
l1 --> l2
l2 --> l3
end
subgraph DoRA_box["DoRA"]
d1["相关系数 = −0.31"]
d2["设计上解耦幅度与方向"]
d3["接近 FT 的学习模式"]
d1 --> d2
d2 --> d3
end
FT_box -. "DoRA 模仿" .-> DoRA_box
LoRA_box -. "DoRA 改进" .-> DoRA_box
2.2 为什么正相关等于”浪费”
考虑一个简单的更新场景。预训练权重 已经大致指向目标方向,但幅度偏小——理想更新是只放大幅度,不改变方向。
对于 FT:可以直接学习 (加大第 列的范数),同时 (不旋转方向)。
对于 LoRA: 是一个固定的矩阵,它同时影响方向和幅度。增大 的规模(比如增大学习率或让 的值变大)会同时放大幅度分量和方向分量。LoRA 无法做到「只放幅度不转方向」。
这就是”耦合”的代价:在需要细粒度控制的场景下,LoRA 的梯度能量有一部分被”浪费”在同时调整两个应该独立变化的维度上。
3. 方法:DoRA 的数学与实现
3.1 DoRA 的核心公式
基于权重分解分析,DoRA 的设计思路直接了当:把 和 分别训练。因为方向矩阵 维度高( 个元素),用 LoRA 做方向更新;幅度向量 只有 个标量,直接训练:
W' = \mathbf{m} \cdot \frac{V + \Delta V}{\|V + \Delta V\|_c} = \mathbf{m} \cdot \frac{W_0 + BA}{\|W_0 + BA\|_c} \tag{6}
可训练参数:
- :幅度向量(直接训练)
- ,:方向 LoRA 矩阵
冻结参数:
- (方向的初始基准)
初始化:,所以训练开始时 ,。和 LoRA 一样,从预训练点出发。
推理合并:训练后一次性计算 ,存成稠密矩阵,推理零开销。
3.2 算法逐步拆解
算法 1:DoRA 微调(逐步展开)
输入:预训练权重 W₀ ∈ ℝ^{d×k},低秩秩 r,目标任务数据集 D
输出:可合并权重 W' ∈ ℝ^{d×k}
——————— 初始化阶段(训练开始前做一次)———————
步骤 1: 计算幅度向量 m ← column_norms(W₀)
# m ∈ ℝ^{1×k},每个元素是 W₀ 对应列的 ℓ₂ 范数
步骤 2: 设 V ← W₀ # 冻结,作为方向基准
步骤 3: 初始化 A ~ Kaiming_uniform(r, k) # LoRA A 矩阵
步骤 4: 初始化 B ← 0_{d×r} # LoRA B 矩阵,全零初始化
步骤 5: 标记可训练:{m, A, B}
步骤 6: 标记冻结:{V (= W₀)}
——————— 前向传播(每个训练步执行)———————
步骤 7: 计算方向增量 ΔV ← B @ A # ∈ ℝ^{d×k}
步骤 8: 计算更新后方向 V' ← V + ΔV # = W₀ + BA
步骤 9: 计算列范数 C ← column_norms(V') # ∈ ℝ^{1×k}
⚠️ 重要:把 C 从计算图中脱离(.detach())
→ 这样反向传播时 C 被视为常数,大幅节省显存
步骤 10: 计算输出权重 W' ← m * (V' / C) # ∈ ℝ^{d×k}
步骤 11: 计算前向输出:output ← W' @ x
——————— 反向传播(autograd 自动处理)———————
步骤 12: 计算 ∂L/∂W' 通过损失函数
步骤 13: 梯度流到 m:
∂L/∂m = (∂L/∂W') · V' / C
= ‖∇_{W'}L‖ · cos(∇_{W'}L, v') # 见公式 (8)
步骤 14: 梯度流到 V' (再流向 A 和 B):
∂L/∂V' = (m / C) · ∂L/∂W' # 见公式 (7)
步骤 15: 用 AdamW 等优化器更新 {m, A, B}
——————— 部署合并(训练结束后做一次)———————
步骤 16: 计算 W'_merged = m * (W₀ + B@A) / column_norms(W₀ + B@A)
步骤 17: 保存 W'_merged(稠密矩阵,形状同 W₀)
步骤 18: 丢弃 {m, A, B}
3.3 从梯度角度解释「负相关」
这是论文第 4.2 节的分析,也是最有洞察力的部分。把公式 (6) 代入,对 和 求偏导(把列范数 视为常数):
对 的梯度(这个梯度会通过 传递到 和 ):
\nabla_{V'} \mathcal{L} = \frac{\mathbf{m}}{C} \cdot \nabla_{W'} \mathcal{L} \tag{7}
这是权重梯度的一个简单缩放——方向不变,幅度按 缩放。
对第 个幅度标量 的梯度(标量,很关键):
\nabla_{m_n} \mathcal{L} = \frac{(\nabla_{W'}\mathcal{L})_n \cdot V'_n}{\|V'_n\|} = \|\nabla_{W'}\mathcal{L}_n\| \cdot \cos\!\left(\nabla_{W'}\mathcal{L}_n,\, V'_n\right) \tag{8}
其中 是 的第 列, 是权重梯度的第 列。
公式 (8) 的直觉解读:
的绝对值等于「损失梯度列向量与当前方向的余弦相似度 × 梯度范数」。
-
场景 A:损失梯度 当前方向()→ 模型需要的是缩放幅度而不是旋转方向 → 大 → 幅度大幅更新,方向小幅更新
-
场景 B:损失梯度 当前方向()→ 模型需要的是旋转方向而不是缩放幅度 → → 方向大幅更新,幅度几乎不动
这正是 FT 观察到的负相关!DoRA 的梯度几何自动路由梯度能量——不需要手工指定”这一步应该改方向还是改幅度”。
图二:DoRA 反向传播中梯度流的方向分离示意
graph TB
L["损失 L"]
dW["∂L/∂W' ∈ ℝ^{d×k}\n(权重梯度)"]
L --> dW
subgraph mag_path["幅度路径"]
dm["∂L/∂m = ‖∂L/∂W'‖·cos(grad, V')\n只有「梯度与当前方向对齐」时才大"]
update_m["更新 m → 幅度大幅变化\n方向保持不动"]
dm --> update_m
end
subgraph dir_path["方向路径 (经过 LoRA)"]
dV["∂L/∂V' = (m/C)·∂L/∂W'\n(缩放后传向 A, B)"]
update_dir["更新 A, B → 方向 ΔV 更新\n幅度不变"]
dV --> update_dir
end
dW --> dm
dW --> dV
result["结果:大 ΔD 时 ΔM 小,大 ΔM 时 ΔD 小\n= FT 观察到的负相关"]
update_m --> result
update_dir --> result
3.4 节省显存的 detach 技巧
原始 DoRA 公式中,列范数 包含 ,所以反向传播需要通过这个范数计算流回 和 。这会引入额外的梯度图节点,占用显著更多显存。
技巧:把 从计算图中脱离(.detach()),在反向传播时把它视为一个常数(但它仍然是用当前 动态计算的,所以值是实时的)。数学上这等价于把公式 (7) 直接作为梯度公式,省略了通过归一化算子的二阶路径。
效果:
- LLaMA-7B 上:显存减少约 24.4%(从 37.3 GB 降到 28.2 GB)
- 准确率损失:约 0.2 个点(可接受)
- VL-BART 上:显存减少约 12.4%,准确率完全无损
# 有 detach(推荐实现):
norms = (W0 + B @ A).norm(dim=0, keepdim=True).detach() # 脱离梯度图
W_prime = m * (W0 + B @ A) / norms
# 无 detach(原始,显存占用更高):
norms = (W0 + B @ A).norm(dim=0, keepdim=True) # 在梯度图内
W_prime = m * (W0 + B @ A) / norms
3.5 DVoRA:LoRA 换成 VeRA 的扩展
DoRA 的方向更新 不必非要用 LoRA。论文把它替换成 VeRA(Vector-based Random Matrix Adaptation,Kopiczko et al., ICLR 2024)作为案例研究:
VeRA 的思路:全部层共享一对随机矩阵 (冻结不训练),每层只学习两个缩放向量 :
可训练参数量比 LoRA 少约 10 倍。把 VeRA 插入 DoRA 的方向更新就得到 DVoRA:
在 LLaMA2-7B + 10K Alpaca 指令微调中,DVoRA(0.04% 参数)在 MT-Bench 上达到 6.00 分,和 DoRA(2.33% 参数)持平,远超 VeRA(5.50)和 LoRA(5.70)。58 倍参数减少,准确率不降。
3.6 系统架构全图
图三:DoRA 系统架构(初始化 → 训练 → 推理合并)
graph LR
subgraph init["初始化"]
W0["W₀ ∈ ℝ^{d×k}\n(预训练权重,冻结)"]
m0["m = ‖W₀‖_c\n(幅度向量,可训练)"]
V0["V = W₀\n(方向基,冻结)"]
W0 --> m0
W0 --> V0
end
subgraph lora["LoRA 分支(可训练)"]
A["A ∈ ℝ^{r×k}\nKaiming 初始化"]
B["B ∈ ℝ^{d×r}\n全零初始化"]
dV["ΔV = B@A\n(低秩方向增量)"]
A --> dV
B --> dV
end
subgraph fwd["前向计算"]
Vp["V' = W₀ + ΔV"]
C["C = ‖V'‖_c(detach)"]
Wp["W' = m · (V'/C)"]
V0 --> Vp
dV --> Vp
Vp --> C
Vp --> Wp
C --> Wp
m0 --> Wp
end
subgraph deploy["部署合并(一次性)"]
merged["W'_merged = m·(W₀+B@A)/‖W₀+B@A‖_c\n形状同 W₀,零推理开销"]
Wp --> merged
end
4. 实验
4.1 常识推理(LLaMA 系列)
实验设置:8 个常识推理子任务(BoolQ, PIQA, SIQA, HellaSwag, WinoGrande, ARC-e, ARC-c, OBQA),训练集合并(共 170K+ 条),测试集独立评估。模型:LLaMA-7B、LLaMA-13B、LLaMA2-7B、LLaMA3-8B。
图四:常识推理准确率汇总
| 模型 | 方法 | 参数占比 | 平均准确率 |
|---|---|---|---|
| LLaMA-7B | ChatGPT 零样本 | — | 77.0 |
| LLaMA-7B | LoRA | 0.83% | 74.7 |
| LLaMA-7B | DoRA†(半秩) | 0.43% | 77.5 (+2.8) |
| LLaMA-7B | DoRA | 0.84% | 78.4 (+3.7) |
| LLaMA-13B | LoRA | 0.67% | 80.5 |
| LLaMA-13B | DoRA | 0.68% | 81.5 (+1.0) |
| LLaMA2-7B | LoRA | 0.83% | 77.6 |
| LLaMA2-7B | DoRA | 0.84% | 79.7 (+2.1) |
| LLaMA3-8B | LoRA | 0.70% | 80.8 |
| LLaMA3-8B | DoRA | 0.71% | 85.2 (+4.4) |
几个值得注意的细节:
-
DoRA 超过了 ChatGPT 零样本(78.4 vs 77.0)——用 7B 模型的参数高效微调打败了 GPT-3.5,而且只用了 0.84% 的参数在训练中更新。
-
DoRA†(半秩)依然超越 LoRA(全秩):在 LLaMA-7B 上 DoRA†(0.43% 参数,)= 77.5,LoRA(0.83%,)= 74.7——用一半参数多了 +2.8 分。这是实际工程中更重要的结论,因为更少参数意味着更少显存、更快训练。
-
改进幅度不单调于模型规模:7B(+3.7)、13B(+1.0)、2-7B(+2.1)、3-8B(+4.4)。这说明改进不是单纯的”更大的模型 LoRA 能力更好所以 DoRA 帮助更小”,而是和模型架构本身的「LoRA 与 FT 之间的学习模式差距」有关。LLaMA3-8B 的架构改动(GQA、RoPE 改进等)可能让 LoRA 的耦合问题更明显,所以 DoRA 提升更大。
4.2 不同秩下的鲁棒性
实验设置:固定 LLaMA-7B,调整 。
图五:不同秩下 LoRA vs DoRA 准确率(LLaMA-7B,常识推理)
| 秩 r | LoRA 平均准确率 | DoRA 平均准确率 | 差距 |
|---|---|---|---|
| r=4 | 39.5(近随机) | 61.9 | +22.4 |
| r=8 | 40.7(近随机) | 77.9 | +37.2 |
| r=16 | 70.9 | 77.5 | +6.6 |
| r=32 | 74.7 | 78.4 | +3.7 |
| r=64 | 65.8 | 72.1 | +6.3 |
最令人震惊的是 r=8 时 37 分的差距——LoRA 在这个秩下几乎崩溃(40.7% ≈ 随机猜测),而 DoRA 仍然保持了 77.9%。
为什么低秩下 LoRA 会崩溃? 回到 §3.3 的梯度分析:LoRA 的梯度能量必须同时被分配到幅度更新和方向更新两个自由度。当 很小时, 的容量极其有限,这个”两头兼顾”的要求变得不可能——要么方向优先,要么幅度优先,但不能同时做好,最终两者都做不好,准确率崩溃。
DoRA 给幅度更新单独划拨了一组参数( 个标量),完全不占 的预算。所以 可以专注于方向更新,即使 ,也能做一些有意义的学习。
4.3 视觉语言理解(VL-BART)
实验设置:VL-BART(CLIP-ResNet101 + BARTBase),四个图文任务(VQAv2, GQA, NLVR2, MSCOCO)+ 四个视频文本任务(TVQA, How2QA, TVC, YC2C)。
| 方式 | 参数占比 | 图文平均分 | 视频文本平均分 |
|---|---|---|---|
| 全量微调 | 100% | 77.3 | 83.5 |
| LoRA | ~6% | 76.5 | (略) |
| DoRA | ~6% | 77.4 | 85.4 |
图文任务上 DoRA 只用 6% 的参数就基本追上了全量微调(77.4 vs 77.3)。视频文本任务上 DoRA 甚至超过了全量微调(85.4 vs 83.5),比 LoRA 高 +1.9 分。视频文本任务需要更强的时序理解能力,这类任务通常需要更”细粒度”的权重调整,DoRA 的解耦设计在这里的优势更明显。
4.4 视觉指令微调(LLaVA-1.5-7B)
实验设置:LLaVA-1.5-7B(Vicuna-1.5-7B 语言模型 + CLIP ViT-L/336px 视觉编码器),在标准视觉指令微调数据上训练,评测 7 个 VL 基准。
| 方法 | 参数占比 | VQAv2 | GQA | VisWiz | SQA | VQAT | POPE | MMBench | 均分 |
|---|---|---|---|---|---|---|---|---|---|
| 全量微调 | 100% | 78.5 | 61.9 | 50.0 | 66.8 | 58.2 | 85.9 | 64.3 | 66.5 |
| LoRA | 4.61% | 79.1 | 62.9 | 47.8 | 68.4 | 58.2 | 86.4 | 66.1 | 66.9 |
| DoRA | 4.63% | 78.6 | 62.9 | 52.2 | 69.9 | 57.0 | 87.2 | 66.1 | 67.6 |
DoRA 均分 67.6,超过 LoRA(66.9)和全量微调(66.5)。特别是 VisWiz(视障用户视觉问答,任务更难)上 DoRA 比 LoRA 高 +4.4 分(52.2 vs 47.8),比全量微调也高 +2.2 分。
DoRA 超过全量微调的原因可能是:视觉指令微调数据量有限,全量微调有过拟合的风险,而 DoRA 的约束结构(低秩方向 + 标量幅度)提供了隐式正则化。
4.5 不同训练样本量的鲁棒性
实验设置:LLaMA2-7B + Alpaca 数据集子集(1000 / 4000 / 7000 / 10000 条),在 MT-Bench 上用 GPT-4 打分(0-10 分)。
图六:MT-Bench 分数 vs 训练样本量(LLaMA2-7B)
| 样本量 | LoRA | DoRA | VeRA | DVoRA |
|---|---|---|---|---|
| 1,000 | 5.41 | 5.70 | 5.21 | 5.43 |
| 4,000 | 5.55 | 5.82 | 5.38 | 5.60 |
| 7,000 | 5.68 | 5.98 | 5.40 | 5.71 |
| 10,000 | 5.70 | 6.00 | 5.50 | 6.00 |
DoRA 的优势在所有样本量下都稳定(+0.29 到 +0.30 分),说明 DoRA 的提升不依赖数据量,不是”用更多数据把差距掩盖掉”的那种假进步。
**DVoRA(0.04% 参数)= DoRA(2.33% 参数)**在 10000 样本时(均为 6.00 分),同时都优于 LoRA(5.70)。这 58 倍的参数效率差距非常实用——意味着在资源极度受限的场景下(比如消费级 GPU),DVoRA 可以用 LoRA 的 1/50 参数量达到 DoRA 的准确率。
4.6 粒度分析:是否需要对所有层都做方向更新
散点图分析表明,当方向变化大时,幅度变化小。因此论文测试了一种”节约型”变体:只对注意力层(Q, K, V, O)做完整 DoRA(方向 + 幅度),对 MLP 层(gate, up, down)只训练幅度标量,不做方向 LoRA。
| 方法 | 参数占比 | LLaMA-7B | LLaMA-13B |
|---|---|---|---|
| LoRA(标准) | 0.83% | 74.7 | 80.5 |
| DoRA(完整) | 0.84% | 78.1 | 81.5 |
| DoRA(节约型) | 0.39% | 77.5 | 81.3 |
节约型 DoRA 用 0.39% 的参数(比 LoRA 少一半)超过 LoRA +2.8/+0.8 分。这说明 MLP 层的主要调整需求确实是幅度而非方向,把 rank 预算集中在注意力层的方向更新上更高效。
5. 与其他方法的设计对比
5.1 DoRA vs LoRA:结构差异总结
图七:DoRA 和 LoRA 的参数结构对比
graph TB
subgraph LoRA_arch["LoRA 架构"]
l_W0["W₀(冻结)"]
l_B["B ∈ ℝ^{d×r}"]
l_A["A ∈ ℝ^{r×k}"]
l_delta["ΔW = BA(耦合幅度+方向)"]
l_out["W' = W₀ + BA"]
l_W0 --> l_out
l_B --> l_delta
l_A --> l_delta
l_delta --> l_out
end
subgraph DoRA_arch["DoRA 架构"]
d_W0["W₀(冻结,方向基准)"]
d_m["m ∈ ℝ^{1×k}(幅度,独立训练)"]
d_B["B ∈ ℝ^{d×r}"]
d_A["A ∈ ℝ^{r×k}"]
d_delta["ΔV = BA(只更新方向)"]
d_norm["归一化 ‖W₀+BA‖_c"]
d_out["W' = m · (W₀+BA)/‖W₀+BA‖_c"]
d_W0 --> d_delta
d_B --> d_delta
d_A --> d_delta
d_delta --> d_norm
d_norm --> d_out
d_m --> d_out
end
| 属性 | LoRA | DoRA |
|---|---|---|
| 额外参数 | ||
| 推理开销 | 零(合并后) | 零(合并后) |
| 幅度更新 | 隐式(通过 BA) | 显式(单独标量) |
| 方向更新 | 隐式(通过 BA) | 显式(低秩 LoRA) |
| 低秩鲁棒性 | 低( 时崩溃) | 高( 仍有效) |
| HF PEFT 支持 | use_dora=False | use_dora=True |
5.2 DoRA vs 权重归一化
权重归一化(Salimans & Kingma)用相同的数学分解,但目的是加速从头训练的收敛,从随机初始化出发,两部分都随机初始化。
DoRA 用同样的分解做预训练权重的微调,从 出发初始化,所以没有初始化敏感的问题。另外,权重归一化里 也是可训练的全矩阵,而 DoRA 里 是冻结的,只有 (低秩)可训练。
5.3 DoRA vs SVD-based 压缩(SVD-LLM, ASVD, Swift-SVD)
关键区别:SVD-based 压缩是把 截断成低秩矩阵(推理时权重是低秩的,存储量减少)。DoRA 是微调方法,训练后权重合并成稠密矩阵,不减少推理存储量,但提升下游任务准确率。
两类方法可以叠加:先用 SVD 压缩减少模型规模,再用 DoRA 做任务特化微调。这是未来的一个有趣应用方向。
5.4 DoRA vs QLoRA(量化微调)
QDoRA = QLoRA 骨架(4-bit 量化主干)+ DoRA 适配器:
在 Orca-Math(10 万条数学文字题)上:
- QLoRA:exact-match = 0.08(LLaMA2-7B)/ 0.23(LLaMA3-8B)
- QDoRA:exact-match = 0.27(LLaMA2-7B)/ 0.31(LLaMA3-8B)
- 全量微调:exact-match ≈ 0.24(LLaMA3-8B)
QDoRA 超过全量微调(0.31 vs 0.24 on LLaMA3-8B),同时保持 QLoRA 的低显存优势。这说明在数学推理这类需要精细权重调整的任务上,DoRA 的解耦更新机制非常有效。
6. 局限性与边界条件
6.1 训练显存
原版 DoRA(不使用 detach 技巧)比 LoRA 多约 24–37% 显存,因为需要保存通过归一化算子的梯度图。带 detach 的高效版基本追平 LoRA。但在使用极低精度训练(int8 优化器)或内存极度受限的场景下,额外的 个幅度标量和动态范数计算的开销仍需评估。
6.2 不同层最佳秩可能不同
DoRA 当前实现对所有层用相同的 rank 。结合 AdaLoRA(自适应秩分配)的思路,理论上可以给不同层分配不同的方向 rank,配合全局的幅度训练,进一步提升参数效率。这个方向论文未做系统验证。
6.3 训练稳定性
论文中使用相同学习率同时训练 (幅度, 个标量)和 (方向低秩矩阵)。两者梯度尺度不同,理论上最优学习率可能不同。如果遇到训练不稳定,分开设置 的学习率(通常可以比 的学习率大 2-5 倍)会有帮助。
6.4 任务覆盖范围
论文重点测试了监督微调(SFT)和指令跟随(MT-Bench),没有直接测试 RLHF 或 DPO 等偏好学习场景。鉴于 DoRA 改变的是梯度动力学,理论上它对 DPO 的低秩更新也应该有类似改善,但需要实验验证。
7. 复现指南
7.1 代码和集成
官方 PyTorch 实现:https://github.com/NVlabs/DoRA
HuggingFace PEFT 集成(最简洁用法):
from peft import LoraConfig, get_peft_model
config = LoraConfig(
r=16,
lora_alpha=32,
use_dora=True, # ← 开启 DoRA,就这一行
target_modules=["q_proj", "k_proj", "v_proj",
"up_proj", "down_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
)
model = get_peft_model(model, config)
7.2 常识推理任务的超参数
以 LLaMA-7B 为例(完整参数见论文 Table 8):
rank r: 16(DoRA),8(DoRA†)
alpha: 32(DoRA),16(DoRA†)
dropout: 0.05
optimizer: AdamW
lr: 2e-4
scheduler: Linear decay
batch_size: 16
warmup_steps: 100
epochs: 3
target_modules: Q, K, V, Up, Down projection
7.3 权重分解分析工具(诊断用)
可以用下面的代码检查自己的模型,判断 LoRA 和 FT 的学习模式差异是否显著:
import torch
def weight_decomp_analysis(W0: torch.Tensor, W_ft: torch.Tensor):
"""
计算 (ΔM, ΔD)——幅度差和方向差
W0, W_ft: (d, k) 的权重矩阵
"""
# 幅度(每列 ℓ₂ 范数)
m0 = W0.norm(dim=0) # (k,)
mft = W_ft.norm(dim=0) # (k,)
# 方向(每列归一化后的单位向量)
v0 = W0 / m0.clamp(min=1e-8).unsqueeze(0)
vft = W_ft / mft.clamp(min=1e-8).unsqueeze(0)
# 幅度差(公式 4)
delta_M = (mft - m0).abs().mean().item()
# 方向差(公式 5)
cos_sim = (v0 * vft).sum(dim=0).clamp(-1, 1) # (k,)
delta_D = (1 - cos_sim).mean().item()
return delta_M, delta_D
# 用法:对比 LoRA 微调权重和 FT 微调权重
# 如果 LoRA 的 (ΔD, ΔM) 呈正相关、FT 的呈负相关,说明 DoRA 会有帮助
对相关系数 Pearson:
import numpy as np
def pearson_corr(delta_D_list, delta_M_list):
d = np.array(delta_D_list)
m = np.array(delta_M_list)
return np.corrcoef(d, m)[0, 1]
# FT 目标: < -0.5(负相关)
# LoRA 现状: > +0.5(正相关)
# DoRA 效果: 接近 FT(负相关)
8. 总结与个人思考
8.1 贡献总结
DoRA 的贡献可以归纳为三层:
第一层(诊断工具):权重分解分析。把任何微调方法的权重变化分解为幅度差和方向差,画散点图,一目了然地展示”这个方法学到的是什么结构的更新”。这个工具独立于 DoRA 本身,未来研究 PEFT 都可以用它做诊断。
第二层(方法):DoRA 本身。一个极其简洁的设计:给幅度加一组标量可训练参数,方向继续用 LoRA。代码改动一行(use_dora=True),但效果系统性优于 LoRA。
第三层(理论连接):梯度分析(§3.3)证明 DoRA 的梯度在几何上自动路由能量——余弦对齐时幅度大幅更新,余弦垂直时方向大幅更新,这在数学上解释了为什么 DoRA 的散点图呈负相关,为什么它比 LoRA 更接近 FT 的学习模式。
8.2 我的几个判断
最重要的实验结果:r=8 时 LoRA 40.7% vs DoRA 77.9%(+37.2 分差距)。这不是精度微调,是数量级的差异,说明在计算受限场景(低秩)下 DoRA 的优势是本质性的,不是”打磨”出来的。
最有价值的 insight:梯度的余弦解释(公式 8)。它把一个经验观察(散点图呈负相关)和数学机制(余弦投影路由梯度能量)连接起来,让人真正理解”为什么这样做有效”,而不只是”实验证明有效”。
让我最意外的结论:DVoRA(0.04% 参数)= DoRA(2.33% 参数)在 MT-Bench 上持平,而且双双超过 LoRA(2.31% 参数)。58 倍的参数差距,准确率无损——VeRA 的共享随机矩阵 + DoRA 的幅度/方向解耦组合起来比任何一方单独使用都更有效。
实践上的建议:
- 如果你现在用 LoRA,把
use_dora=True加上,基本没有任何代价。 - 如果 GPU 显存受限,用 DoRA† 把 rank 减半——比标准 LoRA 省一半参数,还更准。
- 如果显存极度受限,试试 DVoRA(VeRA backend + DoRA 幅度训练)。
- 诊断工具(§7.3)可以帮你判断自己的场景下 LoRA 与 FT 的差距是否主要来自幅度/方向耦合问题。
8.3 还有哪些开放问题
-
是否可以对幅度和方向用不同的学习率? 两者梯度尺度本质上不同( 是标量向量, 是矩阵)。分离学习率是否能进一步提升?
-
DoRA 在偏好学习(DPO, PPO-RLHF)上是否同样有效? RL fine-tuning 的梯度信号比 SFT 更嘈杂,解耦幅度/方向可能更有价值,也可能因为梯度信号本就方向不稳定而失效。
-
能否自适应地给不同层分配不同的 rank (结合 AdaLoRA 的思路)? 在同样的总参数预算下,对敏感层用大 、对不敏感层用纯幅度更新,应该能进一步提升参数效率。
-
DoRA 在极长上下文微调(Context Length Extension)中的表现? 长上下文微调需要调整 RoPE 相关权重,幅度/方向分离是否对这种特殊的微调模式有不同的效果?
附录 A:梯度推导的完整展开
A.1 不用 detach 时的完整梯度(含投影算子)
不使用 detach 时,列范数 是计算图的一部分,反向传播需要通过它传递。对第 列 ,根据链式法则:
\frac{\partial \mathcal{L}}{\partial V'_n} = \frac{m_n}{C_n} \left(I - \frac{V'_n V'^{\top}_n}{C_n^2}\right) \frac{\partial \mathcal{L}}{\partial W'_{:,n}} \tag{A.1}
这个公式本质上是把权重梯度 投影到和 正交的子空间上。正交投影的那部分()用于更新方向;平行于 的那部分被 的梯度(公式 8)吸收用于更新幅度。
这才是最完整的解耦证明:即使不用 detach,梯度几何也自动把能量分配到「幅度通道」和「方向通道」,两者是正交的。detach 只是去掉了二阶的 项,在实践中近似误差极小。
A.2 为什么 detach 近似误差小
被去掉的项是:
其范数 ,其中 是单位方向向量。
两种场景:
-
场景 A(需要更新方向):损失梯度 → 内积 → 被去掉的项 ,detach 误差忽略不计。
-
场景 B(需要更新幅度):损失梯度 → 内积较大,但此时幅度梯度 本身主导更新,方向梯度 本来就应该小 → 被去掉的项即使存在也不影响最终结果。
两个场景下误差都可控,这就是为什么 detach 只损失 0.2 分但节省 24.4% 显存。
A.3 参数量对比(逐层数字)
以 LLaMA-7B 的注意力投影层为例,:
| 方法 | 单层参数量() | 全量 FT 的比例 |
|---|---|---|
| 全量微调 | 100% | |
| LoRA | 0.78% | |
| DoRA | 0.81% | |
| VeRA | 0.049% | |
| DVoRA | 0.073% | |
| Prefix() | 0.49% |
DoRA 比 LoRA 多了 个幅度标量,额外参数量 = 3.1%(相对 LoRA),占整个模型参数的约 0.024%——完全可以忽略。
附录 B:实验细节与可复现细节
B.1 各任务超参数汇总
| 模型 | 任务 | rank r | alpha | dropout | optimizer | LR | 批次 | epoch |
|---|---|---|---|---|---|---|---|---|
| LLaMA-7B | 常识推理 | 16 | 32 | 0.05 | AdamW | 2e-4 | 16 | 3 |
| LLaMA-13B | 常识推理 | 32 | 64 | 0.05 | AdamW | 1e-4 | 16 | 3 |
| LLaMA2-7B | 常识推理 | 32 | 64 | 0.05 | AdamW | 2e-4 | 16 | 3 |
| LLaMA3-8B | 常识推理 | 32 | 64 | 0.05 | AdamW | 1e-4 | 16 | 3 |
| VL-BART | 图文多任务 | 128 | 128 | 0.0 | AdamW | 1e-3 | 300 | 7 |
| VL-BART | 视频文本 | 128 | 128 | 0.0 | AdamW | 3e-4 | 40 | 20 |
| LLaVA-1.5-7B | 视觉指令微调 | 128 | 256 | 0.05 | AdamW | 2e-4 | 16 | 1 |
| LLaMA-7B | 指令微调(Alpaca) | 64 | 64 | 0.0 | AdamW | 4e-4 | 16 | 1 |
B.2 显存测试数据
在单 A100 80GB 上,LLaMA-7B + 常识推理数据集(batch=16, seq=256):
| 配置 | 显存(GB) | 备注 |
|---|---|---|
| DoRA(无 detach) | 37.3 | 完整梯度图 |
| DoRA(有 detach) | 28.2 | 论文默认实现 |
| LoRA(同 rank) | ~26.8 | 参考点 |
| 全量微调 | 80+ | OOM on A100 |
B.3 MT-Bench 评测说明
MT-Bench 包含 80 道多轮对话题(8 大类:写作、角色扮演、提取、推理、数学、编程、STEM、人文),每题两轮,GPT-4 逐题打 1-10 分,最终取平均。
这种评测方式的优点是跨任务覆盖广、对长文本生成质量敏感;缺点是 GPT-4 评分有噪声,不同批次可能有 ±0.2 的方差。论文里 DoRA 在 LLaMA2-7B 上达到 6.0(LoRA: 5.7),差值 0.3 在多次运行中比较稳定。
附录 C:DoRA 的广义解读
C.1 从「自适应学习率」角度理解
从公式 (7) 看,DoRA 对 的梯度是把权重梯度乘以 (列方向上的幅度与范数之比)。这等价于给每一列的更新施加一个依赖幅度的自适应缩放因子。
列幅度大( 大)、归一化后范数小的列(可能是高激活列)会得到更大的梯度缩放,训练时更新更快。这有点像 Adam 的自适应效果,但不是基于梯度历史,而是基于当前权重幅度的几何结构。
从这个角度看,DoRA 是在 LoRA 的梯度上叠加了一层几何预条件器(geometric preconditioner),改善了 LoRA 的优化轨迹。
C.2 从「隐式正则化」角度理解
DoRA 的幅度向量 经过训练后,会根据任务需要调整每列的重要性权重——对任务重要的方向,幅度会增大;对任务不重要的方向,幅度会减小甚至接近零(实际上做了软稀疏化)。
相比 LoRA 把增量 均匀地加到每列,DoRA 的分解允许部分列只做小幅度调整(方向不变,幅度微调),其他列做大幅方向旋转。这种非均匀更新有隐式正则化效果,可以解释为什么 DoRA 在训练数据少时(1000 条样本)仍能稳定超过 LoRA。
C.3 DoRA 与 Riemannian 优化的联系
把权重矩阵的列视为球面上的点(),幅度视为半径,权重空间就是一个缩放球面(scaled sphere)。DoRA 把优化问题分解为两部分:
- 在 上优化幅度向量 (欧氏空间)
- 在 上优化方向矩阵 (乘积球面流形)
虽然 DoRA 的实现并没有用到黎曼优化(Riemannian SGD/Adam),但 detach 技巧实际上是在近似流形上的投影梯度: 忽略了球面约束引入的曲率修正项 。
这说明 DoRA 的学习曲线有流形优化的味道——它的轨迹比 LoRA 更接近”权重流形”上的最优路径。
笔记到此结束。如需进一步了解 LoRA 家族的其他方法(AdaLoRA、PiSSA、MoRA、DVoRA),欢迎参考本站其他博文。