1. 问题定位与核心逻辑
在训练145M参数的MoE模型时,我们遇到了SFT(监督微调)阶段模型输出"胡言乱语"的问题。经过深入分析,这主要源于三个关键因素:
-
学习率设置不当:原1e-6的学习率对于145M小模型来说过低,导致模型参数更新不足,无法有效学习指令跟随能力。
-
数据量比例失调:6.8M的SFT数据量占预训练数据28.8M的23.6%,远超过推荐的1%-5%比例,造成严重的灾难性遗忘。
-
推理格式不匹配:未严格遵循训练时的prompt模板格式,导致模型无法正确理解输入意图。
关键判断依据:如果预训练失败,模型会表现为基本语法错误;而当前"答非所问"的表现正是典型的SFT失败特征。
2. 技术方案与实施细节
2.1 数据准备优化
数据采样策略
- 从原6.8M数据中随机抽取100k-200k条高质量对话样本
- 使用分层抽样确保各主题分布均衡
- 示例采样代码:
python复制import json
import random
def sample_sft_data(input_file, output_file, sample_size=100000):
with open(input_file, 'r') as f:
lines = f.readlines()
sampled = random.sample(lines, min(sample_size, len(lines)))
with open(output_file, 'w') as f:
f.writelines(sampled)
sample_sft_data('sft_512.jsonl', 'sft_100k_sampled.jsonl')
数据质量检查
- 去除包含特殊字符或乱码的样本
- 确保问答对完整性(包含
和 标记) - 检查重复样本比例不超过5%
2.2 训练参数调整
关键参数配置
| 参数 | 原值 | 调整后 | 理论依据 |
|---|---|---|---|
| 学习率 | 1e-6 | 2e-5 | 小模型需要更大学习率 |
| batch_size | 32 | 64 | 充分利用8x4090显存 |
| epochs | 3 | 1-2 | 防止小数据过拟合 |
| max_seq_len | 512 | 512 | 与预训练保持一致 |
完整训练命令
bash复制torchrun --nproc_per_node 8 train_full_sft.py \
--use_moe 1 \
--batch_size 64 \
--learning_rate 2e-5 \
--hidden_size 640 \
--num_hidden_layers 8 \
--max_seq_len 512 \
--data_path ../dataset/sft_100k_sampled.jsonl \
--epochs 1 \
--save_dir ../out_sft_fix \
--save_interval 1000 \
--log_interval 100
2.3 推理流程规范
正确prompt构建方法
python复制def build_prompt(user_input):
# 训练数据格式:<User>问题<Assistant>回答<EOS>
return f"<User>{user_input}<Assistant>"
# 错误示例(缺少Assistant标记):
# prompt = "美国总统是谁"
# 正确示例:
prompt = build_prompt("美国总统是谁")
推理参数建议
- temperature: 0.7-1.0
- top_p: 0.9
- max_new_tokens: 512
- 禁止在输入结尾添加
3. 效果验证与问题排查
3.1 成功指标
- 基础语法:输出通顺的中文句子
- 指令跟随:能正确理解并回答提问
- 多样性:不同输入得到差异化输出
- Loss曲线:训练loss稳定下降至3.0-3.5
3.2 常见问题诊断
问题现象:重复输出
- 可能原因:
- 学习率仍偏低
- 数据多样性不足
- 温度参数过低
- 解决方案:
- 尝试将lr提高到3e-5
- 检查数据采样分布
- 调整temperature=1.0
问题现象:输出乱码
- 排查步骤:
- 检查tokenizer是否匹配
- 验证输入是否超出max_seq_len
- 确认模型权重加载正确
3.3 预训练质量检查
当出现以下情况时需重做预训练:
- 基础语法错误(非逻辑问题)
- 连续输出[UNK]标记
- Loss无法降至4.0以下
预训练参数建议
bash复制torchrun --nproc_per_node 8 train_pretrain.py \
--use_moe 0 \ # 建议先用Dense
--batch_size 128 \
--learning_rate 5e-4 \
--hidden_size 640 \
--num_hidden_layers 8 \
--max_seq_len 512 \
--data_path ../dataset/pretrain_1.41m.jsonl \ # 小数据集快速验证
--epochs 1 \
--save_dir ../out_pretrain_rescue
4. 进阶建议与路线规划
4.1 短期目标(1-2周)
- 完成Dense模型全流程(Pretrain→SFT→DPO)
- 建立baseline评估指标
- 整理可演示的案例库
4.2 中期优化(3-4周)
- 引入LoRA/P-Tuning等高效微调
- 实现gradient checkpointing节省显存
- 添加wandb监控训练指标
4.3 长期发展
- 待Dense稳定后,再开启MoE分支研究
- 对比分析不同架构的优劣
- 撰写技术博客记录实验发现
5. 工程实践建议
- 版本控制:为每个实验阶段创建独立git分支
- 日志记录:详细记录每次实验的超参数
- 增量测试:先在小数据子集(1k样本)验证流程
- 可视化监控:实时查看loss/accuracy曲线
示例实验记录表:
| 实验ID | 模型类型 | 数据量 | 学习率 | 最佳loss | 主要现象 |
|---|---|---|---|---|---|
| exp001 | MoE | 100k | 2e-5 | 3.2 | 能基本对话 |
| exp002 | Dense | 100k | 3e-5 | 2.9 | 回答更流畅 |
在实际操作中,我发现两个关键经验:
- 小模型需要"大胆"的学习率(1e-4量级)
- 数据质量比数量重要得多,人工检查100条样本往往能发现系统性数据问题
