监督微调(Supervised Fine-Tuning)是大语言模型对齐过程中的基础环节,其本质是通过指令-回答配对数据,将通用预训练模型转化为特定领域的专业助手。不同于预训练阶段学习通用语言模式,SFT专注于条件概率的优化,使模型能够准确理解并响应人类指令。
SFT的核心数学原理是条件概率的极大似然估计。给定输入指令x(Prompt)和标准回答y(Response),模型需要最大化P(y|x)的概率。具体实现中,我们使用负对数似然损失(NLL Loss)作为优化目标:
code复制L_SFT(θ) = -Σ log P_θ(y_t|y_<t,x)
这个公式有几个关键特性:
在实际代码中,这个目标通过标签掩码(Label Masking)技术实现。我们将Prompt和Response拼接后,将Prompt对应的标签位置设为-100(PyTorch中表示忽略该位置的损失计算),确保梯度仅来自Response部分。
现代SFT实现通常结合以下关键技术:
LoRA(低秩适应):
4-bit量化:
训练流程优化:
过拟合问题:
灾难性遗忘:
以下是一个优化的SFT训练配置示例:
python复制peft_config = LoraConfig(
r=32,
lora_alpha=64,
target_modules=["q_proj","k_proj","v_proj","o_proj","gate_proj"],
lora_dropout=0.1,
task_type="CAUSAL_LM"
)
training_args = TrainingArguments(
per_device_train_batch_size=4,
gradient_accumulation_steps=8,
learning_rate=2e-4,
num_train_epochs=3,
optim="adamw_torch",
logging_steps=10,
save_strategy="steps",
bf16=True,
gradient_checkpointing=True
)
传统RLHF流程存在两大痛点:
DPO(Direct Preference Optimization)通过数学变换,将强化学习问题转化为监督学习问题,其核心创新点包括:
DPO损失函数:
code复制L_DPO = -E[logσ(β(log(π_θ(y_w|x)/π_ref(y_w|x)) - log(π_θ(y_l|x)/π_ref(y_l|x))))]
其中关键组件:
这个损失函数实现了:
一个生产级DPO实现应包含以下组件:
数据准备:
模型配置:
python复制dpo_config = DPOConfig(
beta=0.1,
loss_type="sigmoid",
label_smoothing=0.1,
max_length=1024,
max_prompt_length=512,
gradient_accumulation_steps=4,
per_device_train_batch_size=2
)
peft_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=ALL_LINEAR_LAYERS,
modules_to_save=["embed_tokens","lm_head"]
)
训练技巧:
模式崩溃:
过拟合:
训练不稳定:
入门配置(7B以下模型):
生产配置(70B模型):
核心框架:
辅助工具:
数据准备阶段(1-3天)
SFT阶段(7B模型约8小时)
DPO阶段(7B模型约12小时)
评估阶段
自蒸馏技术:
对抗训练:
注意力层改进:
记忆增强:
通用能力保持阶段:
领域专业化阶段:
安全对齐阶段:
在实际项目中,我们通常会遇到显存不足的问题。这时可以采用以下技巧:
python复制# 梯度检查点技术
model.gradient_checkpointing_enable()
# 8-bit优化器
optimizer = bnb.optim.Adam8bit(model.parameters(), lr=1e-5)
# 梯度累积
training_args = TrainingArguments(
gradient_accumulation_steps=8,
per_device_train_batch_size=1
)
对于对话任务,Prompt工程同样重要。建议采用以下格式:
text复制<|system|>
你是一个乐于助人的AI助手,回答应简洁专业,不超过3句话。
<|user|>
如何学习Python编程?
<|assistant|>
建议从官方教程开始,重点掌握...