- 引入 MemoryRouterXL 与 v5/v6 流式多线程训练/编码管线 - 修复 prepare_memory_router_dataset 候选池重建缺陷(mega 家族 3568x 加速,输出逐字节相同) - 修复 v5 被破坏的拒答与多跳标签(train 未知样本 319 -> 16319,multi_hop 平均正例 1.00 -> 2.00) - 同存储预算下 V2-128 v6 逐轴 22/22 通过:Top-1 41.12% -> 94.62%,未知拒答 0.00% -> 100.00% - 记录三条被实测推翻的显然优化(logits_to_keep=1 反而慢 55%、XL 容量未带来收益) - 记忆手术跨架构可移植性 14/14,读写关闭时与原生模型逐位相同
7.9 KiB
真实工作泛化能力:用真实形态数据重训路由器的完整结论
⚠️ 本文的端到端数字已被证伪,读之前先看
MEASUREMENT_FIXES.md2026-09-15 复核发现,本文第 3 节起引用的端到端正确率(72.57% / 63.50% / 64.00%) 由两个评分器缺陷造成,不是模型的真实水平:
- 评分器对空白敏感 —— 期望锚点
值班人-5259、模型答值班人 -5259(多一个空格)判错, 19 条多跳用例全部因此被判错(多跳真实是 100.00%,不是 24.00%);- 拒答检测只认固定关键词,漏掉模型实际使用的措辞(「未包含相关信息,无法回答」), 把 52.00% 的未知拒答率报成 0.00%。
修正后,同一份权重、同一份语料的真实水平是 总体 82.00% / 可回答 86.29% / 未知拒答 52.00% / 已知被误拒 2.29%。
本文仍然成立的结论:路由器在未见属性族上确实能练出泛化能力(Top-1 49.14% → 94.86%), 而且该增益不传递到端到端答案 —— 这一条与空白缺陷无关,仍然有效。 本文不再成立的结论:所有以 72.57%/63.50% 为基线的「差值」与「瓶颈排序」, 包括「多跳是瓶颈」和「未知拒答率 4.00%/0.00%」。
1. 做了什么
| 步骤 | 结果 |
|---|---|
| 真实形态训练集 | data/realistic_v2/train.jsonl,3200 条 / 8 类别(多实体、别名、更新冲突、多跳、近邻干扰、噪声、长事实、未知) |
| 真实形态评测集 | data/realistic_v2/eval.jsonl,200 条 / 8 类别 |
| 属性族不相交 | 36 个属性族按字典序三分:训练 24 / 评测 12,overlap = [](评测用的属性名与句式训练时从未出现) |
| 特征编码 | 10,034 文本 / 60 秒(流式+8 线程) |
| 训练 | V2-128(drop-in 几何),从现有交付件出发,12,000 步 / 1e-4 / need+hop 正常权重 |
2. 路由器级:真实泛化能力被练出来了(强结果)
在未见属性族上:
| 检查点 | Top-1 | Recall@3 | MRR | need 特异度 | hop |
|---|---|---|---|---|---|
| step 0(现有交付件) | 49.14% | 78.29% | 66.87% | 0.00 | 0.68 |
| step 1000 | 94.86% | 100.00% | 96.95% | 0.20 | 0.785 |
| step 12000 | 93.71% | 100.00% | 96.57% | 0.32 | 0.765 |
Top-1 +45.72pp、Recall@3 到 100.00%,而且是在训练时从未见过的属性措辞上 —— 这一个数字本身说明: "路由器缺的是真实形态训练数据"这个判断是对的。
3. 但端到端一动不动
同一条 200 条评测集(属性不相交),同一份运行时,只换路由器:
| 总体 | 可回答(175) | 未知拒答(25) | 已知被误拒 | |
|---|---|---|---|---|
| 原版 NM2 | 64.00% | 72.57% | 4.00% | 2.86% |
| 真实语料重训的路由器 | 63.50% | 72.57% | 0.00% | 1.71% |
Top-1 提升 45.72pp → 端到端可回答正确率变化 0.00pp。 逐类别:
| 类别 | 原版 NM2 | 重训 | 差值 |
|---|---|---|---|
| alias_paraphrase | 96.00% | 100.00% | +4.00pp |
| long_fact | 64.00% | 72.00% | +8.00pp |
| multi_entity | 96.00% | 96.00% | 0 |
| multi_hop | 48.00% | 24.00% | −24.00pp |
| near_miss | 88.00% | 100.00% | +12.00pp |
| noise_context | 68.00% | 72.00% | +4.00pp |
| unknown_attribute | 4.00% | 0.00% | −4.00pp |
| update_conflict | 48.00% | 44.00% | −4.00pp |
| 合计 | 64.00% | 63.50% | −0.50pp |
8 类里 4 类改善(+4~+12pp)、3 类退步(−4~−24pp),净 −0.50pp。每类只有 25 条、1 例 = 4.00pp, 所以 ±8pp 都在噪声量级;唯一可能真实的是 multi_hop 的 −24.00pp(6 个用例)。
4. 逐个被证伪的假设(这一步比结论更重要)
| 假设 | 测量结果 | 判定 |
|---|---|---|
| 记录没写进库 | 写入存活 92.00%、目标事实存活 100.00%(35/35) | 否 |
| 排序被先验压住 | 先验置 0 + 纯路由器排序:可回答 77.14% vs 现状 76.57%(1 个用例) | 否 |
| 先验权重要调 | 剂量曲线 1.00/0.50/0.25/0.00 = 65.00%/47.50%/42.50%/40.00%(模板域) | 否,调小更差 |
| 注入记录太多,模型被混淆 | top_k = 4/2/1 → 可回答 72.57% / 66.29% / 52.57% | 否,减少更差 |
| 路由器分数没被用上 | 让路由器全权排序只动 1 个用例(见上) | 部分成立但不是主因 |
结论:在当前架构下,路由器级排序能力不是端到端准确率的约束条件。 这一点现在有两条独立证据链 (模板域的先验/混合实验 + 真实域的"Top-1 +45.72pp 而端到端 0.00pp")。
5. 残差到底落在哪(可辩护的逐类分类,200 条)
| 类别 | 用例 | 正确 | 答了但不对 |
|---|---|---|---|
| alias_paraphrase | 25 | 25(100.00%) | 0 |
| near_miss | 25 | 25(100.00%) | 0 |
| multi_entity | 25 | 24 | 1 |
| long_fact | 25 | 18 | 7 |
| noise_context | 25 | 18 | 6 |
| update_conflict | 25 | 11 | 13 |
| multi_hop | 25 | 6 | 19 |
| unknown_attribute | 25 | 0 | 25 |
| 合计 | 200 | 127(63.50%) | 71(35.50%)(拒答 2、空回复 0) |
残差集中在这三处,而不是"全面不准":
- 未知属性 0/25 —— 全部照答。覆盖机制是固定 24 属性闭集,在真实实体前缀属性上自动旁路(设计如此)。
- 多跳 6/25(24.00%) —— 链条没被跟上,而且比原版更差,说明重训在这类上过拟合了训练里的链条形态。
- 更新冲突 11/25(44.00%) —— 模型答出被取代的旧值。
第 3 点值得单独查:语料里我把"旧值/新值"写成两个不同句式(frames[0] / frames[-1])。
若新值那句解析不出同一属性,write() 的同属性取代就不会触发,旧记录仍是 active → 两条都进证据。
这既是我的语料细节,也对应真实产品缺陷:用户换一种说法更新时,旧值可能不被取代。
6. 结论
- "真实形态训练数据"是路由器泛化的正确杠杆:+45.72pp Top-1(未见过属性族),证据干净。
- 但它不是端到端体验的杠杆:端到端净变化 −0.50pp,8 类里有升有降。
- 端到端剩下的 27.43% 失败集中在三处(未知 25/25 错、多跳 19/25 错、更新冲突 13/25 错), 全部属于运行时逻辑(覆盖判断、多跳执行、冲突取代),不在路由器权重里。
- 因此下一步该做的不是继续训路由器,而是:
- 冲突取代:让"换一种说法的更新"也能取代旧记录(结构化键 + 语义匹配双条件),目标 更新冲突 ≥ 80%;
- 多跳执行:核对 read 路径是否真的按 hop=2 串联两条记录,目标 多跳 ≥ 70%;
- 动态属性词表:覆盖判断要能处理实体前缀属性,目标 未知拒答 ≥ 80%。 路线图建议:多跳与冲突取代优先(各约 20 条错例,且都是逻辑问题、不需要新数据)。
7. 产物
| 文件 | 内容 |
|---|---|
make_realistic_memory_data.py |
训练/评测语料生成器(36 属性族、按族三分切分、含构造 bug 修复注释) |
data/realistic_v2/{train,eval}.jsonl + .manifest.json |
3200 / 200 条,含 sha256 与不相交证明(overlap: []) |
H:\Memory\nm_cache\nm_realistic_v2\feature_cache |
10,034 行特征库(流式编码,60 秒) |
checkpoints/router_realistic_v2_128/ |
真实语料重训的路由器(V2-128,drop-in 几何) |
rv2_{orig,new}_e2e.{json,md} |
第 3 节对照(原版 vs 重训) |
rv2_topk{1,2}_e2e.{json,md} |
第 4 节注入纪律实验 |
rv2_order_{current,routeronly}.{json,md} |
第 4 节排序实验 |
write_survival.json |
第 4 节写入存活诊断 |
diagnose_write_survival.py |
写入存活诊断脚本 |
REALISTIC_CORPUS_FINDINGS.md |
第一版语料(含我 3 个构造 bug 的复盘) |