- 引入 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,读写关闭时与原生模型逐位相同
5.5 KiB
5.5 KiB
NM2.1:合并包 + 整体记忆测试报告
1. NM2.1 是什么
NM2.1 = 原版 NM2 的 Qwen3.5-4B 记忆包 + 本会话交付的路由器,合并方式是把路由器权重 写进模型包本体(不是外挂 sidecar 文件),因此 NM2.1 是一个自包含的模型包。
- 产物:
H:\Memory\dynamic_memory_lab\qwen3_5_4b_natural_memory_v2_1 - fork 内以 junction 暴露:
H:\Memory\V2_dpskw\qwen3_5_4b_natural_memory_v2_1 - 构建脚本:
build_nm2_1_package.py(nm2_1_build_report.json)
合并做法:复制原包 22 个文件后,只把记忆分片
model.safetensors-00005-of-00005.safetensors 里的 16 个 dynamic_memory.memory_router_v2.*
张量替换为交付路由器;其余 47 个张量(含 text_retriever、持久槽、memory policy)逐字节未变。
验证(不是"脚本退出码为 0"):
| 检查 | 结果 |
|---|---|
| 路由器张量与交付件逐位一致(写出后重新读取比对) | 16/16 一致,0 处不符 |
| 非路由张量是否被改动 | 0 处改动 |
| 交付件来源 sha256 | 69f8295e78821e52c0b41b248e7eddbfa47d7e409539f4a13382c0c82d189deb |
实际加载(load_qwen_dynamic) |
router ready: True、text_retriever ready: True |
| 加载出的路由器 == 交付件 | True(0 处不符),2,037,774 参数 |
2. 原版 NM2 已归档
- 包:
E:\归档\01_人工智能\01_训练产物\NM2_原版_qwen3_5_4b_natural_memory_v2_20260912_142722.7z - 22 文件 / 9,535,448,852 字节 → 6.55 GB,
7z t报 Everything is Ok - 已记入
E:\归档\00_索引\操作日志.jsonl;守恒复核精确对上: 45,059 文件 / 110.147 GB = 改动前 45,058 / 103.597 GB + 1 文件 / 6.55 GB - 原包仍留在 H: 原地(归档按该归档库惯例是"复制保留"),所以历史基线对照仍可复现
3. 整体记忆测试结果
同一套电池、同一份运行时,只有模型包不同(run_nm2_battery.ps1)。
| 指标 | 原版 NM2 | NM2.1 |
|---|---|---|
| A 用例数(10 类别) | 110 | 110 |
| A 总体正确率 | 89.09% | 88.18% |
| A 可回答正确率 | 100.00% | 100.00% |
| A 未知拒答率 | 60.00% | 56.67% |
| A 已知问题被误拒率 | 0.00% | 0.00% |
| B 零字面重叠改写回答正确率 | 43.75% | 68.75% |
| B 答成别的属性 | 18.75% | 18.75% |
| B 触发读取 | 56.25% | 93.75% |
| B 平均选中记录 | 3.0625 | 6.0625 |
| C 可回答正确率(24 同形候选) | 65.00% | 65.00% |
| C 答成别的属性 | 35.00% | 35.00% |
| C 未知泄漏率 | 75.00% | 75.00% |
| C 活跃记录 min/max | 23 / 24 | 23 / 24 |
| D 重启后召回 / 作答正确 / 清理生效 | 通过 / 通过 / 通过 | 通过 / 通过 / 通过 |
可复现性说明(重要):NM2.1 的 A 段跑了两次,得到 89.09% 与 88.18%(各差 1 个用例), 未知拒答率 60.00% 与 56.67%(同样差 1 个用例)。因此在这套 110 用例的尺度上, < 1 个百分点(≈1 个用例)的差异属于运行间波动,不作为结论。
结论
- B 段(零字面重叠改写)真实提升 +25.00pp(43.75% → 68.75%),机制是读取门开启率
从 56.25% 升到 93.75%:原版路由器的
need_memory门对这类改写提问过于保守,新路由器 更愿意去查记忆,因此拿到证据并答对。门是本配置下路由器唯一影响端到端结果的杠杆, 这与本会话早先的取证完全一致(随机化排序通路端到端零变化、混合权重独立进程复测零变化)。 - A、C 两段与基线相同:这两套的答案由打包的
text_retriever排序与词面/地址先验决定, 换路由器不改变注入记录集合,所以不改结果。换路由器带来的不是"整体都更强", 而是"该查的记忆会去查了"。 - D 段两边都通过:写入→保存→重启→召回→作答链路完好,清理也生效。
4. 换路由器没有解决的问题(同一份测试里可见,避免误判)
| 问题 | 实测 | 说明 |
|---|---|---|
| 未知问题泄漏 | 75.00%(C 段) | 问库中不存在的属性时仍然给出编造答案;两组检索最高分分布几乎完全重叠,阈值方案已被测量排除 |
| 答成别的属性 | 35.00%(C 段) | 24 个同形候选里排错属性 |
| A 段未知拒答率 | 56.67~60.00% | 未见提升 |
| 记录级排序不由路由器决定 | —— | _record_scores 用打包 text_retriever 覆盖路由器分数(该 retriever 同任务 Top-1 仅 23.20%,路由器 59.60%) |
另外:eval_general_capability.py 需要 comprehensive_general.jsonl,该文件不存在,
所以通用能力回归这一项本次没有跑(A 段里的 benchmark_qa / 未知类别可作部分代理)。
5. 产物清单
| 文件 | 内容 |
|---|---|
H:\Memory\dynamic_memory_lab\qwen3_5_4b_natural_memory_v2_1\ |
NM2.1 合并包本体(22 文件) |
build_nm2_1_package.py / nm2_1_build_report.json |
合并脚本与构建验证报告 |
run_nm2_battery.ps1 |
整体记忆测试电池(-Tag 区分输出,避免互相覆盖) |
compare_nm2_batteries.py / nm2_battery_comparison.{json,md} |
对照表 |
nm2_1_e2e.{json,md} / nm2_1_critical_e2e.{json,md} / nm2_1_runtime_e2e.{json,md} / nm2_1_restart.json / nm2_1_battery_summary.json |
NM2.1 四段结果 |
nm2_orig_*.json/md |
原版 NM2 同套结果(用于对照) |
PRODUCTION_ROUTER.md |
路由器交付说明(含安装与复现命令) |