AI大模型微调(Fine-tuning)完全教程
本教程全面讲解大语言模型微调的核心技术与实战方法,帮助开发者掌握大模型微调的完整技术栈。
目录
- 微调概述与核心概念
- 参数高效微调方法(PEFT)
- 训练数据准备与清洗
- SFT指令微调
- RLHF与DPO对齐训练
- 主流微调框架对比
- 超参数调优
- 分布式训练
- 评估与监控
- 微调后的模型量化与部署
- 实战案例
- 最佳实践与常见问题
1. 微调概述与核心概念
1.1 什么是大模型微调
大模型微调(Fine-tuning)是在预训练大语言模型的基础上,使用特定领域或任务的数据对模型进行进一步训练,使其适应特定场景的过程。与从零训练相比,微调成本极低且效果显著。
1.2 为什么需要微调
| 场景 | 说明 | 示例 |
|---|---|---|
| 领域适配 | 让模型掌握专业知识 | 医疗、法律、金融 |
| 风格定制 | 调整模型输出风格 | 品牌语气、写作风格 |
| 任务优化 | 提升特定任务表现 | 代码生成、文本分类 |
| 成本降低 | 小模型微调替代大模型 | 7B微调后替代70B通用模型 |
| 数据隐私 | 数据不出本地 | 企业内部敏感数据 |
1.3 微调方法分类
- 全参数微调(Full Fine-tuning):更新所有模型参数,效果最好但成本最高
- 参数高效微调(PEFT):只更新少量参数
- LoRA - 低秩适配
- QLoRA - 量化低秩适配
- Prefix Tuning - 前缀微调
- P-Tuning - 提示微调
- Adapter - 适配器
- 对齐训练
- SFT - 监督微调
- RLHF - 人类反馈强化学习
- DPO - 直接偏好优化
1.4 微调 vs RAG vs Prompt Engineering
| 方法 | 适用场景 | 优势 | 劣势 |
|---|---|---|---|
| Prompt Engineering | 简单任务、快速迭代 | 零成本、即时生效 | 受限于上下文窗口 |
| RAG | 知识密集型任务 | 知识可动态更新 | 检索质量影响大 |
| 微调 | 深度领域适配、风格定制 | 效果最好、推理快 | 需要训练数据和算力 |
2. 参数高效微调方法(PEFT)
2.1 LoRA(Low-Rank Adaptation)
LoRA是目前最流行的参数高效微调方法,核心思想是将权重更新分解为低秩矩阵:W' = W + BA,其中B和A是低秩矩阵,r远小于原始维度。
LoRA的优势:
- 可训练参数量仅为原始模型的0.1%-1%
- 显存需求大幅降低
- 效果接近全参数微调
- 可以保存多个LoRA适配器,按需切换
import torch
import torch.nn as nn
class LoRALayer(nn.Module):
def __init__(self, in_features, out_features, rank=8, alpha=16, dropout=0.1):
super().__init__()
self.rank = rank
self.alpha = alpha
self.scaling = alpha / rank
# 原始权重(冻结)
self.linear = nn.Linear(in_features, out_features, bias=False)
self.linear.weight.requires_grad = False
# LoRA可训练参数
self.lora_A = nn.Parameter(torch.randn(rank, in_features) * 0.01)
self.lora_B = nn.Parameter(torch.zeros(out_features, rank))
self.dropout = nn.Dropout(dropout)
def forward(self, x):
base_output = self.linear(x)
lora_output = (x @ self.lora_A.T @ self.lora_B.T) * self.scaling
return base_output + lora_output
使用PEFT库应用LoRA:
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM
def apply_lora(model_name):
model = AutoModelForCausalLM.from_pretrained(
model_name, torch_dtype=torch.bfloat16, device_map="auto"
)
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
total = sum(p.numel() for p in model.parameters())
print(f"可训练参数: {trainable} / {total} ({100*trainable/total:.2f}%)")
return model
2.2 QLoRA(Quantized LoRA)
QLoRA结合4-bit量化和LoRA,在单张消费级GPU上微调大模型。核心创新包括NF4量化、双重量化和分页优化器。
from transformers import BitsAndBytesConfig
from peft import prepare_model_for_kbit_training
def setup_qlora(model_name):
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True,
)
model = prepare_model_for_kbit_training(model)
return model
显存对比:
- LLaMA-7B 全参数微调: 约60GB (FP16)
- LLaMA-7B LoRA: 约16GB (FP16)
- LLaMA-7B QLoRA: 约6GB (4-bit)
2.3 方法对比
| 方法 | 可训练参数量 | 显存需求 | 效果 | 适用场景 |
|---|---|---|---|---|
| 全参数微调 | 100% | 极高 | 最好 | 大规模数据、充足算力 |
| LoRA | 0.1-1% | 中等 | 接近全参数 | 主流选择 |
| QLoRA | 0.1-1% | 低 | 接近LoRA | 消费级GPU |
| Prefix Tuning | 小于1% | 低 | 略低于LoRA | 生成任务 |
| P-Tuning v2 | 1-3% | 低 | 接近LoRA | 理解任务 |
3. 训练数据准备与清洗
3.1 数据格式
SFT指令微调数据格式(Alpaca格式):
{
"instruction": "请将以下英文翻译成中文",
"input": "Machine learning is a subset of AI.",
"output": "机器学习是人工智能的一个子集。"
}
多轮对话格式(ShareGPT格式):
{
"conversations": [
{"from": "system", "value": "你是一个专业的医疗助手"},
{"from": "human", "value": "感冒的症状有哪些?"},
{"from": "gpt", "value": "感冒的常见症状包括发热、咳嗽、流涕、咽痛等。"}
]
}
DPO偏好数据格式:
{
"prompt": "解释什么是量子计算",
"chosen": "量子计算是利用量子力学原理进行信息处理的计算范式...",
"rejected": "量子计算就是用量子来计算,很厉害。"
}
3.2 数据清洗流程
import re
import json
import hashlib
from typing import List, Dict
class DataPreprocessor:
def __init__(self, min_length=10, max_length=4096):
self.min_length = min_length
self.max_length = max_length
self.seen_hashes = set()
def clean_dataset(self, data: List[Dict]) -> List[Dict]:
cleaned = []
for item in data:
if not self._has_valid_content(item):
continue
if not self._check_length(item):
continue
item_hash = hashlib.md5(
json.dumps(item, ensure_ascii=False, sort_keys=True).encode()
).hexdigest()
if item_hash in self.seen_hashes:
continue
self.seen_hashes.add(item_hash)
if self._assess_quality(item) < 0.5:
continue
cleaned.append(item)
return cleaned
def _has_valid_content(self, item):
for key in ['instruction', 'output', 'chosen', 'value']:
if key in item and isinstance(item[key], str) and len(item[key].strip()) > 0:
return True
return False
def _check_length(self, item):
total_len = sum(len(str(v)) for v in item.values() if isinstance(v, str))
return self.min_length <= total_len <= self.max_length
def _assess_quality(self, item):
score = 0.0
output = item.get('output', item.get('chosen', ''))
if 20 <= len(output) <= 2000:
score += 0.3
if not re.search(r'[\x00-\x08\x0b\x0c\x0e-\x1f]', output):
score += 0.3
if item.get('instruction', '').strip():
score += 0.2
return score
3.3 数据增强策略
- 指令改写:使用LLM将同一条指令用不同方式表达
- 翻译增强:中英互译扩展数据
- 输出多样化:对同一指令生成多种风格的回复
- 负样本构造:构造质量较差的回复用于DPO训练
3.4 数据配比建议
| 数据类型 | 比例 | 说明 |
|---|---|---|
| 指令跟随 | 40% | 通用指令执行能力 |
| 领域知识 | 30% | 专业领域问答 |
| 多轮对话 | 20% | 上下文理解能力 |
| 拒绝回答 | 10% | 安全边界训练 |
4. SFT指令微调
4.1 完整训练流程
from transformers import (
AutoModelForCausalLM, AutoTokenizer,
TrainingArguments, Trainer
)
from peft import LoraConfig, get_peft_model
from datasets import load_dataset
def sft_train(model_name, dataset_path, output_dir,
num_epochs=3, batch_size=4, learning_rate=2e-5):
# 1. 加载模型和分词器
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
device_map="auto",
trust_remote_code=True,
)
# 2. 应用LoRA
lora_config = LoraConfig(
r=16, lora_alpha=32,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
lora_dropout=0.05, bias="none", task_type="CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
# 3. 加载和预处理数据
dataset = load_dataset("json", data_files=dataset_path)
def preprocess(examples):
texts = []
for inst, inp, out in zip(
examples["instruction"],
examples.get("input", [""] * len(examples["instruction"])),
examples["output"]
):
if inp:
text = f"### Instruction:\n{inst}\n\n### Input:\n{inp}\n\n### Response:\n{out}"
else:
text = f"### Instruction:\n{inst}\n\n### Response:\n{out}"
texts.append(text)
tokenized = tokenizer(texts, truncation=True, max_length=2048, padding="max_length")
tokenized["labels"] = tokenized["input_ids"].copy()
return tokenized
tokenized_dataset = dataset.map(
preprocess, batched=True,
remove_columns=dataset["train"].column_names
)
# 4. 训练参数
training_args = TrainingArguments(
output_dir=output_dir,
num_train_epochs=num_epochs,
per_device_train_batch_size=batch_size,
gradient_accumulation_steps=4,
learning_rate=learning_rate,
lr_scheduler_type="cosine",
warmup_ratio=0.1,
weight_decay=0.01,
logging_steps=10,
save_steps=100,
save_total_limit=3,
bf16=True,
gradient_checkpointing=True,
report_to="none",
)
# 5. 开始训练
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset["train"],
tokenizer=tokenizer,
)
trainer.train()
trainer.save_model(output_dir)
tokenizer.save_pretrained(output_dir)
return model, tokenizer
4.2 ChatML格式训练
对于对话模型,推荐使用ChatML格式进行训练。每个对话以system消息开始,然后是多轮user/assistant交替。使用特殊标记来标识消息边界。
5. RLHF与DPO对齐训练
5.1 RLHF流程
RLHF(Reinforcement Learning from Human Feedback)包含三个阶段:
- SFT阶段:使用监督数据微调基础模型
- 奖励模型训练:训练一个模型来评估回复质量
- PPO强化学习:使用奖励模型优化策略模型
# 奖励模型训练
from transformers import AutoModelForSequenceClassification
class RewardModel(nn.Module):
def __init__(self, model_name):
super().__init__()
self.model = AutoModelForSequenceClassification.from_pretrained(
model_name, num_labels=1, torch_dtype=torch.bfloat16
)
def forward(self, input_ids, attention_mask):
outputs = self.model(input_ids=input_ids, attention_mask=attention_mask)
return outputs.logits.squeeze(-1)
def train_reward_model(model, dataset, tokenizer):
"""训练奖励模型"""
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-5)
for batch in dataset:
chosen_scores = model(batch["chosen_ids"], batch["chosen_mask"])
rejected_scores = model(batch["rejected_ids"], batch["rejected_mask"])
# Bradley-Terry损失
loss = -torch.log(torch.sigmoid(chosen_scores - rejected_scores)).mean()
loss.backward()
optimizer.step()
optimizer.zero_grad()
5.2 DPO(Direct Preference Optimization)
DPO是RLHF的简化替代方案,无需训练奖励模型和强化学习:
import torch.nn.functional as F
class DPOTrainer:
def __init__(self, model, ref_model, tokenizer, beta=0.1):
self.model = model
self.ref_model = ref_model
self.tokenizer = tokenizer
self.beta = beta
def dpo_loss(self, chosen_logps, rejected_logps,
ref_chosen_logps, ref_rejected_logps):
"""DPO损失函数"""
chosen_rewards = self.beta * (chosen_logps - ref_chosen_logps)
rejected_rewards = self.beta * (rejected_logps - ref_rejected_logps)
loss = -F.logsigmoid(chosen_rewards - rejected_rewards).mean()
return loss
def compute_logprobs(self, model, input_ids, attention_mask, labels):
"""计算序列的对数概率"""
outputs = model(input_ids=input_ids, attention_mask=attention_mask)
logits = outputs.logits
# 计算每个token的对数概率
log_probs = F.log_softmax(logits, dim=-1)
token_logps = torch.gather(log_probs, 2, labels.unsqueeze(2)).squeeze(2)
# 只计算response部分的损失
return token_logps.sum(dim=-1)
def train_step(self, batch):
"""单步训练"""
chosen_logps = self.compute_logprobs(
self.model, batch["chosen_ids"], batch["chosen_mask"], batch["chosen_labels"]
)
rejected_logps = self.compute_logprobs(
self.model, batch["rejected_ids"], batch["rejected_mask"], batch["rejected_labels"]
)
with torch.no_grad():
ref_chosen_logps = self.compute_logprobs(
self.ref_model, batch["chosen_ids"], batch["chosen_mask"], batch["chosen_labels"]
)
ref_rejected_logps = self.compute_logprobs(
self.ref_model, batch["rejected_ids"], batch["rejected_mask"], batch["rejected_labels"]
)
loss = self.dpo_loss(chosen_logps, rejected_logps, ref_chosen_logps, ref_rejected_logps)
return loss
5.3 SimPO和其他方法
SimPO(Simple Preference Optimization)是DPO的进一步简化版本,使用平均对数概率作为隐式奖励,无需参考模型,训练效率更高。
6. 主流微调框架对比
6.1 框架对比表
| 框架 | 特点 | 支持模型 | 推荐场景 |
|---|---|---|---|
| Hugging Face TRL | 官方维护、生态完善 | 所有HF模型 | 通用微调 |
| LLaMA-Factory | 一站式、WebUI | 主流模型 | 快速上手 |
| Axolotl | 配置驱动、功能丰富 | 多种模型 | 高级用户 |
| Unsloth | 速度优化、显存优化 | 主流模型 | 追求效率 |
| Swift | 阿里开源、中文友好 | 通义千问等 | 中文场景 |
6.2 LLaMA-Factory使用
# config.yaml
model_name_or_path: Qwen/Qwen2.5-7B-Instruct
stage: sft
do_train: true
finetuning_type: lora
lora_rank: 16
lora_alpha: 32
lora_target: all
dataset: alpaca_zh
template: qwen
cutoff_len: 2048
per_device_train_batch_size: 2
gradient_accumulation_steps: 8
num_train_epochs: 3
learning_rate: 2.0e-5
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
output_dir: output/qwen2.5-7b-sft
# 启动训练
llamafactory-cli train config.yaml
# WebUI模式
llamafactory-cli webui
6.3 Unsloth使用
from unsloth import FastLanguageModel
def unsloth_train():
# 加载模型(自动优化)
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="unsloth/Qwen2.5-7B-Instruct-bnb-4bit",
max_seq_length=2048,
dtype=None,
load_in_4bit=True,
)
# 应用LoRA(优化版本)
model = FastLanguageModel.get_peft_model(
model,
r=16,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
lora_alpha=16,
lora_dropout=0,
bias="none",
use_gradient_checkpointing="unsloth",
random_state=3407,
)
# Unsloth训练速度提升2倍,显存减少60%
7. 超参数调优
7.1 关键超参数
| 超参数 | 推荐范围 | 说明 |
|---|---|---|
| Learning Rate | 1e-5 ~ 5e-5 | LoRA可用更高LR |
| LoRA Rank (r) | 8 ~ 64 | 任务越复杂用越高 |
| LoRA Alpha | 通常为rank的2倍 | 缩放系数 |
| Batch Size | 4 ~ 16 | 配合gradient accumulation |
| Epochs | 2 ~ 5 | 数据量大可减少 |
| Warmup Ratio | 0.05 ~ 0.1 | 预热比例 |
| Weight Decay | 0.01 ~ 0.1 | 正则化 |
| Max Seq Length | 512 ~ 4096 | 根据数据长度 |
7.2 调优策略
def hyperparameter_search(model_name, dataset, output_dir):
"""超参数搜索"""
import optuna
def objective(trial):
lr = trial.suggest_float("lr", 1e-5, 5e-5, log=True)
lora_rank = trial.suggest_categorical("lora_rank", [8, 16, 32, 64])
batch_size = trial.suggest_categorical("batch_size", [2, 4, 8])
warmup_ratio = trial.suggest_float("warmup_ratio", 0.05, 0.15)
# 训练并评估
metrics = train_and_evaluate(
model_name, dataset, output_dir,
lr=lr, lora_rank=lora_rank,
batch_size=batch_size, warmup_ratio=warmup_ratio
)
return metrics["eval_loss"]
study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials=20)
print(f"最佳参数: {study.best_params}")
return study.best_params
7.3 学习率调度
from transformers import get_cosine_schedule_with_warmup
def get_scheduler(optimizer, num_training_steps, warmup_ratio=0.1):
num_warmup_steps = int(num_training_steps * warmup_ratio)
return get_cosine_schedule_with_warmup(
optimizer,
num_warmup_steps=num_warmup_steps,
num_training_steps=num_training_steps
)
8. 分布式训练
8.1 DeepSpeed ZeRO
{
"zero_optimization": {
"stage": 2,
"offload_optimizer": {"device": "cpu"},
"offload_param": {"device": "none"},
"overlap_comm": true,
"contiguous_gradients": true
},
"bf16": {"enabled": true},
"train_batch_size": 32,
"train_micro_batch_size_per_gpu": 4,
"gradient_accumulation_steps": 8,
"gradient_clipping": 1.0,
"optimizer": {
"type": "AdamW",
"params": {"lr": 2e-5, "weight_decay": 0.01}
}
}
8.2 多GPU训练
# 使用torchrun启动多GPU训练
torchrun --nproc_per_node=4 train.py \
--model_name Qwen/Qwen2.5-7B-Instruct \
--dataset data/train.json \
--output_dir output/multi-gpu \
--deepspeed ds_config.json
# 使用Accelerate
accelerate launch --multi_gpu train.py
8.3 FSDP训练
from torch.distributed.fsdp import FullyShardedDataParallel as FSDP
def setup_fsdp(model):
return FSDP(
model,
sharding_strategy=ShardingStrategy.FULL_SHARD,
mixed_precision=MixedPrecision(
param_dtype=torch.bfloat16,
reduce_dtype=torch.bfloat16,
buffer_dtype=torch.bfloat16,
),
)
9. 评估与监控
9.1 评估指标
def evaluate_model(model, tokenizer, eval_dataset):
"""模型评估"""
results = {}
# 1. 困惑度(Perplexity)
perplexity = compute_perplexity(model, tokenizer, eval_dataset)
results["perplexity"] = perplexity
# 2. 任务特定指标
accuracy = compute_accuracy(model, tokenizer, eval_dataset)
results["accuracy"] = accuracy
# 3. 生成质量
bleu = compute_bleu(model, tokenizer, eval_dataset)
results["bleu"] = bleu
# 4. 安全性评估
safety_score = evaluate_safety(model, tokenizer)
results["safety_score"] = safety_score
return results
def compute_perplexity(model, tokenizer, dataset):
"""计算困惑度"""
import math
total_loss = 0
total_tokens = 0
for batch in dataset:
inputs = tokenizer(batch["text"], return_tensors="pt", truncation=True)
with torch.no_grad():
outputs = model(**inputs, labels=inputs["input_ids"])
total_loss += outputs.loss.item() * inputs["input_ids"].numel()
total_tokens += inputs["input_ids"].numel()
return math.exp(total_loss / total_tokens)
9.2 训练监控
import wandb
def setup_monitoring(project_name, config):
"""设置训练监控"""
wandb.init(project=project_name, config=config)
# 记录关键指标
wandb.define_metric("train/loss", summary="min")
wandb.define_metric("eval/loss", summary="min")
wandb.define_metric("eval/perplexity", summary="min")
def log_metrics(trainer, step):
"""记录训练指标"""
metrics = {
"train/loss": trainer.state.log_history[-1].get("loss"),
"train/learning_rate": trainer.state.log_history[-1].get("learning_rate"),
"train/epoch": trainer.state.epoch,
}
wandb.log(metrics, step=step)
10. 微调后的模型量化与部署
10.1 模型合并
def merge_lora_to_base(model_name, lora_path, output_path):
"""将LoRA权重合并到基础模型"""
from peft import PeftModel
# 加载基础模型
base_model = AutoModelForCausalLM.from_pretrained(
model_name, torch_dtype=torch.bfloat16, device_map="auto"
)
# 加载LoRA
model = PeftModel.from_pretrained(base_model, lora_path)
# 合并权重
merged_model = model.merge_and_unload()
# 保存
merged_model.save_pretrained(output_path)
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.save_pretrained(output_path)
return merged_model
10.2 量化部署
def quantize_model(model_path, output_path, bits=4):
"""量化模型"""
from transformers import BitsAndBytesConfig
import onnxruntime as ort
if bits == 4:
config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
)
elif bits == 8:
config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained(
model_path, quantization_config=config, device_map="auto"
)
# 使用GPTQ量化(更高效)
from optimum.gptq import GPTQQuantizer
quantizer = GPTQQuantizer(bits=4, dataset="c4", group_size=128)
quantized_model = quantizer.quantize_model(model, tokenizer)
quantized_model.save_pretrained(output_path)
10.3 vLLM部署
from vllm import LLM, SamplingParams
def deploy_with_vllm(model_path):
"""使用vLLM部署微调后的模型"""
llm = LLM(
model=model_path,
tensor_parallel_size=1,
gpu_memory_utilization=0.9,
max_model_len=2048,
)
sampling_params = SamplingParams(
temperature=0.7,
top_p=0.9,
max_tokens=512,
)
# 批量推理
prompts = ["你好,请介绍一下自己。"]
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
print(output.outputs[0].text)
return llm
11. 实战案例
11.1 医疗领域微调
# 步骤1: 准备医疗数据
medical_data = [
{
"instruction": "根据症状诊断可能的疾病",
"input": "患者出现发热、咳嗽、乏力,持续3天",
"output": "根据描述的症状,可能的诊断包括:\n1. 流行性感冒 - 最常见,伴有全身症状\n2. 新冠病毒感染 - 需结合流行病学史\n3. 普通感冒 - 症状相对较轻\n建议进行血常规和病原学检测以明确诊断。"
}
]
# 步骤2: 微调
model, tokenizer = sft_train(
model_name="Qwen/Qwen2.5-7B-Instruct",
dataset_path="medical_data.json",
output_dir="output/medical-7b",
num_epochs=3,
learning_rate=2e-5
)
# 步骤3: 评估
metrics = evaluate_model(model, tokenizer, eval_dataset)
print(f"评估结果: {metrics}")
11.2 代码生成微调
code_data = [
{
"instruction": "编写Python函数实现快速排序",
"input": "",
"output": "def quicksort(arr):\n if len(arr) <= 1:\n return arr\n pivot = arr[len(arr) // 2]\n left = [x for x in arr if x < pivot]\n middle = [x for x in arr if x == pivot]\n right = [x for x in arr if x > pivot]\n return quicksort(left) + middle + quicksort(right)"
}
]
12. 最佳实践与常见问题
12.1 最佳实践
- 数据质量优先:少量高质量数据优于大量低质量数据
- 从小模型开始:先在7B模型上验证,再扩展到更大模型
- 逐步迭代:先SFT,再DPO,逐步提升效果
- 充分评估:训练后在多个维度评估模型
- 版本管理:记录每次训练的配置和数据版本
12.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 过拟合 | 数据量少/训练轮次多 | 增加数据、减少epochs、增加dropout |
| 欠拟合 | 学习率低/模型容量不足 | 增大LR、增大LoRA rank |
| 显存不足 | 模型大/batch大 | 使用QLoRA、gradient checkpointing |
| 训练不稳定 | 学习率过高 | 降低LR、增加warmup |
| 灾难性遗忘 | 偏离原始能力 | 混合通用数据训练 |
12.3 安全注意事项
- 安全对齐:确保微调后的模型不会生成有害内容
- 数据脱敏:训练数据中的敏感信息需要脱敏处理
- 红队测试:在部署前进行安全性测试
- 监控与回滚:部署后持续监控,准备回滚方案
总结
本教程详细讲解了大模型微调的完整技术栈,从LoRA/QLoRA等参数高效方法到SFT/DPO训练流程,再到框架选型和部署实践。
关键要点:
- LoRA/QLoRA是当前最推荐的微调方法
- 数据质量比数量更重要
- 先验证再扩展,逐步迭代
- 做好评估和监控
本教程内容原创,仅供参考学习使用。