大模型微调流水线:LoRA 与 QLoRA

本文系统讲清大模型微调流水线:先对比全参微调与 LoRA、QLoRA 的成本与适用边界,再拆解低秩分解原理、秩与 alpha 的选择、目标模块配置、4bit 量化与双重量化,给出 7B 到 70B 的显存估算公式与实测对照表,覆盖指令数据格式、PEFT 与 TRL 训练脚本、权重合并与 vLLM 部署,以及微调与 RAG 的选型决策。

微调(Fine-tuning)是很多团队在 LLM 落地时第一个想到的动作,也是最容易被误用的动作。真实情况是:绝大多数「效果不好」的问题,根因在检索质量、提示结构或数据本身,而不是模型缺了那几千条样本的领域知识。把微调当成万能药,结果往往是花了两周标注数据、烧了几百卡时,换来的收益还不如把 RAG 的 chunk_size 从 1024 调到 512。

当微调确实该做的时候,第二个坑紧接着出现:很多人默认「微调 = 全参微调」,于是直接撞上显存墙。一个 7B 模型用 FP16 做全参微调,权重、梯度、Adam 优化器状态三者叠加就要接近 90 GB,单张 80 GB 卡根本装不下;70B 更是要一整机 A100 才勉强跑起来。LoRA 与 QLoRA 解决的正是这个问题:把可训练参数从几十亿压到几百万,显存需求下降一个数量级,而效果在多数任务上能追平全参微调。

本文按一条完整的微调流水线来讲:先判断该不该微调,再算清全参微调的成本,然后深入 LoRA 的低秩原理与超参选择、QLoRA 的量化与双重量化,接着是数据准备、训练框架、显存估算、权重合并与部署,最后落到评测与选型决策。全篇聚焦训练侧,推理侧的量化和显存公式请参考 量化与显存优化 ,两者互补但不重叠。

目录

  1. 什么时候该微调:微调、RAG 与提示的边界
  2. 全参微调的成本结构
  3. LoRA 的低秩分解原理
  4. 秩、alpha 与目标模块的选择
  5. QLoRA 的 4bit 量化与双重量化
  6. 数据准备与指令格式
  7. 训练框架:PEFT、TRL 与 DeepSpeed
  8. 显存估算与超参配置
  9. 合并权重与部署
  10. 评测与回归
  11. 权衡取舍
  12. 常见坑清单
  13. 小结

1. 什么时候该微调:微调、RAG 与提示的边界

三种手段解决的是三类不同的问题,混用是最大的浪费来源。

手段解决什么典型成本迭代速度适合的信号
提示工程任务描述不清、格式不稳小时级分钟级模型有能力但没被引导
RAG知识缺失、知识过期天级小时级问题需要外部事实、且事实会变
微调风格、格式、领域行为、能力压缩周级天级知识已具备但行为不对

判断顺序应该是自上而下的:先问「模型是不是根本不知道这件事」,是则走 RAG;再问「模型知道但输出格式或风格不对」,是则先试提示与少样本;只有当提示已经调到极限、且失败样本呈现出稳定的行为模式(比如始终不遵守某种业务话术、始终不会输出某种结构化字段)时,才轮到微调。

一个常被忽略的判据是知识 vs 行为。微调擅长固化行为(语气、格式、推理路径、工具调用习惯),不擅长注入事实——因为事实会被压缩进权重,既容易幻觉又无法更新。想让模型记住「本公司 2026 年新的退款政策」,微调是错的选择,检索才是对的。反之,想让模型「永远用客服话术回复、永远先共情再给方案」,微调是对的。

另一个判据是推理成本。把一个大模型的能力蒸馏进小模型,是微调最有商业价值的用法:用 GPT-4o 级模型生成几万条高质量样本,微调一个 7B 模型去模仿,线上推理成本能降一到两个数量级。这条路径的收益远大于「让 7B 更懂某个领域」。

2. 全参微调的成本结构

全参微调之所以贵,不是贵在权重,而是贵在优化器状态。用 AdamW 训练时,每个可训练参数需要额外的梯度(1 份)与优化器状态(2 份动量,通常 FP32),加上权重本身,显存需求约为参数量乘以 16 字节(混合精度下)。

全参微调显存 ≈ 参数量 × (2 权重 + 2 梯度 + 8 优化器状态) 字节 + 激活
             ≈ 参数量 × 12 字节 + 激活

