一、技术背景
前面学习的全参数 SFT,会更新大模型每一层的所有权重参数。 当下开源大模型参数规模普遍达到数十亿、上百亿级别:
- 硬件门槛极高:需要多张高端独显、超大显存,个人设备几乎无法运行;
- 训练耗时久、算力成本高;
- 多次微调容易破坏模型原生的通用能力。
为解决以上问题,LoRA(Low-Rank Adaptation,低秩适配)应运而生,是目前轻量化微调的主流方案。
二、核心概念与原理
1. 基础名词解释
- 秩(Rank):线性代数概念,简单理解为矩阵的 “有效维度”。高秩矩阵信息饱满,低秩矩阵可以用更少参数近似表达核心信息。
- 低秩矩阵:参数量远小于原矩阵,能够近似模拟原矩阵的运算逻辑。
2. LoRA 核心设计思路
大模型的核心计算集中在Transformer 架构的注意力层(Query/Key/Value 投影矩阵),这也是模型学习风格、语义、领域知识的关键位置。 LoRA 做法:
- 冻结原始模型:原模型所有权重完全锁定,全程不做任何更新,保留模型原有能力;
- 旁路新增矩阵:在目标层旁,额外拼接两个小型低秩矩阵 A、B;
- 仅训练新增矩阵:训练过程只更新 \(A、B\) 的参数,原模型零改动;
- 运算叠加:前向传播时,将原矩阵计算结果 + 低秩矩阵计算结果合并,作为最终输出。
3. 关键特点
- 训练参数量极少:相比全量微调,训练参数可减少 90% 以上;
- 不破坏原模型:原始权重不变,规避 “微调后模型通用能力下降” 的问题;
- 兼容性强:主流开源模型(Qwen、ChatGLM、LLaMA 等)均支持;
- 灵活复用:训练得到的 LoRA 权重文件体积很小(几十 MB~ 几百 MB),可以单独保存、随时加载、多套 LoRA 自由切换。
三、LoRA 与 传统全量 SFT 全方位对比
表格
| 对比维度 | 全量参数 SFT | LoRA 低秩微调 |
|---|---|---|
| 参数更新范围 | 模型全部参数 | 仅新增少量低秩矩阵,原模型冻结 |
| 显存 / 硬件要求 | 极高,专业算力集群 / 高端显卡 | 极低,消费级家用显卡即可运行 |
| 训练速度 | 慢 | 大幅加快 |
| 权重文件大小 | 等同于整个大模型(几十 GB 起) | 极小(几十 MB 级别) |
| 模型原有能力 | 可能被改写、破坏 | 完全保留 |
| 最终效果 | 上限略高 | 绝大多数场景和全量 SFT 效果接近 |
四、适用场景 & 不适用场景
✅ 适合使用 LoRA
- 个人开发者、小团队,硬件资源有限;
- 微调模型对话风格、人设、固定话术;
- 轻量化领域知识适配(简单行业问答、文案风格统一);
- 需要制作多套 “风格包”,频繁切换模型效果。
❌ 不适合使用 LoRA
- 对模型底层逻辑、核心能力做深度重构;
- 大规模专业知识灌输(如完整医疗、法律知识库深度改造);
- 追求模型性能极致提升的工业级深度优化。
五、实操流程(对接代码,和 SFT 流程联动)
完整流程和标准 SFT 大体一致,仅多了LoRA 配置环节:
- 数据准备:依旧使用
instruction+input+output标注数据集(和 SFT 数据格式通用); - 加载基础模型 + 分词器,冻结原模型所有权重;
- 配置 LoRA 超参:秩 (rank)、缩放系数、目标层(指定注意力层);
- 配置训练参数:学习率、批次大小、训练轮数;
- 启动训练:仅更新 LoRA 矩阵参数;
- 模型推理:加载原模型 + 对应的 LoRA 权重,测试效果;
- 可选操作:将 LoRA 权重与原模型合并,得到独立的微调后模型。
六、核心超参(面试 / 实操高频考点)
- Rank(秩):LoRA 矩阵的维度,数值越大,可学习的信息越多,参数量也会增加;常规取值 8、16、32;
- lora_alpha:缩放系数,用来调节低秩矩阵输出的权重,平衡原模型与 LoRA 分支的影响;
- target_modules:指定要添加 LoRA 的网络层,一般选择注意力相关层。
七、简化代码片段(Hugging Face PEFT 库标准写法)
行业内统一使用peft库实现 LoRA,示例核心代码:
python
运行
from peft import LoraConfig, get_peft_model # 1. 配置LoRA参数 lora_config = LoraConfig( r=16, # 秩 lora_alpha=32, # 缩放系数 target_modules=["q_proj", "v_proj"], # 作用在注意力层 lora_dropout=0.05, bias="none", task_type="CAUSAL_LM" # 任务类型:因果语言模型 ) # 2. 给模型添加LoRA结构,冻结原模型 model = get_peft_model(model, lora_config) # 后续数据预处理、训练逻辑 和 标准SFT完全一致一、先看懂:传统全量 SFT 结构(对比参照)
大模型每一层本身就是权重矩阵,全量微调逻辑:
plaintext
输入文本 → 分词器转数字编码 ↓ 【原始模型权重矩阵(全部参数)】 ↓ 模型计算 → 输出结果训练时:整个原始矩阵的所有参数,全部更新修改问题:矩阵超大(数十亿参数)→ 吃显存、耗算力。
二、LoRA 核心结构图解(重点)
LoRA 不碰原始矩阵,在旁边额外搭一组小矩阵分支,整体并行计算:
plaintext
输入编码 │ ├───────────────────────────────────┐ │ │ 【原始大模型权重矩阵】 【LoRA 低秩分支】 (全程冻结,参数不变) (仅这里的A、B两个小矩阵参与训练) │ │ └───────────────┬───────────────────┘ ↓ 结果合并相加 │ ↓ 最终输出拆解每一部分
- 原始模型权重完全锁定,就像一台出厂设置不变的机器,保留原本所有知识、能力。
- LoRA 分支(核心)由两个小型低秩矩阵
矩阵A+矩阵B组成,尺寸远小于原模型矩阵。 训练时只更新这两个小矩阵,原模型一动不动。 - 合并输出原模型的计算结果 + LoRA 分支的计算结果 相加,作为最终输出。
形象类比: 原模型 = 主道路(主干道不变) LoRA = 一条极窄的辅路(只修整辅路,主干道不挖不动) 车流(数据)走主干道 + 辅路合并通行,整体走向被辅路轻微引导。
三、LoRA 内部矩阵简化示意(数学视角,结合你深度学习基础)
设原模型某层权重矩阵为 \(\boldsymbol{W}\)(大矩阵,维度很高) LoRA 新增:
- 低秩矩阵 \(\boldsymbol{A}\)
- 低秩矩阵 \(\boldsymbol{B}\)
最终该层输出 = \(\boldsymbol{W}x + \boldsymbol{B}\boldsymbol{A}x\)
- x:模型输入向量
- 训练:只更新 \(\boldsymbol{A}\)、\(\boldsymbol{B}\)
- 冻结:\(\boldsymbol{W}\) 永远不变
秩 (Rank) 理解秩就是矩阵 \(\boldsymbol{A}\)、\(\boldsymbol{B}\) 的维度。
- Rank=8/16:矩阵很小,参数量少,训练快、省显存
- Rank 越大 → 矩阵越大 → 能学习的信息越多,但显存 / 耗时也会上升
四、两种微调 整体流程对比图(文字版)
1)全量 SFT
plaintext
数据 → 分词编码 → 原始大模型(全部参数更新)→ 输出 → 计算损失 → 反向更新所有权重2)LoRA + SFT(工业主流组合)
plaintext
数据 → 分词编码 │ ├→ 原始模型(冻结,不更新) └→ LoRA 小矩阵(仅此处参数更新) │ 结果合并 → 输出 → 计算损失 → 只反向更新LoRA矩阵五、关键知识点复盘(结合图解记忆)
- 为什么省显存? 只训练两个小矩阵,不是几十亿参数的大矩阵,显存占用断崖式下降,家用显卡也能跑。
- 为什么不破坏原模型? 原始权重 \(\boldsymbol{W}\) 全程冻结,模型原本的知识、对话能力完全保留。
- LoRA 文件为什么很小? 训练完只需要保存 \(\boldsymbol{A}\)、\(\boldsymbol{B}\) 两个小矩阵,几十 MB 就能搞定,不像完整模型几十 GB。
- 切换风格怎么实现? 原模型不变,加载不同的 LoRA 文件(不同的 A/B 矩阵),就能切换不同话术、风格。