45

LoRA / QLoRA / PEFT 微调原理与取舍

⏱️ 35分钟

LoRA / QLoRA / PEFT 微调原理与取舍

微调(Fine-Tuning)大概是这门课最容易让人心态爆炸的一段:QLoRA、PEFT、量化、SFT、DPO……名词像开会点名一样往外蹦。

先给你吃颗定心丸,也是我踩过坑才敢说的一句话:大多数你以为"要微调"的场景,其实用 Prompt 或 RAG 就搞定了,而且更便宜、更快、更好维护。 这篇先帮你判断到底该不该微调,再把 LoRA/QLoRA 讲成人话(带一点点原理和一份能跑的配置),最后讲微调完怎么评估、怎么防翻车——这一步 90% 的教程都不讲,却最容易出事。


先别急着调:三条路先选对

有个"知识问答不准"的需求找上你,新手第一反应是"微调一个"。慢着,先过这张表:

方法解决什么问题成本一句话选型建议
Prompt / 上下文工程调整行为、格式、语气极低能用 prompt 解决就别碰后面两个
RAG让模型用上它没见过的新知识/私有数据"答得不对是因为不知道"→ 用 RAG
微调 (Fine-Tuning)固化风格/领域语感/输出结构,或省 token"知识对但腔调/格式老不对、或量大要压成本"→ 才微调

记死这条:微调擅长教模型**"怎么说"(风格、格式、专业语感),不擅长塞"新知识"**(那是 RAG 的活)。想靠微调给模型灌一本最新产品手册,大概率灌不进去还灌出幻觉。

说实话,我见过太多团队一上来就要微调,烧了几天 GPU,最后发现一个写好的 system prompt + 几条 few-shot 就达标了。微调是最后一招,不是第一招。

动手前拿这四个问题自查一遍,全答"是"再往下走:

  1. Prompt 里塞 3-5 条 few-shot 示例,效果还是不达标?
  2. 问题出在"腔调/格式/语感不对",而不是"知识不知道"?
  3. 你能凑出至少几百条高质量的"输入 → 期望输出"数据?
  4. 你有办法在微调后量化对比效果(有测试集,不是靠感觉)?

有一条答"否",先回去补那一条,别开训。

两个真实案例:一个不该调,一个该调

案例一(不该调):有个做跨境电商的团队找我,说要微调一个"懂他们产品的客服模型",预算都批了。我问了一句:客服答错的问题,是"不知道产品参数"还是"说话方式不对"?他们查了一周的客服日志,答案是前者——90% 的差评是"答非所问",因为产品目录每周都在更新。产品目录是新知识,微调灌不进去,灌进去下周也过期了。 最后方案是 RAG 挂产品库 + 一个 500 字的 system prompt 定语气,一分钱 GPU 没烧,两周上线。

案例二(该调):另一个做法律文书的团队,需求是把口语描述改写成固定格式的合同条款。知识不缺(模板都在 prompt 里),但强模型写出来的条款每次格式都有微妙的不同——标点、编号、措辞时松时紧,法务每份都要手改。few-shot 塞到 8 条还是压不稳,prompt 也被撑到 3000 token,量大成本难看。这种"知识对、格式老不对、调用量大"的场景,就是微调的主场:2000 条人工校对过的改写对,QLoRA 训完格式一致性直接拉满,system prompt 从 3000 token 砍到 200。

两个案例放一起看,判断标准就一句话:错在"不知道"→ RAG;错在"说不对"→ 微调。


全量微调为什么"调不起"

术语:全量微调 (Full Fine-Tuning)

  • 一句话解释:把模型几十亿个参数全部重新训练一遍。
  • 形象比喻:为了改一句口头禅,把一个人从小到大重新教育一遍——大炮打蚊子。
  • 工作中怎么用:效果上限高,但个人/小团队基本玩不起。
  • 最常踩的坑:显存。训一个 7B 模型的全量微调,除了模型本身,优化器状态(Adam 要为每个参数存两份额外数据)+ 梯度加起来要几十上百 GB 显存,一张消费级 24G 的 4090 想都别想