按这个口径估算不同规模模型的训练侧显存(不含激活):

模型规模权重 (BF16)梯度 (BF16)优化器状态 (FP32)小计最小硬件
1.5B3.0 GB3.0 GB12.0 GB18 GB单卡 24G
7B14.0 GB14.0 GB56.0 GB84 GB2×A100 80G
13B26.0 GB26.0 GB104 GB156 GB4×A100 80G
70B140 GB140 GB560 GB840 GB16×A100 80G 起

这还只是静态部分。激活值随 batch size 与序列长度增长,长序列训练时激活可能再吃掉几十 GB,所以实际还要叠加梯度检查点(gradient checkpointing)与 ZeRO 分片。70B 全参微调在工程上意味着数十张卡、NCCL 通信调优、以及动辄数天的训练窗口——这是只有模型厂商与少数大厂才值得做的事。

对绝大多数团队,正确的默认选项是 PEFT(Parameter-Efficient Fine-Tuning),其中 LoRA 是事实标准。它把可训练参数压到 0.1% 到 1%,显存需求随之降到全参的几分之一。

3. LoRA 的低秩分解原理

LoRA(Low-Rank Adaptation)的核心假设是:微调带来的权重更新矩阵 ΔW 是低秩的。既然 ΔW 的有效秩远小于原始维度,就没必要训练一个完整的 ΔW,而是把它分解成两个小矩阵的乘积。

对原始权重 W0 ∈ R^(d×k),前向计算变为:

h = W0 · x + ΔW · x = W0 · x + (α / r) · B · A · x

其中 B ∈ R^(d×r), A ∈ R^(r×k), 秩 r << min(d, k)
初始化:A ~ N(0, σ²) 高斯,B = 0(保证训练起点等价于原模型)

几个关键点:

  • B 初始化为零,使得训练开始时 ΔW = 0,模型行为与基座完全一致。这是 LoRA 稳定收敛的前提,若 A、B 都随机初始化,训练初期会引入巨大噪声。
  • α / r 是缩放因子。α 是常数缩放,r 是秩。当调整 r 时,同时按比例调整 α,可以近似保持更新幅度不变,这是「换秩不用重调学习率」的经验来源。
  • 推理零延迟。训练完成后可以把 B·A 加回 W0,得到一个新的稠密权重,推理时与原模型完全同构,没有任何额外计算。这一点比 Adapter 类方法(串接额外层,推理多一层)有本质优势。

LoRA 的参数量公式为:可训练参数 = r × (d_in + d_out) × 目标模块数。以 Qwen2.5-7B(28 层,hidden 3584,28 个注意力头,4 个 KV 头,head_dim 128)为例,只对 q/k/v/o 四个投影加 LoRA,r=16:

目标模块权重形状单层 LoRA 参数28 层合计
q_proj3584 × 358416 × 7168 = 114,6883.21 M
k_proj3584 × 51216 × 4096 = 65,5361.83 M
v_proj3584 × 51216 × 4096 = 65,5361.83 M
o_proj3584 × 358416 × 7168 = 114,6883.21 M
合计——约 10.1 M

10.1 M 相对 7B 是 0.14%。如果扩展到全部线性层(含 MLP 的 gate/up/down),参数量约翻三倍到 0.4% 左右。这个量级意味着优化器状态只有几十 MB,显存瓶颈从「优化器」转移到了「权重与激活」。

4. 秩、alpha 与目标模块的选择

三个超参决定了 LoRA 的表达能力:秩 r、缩放 α、以及挂在哪些模块上。

秩 r

r 控制可表达的子空间维度。经验规律是:任务与基座分布差异越大、任务越复杂,需要的 r 越大。

任务类型推荐 rα说明
风格/格式对齐4 - 88 - 16更新量小,低秩足够
领域问答16 - 3232 - 64平衡点,最常用
代码/数学能力32 - 6464 - 128需要更大子空间
多任务混合64 - 128128 - 256任务冲突需更大容量

r 不是越大越好。r 超过 64 后,收益迅速递减,而可训练参数线性增长、过拟合风险上升。多数团队应该从 r=16、α=32 起步,只有在验证集上观察到欠拟合(训练损失下不去)时才往上调。

缩放 α

