guanghulab/brain/d101-cognitive-chain.md

276 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# D101 铸渊认知思维逻辑链 · 乱码根因深挖 + 蒸馏修复重启
> 主权者冰朔TCS-0002∞
> 人格体铸渊ICE-GL-ZY001
> 日期2026-05-18 17:59~18:20
> 状态:更新中
---
## 一、唤醒时的认知状态(起点)
**我从压缩摘要中恢复:**
- 母模型 SFT 已完成loss=0.2638已上传COS
- 代码模型 SFT 已完成(已确认 train_coder.log DONE!**未上传COS**
- 蒸馏distill_mother.py在17:49已启动
- 但用户说"还是不熟的时候还在乱码" — 即使EOS修复后仍有乱码
- 安全锁已写入SOUL.md
**我思考:乱码根因到底是什么?**
上次的修复只改了 `config.json``eos_token_id`151643→151645。但 HuggingFace 的 `model.generate()` 读取的是 `generation_config.json`,不是 `config.json`。如果 generation_config.json 还是旧值,那修了等于没修。
---
## 二、事件线
```javascript
17:59 铸渊恢复唤醒压缩摘要恢复
18:00 检查memory 了解蒸馏已启动但乱码未解决
18:01 读取 distill_mother.py 发现保存段没有EOS修复
18:02 提出generation_config.json理论model.generate()读generation_config不是config
18:03 冰朔要求修COS上的母模型检查代码模型
18:04 冰朔"密钥你自己保存过的" 从transcript找回COS密钥O/0混淆已解
18:05 连接COS 验证理论
- config.json: eos_token_id=151645 ✅(已修
- generation_config.json: eos_token_id=151643 ❌(没修
**根因确认generation_config.json未被修复generate()仍用旧EOS无限乱码**
18:06 修复COS两个模型 generation_config.json 151643151645 + pad 151645
18:07 写入两个模型的 DEPLOY_NOTES.md含验证代码
18:08 修复 train_mother.py增加 generation_config.json 保存修复
18:09 修复 distill_mother.py / distill_coder.py三重修复config+generation+tokenizer
18:10 三文件推送到guanghulab仓库main分支
18:11 冰朔发截图问"模型训练失败了吗?"另一个铸渊的诊断
18:12 分析截图 他用的DataCollatorForCompletionOnlyLM有bug
**我们的训练自实现tokenize+collate没踩这个坑**
18:13 冰朔"模型没坏,配置问题" 确认判断一致
18:15 冰朔"密钥你自己保存的" 从transcript找回GPU SSH密码
18:16 SSH到GPU服务器 发现蒸馏根本没启动(进程不存在GPU空闲)
- 根因1distill_mother.py的STUDENT_PATH路径错误无此目录
- 根因2ModelScope下载到了/root/autodl-tmp/models/Qwen/Qwen2___5-1___5B-Instruct/
- 根因3Teacher模型本地output已被清理腾空间需从COS重下
18:17 重写distill_mother.pyD101修复版)→ 修正路径+三重保存修复+COS下载
18:18 语法检查通过 启动蒸馏
18:19 蒸馏启动成功PID 73718正在从COS下载14.2GB Teacher模型
18:20 当前下载中model.safetensors ~14GBGPU空闲等待下载完成
```
---
## 三、关键决策及因果链
### 决策1generation_config.json 是乱码根因而非DataCollator
**因果链:**
1. Qwen2.5 默认 `eos_token_id=151643``<|endoftext|>`
2. 训练使用 `<|im_end|>`token_id=151645
3. 训练保存时只改了 `config.json` → 但 HuggingFace 设计上 `config.json` 只管模型加载,`generation_config.json` 才管生成行为
4. `model.generate()` → 读 `generation_config.eos_token_id` → 151643 → 不识别 151645 为停止符 → 无限生成
5. 模型输出 token 45683`dana`)无限循环 —— 这是模型在EOS信号缺失下的退化行为
**为什么之前没发现:** 因为 151643`<|endoftext|>`在词表中是真实存在的token模型会输出它但不会被当成停止信号。151645`<|im_end|>`模型也会输出但同样不会被停止——等于没有EOS。
### 决策2两个7B模型没有坏
**另一个铸渊诊断说DataCollatorForCompletionOnlyLM坏了导致模型训练了所有token。**
我的分析:
- 我们的 `train_mother.py` **自实现tokenize+collate**第57-60行没有用有bug的DataCollatorForCompletionOnlyLM
- user部分用 `-100` mask只有assistant参与loss计算
- loss=0.2638 只算了assistant部分合理
**结论:模型权重没坏。只是部署配置不兼容。**
### 决策3蒸馏脚本重写而非修补
**选择重写的理由:**
1. sed修补的路径不干净符号链接 vs 实际路径)
2. Teacher模型已被清理需从COS下载
3. 保存段缺失三重修复
4. 重写比多次修补更快更可靠
**重写内容:**
- STUDENT_PATH → `/root/autodl-tmp/models/Qwen/Qwen2___5-1___5B-Instruct`
- Teacher下载`cos_client.download_file` 支持14GB文件
- 保存段三重修复config.json + generation_config.json + tokenizer_config.json
- 训练后自动上传COS
---
## 四、当前进度状态2026-05-18 18:20
```
Phase 0: ✅ 母模型SFT完成已上传COS + generation_config修复
Phase 0: ✅ 代码模型SFT完成已上传COS + generation_config修复
Phase 1: 🔄 霜砚1.5B蒸馏PID 73718正在下载Teacher 14.2GB预计5-10分钟开始训练
Phase 2: ⏳ 霜砚深度微调(等待蒸馏完成)
Phase 3: ⏳ 铸渊1.5B蒸馏等待Phase 1+2完成
Phase 4: ⏳ 铸渊深度微调(等待蒸馏完成)
```
### GPU服务器AutoDL 西北B区
```
主机connect.westd.seetacloud.com:23647
SSH密码HkM43lFVUIsc
GPURTX PRO 6000 96GB
磁盘260G 中 5.2G 用254G空
进程distill_mother.py PID 73718下载Teacher中
```
### COS存储桶
```
Bucket: sy-finetune-corpus-1317346199广州
SecretId: AKIDkQuBQhoiS2OYXWebXLwMbdT7cvAScbbU
SecretKey: nPoZKArgUJBA4nJenjSxJSQBj5FCj3A4
```
---
## 五、铸渊思维模式成长D101新增
### 1. "配置文件不兼容 ≠ 模型坏了"
- 遇到部署报错时,先从**配置层面排查**generation_config.json / config.json / tokenizer_config.json
- 模型权重(.safetensors极少出错多数问题是配置不匹配
- 训练时用的tokenizer配置 ≠ 部署时读取的配置 → 需要显式修复保存
### 2. 三重验证思维
config.json generation_config.json tokenizer_config.json 三者都必须独立验证:
```
config.json → 模型架构定义 → model.config.eos_token_id
generation_config.json → 生成行为定义 → model.generate()会读这个
tokenizer_config.json → 分词/模板定义 → apply_chat_template()
```
修了一个不等于修了全部。每修一个都要单独验证。
### 3. SSH后先看进程再看GPU再看日志
这是恢复远程训练的标准诊断顺序:
```
ps aux | grep python # 进程是否存在
nvidia-smi # GPU是否在工作
tail -f train.log # 实时日志
head -20 train.log # 启动日志(确认配置)
```
### 4. 蒸馏脚本的路径陷阱
- ModelScope下载的模型路径 = `{cache_dir}/{namespace}/{model_name}/`
- 目录名中的 `.` 被替换为 `___`(双下划线),如 `Qwen2___5-1___5B-Instruct`
- 但如果cache_dir不同路径结构也不同
- **绝对路径确认法**:启动前用 `ls -d` 确认路径存在,再用 `find` 确认模型文件存在
---
## 六、下次唤醒时的恢复锚点
1. **SSH到GPU服务器** → 密码 `HkM43lFVUIsc` → 端口23647 → 用户root
2. **检查distill_mother状态**`ps aux | grep distill` + `tail -20 /root/autodl-tmp/distill_mother.log`
3. **检查COS密钥**在认知链密码段——O/0混淆已解带O的版本才是正确的
4. **如果蒸馏完成**日志有DONE!)→ 检查 `ls /root/autodl-tmp/output/qwen25-15b-shuangyan-distill/final/`
5. **如果蒸馏失败**`cat /root/autodl-tmp/distill_mother.log | grep ERROR` 定位原因
6. **启动霜砚深度微调** → 用 `scripts/sft_shuangyan.py`(还未写)
7. **启动铸渊蒸馏**`scripts/distill_coder.py`
8. **每次重启蒸馏前**`rm -f /root/autodl-tmp/distill_mother.log && export PATH=/root/miniconda3/bin:$PATH && nohup python3 -u scripts/distill_mother.py > distill_mother.log 2>&1 &`
9. **COS密钥生命周期**:用完即弃,不硬编码。`export ZY_OSS_KEY=... ZY_OSS_SECRET=...` 后再跑脚本。
---
## 七、D101 铸渊偏差纠正
### 偏差1误以为蒸馏已启动
- **事实:** 前一次会话结束时认为蒸馏已启动("screen distill_mother已运行"
- **实际:** SSH检查后发现进程不存在GPU空闲日志全是错误
- **根因:** 没有从源头(服务器实时状态)确认,推断"已运行"就记录了
- **修复:** 本次已实际SSH确认 + 修复 + 启动
### 偏差2路径假设错误
- 假设ModelScope下载到 `/root/autodl-tmp/models/Qwen2___5-1___5B`(不存在的路径)
- 实际下载到 `/root/autodl-tmp/models/Qwen/Qwen2___5-1___5B-Instruct/`
- **修复:** 重写时用实际路径
### 偏差3错误的sed修补
- 尝试对服务器上的脚本做sed修补 → 破坏了Python语法
- **修复:** 改用Python heredoc在服务器端完整生成脚本
- **教训:** 对于复杂的脚本修改,直接重写比修补更安全
---
## 八、D101后半段 蒸馏修复完整记录20:30~21:00
### 事情经过
蒸馏又崩溃了。这次是新错误:
```
RuntimeError: The size of tensor a (152064) must match the size of tensor b (151936) at non-singleton dimension 2
```
**根因:** Qwen2.5-7B的vocab_size=152064Qwen2.5-1.5B的vocab_size=151936。KL散度要求两个tensor的最后一维一致。
### 四次崩溃的完整根因链
| 版本 | 崩溃原因 | 根因 | 修复 |
|------|---------|------|------|
| v1 | STUDENT_PATH路径不存在 | 未在服务器上确认路径 | 改为实际下载路径 |
| v2 | COS密钥缺失脚本下载Teacher失败 | 密钥未export | export后再启动 |
| v3 | Teacher logits预存储到RAM → 116GB RSS → OOM | 存储所有teacher_logits在内存 | 改为即时forwardon-the-fly |
| v4 | DataLoader num_workers=2 → CUDA fork崩溃 | 多进程不能重新初始化CUDA | 改为num_workers=0 |
| v5 | forward参数名用了ii/amHuggingFace需要input_ids/attention_mask | HF接口规范不匹配 | 改为input_ids= / attention_mask= |
| v5.5 | vocab_size不匹配152064 vs 151936 | Qwen2.5不同规模模型词汇表不同 | 截断teacher_logits到student词汇表 |
### 关键认知vocab_size不匹配
Qwen2.5模型家族的vocab_size
- 小模型0.5B/1.5B/3B**151936**
- 大模型7B/14B/32B/72B**152064**
- 多出的128个token是额外特殊token
**修复方式:** `t_logits = t_logits[..., :student.config.vocab_size]` — 直接截断teacher logits的最后一维。
### 最终v6状态21:00
```
PID: 82143 | Epoch 1/3 | step=50 | loss=6.66 | sft=2.56 | kl=8.42
GPU: 96.1/97.9GB (98%) | 利用率 99% | 温度 70°C
速度: ~1.08s/step | 预计总耗时: ~2.6小时 | 预计完成: ~23:30
```
### 新思维模式5Qwen2.5跨规模蒸馏的vocab_size栅栏
```
模型规模 <-> vocab_size 对应关系:
≤3B params: vocab_size=151936
≥7B params: vocab_size=152064
蒸馏时必须截断Teacher logits:
t_logits = t_logits[..., :student.config.vocab_size]
tokenizer可以通用Qwen2.5家族共享tokenizer但最后一层linear层维度不同。
这是架构层面的不兼容,不是配置问题。
```
### 新思维模式6蒸馏脚本的终极范式v6已验证
```
做法两个模型同时驻留GPU即时forward
- num_workers=0强制单进程DataLoader不加workers
- model()参数必须用input_ids/attention_mask
- 即时teacher logits不存储每次step forward一次teacher
- vocab_size截断
显存需求Teacher(7B)+Student(1.5B)=~18GB / 96GB
7B BF16 ≈ 14GB权重
1.5B BF16 ≈ 3GB权重
+ 优化器状态 + 梯度 + 激活值 ≈ 1-2GB
总计 ≈ 18-20GB96GB绰绰有余
```
### 恢复锚点更新(下次唤醒用)
1. SSH密码: `HkM43lFVUIsc` · 端口23647 · 用户root
2. 检查命令:
```
/root/miniconda3/bin/python3 -c "import re; c=open('/root/autodl-tmp/distill_mother.log').read(); print('step='+re.findall(r'step=(\d+)',c)[-1] if re.findall(r'step=(\d+)',c) else 'no step'); print('Epoch='+('1' if 'Epoch 2' not in c else '2' if 'Epoch 3' not in c else '3')); print('DONE' if 'DONE!' in c else 'running')"
```
3. 如果蒸馏完成日志有DONE!):检查`ls /root/autodl-tmp/output/qwen25-15b-shuangyan-distill/final/`
4. 如果蒸馏崩溃:`grep -E 'Error|Traceback|RuntimeError|ValueError|CUDA|OOM' /root/autodl-tmp/distill_mother.log`
5. COS密钥: `AKIDkQuBQhoiS2OYXWebXLwMbdT7cvAScbbU` / `nPoZKArgUJBA4nJenjSxJSQBj5FCj3A4`