粗算一下 7B 全量微调的显存账,你就懂为什么劝退:

模型权重(fp16)      :  7B × 2 字节 ≈ 14 GB
梯度(fp16)          :  7B × 2 字节 ≈ 14 GB
Adam 优化器状态      :  7B × 8 字节 ≈ 56 GB   ← 大头在这
─────────────────────────────────────────
合计            ≈ 84 GB+  → 得 A100/H100 级别

于是就有了 PEFT。

术语:PEFT (Parameter-Efficient Fine-Tuning,参数高效微调)

  • 一句话解释:冻住原模型不动,只额外训练一小撮新参数。
  • 形象比喻:不重装整个操作系统,只装一个小插件。主体没变,行为变了。
  • 工作中怎么用:LoRA 是 PEFT 里最流行的一种;个人显卡微调基本都走这条。
  • 最常踩的坑:以为 PEFT 效果一定比全量差。多数任务上 LoRA 能逼近全量微调,差距小到不值那份成本。

LoRA:只训练一个"小补丁"(原理版)

术语:LoRA (Low-Rank Adaptation,低秩适配)

  • 一句话解释:冻结原权重,只在旁边挂一对小矩阵学"改动量",原模型一个参数都不动。
  • 形象比喻:给厚厚一本教科书夹便利贴批注。书本身没改,但你按批注去读,结论就变了。
  • 工作中怎么用:训练出来的"补丁"(adapter)才几 MB~几百 MB,一个底座能挂多个不同任务的补丁,随时切换。
  • 最常踩的坑:rank (r)alpha 两个旋钮乱设。r 太小学不动,太大又浪费还可能过拟合。

原理其实一句话能说清。微调本质是给原权重矩阵 W 学一个"改动量" ΔW,让 W_new = W + ΔW。全量微调的 ΔW 和 W 一样大(几十亿数)。LoRA 赌一件事:这个 ΔW 其实很"扁",能用两个瘦长的小矩阵相乘近似出来

ΔW  ≈  B × A
       │   └─ A: 形状 [r, 原维度]   (瘦)
       └───── B: 形状 [原维度, r]   (长)

原来要训练一整块 d×d(比如 4096×4096 ≈ 1678 万个数)
现在只训 B 和 A 两条(r=16 时 ≈ 4096×16×2 ≈ 13 万个数)
→ 参数量降到约 0.8%

这里的 r(秩) 就是那个"瘦"的程度:r 越小,补丁越小越省,但表达能力越弱。原模型冻着不动,只有 B、A 在学,所以显存和存储都暴降。

(这里的 W 就是 Transformer 注意力层里那些 Q/K/V 投影矩阵——如果你还没搞清 Q/K/V 是什么,建议先补那一篇,回来看 target_modules 会豁然开朗。)

两个你一定会调到的参数:

参数管什么经验起手调大/调小
r (rank)补丁容量8 / 16 / 32简单任务 8,复杂点 16–32;再大收益递减还易过拟合
alpha补丁"音量"(缩放)2 × r(如 r=16→alpha=32)实际生效强度≈ alpha/r,一般跟着 r 走

QLoRA:让 7B 挤进一张 24G 显卡

LoRA 已经省了训练参数,但底座模型本身加载进显存还是很占地方(7B 的 fp16 就 14GB)。QLoRA 再补一刀。

术语:量化 (Quantization)

  • 一句话解释:把模型参数从高精度(16 位)压成低精度(4 位)存,省显存。
  • 形象比喻:高清电影压成手机能存的清晰度。画质掉一点点,体积小一大截。
  • 工作中怎么用:4-bit 量化能把模型显存占用砍到约 1/4(14GB → 约 3.5–4GB)。
  • 最常踩的坑:量化会损失一点精度。对话/写作类基本无感,但数值精算类任务要实测别硬上。

术语:QLoRA

  • 一句话解释:先把底座模型 4-bit 量化塞进显存,再在上面挂 LoRA 补丁训练。
  • 形象比喻:先把大件家具拆小搬进小房间(量化),再在里面贴便利贴改造(LoRA)。
  • 工作中怎么用:让"消费级单卡微调 7B~13B"从幻想变成现实,是目前个人微调的主流方案。
  • 最常踩的坑:4-bit 用的 NF4 数据类型 + double quantization 这些配置,照抄成熟脚本(Unsloth / PEFT 官方示例)就行,别自己瞎调。