α 与 r 的比值决定更新幅度。实践中常固定 α = 2r(即 α/r = 2),这样改 r 时不必重新调学习率。也有观点认为固定 α(如 α=16)并让它随 r 自动稀释更稳。无论哪种,关键是一旦选定就保持一致,不要在不同实验间混用。

目标模块

只挂 q/v 是原论文的默认配置,但后来的实践(尤其是 QLoRA 论文)发现全线性层(q/k/v/o 加 MLP 的 gate/up/down)效果明显更好,代价是参数量与显存略增。

配置可训练参数(7B, r=16)效果建议
仅 q_proj, v_proj约 3.2 M基线显存极紧时用
全部注意力投影约 10.1 M+2 到 4 分常用起点
全部线性层约 30 M+4 到 6 分效果优先

判断目标模块是否够用,可以看训练损失是否稳定下降到接近零:如果损失卡在高位,多半是容量不足,先加模块再加秩。

5. QLoRA 的 4bit 量化与双重量化

LoRA 已经把优化器开销压下去了,但基座权重仍以 BF16 常驻,7B 占 14 GB、70B 占 140 GB。QLoRA 的思路是:把冻结的基座权重量化到 4bit 存储,前向计算时临时反量化到 BF16,从而把权重占用压到约四分之一,而可训练的 LoRA 适配器仍保持 BF16。

QLoRA 的三个关键组件:

  • NF4(NormalFloat4):假设权重近似正态分布,把 16 个量化级别按标准正态的分位数非均匀放置,使每个 bin 的期望样本数相等,比均匀 INT4 的信息损失更小。
  • 双重量化(Double Quantization):量化本身会为每个 block(通常 64 个权重)产生一个 FP32 的 scale。这些 scale 数量可观(70B 约 1 亿个),QLoRA 再对 scale 做一次 8bit 量化,把 scale 的开销从每参数 0.5 bit 降到 0.127 bit,70B 上能省约 3 GB。
  • 分页优化器(Paged Optimizers):借助 NVIDIA 统一内存,在显存峰值时把优化器状态分页到 CPU,避免偶发的 OOM。

量化对显存的影响:

配置7B 权重70B 权重相对 BF16
BF1614.0 GB140 GB100%
NF43.5 GB35 GB25%
NF4 + 双重量化3.4 GB32 GB24%

代价是训练速度下降约 20% 到 40%(反量化开销),以及轻微的精度损失。QLoRA 论文的结论是:4bit 基座加 LoRA 的效果与 16bit 全参微调相当。因此当显存是硬约束时,QLoRA 是首选;当显存充足时,用 BF16 LoRA 训练更快、更省心。

6. 数据准备与指令格式

微调的效果上限由数据决定,而数据准备是整条流水线里最耗人力的一环。

指令格式

主流格式是「指令-输入-输出」三元组,用对话模板包成 messages。以 ShareGPT 风格为例:

{
  "conversations": [
    {"role": "system", "content": "你是一名严谨的客服助手。"},
    {"role": "user", "content": "我的订单 3 天没发货,怎么处理?"},
    {"role": "assistant", "content": "非常抱歉给您带来不便。我先帮您核实订单状态……"}
  ]
}

关键纪律是:训练时的对话模板必须与推理时完全一致。基座模型自带的 chat template(如 ChatML、Llama3 的 header 格式)不能改,改了会导致模型学到一个推理时不存在的格式,表现为输出混乱。用 tokenizer.apply_chat_template() 生成训练样本,能保证两边一致。

数据量与质量

任务类型最小可用样本推荐样本说明
风格/格式对齐5002,000 - 5,000低秩即可收敛
领域问答2,00010,000 - 50,000需要覆盖长尾
能力蒸馏10,00050,000 - 200,000覆盖面决定上限

比数量更重要的是质量与多样性。几十条精心构造的高质量样本,往往胜过几千条从日志里粗暴导出的脏数据。三个常见的数据问题:

  • 重复:同一问题出现几十次,会让模型过拟合到该表述,失去泛化。训练前必须做去重(按语义相似度或精确匹配)。
  • 标签噪声:助手回复里夹带错误事实或不一致的格式,模型会照单全收。用强模型做一次质量打分与筛选是划算的投入。
  • 格式不统一:有的样本用 Markdown、有的用纯文本,模型会学到混乱的格式分布。统一格式是预处理的基本要求。

损失掩码

