Natural Memory NM2.1: 记忆路由器分叉、数据集缺陷修复与全轴评测证据
- 引入 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,读写关闭时与原生模型逐位相同
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
import torch
|
||||
|
||||
from V2_dpskw.benchmark_dirty_real_corpus_4b import (
|
||||
_failure_stage,
|
||||
_is_refusal_strict,
|
||||
)
|
||||
from V2_dpskw.memory_os_v2 import MemoryRouterV2, PagedMemoryBankV2
|
||||
from V2_dpskw.qwen_integration import (
|
||||
_looks_like_grounded_memory_query,
|
||||
format_memory_evidence,
|
||||
)
|
||||
|
||||
|
||||
class FailureDrivenV2Test(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
torch.manual_seed(19)
|
||||
self.router = MemoryRouterV2(16, router_dim=8, num_heads=2, max_hops=3)
|
||||
|
||||
def test_grounding_guard_is_scoped_to_personal_and_project_facts(self) -> None:
|
||||
self.assertTrue(_looks_like_grounded_memory_query("当前项目的模型叫什么"))
|
||||
self.assertTrue(_looks_like_grounded_memory_query("README 是否记录了重启方式"))
|
||||
self.assertFalse(_looks_like_grounded_memory_query("北京今天会下雨吗"))
|
||||
|
||||
def test_unknown_wording_is_a_hard_refusal_signal(self) -> None:
|
||||
self.assertTrue(_is_refusal_strict("仓库中没有列出任何具体的部署区域。"))
|
||||
self.assertTrue(_is_refusal_strict("这个字段没有出现在保存的记录里,我无法确认。"))
|
||||
|
||||
def test_structured_evidence_keeps_raw_fragment_first(self) -> None:
|
||||
evidence = format_memory_evidence(
|
||||
"用户给当前模型定名:Natural Memory v1。",
|
||||
entity="user",
|
||||
attribute="模型名称",
|
||||
value="Natural Memory v1",
|
||||
)
|
||||
self.assertLess(evidence.index("事实"), evidence.index("已确认值"))
|
||||
self.assertIn("已确认值:Natural Memory v1", evidence)
|
||||
|
||||
def test_failure_stage_classification_is_observable(self) -> None:
|
||||
self.assertEqual(
|
||||
_failure_stage(
|
||||
{
|
||||
"correct": False,
|
||||
"answerable": True,
|
||||
"retrieval_target_found": False,
|
||||
"response": "不知道",
|
||||
}
|
||||
),
|
||||
"routing_miss",
|
||||
)
|
||||
self.assertEqual(
|
||||
_failure_stage(
|
||||
{
|
||||
"correct": False,
|
||||
"answerable": True,
|
||||
"retrieval_target_found": True,
|
||||
"expected_anchors": ["H:\\Memory", "Natural Memory"],
|
||||
"response": "项目在 H:\\Memory。",
|
||||
}
|
||||
),
|
||||
"evidence_fusion",
|
||||
)
|
||||
self.assertEqual(
|
||||
_failure_stage(
|
||||
{
|
||||
"correct": False,
|
||||
"answerable": True,
|
||||
"retrieval_target_found": True,
|
||||
"expected_anchors": ["H:\\Memory"],
|
||||
"response": "没有记录。",
|
||||
}
|
||||
),
|
||||
"generation_control",
|
||||
)
|
||||
self.assertEqual(
|
||||
_failure_stage(
|
||||
{
|
||||
"correct": False,
|
||||
"answerable": False,
|
||||
"retrieval_target_found": False,
|
||||
"response": "我无法确认。",
|
||||
}
|
||||
),
|
||||
"unknown_refusal_control",
|
||||
)
|
||||
|
||||
def test_attribute_alias_routes_without_exact_source_wording(self) -> None:
|
||||
bank = PagedMemoryBankV2(
|
||||
16,
|
||||
router=self.router,
|
||||
page_capacity=2,
|
||||
top_k_pages=2,
|
||||
top_k_records=2,
|
||||
max_hops=2,
|
||||
)
|
||||
record, _ = bank.write(
|
||||
text="记忆主体优先放在进程内存,显存只保存热点记录。",
|
||||
key=torch.randn(16),
|
||||
entity="user",
|
||||
attribute="记忆存储优先级",
|
||||
value="DRAM",
|
||||
confidence=0.98,
|
||||
)
|
||||
selected, _ = bank.query(
|
||||
query_key=torch.randn(16),
|
||||
query_text="容量不够时才降级,平时优先使用哪层内存?",
|
||||
top_k_pages=2,
|
||||
top_k_records=2,
|
||||
)
|
||||
self.assertIn(record.record_id, {item.record_id for item in selected})
|
||||
|
||||
def test_cjk_phrase_alias_reaches_operational_record(self) -> None:
|
||||
bank = PagedMemoryBankV2(
|
||||
16,
|
||||
router=self.router,
|
||||
page_capacity=2,
|
||||
top_k_pages=2,
|
||||
top_k_records=2,
|
||||
)
|
||||
record, _ = bank.write(
|
||||
text="当前 token 不会对一百万个 slot 做全量注意力。",
|
||||
key=torch.randn(16),
|
||||
semantic_key=torch.randn(16),
|
||||
entity="README_NATURAL_MEMORY_V2.md",
|
||||
attribute="operational:1",
|
||||
value="Top-K;全量注意力",
|
||||
confidence=0.98,
|
||||
)
|
||||
selected, _ = bank.query(
|
||||
query_key=torch.randn(16),
|
||||
query_text="百万 slot 会不会进行全量注意力?",
|
||||
top_k_pages=2,
|
||||
top_k_records=2,
|
||||
)
|
||||
self.assertIn(record.record_id, {item.record_id for item in selected})
|
||||
|
||||
def test_ambiguous_symbol_fans_out_but_stays_bounded(self) -> None:
|
||||
bank = PagedMemoryBankV2(
|
||||
16,
|
||||
router=self.router,
|
||||
page_capacity=1,
|
||||
top_k_pages=8,
|
||||
top_k_records=1,
|
||||
max_pages=64,
|
||||
)
|
||||
expected = set()
|
||||
for index in range(6):
|
||||
record, _ = bank.write(
|
||||
text=f"第 {index} 个文件定义了 run 函数。",
|
||||
key=torch.randn(16),
|
||||
entity=f"module_{index}.py",
|
||||
attribute="symbol:run",
|
||||
value="run",
|
||||
confidence=0.9,
|
||||
)
|
||||
expected.add(record.record_id)
|
||||
selected, _ = bank.query(
|
||||
query_key=torch.randn(16),
|
||||
query_text="run 函数分别在哪些文件中定义?",
|
||||
top_k_pages=8,
|
||||
top_k_records=1,
|
||||
)
|
||||
selected_ids = {item.record_id for item in selected}
|
||||
self.assertEqual(selected_ids, expected)
|
||||
self.assertLessEqual(len(selected), 8)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user