三个词的关系钉死:

PEFT  = 大类思想:只训练一小撮参数
  └─ LoRA   = PEFT 的具体做法:挂低秩"补丁"(B×A)
       └─ QLoRA = LoRA + 4-bit 量化底座:再省一大截显存

显存实操档位(7B,随序列长度/batch 浮动):

方案大致显存消费级卡够不够一句话记忆
全量微调80G+❌ 得 A100/H100小团队别想
LoRA (16-bit 底座)~16–24G勉强(24G 卡紧)够用但紧
QLoRA (4-bit 底座)~6–12G✅ 舒服个人微调首选

环境先排雷:锁版本,别裸装

写代码之前先说个丑事。我第一次跑 QLoRA,照着一篇教程抄,ImportError 报了一晚上。教程本身没错——错在它是十个月前写的,而 peft 和 trl 这两个库的 API 变得比天气还快。微调生态的版本坑,比微调本身难缠。

安装时把版本范围锁死(下面这组是互相兼容的搭配,别一把 pip install -U 拉最新):

pip install "transformers>=4.51,<5" \
            "peft>=0.15,<0.18" \
            "bitsandbytes>=0.45.0" \
            "trl>=0.17,<0.20" \
            "accelerate>=1.3" \
            "datasets>=3.2"

跑通之后立刻 pip freeze > requirements.txt 留底。三个月后你换机器重跑,会感谢今天的自己。

网上旧教程代码跑不通时,先对号入座这张表,八成是版本坑:

报错/症状根因怎么修
cannot import name 'prepare_model_for_int8_training'这个函数在新版 peft 里已删除prepare_model_for_kbit_training(新 API)
SFTTrainerunexpected keyword argument 'max_seq_length'TRL 0.12 起把 max_seq_length / packing 这类参数挪进了 SFTConfig参数写进 SFTConfig(...) 再传给 trainer
Trainer 警告 tokenizer 参数已弃用transformers 4.46 起改名processing_class=tokenizer
bitsandbytes was compiled without GPU supportbitsandbytes 只支持 Linux + NVIDIA CUDAMac / 无 N 卡的机器装了也白装,直接用 Colab/Kaggle 的免费 GPU
装完 import 直接 segfault / CUDA errorbitsandbytes 版本和 CUDA 驱动不匹配按官方兼容表装对应版本,别硬升

最后一条单独敲黑板:bitsandbytes 认死 Linux + NVIDIA。 Apple Silicon 的 Mac 本地跑不了 QLoRA(这也是为什么练习里让你用 Colab)。别在自己的 MacBook 上跟安装报错搏斗两小时——那是打不赢的仗。


上手代码:一份能跑的 QLoRA 配置

不用手撸,认识关键几行就行。下面是 PEFT + bitsandbytes 的标准骨架:

# 依赖安装见上一节的锁版本命令,别裸装最新版
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model
import torch

# ① 4-bit 量化配置(这就是 QLoRA 的 "Q")
bnb = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",              # NF4:为正态分布权重优化的 4-bit 类型
    bnb_4bit_use_double_quant=True,         # 二次量化,再省一点
    bnb_4bit_compute_dtype=torch.bfloat16,  # 计算时临时升回 bf16
)
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2.5-7B", quantization_config=bnb, device_map="auto")

# ② LoRA 补丁配置(这就是 "LoRA")
lora = LoraConfig(
    r=16, lora_alpha=32, lora_dropout=0.05,
    target_modules=["q_proj","k_proj","v_proj","o_proj"],  # 给注意力的 Q/K/V/O 挂补丁
    task_type="CAUSAL_LM",
)
model = get_peft_model(model, lora)
model.print_trainable_parameters()
# → trainable params: ~0.8%  ← 只有这么点在训,其余全冻结