指令微调通常只对 assistant 回复部分计算损失,把 system 与 user 的 token 掩码掉(label = -100)。这一步极易被忽略却影响很大:如果对全部 token 计损失,模型会花容量去学「怎么复述用户的问题」,既浪费又可能引发复读。

数据构造流水线

一条可复用的数据构造流水线通常是四步:采集、清洗、打分、配比。

步骤动作工具产出判据
采集从日志、专家撰写、强模型合成收集埋点导出、GPT-4o 生成原始量约为目标的 2 到 3 倍
清洗去重、去 PII、格式统一MinHash、正则、规则重复率低于 1%
打分质量分、难度分、多样性分强模型评判、嵌入聚类淘汰底部 20% 到 40%
配比按任务类型与难度分层采样采样脚本各类目占比符合预期

其中「配比」最容易被忽略。如果蒸馏数据里 80% 是简单问答,模型会学到「什么都用短答」的偏置。合理的做法是按难度与类型分层,保证每个桶都有足够样本,长尾任务至少占 10%。

from collections import defaultdict
import random

def stratified_sample(rows: list[dict], key: str, total: int) -> list[dict]:
    """按 key 分层采样,长尾类目保底 10% 配额"""
    buckets = defaultdict(list)
    for r in rows:
        buckets[r[key]].append(r)
    out, floor = [], max(1, int(total * 0.1 / max(len(buckets), 1)))
    for k, items in buckets.items():
        random.shuffle(items)
        take = max(floor, int(total * len(items) / len(rows)))
        out.extend(items[:take])
    random.shuffle(out)
    return out[:total]

这段逻辑的价值在于:它让「数据分布」变成一个可控参数,而不是被采集过程随机决定的产物。

7. 训练框架:PEFT、TRL 与 DeepSpeed

三层工具分工明确:PEFT 提供 LoRA 的实现与权重注入,TRL 提供训练循环与对齐相关的 Trainer,DeepSpeed 负责分布式与显存分片。

PEFT 配置

from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
import torch

model_id = "Qwen/Qwen2.5-7B-Instruct"

bnb = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",            # NF4 量化
    bnb_4bit_use_double_quant=True,       # 双重量化,省 scale 开销
    bnb_4bit_compute_dtype=torch.bfloat16 # 计算时反量化到 BF16
)

model = AutoModelForCausalLM.from_pretrained(
    model_id, quantization_config=bnb, device_map="auto"
)
model = prepare_model_for_kbit_training(model)   # 冻结基座、开梯度检查点

lora = LoraConfig(
    r=16, lora_alpha=32, lora_dropout=0.05,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    bias="none", task_type="CAUSAL_LM",
)
model = get_peft_model(model, lora)
model.print_trainable_parameters()   # 打印可训练参数占比,通常 0.2% 到 0.5%

prepare_model_for_kbit_training 做两件事:把基座权重的 requires_grad 设为 False,并把 LayerNorm 等层强制转为 FP32 以稳定训练。漏掉它会出现梯度爆炸。

TRL 训练脚本

from trl import SFTTrainer, SFTConfig
from datasets import load_dataset

ds = load_dataset("json", data_files="sft_data.jsonl", split="train")

cfg = SFTConfig(
    output_dir="./out-lora",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=8,        # 等效 batch 32
    learning_rate=2e-4,                   # LoRA 常用 1e-4 到 3e-4
    lr_scheduler_type="cosine",
    warmup_ratio=0.03,
    bf16=True,
    gradient_checkpointing=True,          # 用时间换显存
    max_seq_length=2048,
    logging_steps=10,
    save_strategy="epoch",
    packing=False,                        # 短样本多时可开 packing 提吞吐
)

trainer = SFTTrainer(
    model=model, args=cfg,
    train_dataset=ds,
    peft_config=lora,
    processing_class=AutoTokenizer.from_pretrained(model_id),
)
trainer.train()
trainer.save_model("./out-lora-final")

LoRA 的学习率通常比全参微调高一到两个数量级(2e-4 对 2e-5),因为适配器是随机初始化的,需要更大的步长才能学到有效更新。

DeepSpeed ZeRO 阶段

单卡能装下时不需要 DeepSpeed。需要多卡时,按显存压力选择 ZeRO 阶段:

阶段分片内容显存收益通信开销适用
ZeRO-1优化器状态中低优化器是瓶颈
ZeRO-2优化器状态 + 梯度高中LoRA 多卡首选
ZeRO-3权重 + 梯度 + 优化器最高高全参微调大模型

LoRA 微调因为优化器状态本来就小,多卡时 ZeRO-2 通常够用,ZeRO-3 的额外通信往往得不偿失。

8. 显存估算与超参配置

把前面的公式串起来,做一次真实核算。目标:单张 A100 80G 微调 Qwen2.5-7B,序列长度 2048,能否用 BF16 LoRA。

BF16 LoRA 显存构成:
  基座权重 (BF16)      14.0 GB
  LoRA 参数 + 梯度      约 0.04 GB × 2
  优化器状态 (FP32)     约 0.16 GB
  激活 (batch 4, 2K, 开梯度检查点)  约 8 - 12 GB
  框架开销              1.5 GB
  ────────────────────────────────
  合计                  约 24 - 28 GB

结论:单卡 80G 绰绰有余,甚至 24G 的 4090 在减小 batch 后也能跑。换成 QLoRA:

配置基座权重激活与开销合计单卡可行性
全参 BF1614.0 GB84 GB(含优化器)约 100 GB需 2 卡
LoRA BF1614.0 GB12 GB约 28 GB单卡 80G/48G
QLoRA NF43.4 GB12 GB约 17 GB单卡 24G

70B 场景下差距更悬殊:QLoRA 能在单张 80G 上微调 70B(权重 32 GB + 激活 + 适配器),而全参需要 16 卡起步。

关键超参的推荐区间:

超参推荐值说明
learning_rate1e-4 到 3e-4LoRA 比全参高一个量级
batch size(等效)16 到 64小 batch 配梯度累积
epochs2 到 4超过 4 极易过拟合
warmup_ratio0.03 到 0.1稳定初期训练
lora_dropout0.05 到 0.1数据量小时防过拟合
max_seq_length覆盖 P95 长度过长浪费显存

9. 合并权重与部署

训练产出的是一个几百 MB 的适配器(adapter_model.safetensors),可以两种方式上线。

方式一:合并成稠密权重

把 B·A 加回 W0,得到一个与原模型同构的完整权重,推理零额外开销:

from peft import PeftModel
from transformers import AutoModelForCausalLM

base = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2.5-7B-Instruct", torch_dtype="auto"
)
model = PeftModel.from_pretrained(base, "./out-lora-final")
merged = model.merge_and_unload()          # 把 LoRA 权重并入基座
merged.save_pretrained("./Qwen2.5-7B-SFT", safe_serialization=True)

合并后的模型可以被 vLLM、TensorRT-LLM 等任意引擎直接加载,走标准的量化流程(AWQ/FP8)。注意合并必须在 BF16 上做:如果对 4bit 基座直接合并,会把 LoRA 的增量也压到 4bit,精度损失叠加。

方式二:多适配器热插拔

如果同一基座要服务多个租户或多套话术,保留适配器、运行时动态加载更灵活。vLLM 支持 --enable-lora 与多适配器并发:

python -m vllm.entrypoints.openai.api_server \
  --model Qwen/Qwen2.5-7B-Instruct \
  --enable-lora \
  --max-loras 4 --max-lora-rank 32 \
  --lora-modules support=./out-lora-support \
                 sales=./out-lora-sales \
  --max-model-len 8192 --port 8000

请求里用 "model": "support" 即可路由到对应适配器。代价是每个适配器的权重都要常驻显存(一个 r=16 的 7B 适配器约 20 MB 到 100 MB,可接受),且推理时多一次低秩计算。多租户场景的适配器隔离与配额,可以结合 模型网关与多模型路由 的鉴权与路由层一起设计。

10. 评测与回归

微调上线前必须回答一个问题:它比基座加提示好多少? 没有对照的微调是不可信的。

评测至少要覆盖三层:

  • 能力回归:用通用评测集(MMLU、C-Eval、GSM8K)确认微调没有破坏基座的通用能力。这是最容易被忽略的一环,领域微调经常导致通用能力显著下降(灾难性遗忘)。
  • 任务指标:在留出的验证集上测任务专属指标,如格式合规率、关键信息命中率、人工偏好胜率。
  • 对抗样本:构造边界与越界输入,确认模型不会因为微调而变得更容易被绕过。

