本文从 大模型应用开发技术路线清单 中拆分,聚焦”四、模型微调 Fine-tuning”部分。当 Prompt + RAG 都不够时,用自有数据训练模型。
什么时候需要微调?
微调不是万能的。在决定微调之前,先走完这条决策链:
1 2 3 4 5 6 7 8 9
| 用户需求 → 能用 Prompt 解决吗? │ ├── 能 → 结束(Prompt Engineering) │ └── 不能 → 能用 RAG 解决吗? │ ├── 能 → 结束(RAG) │ └── 不能 → 考虑微调
|
| 场景 |
是否需要微调 |
原因 |
| 通用问答、内容生成 |
❌ Prompt 就够 |
通用能力已经足够 |
| 特定领域知识问答 |
⚠️ 先试 RAG |
知识可以通过检索注入 |
| 特定风格/格式输出 |
✅ 微调效果更好 |
风格难以通过 Prompt 精确控制 |
| 领域术语理解(医疗/法律) |
✅ 微调提升显著 |
需要深层语义理解 |
| 低延迟 / 边缘部署 |
✅ 微调小模型 |
大模型太慢太贵 |
一、微调技术栈
1.1 SFT(监督微调)
SFT 是最基础的微调方式,用指令-回答对训练模型学会”听指令”。
数据格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| { "instruction": "将以下文本翻译成英文", "input": "今天天气真好", "output": "The weather is really nice today" }
{ "conversations": [ {"from": "human", "value": "什么是 Python?"}, {"from": "gpt", "value": "Python 是一种高级编程语言..."}, {"from": "human", "value": "它有什么优点?"}, {"from": "gpt", "value": "Python 的优点包括..."} ] }
|
1.2 LoRA / QLoRA
LoRA(Low-Rank Adaptation)是微调技术的核心突破——只训练少量参数,效果接近全量微调。
核心思想:原始权重矩阵 W 不动,只训练两个小矩阵 A 和 B,让 ΔW = A × B。
1 2 3
| 原始模型:70B 参数 → 全量微调需要 70B × 4 = 280GB 显存 LoRA: 只训练 0.1% 参数 → 显存需求降低到 ~30GB QLoRA: 量化 + LoRA → 显存需求降低到 ~16GB(单卡 4090 可跑)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from peft import LoraConfig, get_peft_model, TaskType
lora_config = LoraConfig( task_type=TaskType.CAUSAL_LM, r=8, lora_alpha=32, lora_dropout=0.1, target_modules=["q_proj", "v_proj", "k_proj", "o_proj"], )
model = get_peft_model(base_model, lora_config) model.print_trainable_parameters()
|
LoRA 关键参数:
| 参数 |
含义 |
推荐值 |
| r |
LoRA 秩,决定可训练参数量 |
8-64(越大越强越慢) |
| lora_alpha |
缩放因子 |
通常 = r × 2 或 r × 4 |
| target_modules |
对哪些层做 LoRA |
q_proj, v_proj, k_proj, o_proj |
| lora_dropout |
防过拟合 |
0.05-0.1 |
1.3 DPO / GRPO(偏好对齐)
DPO(Direct Preference Optimization)直接用偏好数据优化模型,不需要训练 Reward Model。
1 2 3 4 5 6
| { "prompt": "解释量子计算", "chosen": "量子计算利用量子比特的叠加和纠缠特性...", "rejected": "量子计算就是更快的计算机..." }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| from trl import DPOTrainer, DPOConfig
dpo_config = DPOConfig( output_dir="./dpo-model", per_device_train_batch_size=2, learning_rate=5e-7, num_train_epochs=3, beta=0.1, )
trainer = DPOTrainer( model=model, ref_model=ref_model, train_dataset=pref_dataset, tokenizer=tokenizer, args=dpo_config, ) trainer.train()
|
RLHF vs DPO vs GRPO 对比:
| 方法 |
需要 Reward Model |
稳定性 |
复杂度 |
代表 |
| RLHF |
✅ |
中 |
高 |
ChatGPT |
| DPO |
❌ |
高 |
中 |
Zephyr |
| GRPO |
❌ |
高 |
中 |
DeepSeek-R1 |
二、微调数据工程
数据质量 > 数据数量。Garbage In, Garbage Out。
2.1 数据收集策略
| 数据来源 |
优点 |
缺点 |
| 公开数据集 |
质量有保障,即用 |
不够垂直 |
| 业务数据 |
最贴合需求 |
需要清洗和脱敏 |
| 合成数据 |
可大规模生成 |
可能有模式偏差 |
2.2 数据清洗核心流程
1
| 原始数据 → 去重 → 去噪 → 格式标准化 → 质量过滤 → 输出
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import hashlib import json
def clean_dataset(data): """数据清洗流程""" seen = set() unique_data = [] for item in data: key = hashlib.md5( (item["instruction"] + item["output"]).encode() ).hexdigest() if key not in seen: seen.add(key) unique_data.append(item) filtered = [ item for item in unique_data if 20 < len(item["output"]) < 4000 ] filtered = [ item for item in filtered if not contains_harmful_content(item["output"]) ] print(f"清洗:{len(data)} → {len(unique_data)} → {len(filtered)}") return filtered
|
2.3 合成数据生成
用强模型(GPT-4)生成训练数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| def generate_synthetic_data(topic, n=100): """用 GPT-4 生成训练数据""" prompt = f""" 请针对"{topic}"主题,生成 {n} 条高质量的指令-回答对。 格式(JSON 数组): [ {{ "instruction": "具体问题或指令", "input": "补充输入(可选)", "output": "高质量的回答" }} ] 要求: 1. 指令多样化(问答、总结、分析、翻译等) 2. 回答专业、准确、详细 3. 覆盖该主题的不同方面 """ response = client.chat.completions.create( model="gpt-4", messages=[{"role": "user", "content": prompt}], response_format={"type": "json_object"}, ) return json.loads(response.choices[0].message.content)
|
三、工具链
3.1 主流微调框架对比
| 框架 |
特点 |
适用场景 |
| Axolotl |
YAML 配置驱动,上手快 |
快速实验,多种方法对比 |
| Unsloth |
2-5x 加速,显存更低 |
显存有限,追求效率 |
| LLaMA-Factory |
中文社区活跃,Web UI |
中文模型,低代码微调 |
| Hugging Face TRL |
官方库,RLHF/DPO/GRPO |
需要偏好对齐 |
| vLLM |
高性能推理 |
微调后部署 |
3.2 Axolotl 快速上手
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| base_model: Qwen/Qwen2.5-7B model_type: AutoModelForCausalLM tokenizer_type: AutoTokenizer
load_in_4bit: true adapter: qlora lora_r: 16 lora_alpha: 32 lora_target_modules: - q_proj - v_proj - k_proj - o_proj
dataset: - path: data/train.json type: alpaca
sequence_len: 512 sample_packing: true
micro_batch_size: 2 gradient_accumulation_steps: 4 num_epochs: 3 learning_rate: 2e-5 lr_scheduler: cosine warmup_steps: 100
output_dir: ./output/qwen-7b-sft
|
1 2
| accelerate launch -m axolotl.cli.train config.yaml
|
3.3 Unsloth 极速微调
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| from unsloth import FastLanguageModel
model, tokenizer = FastLanguageModel.from_pretrained( model_name="Qwen/Qwen2.5-7B", max_seq_length=2048, load_in_4bit=True, )
model = FastLanguageModel.get_peft_model( model, r=16, target_modules=["q_proj", "k_proj", "v_proj", "o_proj"], lora_alpha=16, use_gradient_checkpointing="unsloth", )
trainer = SFTTrainer( model=model, train_dataset=dataset, max_seq_length=2048, args=TrainingArguments( per_device_train_batch_size=2, num_train_epochs=3, learning_rate=2e-4, ), ) trainer.train()
|
四、模型蒸馏
用大模型(教师)指导小模型(学生)学习:
1 2 3
| 教师模型(GPT-4 / 72B)→ 生成高质量数据/软标签 → 训练学生模型(7B)
效果:7B 模型在特定任务上接近 72B 模型
|
| 蒸馏方法 |
说明 |
复杂度 |
| 数据蒸馏 |
用教师模型生成数据训练学生 |
低(最常用) |
| Logit 蒸馏 |
对齐教师和学生的输出概率分布 |
中 |
| 特征蒸馏 |
对齐中间层的特征表示 |
高 |
1 2 3 4 5 6 7 8 9 10 11
| def distill_data(teacher_model, questions): """用教师模型生成训练数据""" distilled_data = [] for q in questions: answer = teacher_model.generate(q) distilled_data.append({"instruction": q, "output": answer}) return distilled_data
student_model = train_sft(student_model, distilled_data)
|
五、学习建议
- 如果你主要做应用层,微调可以先跳过。但至少要了解 LoRA 的原理和适用场景
- 微调的收益递减曲线很陡:数据质量 > 数据数量 > 模型大小 > 训练技巧
- 先把 Prompt + RAG 做到极致,再考虑微调
上一篇:三、Agent 智能体
下一篇:五、模型推理与部署
返回导航:大模型应用开发技术路线清单