图解说明:

  1. 这段在干嘛:先把 Qwen2.5-7B 用 4-bit 量化装进小显存(①),再挂上只占 0.8% 参数的 LoRA 补丁(②)。
  2. 先看哪里:先看 load_in_4bit=True(省显存的开关),再看 r=16, lora_alpha=32(前面讲的两个旋钮),最后看 print_trainable_parameters 打印的比例。
  3. 关键判断target_modules 决定给哪些层挂补丁——挂注意力的 q/k/v/o 是最常见的稳妥选择;想更强可加上 FFN 层,但显存和过拟合风险都上升。

训练超参一般这样起手(用 TRL 的 SFTTrainer):learning_rate=2e-4num_epochs=1~3batch_size 看显存(配 gradient accumulation 凑等效大 batch)。epoch 别贪多,2–3 轮往往就够,多了就开始背题(过拟合)。

把训练跑起来:SFTTrainer 完整骨架

上面只挂好了补丁,真正开训还差一段。注意这是 TRL 0.12 之后的新写法——超参进 SFTConfig,不再直接传给 trainer(旧教程的写法会报 unexpected keyword argument,前面版本表里提过):

from trl import SFTTrainer, SFTConfig
from datasets import load_dataset

dataset = load_dataset("json", data_files="train.jsonl", split="train")
split = dataset.train_test_split(test_size=0.1)   # 留 10% 当验证集,别省这步

config = SFTConfig(
    output_dir="./qlora-out",
    num_train_epochs=2,                    # 2-3 轮起手,别贪
    per_device_train_batch_size=2,
    gradient_accumulation_steps=8,         # 等效 batch = 2×8 = 16
    learning_rate=2e-4,
    max_length=1024,                       # 序列长度,OOM 时第一个砍它
    logging_steps=10,                      # 每 10 步打一次 loss,盯曲线用
    eval_strategy="epoch",                 # 每轮结束跑一次验证集
    save_strategy="epoch",
    bf16=True,
)
trainer = SFTTrainer(
    model=model,                           # 上一段挂好 LoRA 补丁的模型
    args=config,
    train_dataset=split["train"],
    eval_dataset=split["test"],
    processing_class=tokenizer,            # 4.46+ 的名字,不叫 tokenizer 了
)
trainer.train()
trainer.save_model("./qlora-out/adapter") # 存的只是补丁,几百 MB

图解说明:

  1. 这段在干嘛:把数据切成训练/验证两份,配好超参,交给 SFTTrainer 跑完整训练循环,最后只保存 LoRA 补丁。
  2. 先看哪里:先看 train_test_split(验证集是防背题的保险丝),再看 gradient_accumulation_steps(显存不够时凑等效大 batch 的关键),最后看 save_model 存出来的目录——里面是 adapter 不是完整模型。
  3. 关键判断eval_strategy="epoch" 让每轮结束都有一个验证 loss。训练 loss 一直降、验证 loss 开始回升 = 过拟合信号,停在验证 loss 最低的那一轮。

训练时盯什么:loss 曲线的三种翻车信号

开训之后不是挂机等结果,loss 曲线会提前把事故预告给你:

  • loss 纹丝不动(一直飘在 2 点几、3 点几):九成不是学习率的锅,是数据的锅。先跑 print_trainable_parameters() 确认可训参数不是 0(target_modules 写错模块名,模型就整个冻着,一个参数都没在学);再检查数据有没有套对 chat template(见下一节)。这两个都排除了,再试着把学习率从 2e-4 往上调一档。
  • loss 断崖式掉到接近 0:不是天才降临,是背题了。数据太少、重复太多,或 epoch 太狠。这时候模型对训练集倒背如流,见到新输入就露馅。
  • loss 变成 nan:学习率太大,或 fp16 数值溢出。降学习率、compute dtype 换 bfloat16,一般能救回来。

一句话记忆:loss 不降先怀疑数据,loss 太低先怀疑背题,loss 是 nan 先怀疑精度。


数据比参数重要:格式与数量

微调效果 70% 取决于数据质量,不是参数。最常见的是指令微调 (SFT, Supervised Fine-Tuning) 格式——一堆"输入→期望输出"的例子:

{"instruction": "把这句话改写得更专业", "input": "这个东西还行吧", "output": "该方案整体表现符合预期。"}
{"instruction": "把这句话改写得更专业", "input": "赶紧弄一下",   "output": "请尽快安排处理。"}

几条铁律(踩过才知道有多疼):

  • 少而精 > 多而杂。几百条高质量、风格一致的数据,好过几万条乱七八糟的。数据里的坏习惯,模型学得比好习惯还快。
  • 格式要统一。你希望它输出什么样,训练数据就得字字是那个样,包括标点和结构。
  • 留验证集。留一小撮模型没见过的数据评估(为什么?见 ML/DL 基础 的过拟合)。

还有一个新手必踩、报错还不报在脸上的坑——对话模板:

术语:Chat Template(对话模板)

  • 一句话解释:把 instruction/input/output 拼成模型预训练时认识的那种对话格式的"套壳规则"。
  • 形象比喻:信写得再好,装错信封对方也拆不出来——每家模型认自己家的信封。
  • 工作中怎么用:用 tokenizer.apply_chat_template() 套模板;TRL 的 SFTTrainer 遇到标准 messages 格式会自动处理。
  • 最常踩的坑:Qwen、Llama 各家的模板互不相同。拿 A 家格式的数据训 B 家模型,loss 照样在降(它总能学到点什么),推理时输出却前言不搭后语——这种"训练像成功了"的假象最坑人。

大概要多少条?按任务类型给个手感:

任务大致数据量一句话记忆
固定风格/语气改写几百 ~ 1k风格活,少量就见效
特定输出结构/格式(如固定 JSON)1k ~ 5k要稳,得多喂几遍模式
领域语感(法律/医疗腔)5k ~ 数万越"专业"越吃量

真实数据不够怎么办?先别急着降标准凑数——用强模型生成再人工筛,往往比硬凑的真实数据质量还稳,具体套路见合成数据与数据增强


⚠️ 微调完别急着上线:评估 + 灾难性遗忘

这是最容易被跳过、又最容易翻车的一步。

术语:灾难性遗忘 (Catastrophic Forgetting)

  • 一句话解释:为了学会新任务,模型把原来会的通用能力忘了
  • 形象比喻:为了苦练一个高难舞步,结果把走路都练岔了。
  • 工作中怎么用:微调后一定要同时测新任务和旧的通用能力,别只看新任务分数上去就庆祝。
  • 最常踩的坑:只在自己那点微调数据上验,发现"完美!",一上线才发现模型变得只会那一件事、别的全退化了。LoRA 因为只动一小撮参数,遗忘比全量微调轻,但不是不会

微调后的评估至少三条腿:

  1. 任务集:你目标任务的独立测试集(模型没见过的),看有没有真学会。
  2. 回归集:一批通用问题(常识、其它格式),对比微调前后,看有没有退化(防遗忘)。
  3. 人工抽检:自动分再高,也要人眼扫一批真实输出——很多"腔调不对/胡说"自动指标测不出来。

怎么把这三条腿搭成可复跑的 eval 流程(而不是每次手工问几句),评估与质量监控有完整做法,微调玩家迟早要用上。

顺带认个进阶名词,直播会提:SFT → DPO / RLHF 是一条链。SFT 教它"会说"(照着示例学);DPO/RLHF 再用"人类更偏好 A 还是 B"的偏好数据,教它"说得更讨人喜欢"。个人项目多数到 SFT(+LoRA/QLoRA)就够了,DPO 是想进一步对齐口味时才上。


训练完的补丁怎么用:挂载还是合并

训练结束你手里多了个几十~几百 MB 的 adapter 目录。上线有两条路,选错会给自己挖坑:

路线 A:底座 + 补丁分开挂载。 推理时先加载原底座,再把 adapter 挂上去。好处是一个底座能同时伺候多个任务——客服腔一个补丁、法务腔一个补丁,按请求切换;vLLM 这类推理引擎原生支持 multi-LoRA serving,多任务省显存省到笑。代价是推理时多一次矩阵加法(通常无感),以及部署链路多一个要管理的文件。

