JEV / code /DESIGN.md
cloudyu's picture
Upload JEV v0.7.0 (Qwen3.5-9B distilled from Jev 1.13)
b2f3bf4 verified
|
Raw
History Blame Contribute Delete
16.5 kB
# 基于 qwen3_5 代码路径微调 Jev-API 兼容判断模型 — 设计文档
| 项 | 值 |
|---|---|
| 状态 | **v0.7**(B200 落地;Qwen3.5-9B 全流程完成并验收;27B 转为条件项) |
| 日期 | 2026-09-23 |
| 数据 | `SargeDev/jev-distill-corpus-v3`(Apache-2.0,740,957 行;`data/*.parquet`,审计见 `reports/data_audit.md`) |
| 主干 | **Qwen3.5-9B**(`/root/models/Qwen3.5-9B`,bf16,Apache-2.0,文本路径 8.0B);Qwen3.8-27B 已就位(`/root/models/Qwen3.8-27B`)但**不再必需** |
| 硬件 | 1× NVIDIA B200 183GB(sm_100)· torch 2.13.0+cu130 · transformers 5.16.1 · peft 0.21 · flash-linear-attention 0.5.2 |
| 产出 | `exports/jev-judge-qwen35-9b`(15.9GB 纯文本权重 + 24 槽头 + calibration.json + tokenizer)+ 兼容 HTTP API |
| 工程根目录 | `/root/jev-judge/` |
> v0.6 → v0.7 变更摘要:开发/冒烟从 GB10 迁到 B200 单卡;主干从 27B 改为同代码路径的 9B 快速迭代,**9B 已满足"镜像 Jev"目标,27B 仅作条件兜底**;训练侧加入 token 预算 micro-batch、bf16 autocast + fp32 LoRA master 权重、梯度重计算、LR 退火(cooldown);评估侧加入 D1 占位排除口径与教师间距分层分析;服务侧加入动态批处理。
---
## 0. TL;DR
`(state, question, kind, options)` → 裸文本模板 → 单次前向 → `[decision]:` 末位 hidden → **24 槽 fp32 线性头**(初始化 = lm_head 口头词行,第 0 步 ≡ 零样本受限解码,实测 **8.6e-07 / 1.49e-06 < 1e-5**)→ 按 kind 掩码 softmax → 与 `options` 对齐的校准分布。训练 = KL 蒸馏教师全分布 + score 有序 RPS,主干冻结 + LoRA(r16, α32)。
**最终结果(Qwen3.5-9B,S2 2000 步 + 500 步退火,≈ 32 万样本 ≈ 0.49 epoch,B200 单卡约 1.7 小时)**,test_set_30k 温度校准后:
| 指标 | §8.3 目标 | B0 零样本 | **最终** | 判定 |
|---|---|---|---|---|
| 平均 KL | ≤ 0.15 | 0.510 | **0.0276** | ✅ |
| noul AUROC | ≥ 0.95 | 0.824 | **0.9938** | ✅ |
| noul Brier(soft) | ≤ 0.10 | 0.096 | **0.0022** | ✅ |
| score 期望分 MAE | ≤ 0.35 | 1.130 | **0.119** | ✅ |
| ECE(15 bin) | ≤ 0.03 | 0.094 | **0.0014** | ✅ |
| choice top-1 | ≥ 0.90 | 0.532 | 0.884(总体 top-1 0.904) | ❌ 见 §8.4 |
| ood KL 退化比 | ≤ 2.0 | 1.68 | 7.5(ood 绝对 KL 0.857→**0.208**,top-1 0.52→**0.916**) | ❌ 指标失效,见 §8.4 |
| choice 置换一致性 | — | max\|Δp\| 0.173 / 翻转 38% | **0.031 / 4.7%** | ✅ |
温度:noul 1.004 / choice 0.999 / score 1.004 —— 退火后模型天然校准。服务:单请求 p50 ≈ 90–110 ms,批量 2.5 ms/决策,8 并发 32 req/s(动态批处理)。
## 1. 已验证结论速览(B200 / 9B 实测)
| # | 结论 | 实测值 | 影响 |
|---|---|---|---|
| V1 | 头初始化 ≡ 受限解码(fp32 重算) | 9B **8.64e-07**(4 条构造样本)/ **1.49e-06**(96 条真实 validation 行);27B **4.47e-07** | 预训练信息零损耗注入;B0 白给 |
| V1b | 右填充不变性 | 末位 hidden 相对差 9e-03(9B)/ 4.5e-03(27B),bf16 噪声级 | 可安全按长度桶右填充 |
| V3 | 模块对表(transformers 5.16.1) | GDN 层 Linear 叶子:`in_proj_qkv, in_proj_z, in_proj_a, in_proj_b, out_proj`;attn:`q/k/v/o_proj`;MLP:`gate/up/down_proj` | LoRA 挂 10 类叶子(**去掉 `in_proj_a/b`**:4096→48 的门控标量投影,挂 LoRA 只增加 launch 开销) |
| V4 | 口头词裸形式单 token | `false/true/0–5/A–P` 全部单 token,且行首形式 token 与裸形式一致 | 同 v0.6 |
| V6 | 数据长度(9B tokenizer) | train mean 129.0 / p50 87 / p95 369 / p99 531 / max 856;**零截断**;84.6M tok/epoch | 与 v0.6 一致 |
| V7 | D1 均匀占位 | yuri_v1 noul **137,203/137,203 = 100%**(train),各 split 同为 100%;test_set_30k 含 2,260 行 | 训练降权 0.05;**校准拟合排除**;评估双口径报告 |
| V9 | B0 零样本基线(9B) | test_set_30k KL 0.510 / top-1 0.441 / noul AUROC 0.824 / ECE 0.094;ood KL 0.857 | 27B GB10 是 0.479 / 0.538,9B 略弱 |
| V10 | B200 吞吐 | fwd-only **30–43k tok/s**(fla 内核,mb 32–128);S2 fwd+bwd 无 ckpt **7–10k tok/s**,有 ckpt + 24k tok micro-batch **~9k tok/s**(峰值 34GB) | 9B 1 epoch ≈ 2.6–3.5 h;见 §7 |
| V11 | 激活显存 | 无 ckpt ≈ **10 MB / padded token**(GDN 48×128 扩展维度) | v0.6 §7.3 "无需 ckpt" 估算偏乐观 2×;S2 默认开 ckpt |
| V12 | CPU 固定开销 | 每步 ≈ 300 ms(≈5k 次小 kernel launch:248 个 LoRA 模块 + GDN 胶水);宿主机 load 15–27 时更明显 | micro-batch 必须做大;**两进程并发训练总吞吐反而下降**(3k+3k < 9k) |
| V13 | 学习曲线 | val KL:B0 0.485 → step500 0.094 → 1500 0.038 → 2000 0.0325;退火 500 步 → **0.0260**(全量 validation) | 0.49 epoch 即收敛到目标以下 4×;2 epoch 计划不必要 |
| V14 | 退火收益 | 同一起点(step 2000):直接评估 val KL 0.0347 vs 退火后 **0.0260**(−25%);choice top-1 0.863 → 0.884 | 高 LR 处取的 checkpoint 应做 cooldown |
| V15 | 教师 choice 软标签天花板 | test_set_30k choice 行 top-1 概率中位数 0.70;top-2 间距 <0.05 占 7.5%(该层一致率 0.46≈抛硬币);间距 ≥0.1 的 86% 行一致率 **0.918**,≥0.3 行 0.965;我们 argmax 拿到的教师质量 0.682 vs 完美镜像 0.709(**96%**) | choice top-1 ≥0.90(全体行)对该教师而言接近上限,见 §8.4 |
## 2. 背景与选型(v0.7)
Jev(TypeSafe System One)的 typed decision 由远端 Jev 1.13 产出;`jev-distill-corpus-v3` 提供 74 万行教师全分布软标签。目标是本地镜像。
选型变化:**Qwen3.5-9B**(`model_type: qwen3_5`,与 Qwen3.8-27B 同一套 `Qwen3_5*` 类与 tokenizer 家族、tie=false、无 softcap)作为主线:
- 同代码路径 → 27B 只需改 `model_path`(已在 27B 上跑通门禁);
- Apache-2.0;无 softcap,头初始化精确等价;
- 3× 于 27B 的迭代速度,B200 单卡 0.5 epoch ≈ 1.5 h。
曾评估 Gemma 4 12B:`final_logit_softcapping=30`(需 tanh 修正)、tied embedding、Gemma ToU;作为第二数据点未采用。
## 3. 数据(M1 完成,`reports/data_audit.md`)
Schema、划分纪律与 v0.6 一致。B200/9B tokenizer 复核:schema 违规 0;zero truncation @1024;train kind 占比 noul 52.1% / choice 25.0% / score 22.9%;source 占比 yuri_v3 67.7% / yuri_v1 20.9% / openjev_v2 11.4%;choice 选项数以 4 为主(142k),另有 3/5/7/9/16。
D1 处置(三处一致):训练 `d1_policy: downweight 0.05, scope yuri_v1`;**温度拟合默认排除 yuri_v1 均匀占位行**(否则 family 级温度会学出 T=17 把一切压平);评估报告"全部行"与"排除 D1"两个口径(差异仅在 KL/ECE 小数点后第三位)。
## 4. 兼容 API 规格(实现:`src/jev_judge/server.py`,契约测试 `tests/test_server_contract.py` 7/7)
`POST /v1/decisions` · `POST /v1/decisions:batch`(保序,≤256)· `GET /healthz`
请求 `{"kind","state","question","options","truncate":false,"family":null}`;响应含 `id / kind / options(回显对齐) / distribution(和为 1±1e-4,末位修正) / decision{noul,choice,score,expected_score} / confidence / model{name,version,calibrated} / latency_ms / batch_size`。
422:kind/options 非法(noul 必须 `["false","true"]`,score 必须 `["0".."5"]`,choice 2–16 项);413:超长且 `truncate=false`,或 batch > 256;头 `X-Jev-Judge-Version`;缺 `calibration.json` **拒绝启动**。
**动态批处理**:单 GPU 工作线程,≤4 ms 窗口合批(≤128 项);校验/分词在提交前同步完成,坏请求不会污染批。实测 8 并发 3 → 32 req/s,p50 2.3 s → 251 ms。
⚠️ A1(仍待办):与真实 Jev 契约逐字段 diff。
## 5. 输入模板(冻结,`template.py`,`TEMPLATE_VERSION = bare-v1`)
同 v0.6 裸文本模板。**分词方式:整串自然 BPE**(不分段拼接,避免缝处出现 `" "`+`word` 的不自然切分);仅超长时按 token 截 state(头 60% / 尾 40%)后 decode 重渲染。语料零截断,该路径只服务线上边缘输入。
## 6. 模型架构
同 v0.6 §6.1–6.3(24 槽不相交布局、`W[slot]=lm_head[verbalizer]`、KL + 0.5·RPS、choice 30% 置换增强、KindBatchSampler floor 1/6)。实现细节(B200):
- 加载:不实例化视觉塔——按 shard 流式读取 safetensors,`model.language_model.*`→`model.*` 重映射进 `Qwen3_5ForCausalLM`,跳过 `model.visual.*` / `mtp.*`;初始化头后释放 lm_head(省 2–2.5GB)。同一加载器读取导出的纯文本 bundle。
- 精度:主干 bf16 + `autocast(bf16)`;LoRA adapter **fp32 master 权重**(peft 默认 bf16 会让 1e-4 量级更新被舍入;直接 fp32 计算则走 SIMT sgemm,慢且多 cast);头恒 fp32 且在 autocast 之外;AdamW fused,β=(0.9,0.98),clip 1.0。
- 训练阶段:S0(B0)✅ · S1 头探针(实现,未单独跑:S2 在 30 步冒烟即达 val KL 0.26,探针价值低)· **S2 主交付** ✅ · S3 未触发。
## 7. 训练方案与硬件(B200 实测替代 v0.6 §7 外推)
### 7.1 Micro-batch 策略
优化步 = `batch_size` 个样本(默认 128),内部按长度排序后贪心切成 **B·T ≤ `max_padded_tokens`** 的 micro-batch,loss 按样本权重比例缩放使一步等于整 batch 的加权均值。
- 9B 无 ckpt:`max_padded_tokens` 10k → 峰值 ~100GB,7–10k tok/s,但 128 样本会切成 3–5 个小 micro,CPU 固定开销放大(实测仅 3.8k tok/s);
- **9B 有 ckpt(采用)**:`max_padded_tokens` 24k → 每步 1–2 个 micro,峰值 34GB,稳态 ~9k tok/s;
- 27B(配置已备 `configs/train_27b.yaml`):ckpt + 16k。
### 7.2 实测时长(9B,单卡独占)
| 阶段 | 步数 | 墙钟 |
|---|---|---|
| S2 主跑 0 → 2500 步(0.49 epoch,含 5 次 val_sub 评估) | 2500 | ≈ 1.4 h(前 20 分钟与扫描并发,稍慢) |
| 阶段检查 ×3(暂停训练:校准 + test_set_30k + ood + 500 行置换) | — | ≈ 3.5 min / 次 |
| LR 退火 500 步(warmup 25,0.9×峰值 → 0.02×) | 500 | ≈ 20 min |
| 最终校准 + 全量评估(4 split + 1000 行置换) | — | ≈ 6 min |
| 导出 15.9GB bundle | — | ≈ 1 min |
对照 v0.6 §7.4 的 8×H200/B200 集群测算:单卡 B200 上 9B 达标只需 **≈1.7 h GPU**,无需多卡。
### 7.3 环境要点(B200)
1. fla 0.5.2 的 `chunk_gated_delta_rule` Triton 内核在 sm_100 可用(transformers 经 `kernels` hub 回退机制自动接入);
2. `causal_conv1d` 无法编译:系统 nvcc 12.8 vs torch cu130 版本不匹配 → transformers 回退 `F.conv1d`(前向 ~9% 时间),可接受;
3. Triton JIT 正常(有 python3.11-dev),无需 GB10 的 `_triton_guard`;
4. `PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True`;后台任务用 `scripts/bg.sh`(setsid+nohup);**不要用 `pkill -f` 匹配含自身命令行的字符串**;
5. 宿主机共享 CPU(配额 20 核,load 15–27)会放大 launch 开销并造成偶发 10–30 s 停顿;以中位数吞吐评估。
### 7.4 超参(实际使用)
`configs/train.yaml` + 覆盖 `gradient_checkpointing=true max_padded_tokens=24000`:batch 128,lr 头 2e-4 / LoRA 1e-4,cosine warmup 3% min 10%(原计划 2 epoch 的日程,实际在 step 2500 按检查结论停止),λ_RPS 0.5,D1 downweight 0.05,choice 置换 30%,eval_every 500 × 4000 行,patience 3。
退火:`--init-from checkpoints/s2_9b_seed42/best`,500 步,warmup 5%,lr 头 1.8e-4 / LoRA 9e-5 → ×0.02,seed 43。
### 7.5 10% 扫描(M3,后台进行中)
`scripts/run_scan.sh`:base / λ_RPS=0 / D1 drop / lr×2,各 10% 子集 2 epoch。结果落 `checkpoints/scan_*/log.jsonl`,供下一版并入;不影响本次交付。
## 8. 校准与评估
### 8.1 温度校准
per-kind 标量 T,L-BFGS 最小化 KL,仅 calibration 划分且**排除 D1 占位行**(10,954/13,766);family 级细化阈值 ECE>0.02 & n≥500(最终模型未触发)。最终 T = noul 1.004 / choice 0.999 / score 1.004。
### 8.2 阶段检查流程(v0.7 新增,`scripts/review_checkpoint.sh`)
训练中每 500 步存 best/last;在 step 500 / 1500 / 2500 **SIGSTOP 暂停训练** → 快照 checkpoint → 校准 → test_set_30k + ood 全量评估 + 置换一致性 → 对照预期 → SIGCONT 恢复。三次检查全部单调改善后,依据 V13/V15 在 step 2500 停止长跑改做退火。
| step | val KL | t30k KL | choice top-1 | score MAE | noul AUROC | ECE | ood KL | 翻转率 |
|---|---|---|---|---|---|---|---|---|
| B0 | 0.485 | 0.510 | 0.532 | 1.130 | 0.824 | 0.094 | 0.857 | 38% |
| 500 | 0.094 | 0.081 | 0.817 | 0.224 | 0.977 | 0.022 | 0.296 | 11.2% |
| 1500 | 0.038 | 0.040 | 0.861 | 0.151 | 0.991 | 0.0025 | 0.235 | 6.8% |
| 2000 | 0.0325 | 0.037 | 0.865 | 0.143 | 0.992 | 0.004 | 0.253 | 5.3% |
| 2000+退火 500 | **0.026** | **0.0276** | **0.884** | **0.119** | **0.994** | **0.0014** | **0.208** | **4.7%** |
### 8.3 验收(test_set_30k,温度后)—— 见 §0 表;完整切片见 `reports/eval_s2_9b.md`
按 source×kind:yuri_v3 choice KL 0.05 / openjev choice KL 0.25(snake 等程序化任务最难,top-1 0.84);yuri_v1 占位切片 KL ≈ 0.01(模型输出接近 0.5/0.5)。
### 8.4 两项未达标的判定
1. **choice top-1 0.884 < 0.90**:教师软标签天花板(V15)。在教师有明确倾向的 86% 行上一致率 0.918,与"完美镜像"的差距仅 4%(0.682 vs 0.709 教师质量)。判定:模型已足够忠实;若要冲 0.90 需继续训练 ~5 h 且边际收益 ≤2 点。建议下一版把该指标改为"教师 top-2 间距 ≥0.1 行上的 top-1 ≥ 0.90"(当前 0.918 ✅)。
2. **ood KL 退化比 7.5 > 2.0**:域内 KL 压到 0.028 后比值必然膨胀(B0 时 1.68 只是因为域内也差)。ood 绝对 KL 从 0.857 降到 0.208、top-1 0.52 → 0.916、noul AUROC 0.69 → 0.985。建议改为绝对指标(ood KL ≤ 0.30 且 top-1 ≥ 0.85)。
## 9. 推理服务(bf16,`exports/jev-judge-qwen35-9b`)
| 项 | 值 |
|---|---|
| 形态 | 纯文本权重 4 shards 15.9GB(LoRA 已合并,不含 vision/mtp/lm_head)+ head.safetensors + judge_config.json + calibration.json + tokenizer |
| 显存 | ≈ 17GB |
| 延迟(B200 独占) | 单请求 p50 87 ms(无合批)/ 111 ms(合批窗口 4 ms);batch 128 → 2.5 ms/决策;8 并发 32 req/s p50 251 ms |
| 强约束 | 分布和 1±1e-4;options 回显对齐;缺温度表 fail-fast;低置信度(归一化熵 >0.9)打日志不改响应 |
## 10. 工程结构与命令 —— 见 `README.md`
## 11. 风险与状态
| 风险 | 缓解 | 状态 |
|---|---|---|
| yuri_v1 均匀占位(D1) | 训练降权 0.05;校准排除;评估双口径 | ✅ |
| bf16 舍入破坏等价性 | fp32 重算门禁 + 头恒 fp32 | ✅ 9B/27B PASS |
| fla/causal_conv1d 快核 | fla OK;conv 回退 torch | ✅ 可接受 |
| 激活显存超预期(10MB/tok) | ckpt + token 预算 micro-batch | ✅ |
| 高 LR 处停训 | 500 步退火 | ✅ −25% KL |
| 教师 choice 软标签天花板 | 间距分层报告;建议改指标 | 📝 已记录 |
| A1 契约字段差异 | 上线前与真实 Jev diff | ⏳ 待办 |
| 27B | 仅当 9B 不满足业务需求时启用(`configs/train_27b.yaml`,门禁已过) | 🟢 条件项 |
## 12. 里程碑(v0.7)
| # | 内容 | 状态 |
|---|---|---|
| M0 | 剥塔加载 / 对表 / 口头词 / 等价性门禁(9B、27B)/ B200 吞吐 / B0 | ✅ `reports/m0_qwen35_9b.md`, `reports/b0_qwen35_9b.md` |
| M1 | 数据审计 + D1 + 长度 + parquet | ✅ `reports/data_audit.md` |
| M2 | 模板定案 | ✅ 沿用 v0.6 裸文本;分词改整串 |
| M3 | S2 主跑 + 阶段检查 ×3 + 退火 | ✅ `reports/review/step{0500,1500,2500}.md` |
| M4 | 温度校准 + 全量评估 | ✅ `reports/eval_s2_9b.md`(5/7 达标,2 项判定为指标问题) |
| M5 | 导出 + 服务 + 契约测试 + 压测 | ✅ `exports/jev-judge-qwen35-9b`,7/7 |
| M3b | 10% 超参扫描 | 🟡 后台进行中 |
| — | 27B | ⏸ 条件项 |
## 附录 A:头初始化等价性 —— 同 v0.6(qwen3_5 无 softcap,精确成立;9B 实测 8.6e-07,27B 4.5e-07)
## 附录 B:槽位/口头词总表 —— 同 v0.6;9B/27B tokenizer 均通过单 token 与行首一致性校验(`reports/m0_qwen35_9b.md`)