0. 系列闭环
| 本篇位置 | 上游 | 本篇产出 | 下游 |
|---|---|---|---|
| 第 5/10 篇 | 第 04 篇环境就绪 | Tokenizer、基座、LoraConfig、Dataset | 第 06 篇 SFTTrainer.train() |
本篇结束时:模型已在 GPU 上,LoRA 配置已定义,数据已是 {"text": ...},但尚未有任何梯度更新。
1. 要解决的实际问题
初学者读训练脚本常卡在:
device_map={"": 0}是什么意思,为什么多卡不能这样写- 为什么
LoraConfig写了还要传给SFTTrainer apply_chat_template两个 boolean 搞反会导致什么
本篇按执行顺序对齐 main() 前四步。
2. 实现位置
| 符号 | 行号(约) | 作用 |
|---|---|---|
parse_args() |
72–79 | --gpu_id |
print_device_info() |
130–144 | 打印有效 batch |
load_jsonl_data() |
102–127 | JSONL → Dataset |
main() Step 1–4 |
156–200 | 本篇范围 |
启动:
1 | |
3. 配置区:改动影响面
1 | |
| 改动 | 影响 |
|---|---|
BATCH_SIZE / GRADIENT_ACCUMULATION_STEPS |
显存、有效 batch、总 step 数 |
MAX_SEQ_LEN |
显存线性相关、长对话截断 |
EPOCHS |
过拟合风险、训练时间 |
LORA_* |
adapter 体积与表达能力 |
4. Step 1:Tokenizer
1 | |
4.1 为什么 padding_side=”right”
因果语言模型训练:序列从左到右预测 next token。padding 在右侧,左侧有效内容对齐,mask 才正确。放左侧会把 pad 当成前文,污染 loss。
4.2 pad_token = eos_token
Qwen 系列常无独立 pad。Trainer 组 batch 时需要 pad_token_id;复用 eos 是常规做法,与日志里 pad_token_id: 248046 一致。
4.3 与 verify 的关系
verify_lora.py 第 97–98 行同样 from_pretrained(BASE_MODEL, trust_remote_code=True),不要验证时用另一套 tokenizer 路径。
5. Step 2:基座模型与 device_map
1 | |
5.1 device_map={“”: 0} 语义
HuggingFace Accelerate 语法:键 "" 表示「所有未单独指定的模块」,值 0 为 GPU id。即整模上单卡。
日志对照(all_logs.log 第 15–16 行):
1 | |
5.2 dtype=bfloat16
权重以 bf16 加载,配合 Step 6 的 SFTConfig(bf16=True) 做 autocast 训练。V100 支持;若 GPU 不支持 bf16,需改 fp16 并实测数值稳定。
5.3 此时尚未注入 LoRA
print_trainable_parameters() 若在 Step 6 之前调用,应接近 0% trainable。若已很高,说明误调了 get_peft_model。
6. Step 3:LoraConfig(仅定义)
1 | |
日志在 Step 3 后打印 正在配置 LoRA...,随后加载数据——PEFT 注入发生在 Step 6 构造 Trainer 时。
错误示例:
1 | |
7. Step 4:load_jsonl_data
完整逻辑见第 02 篇。要点复述:
1 | |
加载日志(all_logs.log 第 31 行):
1 | |
之后 TRL 会:
Adding EOS to train datasetTokenizing train datasetwithmax_length=512
TrainingProgressCallback
第 82–99 行定义回调,Step 6 传入。在 logging_steps=1 时逐步打印 loss——all_logs.log 里 [进度 xx%] Step ... 来自此回调的 on_log。
8. 踩坑
坑 1:MPS 上训练 Qwen3.5-4B + LoRA
脚本虽写了 mps 分支,4B 在 Mac 上训练极慢且易 OOM。建议 Mac 只跑 verify,训练用云 GPU。
坑 2:DATA_PATH 相对路径
必须在项目根目录执行 python train_lora_single.py,否则 ./data/... 找不到。
坑 3:空行 JSONLload_jsonl_data 会 skip 空行;若大量空行,len(dataset) 小于文件行数,与预期 1000 不符。
坑 4:修改 MAX_SEQ_LEN 忘记重新估显存
512 → 1024 约翻倍激活显存,V100 上 batch=2 可能 OOM。
9. 小结
- Step 1:Tokenizer,右 padding,pad=eos。
- Step 2:整模上单卡
device_map={"": gpu_id},bf16 加载。 - Step 3:只定义
LoraConfig,不手动 get_peft_model。 - Step 4:messages → chat_template →
Dataset(text=...)。 - 下一步 SFTTrainer 才注入 LoRA 并开训(第 06 篇)。
附录:main() 前四步调用链
1 | |
系列导航
| 篇目 | 链接 |
|---|---|
| 上一篇 | 04 · 环境搭建 |
| 下一篇 | 06 · SFT 实战(下) |
| 索引 | README |