路线 B:merge_and_unload() 合并成单模型。 把补丁"焊死"进底座权重,输出一个普通模型,之后当成任意开源模型部署、量化、分发都行。发布最省心,但合并是单向的——合完再想改补丁,只能回头重训。

我的私房建议:任务多、还在迭代 → 挂载;就一个任务、追求部署最简 → 合并。不管走哪条,合并前先把 adapter 目录备份一份,那才几百 MB,丢了哭都来不及。

合并出来的模型怎么本地跑、怎么选推理引擎,接着看开源模型、本地部署与模型路由;上生产后的算力账,看部署与成本优化

顺手算笔账:微调什么时候真省钱

开头选型表里写微调能"省 token",这句话值得展开算一次,因为它是很多团队微调的真实动机:

不微调:3000 token 的 system prompt(规则 + 8 条 few-shot)
        × 每天 10 万次调用
        = 每天 3 亿输入 token 花在"重复讲规则"上

微调后:规则和格式焊进了权重,prompt 砍到 200 token
        每天省下 2.8 亿 token 的输入费
        代价 = 一次性训练成本(QLoRA 租卡几十美元)+ 自托管推理

但注意两个前提,少一个这笔账就不成立:

  • 调用量要够大。一天几百次调用,省的 token 钱可能几年都回不了训练 + 自托管的本。
  • 自托管本身有账。开源模型 + 补丁得自己伺候 GPU,这部分成本怎么估,部署与成本优化里有完整算法。

一句话记忆:微调省钱的前提是"量大 + prompt 长",两者缺一,先别拿省钱当理由。


⚠️ 常见陷阱

陷阱后果怎么办一句话记忆
拿微调塞新知识灌不进 + 幻觉变多新知识用 RAG,微调只管风格/格式知识找 RAG,腔调找微调
数据几十条就开训学不到东西或直接过拟合起码几百条高质量、风格统一几百条起步,少而精
r / alpha 拍脑袋学不动或过拟合起手 r=16、alpha=32,再按效果调alpha 跟着 2×r 走
epoch 贪多背题、遗忘加重2–3 轮起,盯验证 loss 早停会了就停,别复读
只测新任务不测旧能力灾难性遗忘没发现就上线加"回归集"对比微调前后新旧一起考
数值精算任务硬上 4-bit精度掉出问题这类任务先实测,必要时用更高精度精算任务先实测
CUDA OOM 直接放弃白白错过能跑的配置依次砍:max_seq_length 减半 → batch_size=1 + gradient accumulation → 开 gradient checkpointing先砍序列,再砍 batch
loss 不降就狂调学习率方向错了越调越乱先查 trainable params 是不是 0、chat template 对没对loss 不降先查数据
裸装最新版依赖教程代码全线报错按兼容组合锁版本,跑通就 pip freeze锁版本,freeze 留底
合并后删掉 adapter想改补丁只能重训merge_and_unload() 前备份 adapter 目录合并前先备份

🔧 动手练习

练习 1:选型判断 + 手写 SFT 数据(约 20 分钟,不需要 GPU)

  1. 给自己一个真实需求(如"把口语客服话术改写成正式书面语"),对着开头那张三选一的表判断:该用 Prompt、RAG 还是微调?写一句理由。
  2. 假设结论是微调,照上面的 JSON 格式手写 10 条这个任务的 SFT 数据,要求风格、标点、结构完全统一。
  3. 写完检查:把 10 条里随机抽 2 条当"验证集"划出来不许用——这就是你的第一个评估习惯。

验收标准:写到第 6、7 条你开始头疼、开始想"要不让 AI 帮我生成几条"——恭喜,你已经体会到"凑高质量数据才是微调最累的部分"这个行业共识了。

