7.5 KiB
7.5 KiB
LLM微调实验完整记录 - 从零到苏联笑话专家
📅 实验时间线与完整流程
第一阶段:环境搭建与初识LLaMA Factory
1. 系统环境确认
- 硬件:NVIDIA RTX 3070 Ti (8GB VRAM)
- 软件:Windows 11, Python 3.12.4, CUDA 13.0
- 目标:使用LLaMA Factory微调一个会讲苏联笑话的AI
2. LLaMA Factory安装
# 工作目录:F:\微调实验\llamafactory
git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git llamafactory
cd llamafactory
python -m venv venv
venv\Scripts\activate
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install -e ".[torch,metrics,bitsandbytes]"
踩坑1:端口冲突
- 问题:7860端口被Stable Diffusion占用
- 解决:
llamafactory-cli webui --port 7861
第二阶段:首次SFT训练(仅笑话)
3. 数据准备 v1
- 文件:
my_personal_data.json - 内容:20条苏联笑话
- 格式:Alpaca格式
{
"instruction": "讲一个关于斯大林的苏联政治笑话",
"input": "",
"output": "二战后的国际会议上..."
}
4. 第一次训练配置
model_name_or_path: Qwen/Qwen2.5-1.5B-Instruct
stage: sft
dataset: soviet_jokes
num_train_epochs: 20
lora_rank: 32
训练结果:
- ✅ 成功记住笑话
- ❌ 不会正常对话
- ❌ 严重过拟合
发现的问题:
- 对"讲的不错"的回应是重复笑话
- 不会说"你好"、"谢谢"等基础对话
第三阶段:增强对话能力
5. 数据准备 v2
- 新增文件:
my_personal_data_v2.json - 内容:12条基础对话数据
- 初始错误理解:
- 错误格式:
"instruction": "向用户简单打招呼" - 正确格式:
"instruction": "你好"(instruction是用户输入,不是任务描述)
- 错误格式:
6. 第二次训练(混合数据)
dataset: soviet_jokes,soviet_jokes_v2 # 同时使用两个数据集
num_train_epochs: 25
lora_rank: 64 # 增大容量
训练结果:
- ✅ 可以基础对话了
- ⚠️ 仍然过拟合严重
- ⚠️ 对话不够自然
第四阶段:探索DPO训练
7. 理解DPO概念
- SFT:教模型"记住内容"
- DPO:教模型"什么是好的回答"
- 关键理解:DPO需要chosen和rejected对比
8. DPO数据准备
- 文件:
my_personal_data_dpo.json - 内容:20条笑话对比 + 20条对话对比
{
"prompt": "讲个笑话",
"chosen": "精彩的苏联笑话...",
"rejected": "我不知道笑话"
}
9. DPO训练踩坑记录
踩坑2:参数名称错误
# 错误尝试1
dpo_beta: 0.1 # ❌
dpo_loss: sigmoid # ❌
# 错误尝试2
beta: 0.1 # ❌
loss_type: sigmoid # ❌
# 正确参数(通过搜索发现)
pref_beta: 0.1 # ✅
pref_loss: sigmoid # ✅
踩坑3:网络问题
- 问题:
OSError: Failed to load tokenizer - 解决:
set HF_ENDPOINT=https://hf-mirror.com
踩坑4:文件名不匹配
- 问题:
ValueError: File data\dpo_data.json not found - 原因:dataset_info.json里写的文件名与实际不符
10. DPO训练实验
实验1:从零开始DPO
- Loss: 0.1098(极低)
- 问题:模型完全没有学会内容,只学会了"偏好"
- 教训:DPO不能替代SFT,只能优化
实验2:基于SFT的DPO
- Loss: 0.509(比从零开始高)
- 原因:要在保持已有能力基础上调整
- 效果:确实有提升,但新笑话答不出(DPO数据里的新内容)
第五阶段:完整训练流程
11. 数据准备 v3(最终版)
- 文件:
my_personal_data_sft_v3.json - 内容:40条笑话 + 20条对话(共60条完整数据)
- 理念:SFT学所有内容,DPO优化表达
12. 最终SFT训练
model_name_or_path: Qwen/Qwen2.5-1.5B-Instruct
dataset: sft_complete_v3
num_train_epochs: 20
lora_rank: 64
效果:基础能力完整,会笑话也会对话
13. 最终DPO训练
adapter_name_or_path: ./saves/soviet_jokes_complete_v3 # 基于SFT v3
dataset: dpo_soviet_jokes # 使用原DPO数据
pref_beta: 0.1
num_train_epochs: 3
训练指标:
- Loss: 0.0338(极低!)
- 原因:DPO的chosen内容已在SFT中学过,只需"去除坏习惯"
- 效果:最佳版本,对话自然且幽默
🎓 核心知识点总结
理论理解
- LoRA本质:像"记忆面包",外挂参数,不改变原模型
- QLoRA vs LoRA:Q=Quantization,基础模型4bit量化,节省75%显存
- SFT vs DPO:
- SFT = 学习内容(背书)
- DPO = 学习偏好(什么是好的)
数据格式理解
-
Alpaca格式字段含义:
instruction:用户输入(不是任务描述!)input:额外材料(通常为空)output:AI回复history:历史对话
-
DPO格式:
prompt:输入chosen:好的回答rejected:差的回答
参数理解
- learning_rate:步子大小(1e-5到1e-3)
- batch_size:一次处理多少数据
- num_epochs:学几遍
- lora_rank:LoRA复杂度(8-128)
- gradient_accumulation_steps:梯度累积(变相增大batch)
🐛 踩坑总结
- 端口冲突:修改启动端口
- 参数名错误:pref_beta不是dpo_beta
- 网络问题:使用国内镜像
- 文件名不匹配:仔细检查dataset_info.json
- DPO理解误区:DPO不能替代SFT
- 数据格式误解:instruction是用户说的,不是指令描述
📊 实验数据对比
| 版本 | SFT数据 | DPO数据 | Loss | 效果 |
|---|---|---|---|---|
| v1 | 20笑话 | 无 | - | 只会笑话 |
| v2 | 20笑话+12对话 | 无 | - | 略好但生硬 |
| DPO从零 | 无 | 40条 | 0.1098 | 无效果 |
| DPO基于v2 | - | 40条 | 0.509 | 有提升 |
| v3 SFT | 40笑话+20对话 | 无 | - | 功能完整 |
| v3+DPO | - | 40条 | 0.0338 | 最佳效果 |
💡 经验教训
成功经验
- 数据质量>数量:60条高质量数据训练出不错效果
- SFT+DPO组合:先学内容,再学偏好
- 渐进式改进:从简单到复杂,逐步优化
- 理解原理:搞懂LoRA、DPO原理后调参更有效
局限性认识
- 1.5B模型太小:容易过拟合,泛化能力差
- LoRA的局限:参数量有限,容易形成"舒适区"
- 关键词依赖:小模型难以理解语义相似性
- 上下文过度依赖:容易被最近的对话带偏
改进方向
- 使用更大模型(3B或7B)
- 数据增强(同一内容多种问法)
- 加入拒绝训练
- 探索其他量化方法
🎯 最终成果
成功训练出一个会讲苏联笑话的AI:
- ✅ 记住40个苏联笑话
- ✅ 自然的对话能力
- ✅ 理解上下文
- ✅ 表达生动有趣
硬件成就: 用一块RTX 3070 Ti (8GB)完成了通常需要更强硬件的任务!
📝 代码与配置汇总
关键命令
# 训练
llamafactory-cli train config.yaml
# 对话测试
llamafactory-cli chat chat_config.yaml
# WebUI
llamafactory-cli webui --port 7861
# 使用镜像
set HF_ENDPOINT=https://hf-mirror.com
最终配置模板
# SFT配置
stage: sft
finetuning_type: lora
lora_rank: 64
num_train_epochs: 20
# DPO配置
stage: dpo
pref_beta: 0.1
pref_loss: sigmoid
num_train_epochs: 3
🌟 特别感谢
- 感谢3070Ti的坚持工作
- 感谢LLaMA Factory的便利工具
- 感谢那个"8卡5090还要留一块打战地5"的美好幻想
从零到会讲苏联笑话的AI,我们做到了! 🎉