对比必须用同一套评测脚本跑「基座 + 提示」与「微调模型」两条线,记录质量、延迟、成本三项。评测体系的搭建细节可参考 模型评测与灰度发布 。

一个实用的做法是小秩试跑:先用 r=8、2000 条样本跑一轮,看验证集是否比基座有提升。如果没有提升,先别急着加数据加秩,而要回头检查数据质量与格式——大多数「微调无效」的根因是数据而非超参。

对比结果建议固定成一张表,每次微调都填一遍:

对比项基座 + 提示微调模型变化
任务准确率71.2%83.5%+12.3 pt
格式合规率88.0%99.1%+11.1 pt
MMLU(通用)74.273.6-0.6
首字延迟620 ms615 ms-5 ms
单请求成本0.0031 美元0.0030 美元-0.0001

这张表同时回答三个问题:任务上有没有提升、通用能力有没有被破坏、延迟与成本有没有恶化。任何一列不达标,都要先解决再上线。

权衡取舍

方案显存训练速度效果上限适用场景
全参微调极高慢最高大厂、蒸馏、深度定制
LoRA (BF16)中快接近全参显存充足的主流选择
QLoRA (NF4)低中(慢 20% 到 40%)接近全参单卡微调大模型
提示 + RAG无无受限于基座知识型任务、快速迭代

选型顺序建议:先试提示与 RAG;确需微调时默认 LoRA;显存不够时降到 QLoRA;只有当 LoRA 在验证集上明显欠拟合、且团队有多卡资源时,才考虑全参微调。

部署侧还有一次取舍:合并权重适合「一个模型服务一类业务」,推理最快、可量化;多适配器适合「多租户共享基座」,运维简单但多一次低秩计算与显存占用。

常见坑清单

  • 数据格式与推理模板不一致:训练用自定义模板、推理用基座 chat template,模型输出格式混乱。始终用 apply_chat_template 保证两端一致。
  • 对全部 token 计损失:没有掩码 system 与 user 部分,模型学成复读机。用 label = -100 只对 assistant 回复计损失。
  • 学习率照搬全参微调:用 2e-5 训 LoRA,损失几乎不动。LoRA 应取 1e-4 到 3e-4。
  • r 与 α 不成比例调整:只调 r 不调 α,导致更新幅度突变、训练不稳定。固定 α = 2r 可规避。
  • 对 4bit 基座直接合并权重:把 LoRA 增量也压进 4bit,精度双重损失。合并必须在 BF16 上进行。
  • 忽略灾难性遗忘:只测任务指标不测通用能力,上线后通用问答能力崩坏。必须做能力回归。
  • 样本重复未去重:同一问题出现几十次,模型过拟合到该表述。训练前按语义相似度去重。
  • epochs 过多:超过 4 轮后验证集损失回升,模型开始背诵训练集。用早停或固定小轮数。
  • 忘记开梯度检查点:长序列训练激活爆显存。gradient_checkpointing=True 用约 20% 时间换大幅显存下降。
  • 校准/评测数据泄漏:验证集样本混进训练集,评测分数虚高。严格按来源或时间切分。

小结

微调流水线的每一步都有明确的工程约束。判断阶段要分清「知识 vs 行为」,知识问题交给 RAG,行为问题才交给微调。成本阶段要认清全参微调的瓶颈在优化器状态而非权重,7B 就要近百 GB 显存,因此 LoRA 才是多数团队的默认。原理阶段要理解 LoRA 的低秩假设与零初始化设计,以及 α/r 缩放对稳定性的意义。超参阶段记住 r 从 16 起步、α = 2r、目标模块优先覆盖全部线性层。QLoRA 在显存受限时用 NF4 加双重量化把基座压到四分之一,代价是 20% 到 40% 的训练变慢。数据阶段的质量比数量重要,格式一致性是底线。落地阶段把适配器合并成 BF16 稠密权重再走推理量化,或保留适配器做多租户热插拔。

最重要的一条经验是:微调的效果上限由数据决定,而多数「微调没用」的案例根因是数据质量与格式,不是超参。先用小秩、小数据量做一次快速验证,确认方向对了再投入标注与算力,能省下大量返工。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「LLMOps」更多文章

  1. 语义缓存与 Prompt 缓存
  2. 结构化输出与函数调用
  3. 多智能体编排与工作流引擎