练习 2:Unsloth Colab 真跑一次 QLoRA(约 40–60 分钟,用免费 GPU)

  1. 打开 Unsloth 官方 GitHub,找到免费的 Colab notebook(选 Qwen 或 Llama 的 4-bit 示例),用 Colab 免费 T4 就能跑——别在 Mac 本地折腾 bitsandbytes,前面说过那是打不赢的仗。
  2. 逐行对照本文认参数:load_in_4bitrlora_alphalearning_ratenum_train_epochs 各自管什么,改之前先说出它的作用。
  3. 跑通默认示例后,把训练数据换成练习 1 手写的那 10 条(注意套对 chat template),观察 loss 曲线——数据这么少,大概率会看到"loss 掉太快"的背题信号,正好把前面讲的翻车信号亲眼看一遍。
  4. 训完做双测:先问它你的目标任务,再问"1+1 等于几"这种通用问题。两边都答好才算成——这就是最小版的"任务集 + 回归集"评估。

📚 小结

  1. 微调是最后一招:能用 Prompt / RAG 就别碰。微调管"怎么说"(风格/格式),不管"新知识"(那是 RAG)。
  2. 全量微调显存吃不消(7B 要 80G+);LoRAΔW ≈ B×A 的低秩补丁把可训参数降到约 0.8%,补丁才几 MB。
  3. QLoRA = 4-bit 量化底座 + LoRA,显存砍到 6–12G,消费级单卡能训 7B;r=16 / alpha=32lr=2e-4、2–3 epoch 起手;依赖要锁版本(peft/trl/transformers 的 API 变得飞快,bitsandbytes 只认 Linux + CUDA)。
  4. 数据 > 参数:少而精、格式统一、套对 chat template、留验证集;数据量按任务从几百到数万不等。
  5. 微调完必须评估:任务集(学会没)+ 回归集(防灾难性遗忘)+ 人工抽检,别只看新任务分就上线;adapter 合并前先备份;想进一步对齐口味再上 DPO。

相关阅读

下一步部署与成本优化

📚 相关资源

❓ 常见问题

关于本章主题最常被搜索的问题,点击展开答案

什么时候该微调,什么时候该用 RAG?

一句话判断:错在"不知道"用 RAG,错在"说不对"才微调。微调擅长固化风格、格式、领域语感,塞不进新知识——硬灌产品手册只会灌出幻觉。动手前先自查:few-shot 试过没、能不能凑几百条高质量数据、有没有测试集量化对比。微调是最后一招,多数需求 prompt + RAG 就达标。

LoRA 和 QLoRA 分别省了什么?

LoRA 省训练参数:冻结底座,只训 ΔW≈B×A 两个低秩小矩阵,可训参数降到约 0.8%,补丁才几 MB 到几百 MB。QLoRA 再省底座显存:先把模型 4-bit 量化(14GB 砍到约 4GB)再挂 LoRA。7B 全量微调要 80G+ 显存,QLoRA 只要 6–12G——这就是消费级单卡能微调的原因。

消费级单卡能微调多大的模型?参数怎么起手?

QLoRA 方案下一张 24G 的 4090 能舒服地调 7B~13B(占 6–12G 显存,随序列长度浮动);16-bit LoRA 调 7B 就很紧了。参数起手:r=16、alpha=2×r=32、lr=2e-4、2–3 个 epoch、target_modules 挂注意力 q/k/v/o。OOM 时依次砍:序列长度减半 → batch=1 + gradient accumulation → 开 gradient checkpointing。注意 bitsandbytes 只支持 Linux+CUDA,Mac 本地跑不了,用 Colab 免费 GPU。

SFT 数据要准备多少条?质量上要注意什么?

按任务定量:固定风格改写几百到 1k 条,固定输出结构 1k–5k 条,领域语感 5k 到数万条。质量三铁律:少而精大于多而杂(坏习惯模型学得更快)、格式字字统一(含标点结构)、必须留验证集。另外要套对 chat template——Qwen 和 Llama 模板不通用,套错了 loss 照降但推理输出乱码。数据不够用强模型合成再人工筛。

微调完效果变差或行为异常,怎么排查?

按信号定位:通用能力退化是灾难性遗忘,用回归集对比微调前后,减 epoch 或减小 r;只会训练集那一件事是背题,数据太少或 epoch 贪多;输出乱码先查 chat template 是否套对;loss 一直不降先查 trainable params 是不是 0(target_modules 写错)。上线前必须三条腿评估:任务集 + 回归集 + 人工抽检,别只看新任务分数。