From 3bb4ebd9be0223c36741aa095e4564c847c06029 Mon Sep 17 00:00:00 2001 From: EthanPeng-2048 Date: Thu, 29 Oct 2026 00:37:59 +0800 Subject: [PATCH 1/4] =?UTF-8?q?docs(usage):=20=E7=BA=BF=E7=A8=8B=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E5=A5=91=E7=BA=A6=E6=96=87=E6=A1=A3=EF=BC=88issue=20#?= =?UTF-8?q?38=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 docs/usage/07-thread-safety.md: - 总契约 5 条规则(同引擎并发不安全 / 同模型并发 forward 不安全 / Tensor 无内部同步 / 不同引擎实例互不干扰 / GpuBackend 创建回收线程安全) - CPU 引擎:全局线程池 oversubscribe 风险 + 并发 forward 不安全的具体根源 (sync_readback_slots_ 数据竞争、层 backward 缓存覆写) - GPU 引擎:单命令缓冲裸录制无锁、已加锁部分的清单(不构成并发口径)、 thread_local 录制图的边界、可并行形态(单推理线程 + 队列) - 全局资源共享表 + 服务化设计模板 + 演进口径(不会静默改并发语义) README 与 docs 索引加条目。 --- README.md | 1 + docs/README.md | 1 + docs/usage/07-thread-safety.md | 76 ++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 docs/usage/07-thread-safety.md diff --git a/README.md b/README.md index c7ce914..3f6845a 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ | [训练包](docs/usage/04-train-package.md) | 用 `.nnpkg` 打包超参+训练集,跨设备一键复现训练 | | [作为库嵌入](docs/usage/05-consume-as-library.md) | 把本库嵌进自己的工程(`neuralnet::nn` 门面 / FetchContent) | | [强化学习与可组合训练](docs/usage/06-reinforcement-learning.md) | 具名多输出、GAE、REINFORCE/PPO/GRPO、多模型 Session 与 rollout pipeline | +| [线程安全契约](docs/usage/07-thread-safety.md) | 每个对象的并发口径矩阵 + 服务化下游设计模板 | | [实测结论索引](research/README.md) | **可引用的实验结论**(MNIST 准确率 / f16 回弹根因 / 三值 STE / 三值尺度规则):结论 + 证据 + 重跑命令 + 边界 | | [参与本项目](CONTRIBUTING.md) | 给非作者的入口:构建、测试、代码规范、提 PR、CI 口径 | diff --git a/docs/README.md b/docs/README.md index 2e27b7f..fdaae04 100644 --- a/docs/README.md +++ b/docs/README.md @@ -57,6 +57,7 @@ | [`04-train-package.md`](usage/04-train-package.md) | `.nnpkg` 训练包 | | [`05-consume-as-library.md`](usage/05-consume-as-library.md) | 把库嵌进自己工程(`neuralnet::nn` 门面 / FetchContent) | | [`06-reinforcement-learning.md`](usage/06-reinforcement-learning.md) | RL:具名多输出、experience/GAE、REINFORCE/PPO/GRPO、多模型 Session、可替换 rollout pipeline | +| [`07-thread-safety.md`](usage/07-thread-safety.md) | **线程安全契约**:每个对象的并发口径矩阵 + 服务化下游设计模板(issue #38) | ### development/(给调用者) diff --git a/docs/usage/07-thread-safety.md b/docs/usage/07-thread-safety.md new file mode 100644 index 0000000..19a4f30 --- /dev/null +++ b/docs/usage/07-thread-safety.md @@ -0,0 +1,76 @@ +# 线程安全契约 + +> **一句话结论**:本库**不提供任何跨线程并发调用保证**——服务化/多线程下游请用 +> 「**每 worker 一线程一引擎**」模型,或对共享引擎做**外部串行化**。 +> 本文给出每个对象的明确口径与依据,让下游不必靠猜(issue #38)。 + +## 1. 总契约 + +| # | 规则 | 依据 | +|---|---|---| +| 1 | **同一 `ComputeEngine` 实例上的并发调用(forward/backward/read/write/begin_batch…)不安全**,必须外部同步 | 引擎持有可变槽(见 §2);GPU 录制单命令缓冲(见 §3) | +| 2 | **同一 `Model` 实例上的并发 forward 不安全**,即使引擎不同也不行(一个 Model 只绑一个引擎,等价于规则 1) | 层在 forward 时写内部缓存(`input_cache_` / `col_cache_` 等,为 backward 保留) | +| 3 | **同一 `Tensor` 的并发读写不安全**(含"A 线程录命令、B 线程 read"——必须有 happens-before 边界) | `Tensor` 无任何内部同步 | +| 4 | **不同引擎实例之间互不干扰**(每引擎一套状态) | 引擎状态不跨实例共享(例外:全局线程池,见 §4) | +| 5 | `GpuBackend::shared()` 的**创建/回收**线程安全;拿到之后的引擎操作仍受规则 1 约束 | weak 缓存 + mutex(v1.10.0 起) | + +## 2. CPU 引擎(`CpuEngine` / `CpuModel`) + +- **op 内部已并行**:大张量算子经全局 `ThreadPool`(`hardware_concurrency` 线程)按块并行。 + 用户线程再并发调 forward **不会加速**,反而 oversubscribe(N 用户线程 × M 池线程)。 +- **并发 forward 不安全的具体根源**(不止"大概率不行"): + - 引擎的标量回读槽 `sync_readback_slots_`(`compute_engine.hpp`)是共享可变 + `std::vector`——并发 `submit_scalar_readback` = 数据竞争; + - 层的 backward 缓存(如 `Linear::input_cache_`)在 forward 中被覆写——同模型 + 并发 forward 会让 backward 用错缓存(静默错误,不报错)。 +- **可并行的形态**:每线程一个 `CpuEngine` + 一个 `Model`(权重各自持有; + 模型大时显存/内存翻倍,见 §5 的取舍)。 + +## 3. GPU 引擎(`GpuEngine` / `GpuBackend`) + +- **录制是单命令缓冲**:`begin_batch()` 后所有原语录进当前帧的 `batch_cmd_` + (`compute_vk_backend_frame.inc`)——**无锁的裸录制**,并发录 = 数据竞争 + (不会稳定崩溃,会静默录坏命令流)。同一引擎必须串行。 +- **已加锁的部分**(只保证内部一致性,不构成"可并发调用"的口径): + 队列提交(`queue_mutex_`)、延迟销毁/描述符回收(`pending_mutex_`)、 + 内存池(`compute_memory_pool.hpp` 的 `mutex_`)、staging 环(atomic 游标)。 +- **表达式录制图是 `thread_local`**(`expr_graph.hpp`,D3 修复):A 线程 + `begin_expr` 不影响 B 线程的录制图指针——但录进去的求值仍走同一引擎, + 规则 1 照旧。 +- **可并行的形态**: + - 每连接一线程 + 每线程一个 `GpuBackend::shared()`?——**不行**:`shared()` + 返回**同一个** backend 实例(按设备缓存)。真正的隔离需要每 worker 进程, + 或外部串行化(mutex/队列),或等待未来的多引擎多队列支持。 + - 现实建议:GPU 推理服务用**单推理线程 + 请求队列**(这正是多数下游已采用 + 的形态),CPU 评估等旁路任务另开 CPU 引擎。 + +## 4. 全局资源(跨引擎也共享) + +| 资源 | 口径 | +|---|---| +| 全局 `ThreadPool`(`extern/threadpool`,`core_threadpool.hpp` 单例) | 池本身线程安全;所有 CPU 引擎共享 → 多引擎并发 forward 会 oversubscribe,可通过环境/配置调池大小(见该头文件) | +| 精度编译期特化表 / 剖析计数器(`core_profile.hpp`) | 内部有 mutex,线程安全(只影响诊断输出,不影响计算语义) | +| AOT 融合注册表(闭合世界) | 构建期生成、运行期只读 → 安全 | + +## 5. 服务化下游的设计模板 + +``` +✅ 推荐(HTTP 服务、每连接一线程的宿主): + 主线程 / 池:接受请求 → 无状态分发 + 推理:单推理线程 + mutex 或请求队列(GPU); + 或每 worker 线程一个 CpuEngine+Model(CPU,注意 oversubscribe) + +❌ 不要: + 多个 HTTP 线程直接并发调同一 Model::forward(GPU 命令流静默录坏 / + CPU 缓存互相覆写——两者都**不报错**,输出错但不崩) +``` + +**迁移提示**(对已在用全量串行化的下游):并行化的正确粒度是**引擎实例级** +(规则 4),不是调用级。想提升 GPU 吞吐,目前的路径是多进程 +(每进程一卡)而非多线程。 + +## 6. 版本与演进 + +- 本文档口径自 **v1.13.1 / v1.14.0** 时期成立(issue #38 立档)。 +- 若未来引入"引擎级并发安全"承诺(如 GPU 多命令缓冲录制、CPU 引擎无状态化), + 将以 API 变化(版本第 2 位递增)+ 本文档更新的形式发布,不会静默改变。 From 7c8a80a1090bc292246c16888b1c8abe79c284a3 Mon Sep 17 00:00:00 2001 From: EthanPeng-2048 Date: Fri, 30 Oct 2026 00:26:04 +0800 Subject: [PATCH 2/4] =?UTF-8?q?docs:=20=E7=89=88=E6=9C=AC=E5=8F=B7=C2=B7?= =?UTF-8?q?=E5=88=86=E6=94=AF=C2=B7=E5=8F=91=E5=B8=83=E6=B2=BB=E7=90=86?= =?UTF-8?q?=E8=90=BD=E6=A1=A3=20todo/33=20+=20=E6=96=87=E6=A1=A3=E7=B4=A2?= =?UTF-8?q?=E5=BC=95=E8=A1=A5=E9=BD=90=E4=B8=8E=E8=BF=87=E6=97=B6=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 docs/todo/33-version-branch-and-release-policy.md(32 号已被 feature 分支 RFC 文档占用,故取 33),固化三条规则: ① 版本号规则 v1..<漏洞修复>,版本权威 = git tag(另注明历史遗留的 非规范 tag v.1.3.0 / nightly / archive/* 不属版本序列); ② 发布版本号必须由人提出,agent 不得擅自决定版本号或执行发布动作 (git tag / gh release / project(VERSION) 定档 / release note 定稿); ③ dev 及功能分支从不写版本号,定档与发布只发生在 main。 入口只留引用,规则正文独立成文: - AGENTS.md:文首加「开发规范/发布要求只给引用」行;§11 补 todo/24/25/26/28/ 29/30/33 与 usage/07 索引行;release-notes 行拆为「规范+索引」与「逐册」 两行且不再写死当前版本 - CONTRIBUTING.md §0 加「提发布/定版本号」入口,§4 分支表后加三条规则摘要 - docs/README、docs/todo/README、todo/25 关联、release-notes/README(细则 6) 补引用;todo/README 编号规则改为「新增接当前最大号」(不再写死 02…31) 过时信息清理(2026-10-30 实测刷新): - 18-roadmap §2:版本行 v1.12.0 → v1.13.0(tag/VERSION/覆盖范围,复现命令改 git tag --list 'v1.*',表内管道已转义);include 82/44681、src 90/31730、 docs 67 篇、ctest 64/62、最大源文件 2797/1981 - ctest 计数三处互相矛盾的旧值(18 §8.1「54/41/52」、18 §8.2 规则硬编码、 CONTRIBUTING 自查「52/54」、todo/12 头部「67/69/56」、AGENTS §11「69/67」) 统一为 64(GPU 树)/ 62(无 Vulkan 树)= 51 目标 + 13 变体(2026-10-26 24e0599 下沉 7 测试后口径);12 号删除失效的「AGENTS §7 枚举」指针, 标注 error_macro/kvrec/nnvocab/dataset 四测试已迁 extern/* 子仓 - docs/README release-notes 覆盖范围 → v1.5.0…v1.13.0;CMakeLists 注释去掉 写死的「当前 v1.12.0」(仅注释,无功能影响) - 历史记录行(已完成项、history、release note、带日期实测)按 18 §2 口径说明 原样保留 --- AGENTS.md | 14 +++- CMakeLists.txt | 2 +- CONTRIBUTING.md | 8 +- docs/README.md | 5 +- docs/release-notes/README.md | 1 + docs/todo/12-compute-engine-inventory.md | 11 +-- docs/todo/18-roadmap.md | 20 ++--- docs/todo/25-release-requirements.md | 3 +- .../33-version-branch-and-release-policy.md | 80 +++++++++++++++++++ docs/todo/README.md | 3 +- 10 files changed, 125 insertions(+), 22 deletions(-) create mode 100644 docs/todo/33-version-branch-and-release-policy.md diff --git a/AGENTS.md b/AGENTS.md index 8d86bca..b3238ea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,6 +2,7 @@ > 本文档专为 AI 编码助手编写:用最少 token 建立项目心智模型,快速开始开发。 > 人类向的完整文档在 `docs/`(索引见 §11)。**改代码前必读 §5 铁律与 §10 高频坑。** +> **开发规范 / 发布要求等规则正文不在本文,本文只给引用**:C++ 开发规范 → `docs/todo/10-development-standards.md`;版本号规范(格式/位定义)→ `docs/release-notes/README.md` §1;版本号·分支·发布治理(**发布须由人提出、agent 不得擅自发布**;`dev` 不写版本号、发布只在 `main`)→ `docs/todo/33-version-branch-and-release-policy.md`;大版本发布清单 → `docs/todo/25-release-requirements.md`;分支模型与提 PR → `CONTRIBUTING.md` §4。 > 本文只记录**当前状态**;演进记录、已修复勘误、被否决方案与性能 A/B 过程统一归档在 `docs/history/history.md`(索引见 §11)。当前能力清单见 §12。 ## 1. 项目一句话 @@ -378,7 +379,8 @@ auto report = NN_UNWRAP(session.train_step( |------|--------| | `README.md` | **文档总索引与分册定位**(含 2026-10-11 整理记录) | | `history/history.md` | **全仓唯一的历史状态归档**:演进记录 / 已修复勘误 / 被否决方案 / 性能 A/B 过程。代码注释与其他文档只记录当前状态;查"为什么当初这么改、旧数字是多少"只来这里。**原 `development/15`(ComputeEngine Refresh 设计)与 `16`(P0 盘点)、已删的 `13`(重构清单)均归档在本文** | -| `release-notes/v*.md` | 面向使用者的版本变更说明(破坏性 API 变更 + 迁移指南 + 验收基线)。当前为 `release-notes/v1.12.0.md`(v1.11.0 → **RL 基础设施:schema/具名多输出、GAE、REINFORCE/PPO/GRPO、多模型 Session、rollout pipeline**;无破坏性 API,模型格式 v8 不变)。上一版 `v1.11.0.md` = TrainingSession 单步协议与 global/micro batch 语义;预发布候选记录保留在 `v1.10.0-rc0.md` / `v1.10.0-rc0.1.md` | +| `release-notes/README.md` | **版本号规范与逐册索引**:格式 `v1..<漏洞修复>`、位定义与递增条件、rc / 勘误细则(§1)+ 每册主题索引(§2)。最新版本以 `git tag` 为准,索引不写死当前号 | +| `release-notes/v*.md` | 面向使用者的版本变更说明(发布范围 / 主题 / 破坏性 API 变更 + 迁移指南 / 验收基线);预发布候选 `v1.10.0-rc0` / `v1.10.0-rc0.1` 同样成册保留。逐册索引见 `release-notes/README.md` §2 | ### 介绍类(docs/introduction/) @@ -414,7 +416,7 @@ auto report = NN_UNWRAP(session.train_step( | `todo/04-memory-optimization.md` | 显存优化:L1 激活重计算(梯度检查点)/ L2 内存池整块归还(均已实施);L3 远期 | | `todo/08-pitfalls-and-lessons.md` | **踩坑警示录,改代码前读** | | `todo/10-development-standards.md` | C++ 编码规范全文 | -| `todo/12-compute-engine-inventory.md` | **引擎接口盘点(复现:`bench/doc_inventory.ps1`):52 个 virtual 方法、Layer 直调 32 个(基础设施/数据搬运/状态扫描/fold 执行(自登记)/IR-C 录制段开合/三值打包/张量形变/精度落盘/RL 行带适配)、两套 CPU 求值机制(DSL 模板 + IR 解释器)、ctest 69 个测试(无 Vulkan 树 67);演进记录见 `docs/history/history.md`** | +| `todo/12-compute-engine-inventory.md` | **引擎接口盘点(复现:`bench/doc_inventory.ps1`):52 个 virtual 方法、Layer 直调 32 个(基础设施/数据搬运/状态扫描/fold 执行(自登记)/IR-C 录制段开合/三值打包/张量形变/精度落盘/RL 行带适配)、两套 CPU 求值机制(DSL 模板 + IR 解释器)、ctest 64 个注册(无 Vulkan 树 62);演进记录见 `docs/history/history.md`** | | `todo/14-f16-stable-gpu-loss-frozen.md` | **故障报告(2026-09-26;2026-10-13 ✅ 已修/根因订正):GPU `stable=f16` 训练 loss 打印冻结(权重不冻结)——真因 = CE 的 (1,1) loss 归约按 `stable=f16` 落盘溢出,非回读链;触发矩阵、测试覆盖缺口、证据与复现** | | `todo/17-unified-tensor-engine.md` | **统一 Tensor/ComputeEngine/MemoryPool 底层架构总纲(2026-09-30 裁定;M1-M6 全部已实施 2026-09-30,仅 M7 未立项):访问不变量(Tensor 存储私有、一切经引擎,已立为铁律 #11)、InitSpec 声明式初始化、批量 read/write、Matrix 降级为宿主 I/O 载体(L2+ 禁用 = 铁律 #12)、内存池契约统一、`import` 跨设备拉取、Layer 删每调用 engine 形参(M6 段 C,Loss/DSL/辅助对象保留形参见 §8);吸收原 15 未实施的 P2-P6(改期 M1-M7)。立项前先读本文件 + §5 分期 + §8** | | `todo/18-roadmap.md` | **未来方向路线图 + 未完成项裁定台账(2026-10-01,13 号清单的承接者):RL 主线 ✅(2026-10-23)+ P0-P4 分期(P4 = 持续优化方向,2026-10-14 立项)、13 号逐条裁定(做/条件触发/不做)、触发式立项条件、非目标、门禁与验收口径。查"某件事该不该做、做到什么算完成、避免重复立项"时读本文;**执行排序不在本文**(见 `todo/27-execution-plan.md`)** | @@ -424,6 +426,13 @@ auto report = NN_UNWRAP(session.train_step( | `todo/21-quantized-weights.md` | **三值(1.58-bit)量化权重与 BitLinear(2026-10-09 设计定稿 → 2026-10-10 **P1 已实施**,分支 `dev/t1_58`):`Precision::T1_58` + `Layer::precision_support()`(按槽声明、`init` 期校验)+ `BitLinear`(量化 forward / STE backward);含 Lumina-Engine `TQ1_0` 参考实现拆解、`§4.9` 实现与设计的差异、`§8` 架构图、`§10` 提交清单。**已裁定**:尺度 = absmean + per-row(absmax 只剩 0.13~1.29 bit 信息,实测见 `research/ternary_scale/`)、打包 = `TQ1_0` 编码 + 行级块、命名 `T1_58` / CLI 无别名 / 层名 `BitLinear`、D3 = (a)+(b)、D5 = ③(P1 只覆盖 MLP;GPT 侧由 P1.5 补齐,RAPT/ViT 仍拒绝);**仍待定** D6(P2 行步长/对齐)。前置证据 `research/ternary_ste/`**;验收 `src/t1_58_test.cpp`(+`--gpu` 变体) | | `todo/22-bitnet-2b4t-architecture.md` | **BitNet b1.58 2B4T 的结构对齐(2026-10-10 立项 + **S1/S2/S3 三步已实施并提交**,分支 `dev/t1_58`):三项结构差距 = SubLN / GQA / tied embedding,均为**可选开关、默认关**。**已裁定**:SubLN 封装在子层内部(`AttentionBase`/`FeedForward` 的可选 `unique_ptr`,**不是** `NormType` 新值、**不是** block 的第三个 norm)、类型跟随 `norm_type`;GQA 头映射 = `kv = h/(n_head/n_head_kv)`(llama.cpp FA 与 HF `repeat_kv` 互证)+ 显式展开 K/V 头(前向 `gather_rows` / 反向 `scatter_add_rows`,fold 与 AOT 注册表零改动);tied embedding 在 `GPTModel` 内一个开关(梯度**累加**进 `grad_token_emb_`);**不加 CLI 预设**(GUI 留待以后);`ModelSpec` 追加 `subln`/`n_head_kv`/`tie_embeddings` 三键(缺键 = 旧语义,不升 MODEL_VERSION)。**验收 `src/bitnet_struct_test.cpp`(+`--gpu`)**:GQA 退化与 MHA 逐位一致、GQA↔按块映射复制成 MHA 前向差 0、tied 梯度累加差 0;102 上全量 ctest 30/30。**实施记录见本文 §10**。**待定**:FFN 激活 ReLU²(需确认官方 `hidden_act`;llama.cpp 对 gated squared relu `GGML_ABORT`,无对拍)、GQA in-kernel 版(P2)、HF 权重转换器。**结构侧**与 21 号(权重侧 `T1_58`/`BitLinear`)是两条正交的腿** | | `todo/23-library-design-cleanup-and-model-file-roles.md` | **库级违规设计清理(2026-10-11 **已实施**):模型文件角色 + 参数形态协议 + 引擎能力体系**(范围 = **整个库**,不只三值)。三轮裁决要点:① 参数级 `kind`(Dense / TernaryLatent / TernaryPacked2 / TernaryPacked3 / 预留 int8);② **不引入**可训练/不可训练状态;③ 能力谓词 = 具体引擎私有、**不得进基类**、不作对外标签、只作内部分发(设备不支持走引擎内降级/报错),能力**信息**走**统一对外查询通道**(`describe()`);④ 文件角色拆开:**`.nnmodel`**(推理,`.bin` 接替者)与 **`.nnckpt`**(含训练参数,`--save-interval` 写它);⑤ 热路径审查(基类能力分支 + `eval_expr` 每次求值双份归因 → 编译期标签 / init 期常量 / 引擎内就地回退);⑥ `sub_layers()` 与 NNQT 独立格式、`--export-deploy` 等标签**全部删除**(`BitLinear` 的 f16 稠密 A/B 开关保留)。**§3 待裁决已定**:`EngineInfo` 结构体 + `text()`、接口名 `describe()`;`.nnmodel` 不留 latent;旧 `.bin` 只读不写、不提供转换工具。落地验收见 21 §4.15 与 `src/model_roles_test.cpp` | +| `todo/24-f16-training-defects.md` | **f16 训练缺陷台账**:全 f16 NaN / loss 冻结 / `--f16` 降速;立项 F1–F7(F5 ✅ 已可训练;F6 = 真 f16 Plan B;F7 = 标准 `--f16` Plan A) | +| `todo/25-release-requirements.md` | **大版本发布必做清单**(`1.x.y → 1.(x+1).0`):端到端模型训练测试 / 发布文档 / 完整 ctest + Debug 构建 / 四组「编译器 × 标准库」矩阵 | +| `todo/26-f16-speedup-plan.md` | **f16 提速与两套 f16 计划**:Plan A = 标准 `--f16`(AMP 式,推荐默认);Plan B = 全流程真 f16(零转换门禁),§8 分列 | +| `todo/28-lifecycle-v3.md` | **生命周期 v3(✅ 已随 v1.10.0 发布)**:删 `EngineId`/`stamp_`/`adopt`/`bound`,设备域从存储派生;改生命周期 / Tensor / 引擎绑定前读 | +| `todo/29-session-architecture.md` | Session 层所有权设计:Model + Optimizer 同生共死、`InferenceSession` / 通用 `TrainingGroupSession` 占位;训练状态归属由 30 号修订 | +| `todo/30-training-session-step.md` | **TrainingSession 单步协议(✅ 随 v1.11.0 发布)**:micro-batch 入、内置梯度累积、global batch 归一化、`batch_size` = 理论 batch;改训练入口前读 | +| `todo/33-version-branch-and-release-policy.md` | **版本号·分支·发布治理**:`v1..<漏洞修复>` 规则、**发布版本号必须由人提出(agent 不得擅自发布)**、`dev` 不写版本号、发布只在 `main` | ### 使用类(docs/usage/,**给调用者**) @@ -435,6 +444,7 @@ auto report = NN_UNWRAP(session.train_step( | `usage/04-train-package.md` | `.nnpkg` 训练包 | | `usage/05-consume-as-library.md` | **把库嵌进自己工程(add_subdirectory/FetchContent):`neuralnet::nn` 门面、`NN_ENABLE_GPU`/`NN_BUILD_APPS` 开关、`nn_enable_gpu_fusion`、故障排查** | | `usage/06-reinforcement-learning.md` | **RL 与可组合训练基础设施**:named output/schema、experience/GAE、PolicyDistribution、REINFORCE/PPO/GRPO、TrainingGroupSession、可替换 rollout pipeline、AOT 与测试口径 | +| `usage/07-thread-safety.md` | **线程安全契约**:每个对象的并发口径矩阵 + 服务化下游设计模板(issue #38) | ## 12. 当前状态 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3aaf99d..f9c1128 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.30) # 否则链接期会出现 std 符号 ABI 不匹配)。 # 本文件不再隐式挑选编译器或 stdlib,避免与调用方/CI 的设置冲突。 -# VERSION 以 git tag 为准(当前 v1.12.0;本仓无 CONFIGURE_FILE 消费该字段, +# VERSION 以 git tag 为准(本仓无 CONFIGURE_FILE 消费该字段, # 它只是元数据——发版时同步到最新 tag,实际版本以 git tag / gh release 为准) project(neuralnet.cpp VERSION 1.13.0 LANGUAGES CXX) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1b7370d..337f34a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,6 +17,7 @@ | 扩展引擎原语 / 改 GPU 后端 | [`docs/development/01-compute-engine-development.md`](docs/development/01-compute-engine-development.md) + `AGENTS.md` §7 | | **改本仓的代码** | [`AGENTS.md`](AGENTS.md)(**先读 §5 铁律与 §10 高频坑**) | | 看"下一步该做什么" | [`docs/todo/18-roadmap.md`](docs/todo/18-roadmap.md) | +| 提发布 / 定版本号 | [`docs/todo/33-version-branch-and-release-policy.md`](docs/todo/33-version-branch-and-release-policy.md)(**版本号必须由人提出,agent 不得擅自发布**;`dev` 不写版本号,发布只在 `main`)+ [`docs/todo/25-release-requirements.md`](docs/todo/25-release-requirements.md) | | 看"为什么当初这么改" | [`docs/history/history.md`](docs/history/history.md)(全仓唯一历史归档) | --- @@ -149,11 +150,16 @@ clang-format -i path/to/new_file.hpp | `hotfix/` | 热修复分支:**只修复一个 bug** | 完成后合入 `dev`,随即删除 | 其他历史分支命名(`feat/`、`fix/`、`docs/` 等)已废止。文档类改动可直接在 `main` 提 PR。 + + **版本号与发布规则**(正文与真源表见 [`docs/todo/33-version-branch-and-release-policy.md`](docs/todo/33-version-branch-and-release-policy.md)): + ① 版本号格式 `v1..<漏洞修复>`(位定义见 [`docs/release-notes/README.md`](docs/release-notes/README.md) §1),**版本权威 = `git tag`**; + ② **`dev` 及其上的功能分支从不写版本号**——不 bump `project(VERSION ...)`、不建 release note 册、不打 tag;定档与发布**只发生在 `main`**; + ③ **发布版本号必须由人提出并明确给出**,agent(AI 编码助手)不得自行决定版本号或执行发布动作(`git tag` / `gh release` 等)。 2. **一次 PR 一件事**。大改动请先在 issue/讨论里对齐设计——本仓有「先写设计稿进 `docs/todo/`, 裁定后再实施」的习惯(`docs/todo/` 就是项目开发者的工作区)。 3. 提交前自查: ```bash - cmake --preset dev && cmake --build --preset dev && ctest --preset dev # 测试必须绿(当前口径:无 Vulkan 52 项 / 开 GPU 54 项) + cmake --preset dev && cmake --build --preset dev && ctest --preset dev # 测试必须绿(当前口径:无 Vulkan 62 项 / 开 GPU 64 项) python bench/gui_cli_audit.py # 改了 gui.py / cli_controllers.py / 任一 CLI 选项后必跑(七节:声明式字段表 ↔ Controller 闭包、断点续训禁列、多轮对话闭环;当前 exit 0) python bench/gui_draw_logic_audit.py # 改了画板绘制路径后必跑(桩替换 customtkinter,无需 GUI) python bench/gui_draw_runtime_audit.py # 同上(真机:功能闭环 + 拖动开销对照;无显示时 77 = SKIP) diff --git a/docs/README.md b/docs/README.md index fdaae04..3e4f022 100644 --- a/docs/README.md +++ b/docs/README.md @@ -90,6 +90,9 @@ - `todo/28` / `todo/29` / `todo/30` — **生命周期 v3 / Session 层 / TrainingSession 单步协议** (P2a/P2b 已随 `v1.10.0` 发布;30 号于 2026-10-22 冻结 micro-batch、梯度累积与 global-batch 归一化边界,随 `v1.11.0` 发布)。 - `todo/24` / `todo/25` — f16 训练缺陷台账 / **大版本发布要求**(`1.x.y → 1.(x+1).0`)。 +- `todo/10` / `todo/08` — **C++ 开发规范全文** / **踩坑警示录**(改代码前读)。 +- `todo/33` — **版本号·分支·发布治理**:版本号规则、**发布须由人提出(agent 不得擅自发布)**、 + `dev` 不写版本号、发布只在 `main`。 ### 总档 @@ -102,7 +105,7 @@ | [`../CMakePresets.json`](../CMakePresets.json) | 预设构建(`cmake --preset dev` 等)——见 CONTRIBUTING §1 | | [`benchmarks/2026-09-25-vulkan-vs-cuda.md`](benchmarks/2026-09-25-vulkan-vs-cuda.md) | Vulkan 后端 vs CUDA(torch)基准 | | [`benchmarks/2026-10-06-vulkan-vs-torch.md`](benchmarks/2026-10-06-vulkan-vs-torch.md) | 第二轮复测 | -| `release-notes/v1.5.0.md` … `v1.12.0.md` | 版本变更说明,覆盖 v1.5.0 → v1.12.0 的全部 tag(`v1.5.1` / `v1.6.1` / `v1.7.1` / `v1.8.0` 为 2026-10-18 补写;`v1.10.0-rc0` / `v1.10.0-rc0.1` 为正式版前的预发布候选记录;**大版本发布要求**见 [`todo/25-release-requirements.md`](todo/25-release-requirements.md)) | +| `release-notes/v1.5.0.md` … `v1.13.0.md` | 版本变更说明,覆盖 v1.5.0 → v1.13.0 的全部 tag(`v1.5.1` / `v1.6.1` / `v1.7.1` / `v1.8.0` 为 2026-10-18 补写;`v1.10.0-rc0` / `v1.10.0-rc0.1` 为正式版前的预发布候选记录;**大版本发布要求**见 [`todo/25-release-requirements.md`](todo/25-release-requirements.md)) | ## 3. 2026-10-11 文档整理记录 diff --git a/docs/release-notes/README.md b/docs/release-notes/README.md index ed74559..1a8f3f4 100644 --- a/docs/release-notes/README.md +++ b/docs/release-notes/README.md @@ -19,6 +19,7 @@ 3. **已发布版本不重打**:tag 一旦发布即冻结;发布后发现的问题以勘误块追加在该版本 release note 顶部,并指向修复版本(例:见 `v1.10.0.md` 勘误)。 4. **子仓库**(`extern/base` 等 5 个 submodule)遵循同一 `v1..<漏洞修复>` 规范,各自独立编号;基线 `v1.0.0` 已锁定于与主仓库 v1.13.0 同期的快照。 5. 每册 release note 的头部固定给出:发布范围(上一 tag → 本 tag)、主题、兼容性评级、验收基线。 +6. **发布治理**:版本号的定档与发布必须由**人**明确提出,**agent 不得擅自决定版本号或执行发布**(`git tag` / `gh release` 等);`dev` 与功能分支不写版本号,定档与发布只发生在 `main`。正文见 [`../todo/33-version-branch-and-release-policy.md`](../todo/33-version-branch-and-release-policy.md)。 ## 2. 目录索引 diff --git a/docs/todo/12-compute-engine-inventory.md b/docs/todo/12-compute-engine-inventory.md index 4e5523a..f1b6b2b 100644 --- a/docs/todo/12-compute-engine-inventory.md +++ b/docs/todo/12-compute-engine-inventory.md @@ -9,11 +9,12 @@ > **当前数字**(2026-10-23 实测):引擎 virtual **52 个方法**(`bench/doc_inventory.ps1` 口径。注意 `rg -c "\bvirtual\b"` 在 `compute_engine.hpp` 里原始计 **54** 处 = 52 方法 + 析构 1 + 注释里的词 1,勿混用口径);Layer/Loss/Optimizer 直调 **32 个**(含 `begin_expr`——由 `Adam::step`/`AdamW::step` 打开 IR-C 录制段;含 `cast_into`——层内结果按 profile 落精度;RL 多输出层新增 `slice_rows`/`insert_rows`/`try_create_tensor` 等行带适配路径); > 其余 20 个公开入口只服务 DSL lowering / 序列化 / CLI / 适配层 / 测试,见 §2); > CPU 求值机制 **2 套** -> (DSL 模板路径 + IR 解释器,见 §3);ctest **67** 个(**无 Vulkan 树**;GPU 树 **69**)= -> **56 个测试目标 + 13 个变体/附加**(**完整枚举只写在 `docs/todo/18` §2 / `AGENTS.md` §7**, -> 此处不重复以免漂移)。其中 `fused_gpu_test` = 融合 shader **逐形态** GPU 对拍;`expr_graph_test` = IR-C 图融合分析(CPU 12 用例);`error_macro_test` -> = 错误处理宏族(`NN_UNWRAP`/`NN_EXIT`/`NN_TRY_MSG`/`NN_FAIL`);`kvrec_test`/`nnvocab_test`/`dataset_test` -> = 统一数据集(KVRecord v2 / `.nnvocab` / `.nndataset`,见 `docs/todo/19`); +> (DSL 模板路径 + IR 解释器,见 §3);ctest **62** 个(**无 Vulkan 树**;GPU 树 **64**,2026-10-30 实测)= +> **51 个测试目标 + 13 个变体/附加**(**完整枚举只写在 `docs/todo/18` §2**, +> 此处不重复以免漂移)。其中 `fused_gpu_test` = 融合 shader **逐形态** GPU 对拍;`expr_graph_test` = IR-C 图融合分析(CPU 12 用例); +> `error_macro_test`(错误处理宏族 `NN_UNWRAP`/`NN_EXIT`/`NN_TRY_MSG`/`NN_FAIL`)与 `kvrec_test`/`nnvocab_test`/`dataset_test` +> (统一数据集 KVRecord v2 / `.nnvocab` / `.nndataset`,见 `docs/todo/19`)**已下沉子仓** +> (2026-10-26 `24e0599`:本体在 `extern/base` / `extern/kvrecord` / `extern/tokenizer` / `extern/dataset` 各自 `tests/`,主仓 ctest 不再注册); > `zipt_test` 随 ZiPT 移除,见 `docs/history/history.md`;`dsl_shape_infer_test` = `dsl::compute`/`compute_reduce` 的**无形状重载**(推导口径 + 负例)。 > > 历史演进与收敛记录(计算类原语全量迁 DSL、算子收敛与遗留物 diff --git a/docs/todo/18-roadmap.md b/docs/todo/18-roadmap.md index 86556bb..4772a3a 100644 --- a/docs/todo/18-roadmap.md +++ b/docs/todo/18-roadmap.md @@ -58,18 +58,18 @@ | 维度 | 实测 | 复现 | |---|---|---| -| `include/` | **96 个 `.hpp` / 50609 行** | `Get-ChildItem include -Recurse -Filter *.hpp` + 逐文件 `Get-Content` 计数 | -| `src/` | **97 个 `.cpp` / 33641 行** | 同上换 `src -Filter *.cpp` | +| `include/` | **82 个 `.hpp` / 44681 行** | `Get-ChildItem include -Recurse -Filter *.hpp` + 逐文件 `Get-Content` 计数 | +| `src/` | **90 个 `.cpp` / 31730 行** | 同上换 `src -Filter *.cpp` | | `shaders/` | **22 个 `.comp`** | `Get-ChildItem shaders -Recurse -Filter *.comp` | -| `docs/` | **63 篇 `.md`**(含 `history/history.md` 与 `release-notes/`) | `Get-ChildItem docs -Recurse -Filter *.md` | -| 最大源文件 | `expr_glsl_gen.hpp` **3435** 行、`compute_cpu_engine.hpp` **2796**、`compute_gpu_engine.hpp` **2576**、`compute_engine.hpp` **2228**、`expr_dsl.hpp` **1980**、`gui.py` **2038**、`rl_policy.hpp` **1200**、`backend/compute_vk_backend.hpp` **856**(v1.8.1 拆 4 片段后回落)。**`src/text_train.cpp` 已不在榜**——P1-1 模块化后 1830 → **450** 行(循环/恢复/断点拆到 `cli/text_train_*.hpp`) | 逐文件 `(Get-Content $f).Count` | -| ctest | **69 个测试**(GPU 树)= 56 个测试目标(`list(APPEND NN_TEST_TARGETS` 计数)+ 13 个变体/附加(`cnn_test_gpu`、`cnn_test_f16`、`cnn_test_f16_gpu`、`rapt_test_f16`、`rapt_test_f16_gpu`、`batchnorm_test_gpu`、`t1_58_test_gpu`、`bitnet_struct_test_gpu`、`write_epoch_test_gpu`、`ternary_gemm_test_gpu`、`adam_quant_test_gpu`、`fusion_custom_layer_example`、`expr_fuse_test`);**无 Vulkan 的树注册 67 条**(`fusion_custom_layer_example` / `expr_fuse_test` 是 GPU 专属门禁) | `ctest --test-dir build -N` | +| `docs/` | **67 篇 `.md`**(含 `history/history.md` 与 `release-notes/`) | `Get-ChildItem docs -Recurse -Filter *.md` | +| 最大源文件 | `expr_glsl_gen.hpp` **3435** 行、`compute_cpu_engine.hpp` **2797**、`compute_gpu_engine.hpp` **2576**、`compute_engine.hpp` **2228**、`expr_dsl.hpp` **1981**、`gui.py` **2038**、`rl_policy.hpp` **1200**、`backend/compute_vk_backend.hpp` **856**(v1.8.1 拆 4 片段后回落)。**`src/text_train.cpp` 已不在榜**——P1-1 模块化后 1830 → **450** 行(循环/恢复/断点拆到 `cli/text_train_*.hpp`) | 逐文件 `(Get-Content $f).Count` | +| ctest | **64 个注册**(GPU 树,2026-10-30 实测)= 51 个测试目标(`list(APPEND NN_TEST_TARGETS` 计数)+ 13 个变体/附加(`cnn_test_gpu`、`cnn_test_f16`、`cnn_test_f16_gpu`、`rapt_test_f16`、`rapt_test_f16_gpu`、`batchnorm_test_gpu`、`t1_58_test_gpu`、`bitnet_struct_test_gpu`、`write_epoch_test_gpu`、`ternary_gemm_test_gpu`、`adam_quant_test_gpu`、`fusion_custom_layer_example`、`expr_fuse_test`);**无 Vulkan 的树注册 62 条**(`fusion_custom_layer_example` / `expr_fuse_test` 是 GPU 专属门禁) | `ctest --test-dir build -N` | | 引擎接口 | **52 个 virtual 方法**、Layer/Loss/Optimizer 直调 **32 个**;`L2-VIOLATIONS: 0`;宿主桥 39 处(仅披露,2026-10-23 实测) | `pwsh -File bench/doc_inventory.ps1` | -| 版本 | release **v1.12.0**,git tag **`v1.12.0`**;`CMakeLists.txt` 的 `project(... VERSION 1.12.0)`(口径仍为 **git tag 是版本权威**);`release-notes/` 覆盖 **v1.5.0 → v1.12.0 的全部 tag**(含 `v1.10.0-rc0` / `rc0.1` 两个预发布候选;历史补写记录见 release-note 索引) | `git describe` + 读 `CMakeLists.txt` + `ls docs/release-notes/` | +| 版本 | release **v1.13.0**,git tag **`v1.13.0`**;`CMakeLists.txt` 的 `project(... VERSION 1.13.0)`(口径仍为 **git tag 是版本权威**;版本号·分支·发布治理见 `33`);`release-notes/` 覆盖 **v1.5.0 → v1.13.0 的全部 tag**(含 `v1.10.0-rc0` / `rc0.1` 两个预发布候选;历史补写记录见 release-note 索引) | `git tag --list 'v1.*' \| sort -V \| tail` + 读 `CMakeLists.txt` + `ls docs/release-notes/` | | CI | `.github/workflows/cmake-single-platform.yml`:clang++ / Ninja / Release / `NN_ENABLE_NATIVE=OFF`,Linux + Windows;**开 `NN_ENABLE_TESTS` 并跑 ctest**(v3 起设备域检查默认生效,无需第二轮调试开关门禁)。另有 `msvc-debug` job:Windows + Visual Studio 18 2026(cl.exe)/ Debug / `NN_ENABLE_GPU=OFF` 纯 CPU / ctest(除已知 C11 外全跑;P1-5,2026-10-18) | 读该 workflow | > 口径说明:表中行数均为**总行数**(实测刷新)。 -> `69`(GPU 树)/ `67`(无 Vulkan 树)是当前唯一正确计数;`--preset` 各树同口径(GPU 是否可用决定 +> `64`(GPU 树)/ `62`(无 Vulkan 树)是当前唯一正确计数;`--preset` 各树同口径(GPU 是否可用决定 > 两条 GPU 专属门禁是否注册)。文档中其它 ctest 计数写法属**历史记录**:已完成行(如 P2-3/P2-8 的 > "47/47")与 `docs/history/history.md` 的旧数字是当时的验收事实,不属计数口径冲突;**新增/修改文档 > 时写当前值**。口径差异来源见 §3 工程化第 4 条。 @@ -355,7 +355,7 @@ f16(P2-14/P2-15)与训练性能(P4-1/P4-2/P4-3)仍按原裁定暂缓, | 基线 | 口径 | 当前值 / 复现 | |---|---|---| | build | 全绿、零告警(`-Werror`) | `cmake -B build -G Ninja -DNN_ENABLE_TESTS=ON && cmake --build build` | -| ctest | **实测 54**(41 目标 + 13 变体/附加;无 Vulkan 树 52);需 Vulkan 用例退出码 77 = skip | `ctest --test-dir build` | +| ctest | **实测 64**(51 目标 + 13 变体/附加;无 Vulkan 树 62);需 Vulkan 用例退出码 77 = skip | `ctest --test-dir build` | | L2 分层审计 | `L2-VIOLATIONS: 0`(宿主桥用量只披露) | `pwsh -File bench/doc_inventory.ps1` 第 [4] 节(实测:virtual 52 / host_bridge 39) | | CPU 字节锚 | `--steps 20` hash = `6f8849f14da23110` | 逐位一致 | | GPU 字节锚 | dev2 hash = `8ef51b2927253c50` | 逐位一致(GPU 档位按 17 §6 容差规则) | @@ -366,8 +366,8 @@ f16(P2-14/P2-15)与训练性能(P4-1/P4-2/P4-3)仍按原裁定暂缓, ### 8.2 本轮新增门禁(P0 后生效) -1. **CI 必须执行 ctest**:日志需出现当前全部用例(**54**,无 Vulkan 树 52);77 = skip 不算失败(P0-1)。 -2. **开发文档不得出现 ctest 计数的旧写法**:统一写实测 **54**(GPU 树)/ **52**(无 Vulkan 树)——已完成行与 history 归档里的旧数字是当时记录,不算冲突(P0-2 ✅)。 +1. **CI 必须执行 ctest**:日志需出现当前全部用例(**64**,无 Vulkan 树 62,真源 = §2 ctest 行);77 = skip 不算失败(P0-1)。 +2. **开发文档不得出现 ctest 计数的旧写法**:统一写实测**当前值**(真源 = §2 ctest 行与口径说明;2026-10-30 = **64**〔GPU 树〕/ **62**〔无 Vulkan 树〕)——已完成行与 history 归档里的旧数字是当时记录,不算冲突(P0-2 ✅)。 3. **BatchNorm 行为门禁**:构造 batchnorm 规格必须有可观测结果(报错或正确层),不允许静默降级(P0-3)。**✅ 已满足**:真层 + `batchnorm_test` 工厂断言。 4. **危险精度组合**:启动期**告警**(仅警告、不失败、不改退出码)——口径与细则见 [`24-f16-training-defects.md`](24-f16-training-defects.md) §2.3 / §5 F1(P1-3)。 5. **审计覆盖补强**:`bench/doc_align_audit.ps1` 的 [A] **✅ 已扩展到 markdown 链接目标**(E8,2026-10-15);新增死链会在审计里以 [A] 计数非 0 暴露。 diff --git a/docs/todo/25-release-requirements.md b/docs/todo/25-release-requirements.md index 6f04208..1fef40c 100644 --- a/docs/todo/25-release-requirements.md +++ b/docs/todo/25-release-requirements.md @@ -3,7 +3,8 @@ > **读者**:项目维护者 / 发布者。本分册定位见 [`README.md`](README.md); > 历史归档在 [`../history/history.md`](../history/history.md)。 > 关联:[`18-roadmap.md`](18-roadmap.md)(**git tag 是版本权威**); -> [`24-f16-training-defects.md`](24-f16-training-defects.md)(F2 的端到端全 f16 训练归口本清单第 1 项)。 +> [`24-f16-training-defects.md`](24-f16-training-defects.md)(F2 的端到端全 f16 训练归口本清单第 1 项); +> [`33-version-branch-and-release-policy.md`](33-version-branch-and-release-policy.md)(**发布须由人提出、agent 不得擅自发布;`dev` 不写版本号、发布只在 `main`**——清单全绿也不等于可发版)。 ## 0. 适用范围 diff --git a/docs/todo/33-version-branch-and-release-policy.md b/docs/todo/33-version-branch-and-release-policy.md new file mode 100644 index 0000000..a6a55bb --- /dev/null +++ b/docs/todo/33-version-branch-and-release-policy.md @@ -0,0 +1,80 @@ +# 33 — 版本号、分支与发布治理规范 + +> **读者**:项目开发者与 AI 编码助手(agent)。本分册定位见 [`README.md`](README.md); +> 历史归档在 [`../history/history.md`](../history/history.md)。 +> 关联:[`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) §4(分支模型表 / 提 PR)、 +> [`../release-notes/README.md`](../release-notes/README.md) §1(版本号格式与位定义全文)、 +> [`25-release-requirements.md`](25-release-requirements.md)(大版本必做清单)、 +> [`18-roadmap.md`](18-roadmap.md) §2(**git tag 是版本权威**)。 +> +> `AGENTS.md` 与 `CONTRIBUTING.md` 对本文**只留引用**;三条规则的正文以本文为准。 + +## 0. 三条规则(正文见 §1–§3) + +1. **版本号规则**:`v1..<漏洞修复>`;版本权威 = `git tag`。 +2. **发布必须由人提出**:定哪个号、何时发,由人明确给出;**agent 不得擅自决定版本号或执行发布**。 +3. **版本号与分支绑定**:`dev` 及功能分支**从不写版本号**;定档与发布**只发生在 `main`**。 + +## 1. 版本号规则 + +格式 `v1..<漏洞修复>`(例 `v1.13.0`、`v1.8.2`)。位定义 / rc / 勘误 / 子仓同规范的 +**全文**在 [`../release-notes/README.md`](../release-notes/README.md) §1;本节只复述治理相关部分: + +| 位 | 名称 | 递增条件(摘要,全文见 release-notes/README §1) | +|---|---|---| +| 第 1 位 | 主版本 | 极少动:模型文件格式不兼容、项目定位级重构 | +| 第 2 位 | **API 变化** | 对外接口(头文件 API / CLI 选项 / 文件格式键 / CMake 开关)新增或语义变更;**破坏性变更只允许出现在这一位**,release note 须附迁移章节 | +| 第 3 位 | **漏洞修复** | 不改 API 的缺陷 / 数值 / 性能修复;行为只允许从"错"变"对" | + +- **版本权威 = `git tag`**:`CMakeLists.txt` 的 `project(... VERSION ...)` 与 `docs/release-notes/v*.md` + 都向 tag 对齐;一个正式 tag 配一册 release note。 +- **已发布版本不重打**:tag 发布即冻结;问题以勘误块追加在该册顶部并指向修复版本。 +- **当前最新版本不在本文维护**(写死号必然过时),查法: + ```bash + git tag --list 'v1.*' | sort -V | tail -1 # 最新正式版 + ``` + 历史遗留的非规范 tag(拼写错误的 `v.1.3.0`、`nightly`、`archive/*`、`0.1.0-Transformer` 等) + **不属版本序列**,不作版本权威,也不得仿照其命名。 + +## 2. 发布必须由人提出(agent 不得擅自发布) + +1. **版本号由人定档**:发版升哪一位、用正式号还是 rc、何时发,必须由**人**(维护者)在 + issue / 讨论 / 明确指令里写出;agent(AI 编码助手)**不得**自行推断或决定版本号。 +2. **人未给出明确的版本号与发布指令前,agent 禁止执行任何"把版本号变成发布事实"的动作**: + - `git tag` / `git push --tags` / `gh release create|edit|publish`; + - 改 `CMakeLists.txt` 的 `project(VERSION ...)` 为新的定档值; + - 在 `docs/release-notes/` 新建 `v*.md` **定稿**(草案可写,但必须标注"未定档")。 +3. **人发出指令后 agent 只是执行者**:可按 [`25-release-requirements.md`](25-release-requirements.md) + 清单代跑,但执行**前**须复述将用的版本号与动作清单并得到确认;号与内容不一致时**停下报告**, + 不得自行改号或"顺手"发版。 +4. **清单全绿 ≠ 可发布**:必做项全部就绪也不产生发布权——没有人的定档指令就不发。 + +> 违反口径:agent 擅自打出的 tag / release / 定稿 release note 一律视为无效产物,由人删除后 +> 按本文重走;事件记入 `docs/history/history.md`。 + +## 3. 开发分支与版本号的绑定 + +分支模型表(`main` / `dev` / `feature/` / `hotfix/` 的定位与流转)见 +[`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) §4;本节只钉**版本号落在哪条分支**: + +1. **`dev` 及其上的功能分支从不写版本号**: + - 不 bump `CMakeLists.txt` 的 `project(VERSION ...)`; + - 不新建 / 不定稿 `docs/release-notes/v*.md`; + - 不打任何 tag。 + "下一版可能是几号"只允许作为**讨论**出现在 issue / PR 描述里,不落进分支内容。 +2. **版本号必须在 `main` 分支发布**:定档、打 tag、发 GitHub release、同步 + `project(VERSION ...)`、release note 定稿——全部只发生在 `main`(发布基线 = `main`,tag 打在这里)。 +3. **流转顺序**:`feature/*` / `hotfix/*` → 合入 `dev` → 经审核合入 `main` → **在 `main` 上**按 + §1 定格式、按 §2 由人发起发布。 +4. 纯文档改动(含本文)可直接在 `main` 提 PR:文档不携带版本号,不受"dev 不写版本号"约束。 + +## 4. 真源表(谁管什么) + +| 主题 | 真源 | +|---|---| +| 版本号格式 / 位定义 / rc / 勘误细则 | [`../release-notes/README.md`](../release-notes/README.md) §1 | +| 分支模型(分支表与流转) | [`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) §4 | +| 版本号·分支·发布治理(本文三条规则) | 本文(`docs/todo/33-version-branch-and-release-policy.md`) | +| 大版本发布必做清单 | [`25-release-requirements.md`](25-release-requirements.md) | +| 版本权威与现状实测 | `git tag`;[`18-roadmap.md`](18-roadmap.md) §2 | +| 发布范围 / 主题 / 迁移指南 | [`../release-notes/`](../release-notes/) 每版一册 | diff --git a/docs/todo/README.md b/docs/todo/README.md index 901179d..d0f5c0b 100644 --- a/docs/todo/README.md +++ b/docs/todo/README.md @@ -13,7 +13,7 @@ 新增内容先判断属于哪一类:能二值化成"做/不做"的进 18,只描述顺序与动作的进 27。 - **允许带进度状态**(✅ 已实施 / ⏳ 待做 / ❌ 已否决),但**不写历史叙事**—— 演进过程、被否决方案的理由、旧数字一律进 `../history/history.md`。 -- 编号沿用历史编号(`02`…`31`),**编号缺号是正常的**(`05` `06` `20` 等留在 +- 编号沿用历史编号(**新增接当前最大号**,不重排旧号),**编号缺号是正常的**(`05` `06` `20` 等留在 `development/`;`13` 已删除;`15` `16` 已并入 `history/history.md`)。 ## 分类与索引 @@ -55,6 +55,7 @@ | [`14-f16-stable-gpu-loss-frozen.md`](14-f16-stable-gpu-loss-frozen.md) | **已修故障报告(根因已订正)**:GPU `--precision-stable f16` 训练 loss 打印冻结——真因 = CE 的 `(1,1)` 归约输出按 f16 落盘溢出(不是回读链) | | [`24-f16-training-defects.md`](24-f16-training-defects.md) | **f16 训练缺陷台账**:全 f16 NaN / loss 冻结 / `--f16` 降速——含报告核对与立项 F1–F7(F5 = 可训练性已完成;**F6 = 真 f16(Plan B)**;**F7 = 标准 `--f16`(Plan A)**) | | [`25-release-requirements.md`](25-release-requirements.md) | **大版本发布要求**(`1.x.y → 1.(x+1).0`):端到端模型训练测试 / 发布文档 / 完整 ctest + Debug 构建 / 多编译器 × 标准库矩阵 | +| [`33-version-branch-and-release-policy.md`](33-version-branch-and-release-policy.md) | **版本号·分支·发布治理(三条红线)**:`v1..<漏洞修复>` 规则、**发布版本号必须由人提出(agent 不得擅自发布)**、`dev` 不写版本号、发布只在 `main`。定版本号 / 发版 / 改分支策略前读 | ## 相关(相邻分册 / 总档) From 91a9bfd401d5d2a6c5b957c9c5d7fa37a011e6de Mon Sep 17 00:00:00 2001 From: EthanPeng-2048 Date: Fri, 30 Oct 2026 23:07:18 +0800 Subject: [PATCH 3/4] =?UTF-8?q?docs:=20=E6=96=87=E6=A1=A3=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E6=88=90=E6=96=87=20+=20=E7=9B=AE=E5=BD=95=E9=87=8D?= =?UTF-8?q?=E6=9E=84=20+=20=E6=9C=BA=E5=99=A8=E5=AE=A1=E6=9F=A5=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=20+=20=E6=A0=B9=20README=20=E9=87=8D=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 规范成文(docs/contributors/documentation-standard.md,此前无规范): - 分册职责矩阵 + 编号制度成文(internal/ = 稳定 ID 跳号;调用者分册 = 阅读顺序连续编号;contributors/ = 无编号主题名) - 单篇头部模板强制(读者 / 一句话结论 / 状态)+ 封闭状态词表 - 内容标注体系:代码示例角色(example api / snippet / cli)、API 符号 反引号口径、事实三分(机械事实 / 设计意图 / 未验证主张) - 历史性记载禁令:history/ 之外(含代码注释)不得出现"已在 commit xxx 修复"式叙事,一律改写为当前事实 目录重构: - docs/todo/ → docs/internal/(原名只覆盖待办语义,实际承载设计/台账) - 新增 docs/contributors/ 分册:cpp-standards(原 todo/10)、pitfalls (原 todo/08)、release-policy(原 todo/33)、release-requirements (原 todo/25)+ 新写 documentation-standard - docs/development/ 编号按阅读顺序重排(cmake-integration→01、 cpp-api-manual→02、write-a-custom-layer→03、compute-engine→04、 vulkan-backend-map→06、engine-ownership→07、rapt→08、ergonomics→09), 删除转发页 08-object-lifetimes(真源 = 07) - 全仓引用同步(136 个文件,含 gui.py/CMakeLists/bench 注释) 机器审查升级(scripts/doc_audit.py,跨平台,取代 ps1 口径): - 移植 ps1 A–D/F 类(文件/链接、已删符号、数字断言、CLI 参数、符号/测试名) - 新增 E 类(头部模板 + 状态词 + 索引登记)、G 类(提取全部 408 个代码块 生成人工复核清单)、H 类(历史性记载,行内 allow 豁免机制) - 全绿;ps1 保留至 Windows 侧迁移完成 根 README 重写为项目介绍(30 秒决策框架): - 图标(assets/icon-{dark,light}.svg)+ 亮点表 + "它不做什么"诚实边界 + 最短可跑路径 +
折叠次要信息;文档索引职责移交 docs/README.md 其余:全部 docs/**.md 补齐头部模板与状态词;release-notes 逐册登记; history.md 归档历次整理叙事(docs/README §3/§4 迁出) --- .github/workflows/cmake-single-platform.yml | 2 +- AGENTS.md | 135 ++--- CMakeLists.txt | 10 +- CONTRIBUTING.md | 61 ++- README.md | 413 ++++----------- assets/icon-dark.svg | 28 + assets/icon-light.svg | 28 + bench/doc_align_audit.ps1 | 6 +- bench/doc_inventory.ps1 | 4 +- bench/gui_cli_audit.py | 2 +- docs/README.md | 150 +++--- docs/benchmarks/2026-09-25-vulkan-vs-cuda.md | 6 +- docs/benchmarks/2026-10-06-vulkan-vs-torch.md | 2 +- docs/contributors/README.md | 39 ++ .../cpp-standards.md} | 7 +- docs/contributors/documentation-standard.md | 170 ++++++ .../pitfalls.md} | 9 +- .../release-policy.md} | 17 +- .../release-requirements.md} | 22 +- ...integration.md => 01-cmake-integration.md} | 1 + ...cpp-api-manual.md => 02-cpp-api-manual.md} | 23 +- ...om-layer.md => 03-write-a-custom-layer.md} | 5 +- ...nt.md => 04-compute-engine-development.md} | 11 +- docs/development/05-mixed-precision.md | 38 +- ...ackend-map.md => 06-vulkan-backend-map.md} | 2 + ...ne-ownership.md => 07-engine-ownership.md} | 10 +- docs/development/08-object-lifetimes.md | 8 - ...rapt-algorithm.md => 08-rapt-algorithm.md} | 7 +- ...omics.md => 09-custom-layer-ergonomics.md} | 14 +- docs/development/README.md | 38 +- docs/history/history.md | 276 ++++++---- .../00-code-review-remediation.md | 5 +- docs/{todo => internal}/02-operator-fusion.md | 3 +- docs/{todo => internal}/03-ir-optimization.md | 3 +- .../04-memory-optimization.md | 3 +- .../12-compute-engine-inventory.md | 7 +- .../14-f16-stable-gpu-loss-frozen.md | 1 + .../17-unified-tensor-engine.md | 3 +- docs/{todo => internal}/18-roadmap.md | 61 +-- docs/{todo => internal}/19-unified-dataset.md | 6 +- .../21-quantized-weights.md | 10 +- .../22-bitnet-2b4t-architecture.md | 4 +- ...ary-design-cleanup-and-model-file-roles.md | 1 + .../24-f16-training-defects.md | 9 +- .../{todo => internal}/26-f16-speedup-plan.md | 1 + docs/{todo => internal}/27-execution-plan.md | 1 + docs/{todo => internal}/28-lifecycle-v3.md | 14 +- .../29-session-architecture.md | 2 +- .../30-training-session-step.md | 2 +- .../31-rl-training-primitives.md | 2 +- .../32-trainer-skeleton-and-openspec.md | 2 +- docs/{todo => internal}/README.md | 24 +- docs/introduction/01-architecture.md | 4 +- docs/introduction/02-performance.md | 2 + docs/introduction/03-algorithm-reference.md | 2 + docs/introduction/04-innovative-designs.md | 2 + docs/release-notes/README.md | 23 +- docs/release-notes/v1.10.0-rc0.1.md | 4 +- docs/release-notes/v1.10.0-rc0.md | 4 +- docs/release-notes/v1.10.0.md | 16 +- docs/release-notes/v1.11.0.md | 10 +- docs/release-notes/v1.12.0.md | 4 +- docs/release-notes/v1.5.0.md | 6 +- docs/release-notes/v1.5.1.md | 2 +- docs/release-notes/v1.6.0.md | 6 +- docs/release-notes/v1.7.0.md | 6 +- docs/release-notes/v1.8.0.md | 2 +- docs/release-notes/v1.8.1.md | 4 +- docs/release-notes/v1.8.2.md | 18 +- docs/release-notes/v1.9.0.md | 8 +- docs/usage/01-quickstart-model.md | 8 +- docs/usage/02-quickstart-train-infer.md | 6 +- docs/usage/03-compute-engine-usage.md | 20 +- docs/usage/04-train-package.md | 4 +- docs/usage/05-consume-as-library.md | 4 +- docs/usage/06-reinforcement-learning.md | 2 +- docs/usage/07-thread-safety.md | 2 + gui.py | 4 +- include/neuralnet.cpp/algebra_matrix.hpp | 4 +- include/neuralnet.cpp/batch_source.hpp | 4 +- .../cli/cli_precision_warning.hpp | 4 +- .../cli/text_train_checkpoint.hpp | 6 +- .../neuralnet.cpp/cli/text_train_config.hpp | 12 +- include/neuralnet.cpp/cli/text_train_loop.hpp | 2 +- .../neuralnet.cpp/cli/text_train_recovery.hpp | 10 +- include/neuralnet.cpp/compute_engine.hpp | 16 +- .../neuralnet.cpp/compute_layer_attention.hpp | 6 +- include/neuralnet.cpp/compute_layer_base.hpp | 14 +- .../neuralnet.cpp/compute_layer_bitlinear.hpp | 4 +- .../compute_layer_feedforward.hpp | 2 +- include/neuralnet.cpp/compute_layer_gpt.hpp | 2 +- include/neuralnet.cpp/compute_layer_rapt.hpp | 6 +- include/neuralnet.cpp/compute_loss.hpp | 4 +- include/neuralnet.cpp/compute_optimizer.hpp | 6 +- include/neuralnet.cpp/compute_tensor.hpp | 14 +- include/neuralnet.cpp/core_domain.hpp | 2 +- include/neuralnet.cpp/core_observer_ptr.hpp | 2 +- include/neuralnet.cpp/dataset_samples.hpp | 2 +- include/neuralnet.cpp/domain_mnist.hpp | 4 +- include/neuralnet.cpp/engine.hpp | 2 +- include/neuralnet.cpp/expr_dsl.hpp | 8 +- include/neuralnet.cpp/expr_emitter.hpp | 2 +- include/neuralnet.cpp/expr_glsl_gen.hpp | 6 +- include/neuralnet.cpp/expr_graph.hpp | 2 +- include/neuralnet.cpp/expr_opt.hpp | 6 +- include/neuralnet.cpp/expr_spec.hpp | 4 +- include/neuralnet.cpp/model_container.hpp | 4 +- include/neuralnet.cpp/model_serialization.hpp | 12 +- include/neuralnet.cpp/model_spec.hpp | 4 +- include/neuralnet.cpp/rl_experience.hpp | 2 +- include/neuralnet.cpp/rl_pipeline.hpp | 2 +- include/neuralnet.cpp/rl_policy.hpp | 2 +- include/neuralnet.cpp/run_driver.hpp | 2 +- include/neuralnet.cpp/tensor_schema.hpp | 2 +- include/neuralnet.cpp/ternary_pack.hpp | 4 +- include/neuralnet.cpp/text_train_config.hpp | 2 +- include/neuralnet.cpp/text_trainer.hpp | 4 +- include/neuralnet.cpp/train_state.hpp | 8 +- include/neuralnet.cpp/training_session.hpp | 2 +- research/README.md | 6 +- research/f16_weight_decay/REPORT.md | 4 +- research/rla/README.md | 2 +- research/ternary_scale/REPORT.md | 2 +- research/ternary_scale/probe_scale.cpp | 2 +- research/ternary_ste/REPORT.md | 4 +- research/ternary_ste/poc_binary_ste.cpp | 2 +- research/ternary_ste/poc_ternary_ste.cpp | 2 +- scripts/doc_audit.py | 487 ++++++++++++++++++ shaders/scatter_add.comp | 2 +- src/adam_quant_test.cpp | 2 +- src/bitnet_struct_test.cpp | 6 +- src/chat_prompt_test.cpp | 2 +- src/cli_precision_warning_test.cpp | 4 +- src/dataset_convert.cpp | 4 +- src/dataset_gen.cpp | 2 +- src/dataset_samples_test.cpp | 2 +- src/dsl_shape_infer_test.cpp | 2 +- src/expr_fused_key_test.cpp | 2 +- src/expr_graph_test.cpp | 2 +- src/expr_matmul_test.cpp | 4 +- src/expr_opt_test.cpp | 2 +- src/expr_reduce_test.cpp | 2 +- src/f16_precision_test.cpp | 4 +- src/layer_lifetime_test.cpp | 2 +- src/lifetime_contract_test.cpp | 2 +- src/mnist_train.cpp | 16 +- src/model_roles_test.cpp | 2 +- src/optimizer_state_test.cpp | 2 +- src/rl_experience_test.cpp | 2 +- src/t1_58_test.cpp | 2 +- src/tensor_precision_test.cpp | 2 +- src/tensor_schema_test.cpp | 2 +- src/ternary_gemm_test.cpp | 2 +- src/test_common.hpp | 2 +- src/text_train.cpp | 14 +- src/text_train_modules_test.cpp | 6 +- src/text_trainer_test.cpp | 2 +- src/train_state_test.cpp | 2 +- src/training_session_test.cpp | 4 +- src/write_epoch_test.cpp | 2 +- tools/scan_exprs.cpp | 10 +- 161 files changed, 1695 insertions(+), 1021 deletions(-) create mode 100644 assets/icon-dark.svg create mode 100644 assets/icon-light.svg create mode 100644 docs/contributors/README.md rename docs/{todo/10-development-standards.md => contributors/cpp-standards.md} (98%) create mode 100644 docs/contributors/documentation-standard.md rename docs/{todo/08-pitfalls-and-lessons.md => contributors/pitfalls.md} (98%) rename docs/{todo/33-version-branch-and-release-policy.md => contributors/release-policy.md} (87%) rename docs/{todo/25-release-requirements.md => contributors/release-requirements.md} (92%) rename docs/development/{cmake-integration.md => 01-cmake-integration.md} (99%) rename docs/development/{cpp-api-manual.md => 02-cpp-api-manual.md} (98%) rename docs/development/{write-a-custom-layer.md => 03-write-a-custom-layer.md} (98%) rename docs/development/{01-compute-engine-development.md => 04-compute-engine-development.md} (98%) rename docs/development/{07-vulkan-backend-map.md => 06-vulkan-backend-map.md} (98%) rename docs/development/{09-engine-ownership.md => 07-engine-ownership.md} (93%) delete mode 100644 docs/development/08-object-lifetimes.md rename docs/development/{06-rapt-algorithm.md => 08-rapt-algorithm.md} (97%) rename docs/development/{20-custom-layer-ergonomics.md => 09-custom-layer-ergonomics.md} (94%) rename docs/{todo => internal}/00-code-review-remediation.md (99%) rename docs/{todo => internal}/02-operator-fusion.md (99%) rename docs/{todo => internal}/03-ir-optimization.md (98%) rename docs/{todo => internal}/04-memory-optimization.md (99%) rename docs/{todo => internal}/12-compute-engine-inventory.md (99%) rename docs/{todo => internal}/14-f16-stable-gpu-loss-frozen.md (99%) rename docs/{todo => internal}/17-unified-tensor-engine.md (99%) rename docs/{todo => internal}/18-roadmap.md (93%) rename docs/{todo => internal}/19-unified-dataset.md (99%) rename docs/{todo => internal}/21-quantized-weights.md (99%) rename docs/{todo => internal}/22-bitnet-2b4t-architecture.md (99%) rename docs/{todo => internal}/23-library-design-cleanup-and-model-file-roles.md (99%) rename docs/{todo => internal}/24-f16-training-defects.md (96%) rename docs/{todo => internal}/26-f16-speedup-plan.md (99%) rename docs/{todo => internal}/27-execution-plan.md (99%) rename docs/{todo => internal}/28-lifecycle-v3.md (95%) rename docs/{todo => internal}/29-session-architecture.md (99%) rename docs/{todo => internal}/30-training-session-step.md (99%) rename docs/{todo => internal}/31-rl-training-primitives.md (99%) rename docs/{todo => internal}/32-trainer-skeleton-and-openspec.md (99%) rename docs/{todo => internal}/README.md (82%) create mode 100644 scripts/doc_audit.py diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 65c4e0b..095b574 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -233,7 +233,7 @@ jobs: # 注:v3 生命周期起删除"绑定调试开关"第二轮 ctest —— 设备域检查已从 # "库外豁免 + 调试开关"升级为**默认入口检查**(每个操作数必须属于本引擎域), - # 不再需要补丁式第二轮门禁。见 docs/todo/28-lifecycle-v3.md §4.3。 + # 不再需要补丁式第二轮门禁。见 docs/internal/28-lifecycle-v3.md §4.3。 # 将编译产物打包为 7z - name: Package binaries (Linux) diff --git a/AGENTS.md b/AGENTS.md index b3238ea..ba8962c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ > 本文档专为 AI 编码助手编写:用最少 token 建立项目心智模型,快速开始开发。 > 人类向的完整文档在 `docs/`(索引见 §11)。**改代码前必读 §5 铁律与 §10 高频坑。** -> **开发规范 / 发布要求等规则正文不在本文,本文只给引用**:C++ 开发规范 → `docs/todo/10-development-standards.md`;版本号规范(格式/位定义)→ `docs/release-notes/README.md` §1;版本号·分支·发布治理(**发布须由人提出、agent 不得擅自发布**;`dev` 不写版本号、发布只在 `main`)→ `docs/todo/33-version-branch-and-release-policy.md`;大版本发布清单 → `docs/todo/25-release-requirements.md`;分支模型与提 PR → `CONTRIBUTING.md` §4。 +> **开发规范 / 发布要求等规则正文不在本文,本文只给引用**:C++ 开发规范 → `docs/contributors/cpp-standards.md`;版本号规范(格式/位定义)→ `docs/release-notes/README.md` §1;版本号·分支·发布治理(**发布须由人提出、agent 不得擅自发布**;`dev` 不写版本号、发布只在 `main`)→ `docs/contributors/release-policy.md`;大版本发布清单 → `docs/contributors/release-requirements.md`;分支模型与提 PR → `CONTRIBUTING.md` §4。 > 本文只记录**当前状态**;演进记录、已修复勘误、被否决方案与性能 A/B 过程统一归档在 `docs/history/history.md`(索引见 §11)。当前能力清单见 §12。 ## 1. 项目一句话 @@ -29,7 +29,7 @@ cmake -B build -G Ninja -DNN_ENABLE_TESTS=ON && cmake --build build && ctest --t - **预设构建(`CMakePresets.json`,2026-10-11 落地)**:`cmake --preset <名>` + `cmake --build --preset <名>` + `ctest --preset <名>`;`cmake --list-presets` 看全部。六个 preset = `release`(Release+native,无测试)/ `dev`(+`NN_ENABLE_TESTS`)/ `debug`(`-O0 -g`)/ `portable`(`NN_ENABLE_NATIVE=OFF`,发布/CI 口径)/ `cpu`(`NN_ENABLE_GPU=OFF`,纯 CPU 最短路径)/ `probes`(+`NN_ENABLE_PROBES`)。`binaryDir` = `build/`;另有 `caller` 无关的 `build`/`test`/`workflow` preset(`cmake --workflow --preset dev` 一条命令走完)。**preset 只描述本仓的构建口径,不改变 CMakeLists 的默认值**——不带 preset 的 `cmake -B build -G Ninja` 行为与以前逐字相同。 - **探针统一编译门 `NN_ENABLE_PROBES`(默认 OFF,2026-10-10)**:凡"在**热路径**采样/打印/下载/扫描"的诊断代码一律走这个门——库内 `nn_dbg_scan`(`NN_F16_DEBUG` 逐中间量扫描)、`NN_PREC_TRACE`(变体分派与边界 cast 形状归因 `note_temp_`)、`nn::dsl::env_flag` / `ComputeEngine::prec_env_flag`(门关时**不求值 getenv**、恒 false)、`text_train` 的 `NN_NAN_TRACE` / `NN_MEM_STATS`,以及探针可执行目标 `mem_probe` / `f16_cpu_probe` / `gpu_stability_probe`(门关时**连目标都不创建**)。门经 `nn_core` 的 **INTERFACE** 定义传播(`NN_ENABLE_PROBES=1`)→ 所有 TU 与嵌入消费方取值一致(同头两种语义 = ODR 隐患);`core_config.hpp` 把它折成 `NN_PROBES_ENABLED`(0/1)。**默认构建里探针不参与编译**:没有额外分支、没有字符串、没有 host 下载路径,相关环境变量一律无效——探针只在排障时 `-DNN_ENABLE_PROBES=ON` 重新配置,不允许"设了环境变量就悄悄拖慢正常训练/推理"。**例外(不进本门)**:① 初始化期读一次并缓存的**行为开关**——`NN_VULKAN_DEVICE` / `NN_VULKAN_NO_16BIT_ALU` / `NN_VULKAN_NO_TIMELINE`(设备与特性逃生阀)、`NN_POOL_BLOCK_MB` / `NN_POOL_LADDER_MAX_MB` / `NN_NO_EARLY_REAP` / `NN_CPU_PAUSE` / `NN_GPU_PROFILE`(池/调度 A/B),新增同类开关必须"读一次 + 缓存";② `f16_writeback_probe` 是**注册在 ctest 的回归用例**(断言 in-place f16 写回 + 8 步 Adam 参数必须移动),刻意保留在默认测试门禁里。凡是"覆盖率/归因"类验收(如 `NN_PREC_TRACE` 的 V1 覆盖实测)必须在探针构建下复现。 - **作为库被消费(嵌入 3rd_party / FetchContent)**:门面目标 `neuralnet::nn`——消费方 `add_subdirectory` 后 `target_link_libraries(app PRIVATE neuralnet::nn)` + `#include ` 即可(C++26/线程/`NN_HAS_VULKAN`/SPIR-V 嵌入头目录/Vulkan 链接/shader 生成顺序全部经接口传递)。嵌入时 `NN_BUILD_APPS` 默认 OFF(不编本仓 app/工具;顶层工程默认 ON);`NN_ENABLE_GPU=AUTO|ON|OFF` 一行控制 GPU(`OFF`=纯 CPU 最快路径,`ON`=缺 Vulkan/glslc 配置期失败);自研 `dsl::compute` 的融合注册 `nn_enable_gpu_fusion( MAIN )`(仅 GPU 启用时有定义;**函数体在调用方作用域求值**,库内路径经 `NN_LIB_SOURCE_DIR`/`NN_LIB_BINARY_DIR` CACHE 变量解析,函数内不可用 `CMAKE_SOURCE_DIR`)。样例 `examples/downstream/`(独立工程),指南 `docs/usage/05-consume-as-library.md`。⚠ 两条实测约束:① `Vulkan::Vulkan` 是 imported 目标**不可跨目录直接引用**(消费方直接链接报 target not found),一律经 `neuralnet::nn` 传递;② 库头文件需要 `-Wno-pass-failed`/`-fexperimental-library`(Clang)与 `/utf-8`(MSVC),已作为接口选项随门面传递——漏传时消费方开 `-Werror` 会挂在 `#pragma clang loop` 警告上。 -- **编译提速(默认已开启,无需额外配置)**:本工程 header-only,单 TU 17.5s 的大头是重复 parse `nn.hpp`(含 44 份原语 SPIR-V 嵌入头 + AOT 融合注册表)。已落地五件事:① `NN_ENABLE_PCH`——`nn.hpp` 预编译一次,由编译条件相同的目标 `REUSE_FROM nn_pch` 共享(本机 GPU+tests 构建实测 48 个候选目标、其中 2 个自带 PCH);② `CMAKE_CXX_SCAN_FOR_MODULES OFF`——本项目零 C++ 模块,省掉每 TU 一次 `clang-scan-deps`;③ `scan_exprs` 的 glslc **并行**(`NN_SCAN_JOBS=` 覆盖,`=1` 回串行)+ `fused_registry.hpp` **内容稳定写入**(内容不变则不动 mtime,靠自定义命令的 `restat` 掐断下游全量重编);④ 编译器缓存探测扩到 ccache/**sccache**(`-DNN_COMPILER_LAUNCHER=` 可指定);⑤ **ccache × 共享 PCH 的兼容**(2026-10-11)——ccache 手册要求 Clang 侧 `sloppiness=pch_defines,time_macros` + `-include-pch` + **`-fno-pch-timestamp`** 三项齐备才肯缓存"用了 PCH 的 TU";前两项由构建系统用 `cmake -E env` 钉进 `RULE_LAUNCH_COMPILE` 前缀(**不依赖用户全局 ccache 配置**),第三项(cc1 开关,必须 `-Xclang` 形式)自动加到 PCH 生成方与全部使用方。**修复前每一个用 PCH 的 TU 都记 "Could not use precompiled header" → 42+ 个目标的编译全部不可缓存**(缓存形同虚设却看不出来);修复后同一个 TU:30.2s → **0.11s**(Release,命中缓存)。顺带删掉 `RULE_LAUNCH_LINK`(本项目不做 LTO,ccache 包链接只有开销)。实测(Debug/本机):全量净构建 125.5s→72.7s、改单个源文件 43.9s→10.4s;Release+tests+GPU 全量冷构建 13m26s / 8 核(单个 TU ≈30s、PCH ≈54s;`-ftime-trace` 归因:**后端 29.1s vs 前端 4.0s** —— PCH 之后的大头已是 LLVM 优化/代码生成,不是头解析;口径与复现见 `docs/development/cmake-integration.md` §8)。**⚠ 两条不变量**:(a) 收集器目标(`scan_exprs`、`*_nnfusion_collect`)**不套 PCH**——前者在源文件内、include 之前 `#define NN_EXPR_SCAN`,PCH 会先于该宏展开 `nn.hpp` → DSL 收集钩子失效(注册表空);(b) 新写"生成物参与 PCH"的场景必须显式 `add_dependencies(, <生成边>)`——`__has_include` 在 PCH 里**一次性**求值,早于生成完成就整块落空且因无 depfile 记录而永不重试。 +- **编译提速(默认已开启,无需额外配置)**:本工程 header-only,单 TU 17.5s 的大头是重复 parse `nn.hpp`(含 44 份原语 SPIR-V 嵌入头 + AOT 融合注册表)。已落地五件事:① `NN_ENABLE_PCH`——`nn.hpp` 预编译一次,由编译条件相同的目标 `REUSE_FROM nn_pch` 共享(本机 GPU+tests 构建实测 48 个候选目标、其中 2 个自带 PCH);② `CMAKE_CXX_SCAN_FOR_MODULES OFF`——本项目零 C++ 模块,省掉每 TU 一次 `clang-scan-deps`;③ `scan_exprs` 的 glslc **并行**(`NN_SCAN_JOBS=` 覆盖,`=1` 回串行)+ `fused_registry.hpp` **内容稳定写入**(内容不变则不动 mtime,靠自定义命令的 `restat` 掐断下游全量重编);④ 编译器缓存探测扩到 ccache/**sccache**(`-DNN_COMPILER_LAUNCHER=` 可指定);⑤ **ccache × 共享 PCH 的兼容**(2026-10-11)——ccache 手册要求 Clang 侧 `sloppiness=pch_defines,time_macros` + `-include-pch` + **`-fno-pch-timestamp`** 三项齐备才肯缓存"用了 PCH 的 TU";前两项由构建系统用 `cmake -E env` 钉进 `RULE_LAUNCH_COMPILE` 前缀(**不依赖用户全局 ccache 配置**),第三项(cc1 开关,必须 `-Xclang` 形式)自动加到 PCH 生成方与全部使用方。**修复前每一个用 PCH 的 TU 都记 "Could not use precompiled header" → 42+ 个目标的编译全部不可缓存**(缓存形同虚设却看不出来);修复后同一个 TU:30.2s → **0.11s**(Release,命中缓存)。顺带删掉 `RULE_LAUNCH_LINK`(本项目不做 LTO,ccache 包链接只有开销)。实测(Debug/本机):全量净构建 125.5s→72.7s、改单个源文件 43.9s→10.4s;Release+tests+GPU 全量冷构建 13m26s / 8 核(单个 TU ≈30s、PCH ≈54s;`-ftime-trace` 归因:**后端 29.1s vs 前端 4.0s** —— PCH 之后的大头已是 LLVM 优化/代码生成,不是头解析;口径与复现见 `docs/development/01-cmake-integration.md` §8)。**⚠ 两条不变量**:(a) 收集器目标(`scan_exprs`、`*_nnfusion_collect`)**不套 PCH**——前者在源文件内、include 之前 `#define NN_EXPR_SCAN`,PCH 会先于该宏展开 `nn.hpp` → DSL 收集钩子失效(注册表空);(b) 新写"生成物参与 PCH"的场景必须显式 `add_dependencies(, <生成边>)`——`__has_include` 在 PCH 里**一次性**求值,早于生成完成就整块落空且因无 depfile 记录而永不重试。 - Vulkan 可选:CMake 自动探测 Vulkan + glslc,找到则定义 `NN_HAS_VULKAN` 启用 GPU,否则纯 CPU。支持多 Vulkan 设备选择(`--gpu` 参数,见 `cli/cli_gpu_option.hpp`)。 - **本机 GPU 测试(NVIDIA GeForce GTX 850M,Maxwell / 驱动 580.178.04 / Vulkan)**:① 设备节点 `/dev/nvidia*` 在受限沙箱内**不可见** → GPU 测试必须在非沙箱(提权)环境执行,否则只会落到 llvmpipe(软件光栅,慢且 f16 行为不同);② 显式选卡 `NN_VULKAN_DEVICE=850M`(等价 CLI `--gpu=850M`),不写也会被自动选中(打分:独显 3 > 核显 2 > llvmpipe 1),显式写只是免歧义;③ Maxwell 无 `shaderFloat16`(f16 存储可用、f16 ALU 走回退)→ **f16 分派变体(V1/V2)的权威覆盖仍以 40HX(`ethan@192.168.1.102`)为准**,850M 适合跑"接线/闭合世界/三值正确性"这类冒烟与回归。 - **本项目不支持 CUDA**:后端仅 CPU / Vulkan,CLI 无 `--cuda` 参数;文档勿声称支持 CUDA。 @@ -54,22 +54,22 @@ cmake -B build -G Ninja -DNN_ENABLE_TESTS=ON && cmake --build build && ctest --t | 表达式 DSL / 融合 IR | `expr_dsl.hpp` / `expr_spec.hpp` / `expr_opt.hpp` / `expr_registry.hpp` / `expr_graph.hpp`(IR-C 图融合 = **现行能力**:`expr_graph.hpp` + `begin_expr/end_expr` + `dsl::start_expr/end_expr` + GPU 图执行;P1 链/P2 写穿多输出,已接入 Adam/AdamW step) | | 后端代码生成(IR-D emitter 抽象) | `expr_emitter.hpp`(注册表)+ `expr_glsl_gen.hpp`(GlslEmitter) | | 模型容器/规格/序列化 | `model_container.hpp` / `model_spec.hpp` / `model_serialization.hpp` / `model_keyvalue_record.hpp` | -| 训练生命周期容器(推荐入口) | `training_session.hpp`:`TrainingSession` 拥有 `Model` + `Optimizer` + `TrainingSessionState`(optimizer 先于 Model 析构),`train_step` 处理单 Tensor 输出,`train_named_step` 处理 `GradientBundle`/具名多输出;两者共享累积/归一化/update 语义。不拥有数据/epoch/lr 曲线/断点策略(docs/todo/30) | +| 训练生命周期容器(推荐入口) | `training_session.hpp`:`TrainingSession` 拥有 `Model` + `Optimizer` + `TrainingSessionState`(optimizer 先于 Model 析构),`train_step` 处理单 Tensor 输出,`train_named_step` 处理 `GradientBundle`/具名多输出;两者共享累积/归一化/update 语义。不拥有数据/epoch/lr 曲线/断点策略(docs/internal/30) | | RL 与可组合训练 | `rl.hpp` 薄聚合;`tensor_schema.hpp`/`named_tensor_set.hpp`、`compute_layer_bundle.hpp`、`rl_experience.hpp`、`rl_policy.hpp`、`training_group_session.hpp`、`rl_pipeline.hpp`。指南 `docs/usage/06-reinforcement-learning.md` | | 训练工厂(数据集 → global batch → 循环) | `text_trainer.hpp`:`nn::TextTrainer`(`create(session, dataset, TextTrainConfig)` → `fit()`;global→micro batch 切分、shuffle/lr 调度/非阻塞 loss 回读/测试评估/`TrainState` 与断点状态装配;Step 回调承载文本 sparse-CE)+ `text_train_config.hpp`(`nn::TextTrainConfig` = 训练配方唯一真源)+ `lr_scheduler.hpp`(update-step 级 lr) | | MNIST / GPT / CNN / RLA / 分词器 模型工厂 | `domain_mnist.hpp` / `domain_gpt.hpp` / `domain_cnn.hpp` / `domain_rla.hpp` / `domain_tokenizer{,_base,_bpe,_charbpe}.hpp` | | 训练/推理 CLI 入口 | `src/mnist_train.cpp` 等;公共 CLI 逻辑在 `include/neuralnet.cpp/cli/`(**`cli_help.hpp` = 各 `--help` 的统一排版器**:宽度感知对齐、统一版式;改帮助/加选项前先读其文件头的审计约定)。**`text_train` 已模块化(P1-1)且训练循环已上收库层(P2b)**:`cli/text_train_config.hpp`(`TrainConfig : nn::TextTrainConfig` + `--help` + argv 解析 = CLI 参数解析层,**唯一允许 `std::exit`**)、`cli/text_train_loop.hpp`(只装 CLI hooks:梯度日志/探针/`.nnckpt` 写盘 → 调 `TextTrainer::fit()`)、`cli/text_train_recovery.hpp`(`--resume`)、`cli/text_train_checkpoint.hpp`(`.nnckpt`/`.nnmodel` 产出 + 退出码语义);`src/text_train.cpp` 只留接线与唯一出口 `main`,三个模块**不得终止进程**(经 `Result` 上抛;门禁 `bench/doc_inventory.ps1` 第 [6] 节) | | 推理采样(top-k / top-p / 重复惩罚 / 种子)+ 多轮对话(`--turn`/`--reply-out`/`--system`) | 采样:`compute_layer_base.hpp`(`SamplingConfig` + 共用 `sample_next_token_`,**host 侧采样、不进 AOT 闭合世界**)+ `compute_layer_{gpt,rapt}.hpp` 的 `generate`(配置重载;旧 temperature 重载 = 全默认语义)+ `src/text_infer.cpp` 的 `--top-k`/`--top-p`/`--repeat-penalty`/`--repeat-window`/`--seed`。多轮:prompt 构建唯一真源 = `domain_tokenizer_base.hpp` 的 `Tokenizer::chat_prompt`(`ChatTurn` + 对话标记模板 + 按整轮截断到 `seq_len`);CLI 侧 `--interactive`(进程内累积)与 `--turn`(历史由调用方自带,一次一问)+ `--reply-out`(回复落盘,GUI 取回复不解析日志);GUI 侧 `cli_controllers.py` 的 `ChatSession` + `gui.py` 的「GPT 推理」页多轮面板;门禁 `chat_prompt_test` + `bench/gui_cli_audit.py` 第 [7] 节 | -| 统一数据集(`.nndataset`/`.nnvocab`/KVRecord v2) | `dataset.hpp`(`nn::Dataset` 只读类 + 生成期公共件;存储单位 = **doc**,`DatasetSubset{Train,Test}`)/ `dataset_samples.hpp`(训练单位 = **样本**:`TextSample`/`TextSampleSet`——切窗 + batch 装配;`steps_per_epoch(global_batch_size)` 是 optimizer update 数的派生量)/ `dataset_format.hpp`(文件标签/词表 blob/`.nnvocab` 编解码)/ `model_keyvalue_record.hpp`(KVRecord v1+v2);生成/转换 CLI 在 `src/dataset_gen.cpp` / `src/dataset_convert.cpp`(设计与裁决见 `docs/todo/19-unified-dataset.md`) | +| 统一数据集(`.nndataset`/`.nnvocab`/KVRecord v2) | `dataset.hpp`(`nn::Dataset` 只读类 + 生成期公共件;存储单位 = **doc**,`DatasetSubset{Train,Test}`)/ `dataset_samples.hpp`(训练单位 = **样本**:`TextSample`/`TextSampleSet`——切窗 + batch 装配;`steps_per_epoch(global_batch_size)` 是 optimizer update 数的派生量)/ `dataset_format.hpp`(文件标签/词表 blob/`.nnvocab` 编解码)/ `model_keyvalue_record.hpp`(KVRecord v1+v2);生成/转换 CLI 在 `src/dataset_gen.cpp` / `src/dataset_convert.cpp`(设计与裁决见 `docs/internal/19-unified-dataset.md`) | | 训练 step 剖析器(`NN_PROFILE=1` 门控) | `core_profile.hpp`(聚合器:帧栈 inclusive/exclusive 双口径、`stage::op` 聚合、`NN_PROFILE_TRACE` Chrome trace、`device_add` 设备侧回填(含 per-key 归因表)、`interned`/`interned_detail` 动态名驻留);插桩点:`compute_engine.hpp` 42 个 NVI 入口 + `expr_dsl.hpp` 三入口(CPU 模板路径不经引擎,须单独计时)+ 两引擎 public-virtual override + `text_train` phase + Model/GPT/RAPT/Transformer 逐层逐块 scope + `compute_vk_backend.hpp` timestamp query(设备侧 kernel 表 / per-key 归因 / GPU busy%) | | 构建期工具(AOT 融合) | `tools/scan_exprs.cpp`(**单步** = 收集 + 生成)/ `tools/fused_generate.hpp`(生成阶段,原独立工具 `gen_fused`;另有 `tools/decode_fused.py` 调试用)。**库外使用者**:CMake 函数 `nn_enable_gpu_fusion( MAIN <含 main 的源>)`(定义在 `CMakeLists.txt`,样例 `examples/fusion_custom_layer*`) | -| 批量改写 / 一致性审计(改多处时用,均带 `-DryRun`) | `tools/edit_ranges.ps1`(行区间删除:四重断言 + **花括号平衡护栏**)/ `tools/test_refactor.ps1`(删定义块 / 插 include / 正则替换)/ `tools/apply_nn_try.ps1`(`auto X = f(); if (!X) …` → `NN_TRY`/`NN_TRY_CHECK`,L2 层,带 `-DryRun` 计数)/ `tools/doc_rename.ps1`(文档词法改名)/ `bench/doc_align_audit.ps1`(文档↔代码对齐审计:文件/符号/CLI/数字/测试名)/ `bench/doc_inventory.ps1`(引擎接口盘点 + **第 [4] 节 L2+ 分层审计:`Matrix`/Matrix 型 I/O 动词零命中门禁,铁律 #12** + **第 [5] 节手写 `return std::unexpected` 残留门禁,基线 0**) | +| 批量改写 / 一致性审计(改多处时用,均带 `-DryRun`) | `tools/edit_ranges.ps1`(行区间删除:四重断言 + **花括号平衡护栏**)/ `tools/test_refactor.ps1`(删定义块 / 插 include / 正则替换)/ `tools/apply_nn_try.ps1`(`auto X = f(); if (!X) …` → `NN_TRY`/`NN_TRY_CHECK`,L2 层,带 `-DryRun` 计数)/ `tools/doc_rename.ps1`(文档词法改名)/ `scripts/doc_audit.py`(文档↔代码对齐 + 文档规范审计:文件/链接/符号/CLI/头部模板/索引登记/历史性记载/代码示例清单;改文档必跑)/ `bench/doc_inventory.ps1`(引擎接口盘点 + **第 [4] 节 L2+ 分层审计:`Matrix`/Matrix 型 I/O 动词零命中门禁,铁律 #12** + **第 [5] 节手写 `return std::unexpected` 残留门禁,基线 0**) | | 与 PyTorch 对拍 | `compare_with_torch/`(model.py / text_train.py / text_infer.py) | | GUI ↔ CLI 一致性(改 `gui.py`/`cli_controllers.py`/任一 CLI 选项后跑) | `bench/gui_cli_audit.py`(**七节**:GUI→CLI flag 差集 + 反向缺失、幽灵选项=帮助声明 vs 解析分支、`gui.py` 的 `self.X` 赋值静态校验、优化器名单、**声明式字段表 ↔ Controller 闭包(P2-6)**、**断点续训禁列(P1-2)**、**多轮对话闭环(P0-5 尾项)**;退出码 0 = 无偏差。复现:`python bench/gui_cli_audit.py`) | | 加/改 GUI 参数行(P2-6 声明式表) | `gui.py` 各 Tab 的 `fields()` —— **一个 `Field` = 一行 UI + 一条 `collect_args` 语义**(`Field`/`collect_fields`/`ParamsMixin` 在文件中部);表表达不了的条件语义(engine→`--gpu`、精度预设→`--f16`/`--t1_58`、输入方式→`input`)留在该 Tab 的 `collect_args` 后处理里,并用 `_v()`/`ui_only=True` 声明给门禁 | | 参与/贡献入口(**给非作者**:构建/测试/规范/PR/CI 口径) | `CONTRIBUTING.md` + `CODE_OF_CONDUCT.md`;预设构建 `CMakePresets.json`(`cmake --preset dev/portable/cpu/probes`) | | 可引用的实测结论(结论/证据/重跑命令/边界) | `research/`(索引 `research/README.md`;一次研究一个子目录)。代码/设计稿引用这些结论时按四段式引用 | -| 代码风格(机器可读) | `.clang-format`(**目标风格**,用 `git clang-format` 只格式化自己的改动行;**不要**整仓重排)+ `.editorconfig` + `.gitattributes`(全仓 **LF**);规则文本见 `docs/todo/10-development-standards.md` §8 | +| 代码风格(机器可读) | `.clang-format`(**目标风格**,用 `git clang-format` 只格式化自己的改动行;**不要**整仓重排)+ `.editorconfig` + `.gitattributes`(全仓 **LF**);规则文本见 `docs/contributors/cpp-standards.md` §8 | ## 4. 分层架构(L0→L5,严格单向依赖,上层只依赖下层公有接口) @@ -147,9 +147,9 @@ Matrix → engine.from_matrix → Tensor[GPU] → forward/loss/optimizer 全程 **多精度**:`Precision`(F16/F32 为**存储/舍入**精度;BF16/F64 是保留值,使用即报错)贯穿张量存储与算子输出;`PrecisionProfile{param/compute/stable/optimizer}` 做模型级配置。语义锚点见 `precision.hpp` 头注释与 `docs/development/05-mixed-precision.md`。 -**三值权重(T1_58,1.58-bit)**:`Precision::T1_58` 是**离散化**而不是舍入——它把权重按逐行 absmean 尺度投影到 `{-1,0,+1}`、需要额外尺度 γ,且**不进提升序**(`precision_rank()` 无定义,`max_precision` 对它 fail-fast)。P1 里它**不是存储精度**(`precision_bytes = 0`;`create_tensor`/`from_matrix`/`dsl::compute` 一律拒绝拿它建张量/当输出),只作为 `PrecisionProfile.param` 的一句声明 + 层能力集合的取值。落地形态:**每个 Layer 按槽声明自己支持的精度**(`PrecisionSupport{param,compute,stable,optimizer}`,默认 `{f16,f32}×四槽` → 既有层一行不改),`Layer::init`(NVI 首步)做唯一校验,不兼容组合 = **初始化期报错**(层名 + 槽位 + 取值 + 允许集合);`set_precision_profile` 在已 init 时 fail-fast("profile init 后不可变")。谁声明什么:`BitLinear`(三值线性层:量化 forward + STE backward,latent 恒 f32)`param={T1_58}`、其余层默认。CLI 只有 `--precision-param t1_58`(**无别名**;compute/stable/optimizer 收它即解析期报错),`ModelSpec.weight_quant` 记住"该模型用 BitLinear"(缺键 = None → 旧文件零破坏)。**接线范围(P1 = MLP,P1.5 = GPT)**:GPT 的 4 个投影 / `fc1_/fc2_` / 未 tie 的 `lm_head_` 全部走 `make_linear_layer` 工厂(成员类型 `std::unique_ptr`,与 `make_norm_layer` 同一先例),开关判据唯一 `effective_weight_quant()`(`precision.param == T1_58` ⇔ `weight_quant == T1_58`),profile 由 `split_ternary_profile()` 分流(`param=T1_58` 只给 BitLinear;复合层自身 / norm / 位置编码拿 param 归一化为 f32 的那份;未以三值模式构造却收到 T1_58 → fail-fast,不静默降级);**RAPT / ViT 明确拒绝**(`--arch rapt --precision-param t1_58` 前置报错;ViT 在 `PatchEmbedding` 能力校验处报错)。GPU 侧结构由 `scan_exprs` 的模型 pass 登记(含两条三值 GPT 用例;结构数 107)。完整设计/架构图/验收见 `docs/todo/21-quantized-weights.md` §4.10 与 `docs/todo/22-bitnet-2b4t-architecture.md` §3.4。 +**三值权重(T1_58,1.58-bit)**:`Precision::T1_58` 是**离散化**而不是舍入——它把权重按逐行 absmean 尺度投影到 `{-1,0,+1}`、需要额外尺度 γ,且**不进提升序**(`precision_rank()` 无定义,`max_precision` 对它 fail-fast)。P1 里它**不是存储精度**(`precision_bytes = 0`;`create_tensor`/`from_matrix`/`dsl::compute` 一律拒绝拿它建张量/当输出),只作为 `PrecisionProfile.param` 的一句声明 + 层能力集合的取值。落地形态:**每个 Layer 按槽声明自己支持的精度**(`PrecisionSupport{param,compute,stable,optimizer}`,默认 `{f16,f32}×四槽` → 既有层一行不改),`Layer::init`(NVI 首步)做唯一校验,不兼容组合 = **初始化期报错**(层名 + 槽位 + 取值 + 允许集合);`set_precision_profile` 在已 init 时 fail-fast("profile init 后不可变")。谁声明什么:`BitLinear`(三值线性层:量化 forward + STE backward,latent 恒 f32)`param={T1_58}`、其余层默认。CLI 只有 `--precision-param t1_58`(**无别名**;compute/stable/optimizer 收它即解析期报错),`ModelSpec.weight_quant` 记住"该模型用 BitLinear"(缺键 = None → 旧文件零破坏)。**接线范围(P1 = MLP,P1.5 = GPT)**:GPT 的 4 个投影 / `fc1_/fc2_` / 未 tie 的 `lm_head_` 全部走 `make_linear_layer` 工厂(成员类型 `std::unique_ptr`,与 `make_norm_layer` 同一先例),开关判据唯一 `effective_weight_quant()`(`precision.param == T1_58` ⇔ `weight_quant == T1_58`),profile 由 `split_ternary_profile()` 分流(`param=T1_58` 只给 BitLinear;复合层自身 / norm / 位置编码拿 param 归一化为 f32 的那份;未以三值模式构造却收到 T1_58 → fail-fast,不静默降级);**RAPT / ViT 明确拒绝**(`--arch rapt --precision-param t1_58` 前置报错;ViT 在 `PatchEmbedding` 能力校验处报错)。GPU 侧结构由 `scan_exprs` 的模型 pass 登记(含两条三值 GPT 用例;结构数 107)。完整设计/架构图/验收见 `docs/internal/21-quantized-weights.md` §4.10 与 `docs/internal/22-bitnet-2b4t-architecture.md` §3.4。 -**三值精度预设(CLI `--t1_58`,2026-10-10 落地)**:`profile_t1_58()` = `{param=T1_58, compute=F16, stable=F32, optimizer=F32}` —— 定义上就是 `profile_f16()` 把 `param` 换成三值(另三槽在同一函数里派生 → 不会与 `--f16` 各自漂移),即"**其他默认 f16、模型参数 1.58**";CLI `--t1_58`、GUI 两个训练页的"精度预设"下拉各一项,三条命令等价:`--t1_58` == `--f16 --precision-param t1_58` == `--precision-param t1_58 --precision-compute f16`。实测验收见 `docs/todo/21-quantized-weights.md` §4.10。 +**三值精度预设(CLI `--t1_58`,2026-10-10 落地)**:`profile_t1_58()` = `{param=T1_58, compute=F16, stable=F32, optimizer=F32}` —— 定义上就是 `profile_f16()` 把 `param` 换成三值(另三槽在同一函数里派生 → 不会与 `--f16` 各自漂移),即"**其他默认 f16、模型参数 1.58**";CLI `--t1_58`、GUI 两个训练页的"精度预设"下拉各一项,三条命令等价:`--t1_58` == `--f16 --precision-param t1_58` == `--precision-param t1_58 --precision-compute f16`。实测验收见 `docs/internal/21-quantized-weights.md` §4.10。 **三值性能优化(2026-10-11 落地,docs 21 §4.12)——改三值相关代码前必读**: ① **写版本(write epoch)**:`Tensor` 的**存储对象**(`MatrixT` / `GpuBuffer`)持单调 @@ -250,10 +250,10 @@ load_state`(含 Adam 的 `t`);读写 API = `CheckpointState` / `peek_train 8. **确定性**:任何"依赖容器迭代顺序"的决策点(BPE 平局打破、ID 分配等)必须显式排序/按 key 打破平局;并行化后结果必须与单线程逐字节一致。 9. **大词表禁止物化 one-hot**:用 `CrossEntropyLoss::forward_sparse`(整数标签 + loss_mask)。 10. **`//` 注释中禁止出现 `\` 反斜杠**(尤其行尾):GCC 行拼接会把下一行并入当前注释——轻则 `-Wcomment -Werror` 编译失败,重则下一行代码被静默吞掉。 -11. **张量存储不可绕过引擎(M1,docs/todo/17 §4.1)**:一切 Tensor 的创建/读写/reshape 必须经 ComputeEngine(`create_tensor/from_matrix/to_matrix/reshape` 等);存储访问器(`cpu_matrix/cpu_shared/gpu_tensor/gpu_shared`)与静态直构工厂(`Tensor::from_matrix/cpu/...`)**已私有**,绕过 = 编译错误。库内豁免仅两条:引擎 friend(ComputeEngine/CpuEngine/GpuEngine)与 `detail::TensorAccess`(DSL 求值器专用通道,**库外禁用**,违反靠 grep 审计抓)。 -12. **L2+ 计算路径禁用 Matrix(M4,docs/todo/17 §4.6 + §3 D11)**:Layer/Loss/Optimizer/Model 头文件里不得出现 `Matrix`/`MatrixT` 类型,也不得调用 Matrix 型 I/O 动词(`from_matrix`/`to_matrix`/`copy_from`)。层自算的辅助数据(索引/位置编码/掩码/斜率/编码表等——没有引擎侧生成原语的那类)一律走 **span 宿主桥** `detail::upload_span/download_span/download_vector`(内部是 M3 的批量 `write`/`read`,见 `compute_engine.hpp` 尾部)或 `create_tensor`+`InitSpec`/`zero` 就地建张量;数据集、预训练权重、对拍与落盘等大批量 I/O 仍在 I/O 层用 `from_matrix`/`to_matrix`。**审计口径**:`pwsh -File bench/doc_inventory.ps1` 第 [4] 节,验收 = `L2-VIOLATIONS: 0`(宿主桥用量只披露不判违规)。 -13. **引擎能力体系(docs/todo/23 §2.3)**:能力谓词是**具体引擎的私有实现细节**(私有成员 / 编译期常量),**不得出现在基类 `ComputeEngine`**,也**不得被 Layer/L4/L5/CLI/测试调用**;基类 NVI 入口**不做能力分支**(精度策略下沉到各引擎的 `*_impl`)。能力**信息**只经 `ComputeEngine::describe()` 返回的 `EngineInfo` 披露(`text()` 是稳定一行摘要),且**禁止用于选路**——选路必须走引擎内部谓词。热路径政策:由**引擎类别**决定的(如 CPU 引擎没有原生 f16 搬运/归约)用编译期标签消分支;由**设备**决定的在 init 期解析成常量成员;**每结构可变**的(有无该表达式的融合变体)不当能力用,由实现内部一次解析。 -14. **参数形态协议(v7,docs/todo/23 §2.2)**:模型文件的每个参数条目带**参数级 `kind`**(`ParamKind`:Dense / TernaryLatent / TernaryPacked2 / TernaryPacked3 / 预留 I8Packed4),由**拥有该参数的层**经 `Layer::export_param(index, ModelRole)` / `import_param(index, entry)` 决定落盘/载入形态;`index` 与 `parameters()` **同序**(复合层经受保护的 `param_children()` 按顺序转发)。**禁止**在序列化层 `dynamic_cast` 具体层类型;**禁止**恢复层树枚举型公开 API(`sub_layers()` 已删)。形态不被接受必须 **fail-fast**(层名 + 期望 + 实际),不得静默降级。 +11. **张量存储不可绕过引擎(M1,docs/internal/17 §4.1)**:一切 Tensor 的创建/读写/reshape 必须经 ComputeEngine(`create_tensor/from_matrix/to_matrix/reshape` 等);存储访问器(`cpu_matrix/cpu_shared/gpu_tensor/gpu_shared`)与静态直构工厂(`Tensor::from_matrix/cpu/...`)**已私有**,绕过 = 编译错误。库内豁免仅两条:引擎 friend(ComputeEngine/CpuEngine/GpuEngine)与 `detail::TensorAccess`(DSL 求值器专用通道,**库外禁用**,违反靠 grep 审计抓)。 +12. **L2+ 计算路径禁用 Matrix(M4,docs/internal/17 §4.6 + §3 D11)**:Layer/Loss/Optimizer/Model 头文件里不得出现 `Matrix`/`MatrixT` 类型,也不得调用 Matrix 型 I/O 动词(`from_matrix`/`to_matrix`/`copy_from`)。层自算的辅助数据(索引/位置编码/掩码/斜率/编码表等——没有引擎侧生成原语的那类)一律走 **span 宿主桥** `detail::upload_span/download_span/download_vector`(内部是 M3 的批量 `write`/`read`,见 `compute_engine.hpp` 尾部)或 `create_tensor`+`InitSpec`/`zero` 就地建张量;数据集、预训练权重、对拍与落盘等大批量 I/O 仍在 I/O 层用 `from_matrix`/`to_matrix`。**审计口径**:`pwsh -File bench/doc_inventory.ps1` 第 [4] 节,验收 = `L2-VIOLATIONS: 0`(宿主桥用量只披露不判违规)。 +13. **引擎能力体系(docs/internal/23 §2.3)**:能力谓词是**具体引擎的私有实现细节**(私有成员 / 编译期常量),**不得出现在基类 `ComputeEngine`**,也**不得被 Layer/L4/L5/CLI/测试调用**;基类 NVI 入口**不做能力分支**(精度策略下沉到各引擎的 `*_impl`)。能力**信息**只经 `ComputeEngine::describe()` 返回的 `EngineInfo` 披露(`text()` 是稳定一行摘要),且**禁止用于选路**——选路必须走引擎内部谓词。热路径政策:由**引擎类别**决定的(如 CPU 引擎没有原生 f16 搬运/归约)用编译期标签消分支;由**设备**决定的在 init 期解析成常量成员;**每结构可变**的(有无该表达式的融合变体)不当能力用,由实现内部一次解析。 +14. **参数形态协议(v7,docs/internal/23 §2.2)**:模型文件的每个参数条目带**参数级 `kind`**(`ParamKind`:Dense / TernaryLatent / TernaryPacked2 / TernaryPacked3 / 预留 I8Packed4),由**拥有该参数的层**经 `Layer::export_param(index, ModelRole)` / `import_param(index, entry)` 决定落盘/载入形态;`index` 与 `parameters()` **同序**(复合层经受保护的 `param_children()` 按顺序转发)。**禁止**在序列化层 `dynamic_cast` 具体层类型;**禁止**恢复层树枚举型公开 API(`sub_layers()` 已删)。形态不被接受必须 **fail-fast**(层名 + 期望 + 实际),不得静默降级。 ## 6. 数据布局约定 @@ -270,7 +270,7 @@ GPT 序列展平: 列序 i = b*seq + t(batch-major,全局唯一约定) - Layer 内用 `nn::dsl`(`expr_dsl.hpp`)写普通数学表达式;CPU 编译期模板直接求值(内联+SIMD),GPU 折叠成 `ExprSpec`(扁平 IR,`expr_spec.hpp`)→ 按 key 查预编译融合 shader。 - 主要入口:`dsl::compute(engine, expr, rows, cols)`(一行表达式,最常用——**输出形状可省**,推导口径见下条 bullet);把结果写进既有张量(原地更新,零分配)用 `dsl::compute_into(engine, expr, dst)`;归约语义用 `dsl::compute_reduce`。**跨表达式融合(IR-C)为现行能力、已接入训练路径**:`engine.begin_expr()/end_expr()` + `ExprSegment` RAII 守卫 + `expr_graph.hpp` 图融合分析(`dsl::start_expr/end_expr` = 单表达式跨行语法糖,不是跨表达式)。融合两条规则:**P1 链**(单输出;两节点均逐元素/无归约/同形状/同精度,tail 恰一个消费者且被 Linear 视图引用,matmul 头链可用)与 **P2 分量**(纯逐元素 F32 同形状节点按依赖边连通成组,多消费者/菱形不再是边界,**写穿全部成员输出** = `ExprSpec.extras`(≤4);预算超限分裂多 kernel);kernel 按**确定性稳定拓扑序**执行。GPU 真录制(`execute_fused_graph`,复合 kernel 直接写回 tail 占位存储);CPU 普通运行 no-op(数值不变),`NN_EXPR_SCAN` 下 `end_expr` 跑同一融合分析并登记复合 spec(闭合世界两端一致)。已接入 `Adam::step`/`AdamW::step`(每张量 1 个多输出 kernel)。**P3 跨链批量派发**:`execute_fused_graph` 把同结构、同参数值、互不依赖的 kernel 按组键(结构 key + consts/rparams/vp 值序列;贪心按列表序收集、单组 CAP 32)合成**一次批量派发**——纯逐元素结构(含 extras 复合)生成期追加 `key#b` 批量变体(实例表 + buffer device address,逐实例尾槽 (count,cols)),后端 `run_fused_gpu_batch`;`NN_IRC_NO_BATCH=1` 关闭批量(A/B 逃生阀)、`NN_IRC_TRACE=1` 打 `[ir-c][batch]`/`[ir-c][batch-degrade]`,`#b` 未登记/无 BDA = 逐 kernel 降级回退(可观测,非错误)。⚠ **闭合世界与精度的交互**:融合分组依赖精度(P2 要全 F32、P1 要同精度),混精度 profile 会产出 f32 扫描期未登记的复合结构——不做构建期精度组合枚举,而是**运行期通用降级**:复合 kernel 未登记(或写穿前置条件不满足)时拆回成员逐个派发(成员都是已登记的个体结构;`NN_IRC_TRACE=1` 可见 `[ir-c][degrade]`),未登记的**单节点**结构仍是硬报错。历史与取舍见 `docs/history/history.md`「IR-C 定位修正与恢复立项」条。**设计原则(用户裁定):不为单一操作加专用原语**——Adam 多状态更新、CE online-softmax 等一律走通用机制(图融合扩展 / fold 通用折叠)。分组归约(MaxPool 窗口等)用 `dsl::grouped_reduce_sum/max(tensor, R)` 视图(**R 走运行期视图参数 `vp`、不进 key**——同一结构不同 R 共享一个 shader);**alpha 缩放**写成 `dsl::matmul(..., batch) * dsl::rparam(alpha)` 尾链(rparam 值不进 key)。 -- **`dsl::compute` / `dsl::compute_reduce` 可省输出形状**:输出网格由表达式推导(`expr_dsl.hpp` 的 `GridInfer`:张量叶/形状保持视图按广播规则合并;归约视图与归约指令贡献**输入整网格**;`grouped_reduce(t,R)` → `(rows/R, cols)`;matmul 段 → `(batch·M, N)`,GQA 的 batch/ratio 行块同 `to_spec` 的 k 口径;标量、网格索引叶、稀疏与批视图中性)。**冲突 / 不可推导 / 全无贡献者 = 明确报错**并提示改用显式形式(绝不猜形状)。回归 `src/dsl_shape_infer_test.cpp`,细则见 `docs/development/cpp-api-manual.md` §6。 +- **`dsl::compute` / `dsl::compute_reduce` 可省输出形状**:输出网格由表达式推导(`expr_dsl.hpp` 的 `GridInfer`:张量叶/形状保持视图按广播规则合并;归约视图与归约指令贡献**输入整网格**;`grouped_reduce(t,R)` → `(rows/R, cols)`;matmul 段 → `(batch·M, N)`,GQA 的 batch/ratio 行块同 `to_spec` 的 k 口径;标量、网格索引叶、稀疏与批视图中性)。**冲突 / 不可推导 / 全无贡献者 = 明确报错**并提示改用显式形式(绝不猜形状)。回归 `src/dsl_shape_infer_test.cpp`,细则见 `docs/development/02-cpp-api-manual.md` §6。 - **fold 段(P-C1/C2)**:`ExprSpec.fold = FoldSpec`(分块状态归约:键域逐块 body + 行标量态跨块进位 + `vecacc` 行向量态块累加 + 向量域 finalize)——**通用折叠表达式机制,不含任何注意力专属语义**(与注意力无关的通用样例 rowmax/rowsum/softmax_denom/logsumexp 在 `expr_fold.hpp`;`make_fold_logsumexp` 的 finalize 为多指令链 `lse = m + log(l)`,校验按 def-before-use 链放行)。fold **值构造走 `FoldAnchor` 自登记**(与 `FusedAnchor` 同机制,见下"收集"条:通用样例由 `expr_fold.hpp` 末尾登记、`make_fold_logsumexp` 由消费方 `compute_loss.hpp` 登记);注意力 forward 直调 `engine.eval_expr(make_fold_attn_o(...))`(不经 DSL 钩子,其全部组合由**定义方** `compute_layer_attention.hpp` 的 `attn_fold_anchor` 自登记——**P4-4 ① 起 `scan_exprs` 不再有 fold 登记块**);该构造与**掩码种类 `AttnMaskKind`(Plain/Causal/CausalDoc)定义在 `compute_layer_attention.hpp`**(按 AOT 原则"表达式文本只出现在 Layer"归位)——位置偏置是**正交的第二入参** `bool score_bias`(由 `PositionEncoder::has_score_bias()` 给出),掩码清单是 **X 宏单一真源**(`NN_ATTN_MASK_KIND_LIST` 同时展开枚举与登记表)→ 5 个掩码/偏置组合 × {MHA,GQA} 共 10 条结构在静态初始化期登记,**新增掩码/组合只改定义方、不改 `scan_exprs`**(漏登记 = GPU 闭合世界硬报错的最后一个已知风险点由此消除);`FoldSpec.tri_skip`(行界整块跳过)进 key(codegen 分歧点);`EXPR_FOLD_BLOCK=128`/`EXPR_FOLD_ROWS_PER_WG=2` 为 CPU/GPU 共享常量(改则两侧同改)。fold v1 生成器含两项通用优化:归约输入内联(被归约独占的临时量逐块重算、不物化 `e[n][128]`)与循环剥离预取软件流水(消串行延迟链;累加序不变 = CPU/GPU 逐位同序)。fold v2 生成器(双域)含三项**恒等**优化(字节锚不动):tri_skip 空块 `continue` **整块跳过**(此前只钳 valid、块内屏障照跑;空块的 m/α/l/O 更新全为恒等元,可达态论证见生成器注释)、元素链**按读集载入/按写集存回**(消死加载,出口 shared 逐位一致)、归约 gather/shuffle **收在 subgroup0**(sred 本只取 lane0,其余 subgroup 结果全被丢弃)。同窗 A/B 注意力 fwd fold −5%;相位消融探针(临时、已删):vecacc ≈57%、mm ≈15%、掩码链+归约+屏障 ≈28%——vecacc 展宽 = **P2-2 已实施**(FP 求和序变更 = 移 GPU 锚,已获批):veclen 不进 key → 运行期 **uniform 双路径**(0 < vs ≤ 256 = **j 分片跨线程**:c=tid%vs、片地板划分精确覆盖 [0,valid)、块循环后每行一次槽归约(复用 spart、`o` 不跨线程);vs > 256 = 现行 dd 步进 + 4 累加器),热路径用**标量累加器 ob0..ob3 恒寄存器**——动态下标 `o[4][4]` 数组落 local/scratch 是流量雷区(首版数组累加 A/B 反慢 26%,教训见 history「P2-2」条),尾段按固定累加器序展开零动态下标;同窗 A/B fold 3838 → **2656 µs(−30.8%)**、E2E step 95.4 → 90.6 ms(−5.0%);GPU 字节锚随之移动(新值见 §12 锚行,CPU 锚不动)。详见 `expr_fold.hpp` 与 `expr_spec.hpp` 的 FoldSpec 注释。 - **构建期单步**(CMake 自动编排,改 Layer 内联表达式后重跑构建即可)——`scan_exprs` 同进程**收集 + 生成**: 1. **收集**:只收集**结构**(= 唯一需要构建期枚举的东西)。两个来源**互补、不冗余**(`NN_SCAN_DUMP_SOURCES=1` 可逐条打印来源):`FusedAnchor` 在静态初始化期按表达式**类型**自登记(编译期可达,dry-run 跑不到的分支也覆盖);fold 结构走 **`FoldAnchor`** 同机制自登记、**由定义方挂锚**(通用样例与 3 个 v1 样例在 `expr_fold.hpp` 末尾,注意力组合在 `compute_layer_attention.hpp` 的 `attn_fold_anchor`——掩码清单 X 宏 `NN_ATTN_MASK_KIND_LIST` 同时展开枚举与登记表,新增掩码/组合不改 `scan_exprs`;P4-4 ①,2026-10-15);per-layer dry-run + 模型 pass 执行补齐**运行期配置决定**的变体(视图种类/项数在类型层面推不出,符号实例 `Expr{}` 与真实实例会折叠出不同 key);matmul trans 族与测试覆盖仍由 `scan_exprs` **显式登记**。**只跑 f32 一遍**——实测 f16 遍对结构贡献为 0(跳过它结构数不变),该两遍已删除。**实测分工(126 条;另有样例口径:`nn_enable_gpu_fusion` 收集器 = 库内 126 + 样例自定义 2 = 128)**:per-layer+显式 58、模型 pass +32 = **dry-run 侧 90**、锚点 92(新增 36),重叠 56 → **锚点独有 36、dry-run 独有 34**(项目 4/5 后:输入槽去重令锚点符号结构与真实张量结构 key 分叉、且 Softmax fwd/bwd 补入 dry-run)。所以**任何一方单独删掉都会丢结构**——dry-run/model pass 是结构的主要来源,删不掉(**唯一例外 = fold**:dry-run 一条 fold 都产不出,14 条 fold 全部来自自登记)。**⚠ 输入槽去重的覆盖约定**:`SpecBuilder::add_input` 对"同张量+同视图"去重,但锚点符号实例(占位张量)不参与去重 → **含重复同张量输入的表达式必须有 dry-run/模型 pass 覆盖**,否则运行期去重后的新 key 未登记 = 闭合世界硬报错(实测 `Softmax::backward` 中招后补 dry-run;见 `docs/history/history.md`「项目 4/5」条)。 @@ -278,12 +278,12 @@ GPT 序列展平: 列序 i = b*seq + t(batch-major,全局唯一约定) - **精度签名不再是构建期集合**("签名从身份降级为参数"):V1 的 GLSL 对每个输入/输出各声明 f32 + `float16_t` 双视图,加载/存储处按 push constant `uint prec`(bit i = 输入 i 为 f16,bit16 = 输出 f16)走 uniform 分支,**一份 shader 覆盖任意签名**。因此构建期不需要枚举签名,也**不存在回填清单**(`tools/prec_backfill.txt` 已删除,`NN_PREC_TRACE` 的"补变体"流程随之失效)。⚠ 精度路径仍有**三档**、不是"永不 miss":`key#a`(native16)→ `key#x`(V1 运行期分派)→ **基类边界 cast**;当某个结构的 `#x` 生成被跳过(`[skip] 分派变体…`)、`NN_SCAN_NO_DISPATCH=1`、或设备无 16bit 存储时,运行期会 miss 并落到边界 cast(`[prec][miss]` 仍会触发,它是通用诊断)。**V2 谓词含常量值判据而常量值不进 key**:运行时选 `#a` 前会用**真实实例的 spec 重跑** `expr_prec_sig_native16`,否则"生成时那一个实例的常量"会被套用到同结构但常量不同的实例上(微值在 f16 下 flush-to-0 = 静默错值)。**变体选择事件(V1/V2)一律打 `NN_PREC_TRACE` 日志**(V0 默认路径不打——f32 热路径会淹没输出;V1 分支曾漏打,导致"V1 从未被使用"的错误判断),且**只在确认命中后打、只由真正 dispatch 的入口打**(`supports_expr_precision_variant` 只是查询,它打日志会让计数翻倍:实测修复前 12040 行 = 6020 次真实分派 × 2)。**实测 V1 覆盖**(`NN_PREC_TRACE=1 f16_precision_test`):6022 条命中日志 / 24 条 distinct 结构 = **20 条 V1(`#x`)+ 4 条 V2(`#a`)**,V1 覆盖**全部四个生成器族**(元素 9 / 归约 6 / matmul 4 / fold 1),且该测试用 `CHECK_NEAR` 容差断言;miss 为 0。 - **新增调用点无需改动其他文件**(实测):在 Layer 头里新写一个 `dsl::compute`(其结构不在任何 dry-run / 模型 pass 覆盖内)→ 锚点独有 +1、结构 +1、注册表新增 `key` / `key#x` / `key#a` 三条,**其他文件零改动**。 - **编译期精度特化(`key#s` / `key#xxxx`,2026-10-13)——改 f16 变体选路前必读**:`#x` 的"一个 shader 覆盖任意签名"在热循环里每次读写都要带 `((prec >> i & 1u) ? float(bNh[…]) : bN[…])` 三元,**实测这一项就是 f16 变慢的主因**(850M:CE 融合注意力 146.1→120.0 ms,同机 f32 基线 117.2)。因此生成期追加两类**静态签名**变体(与 `#x` 数值逐字等价,只需 16 位存储、**不需要 `shaderFloat16`**):`key#s` = "全输入 f16 + 输出 f16"(无条件发射,兜底)与 `key#xxxx` = **扫描期真实观察到的签名**(`ExprRegistry::variants`;`scan_exprs` 的 dry-run **与模型 pass 各跑 f32 + f16 两遍**,`scan_register`(`dsl::compute*`)与 CPU 引擎 `eval_expr*` 入口(fold / 直接求值**不经** dsl::compute,必须在引擎入口补记)按真实张量精度 + 真实 P 登记)。**运行期查找序 = `#a`(原生 f16)→ `#xxxx` → `#s` → `#x` → 基类边界 cast**;未枚举到的签名照旧落 `#x`,所以特化集合**只是优化、不是身份**(`ExprRegistry::variants` 是"优化清单",`specs` 才是结构身份)。⚠ **网格粒度变体也可叠加在特化签名上(2026-10-14)**:`#f`(细 tile)与 `#ks`/`#kr`(K 切分)现在对**每个静态签名变体**各发一份(键形如 `key#10003#ks`),网格饥饿形状(大 batch 的 wgrad)在 f16 下同样拿到 K 切分——40HX 实测该结构 **f16 16.0 ms/块 < f32 25.1 ms/块**(此前 f16 掉回 64-tile = 79 ms/块)。两条不变量:① `#ks` 的输出**恒 f32**(写的是部分和缓冲,后端按 f32 分配)→ 生成器把输出声明钉成 `float`,注入 sig 只决定 A/B 读取类型;② 后缀可叠加 ⇒ 后端"`#f`/`#ks`/`#kr` 无需 16 位存储"的豁免**只对纯 V0 键**成立(判据 = 去掉网格尾后缀后仍含 `#` 即需要 16 位存储)。运行期派发哨兵 `#x` **不**叠加网格变体(它多一个 `prec` PC 槽、绑定翻倍)。**批量变体同理(2026-10-14,P2-12 已完成)**:`#b` 对**每个 extras 为空的静态签名变体**各发一份(键形如 `key#0002#b`;extras 的元素类型不在 `ExprPrecSig` 编码里 → 带 extras 的 f16 结构仍逐 kernel 降级)。⚠ **P2-12 的残差(Adam 复合 kernel 在 `--f16` 下逐成员降级、绕开批量队列)根因是 "scan 与运行期不同源",不是派发器**——两条不变量:① **scan 的优化器 dry-run 必须把当前 pass 的 precision profile 透传给 `create_optimizer`**(文本路径 `text_train` 本来就在传;漏传 = f16 pass 仍按默认 f32 profile 定 `upd_prec`/写目标精度 ⇒ 融合出的复合结构与运行期不同 ⇒ 运行期命中不到 ⇒ 降级);② **复合 kernel(≥2 成员)的运行期精度签名必须在 scan 的 CPU `end_expr` 补记**(= `add_variant(spec, expr_prec_sig_of(输入张量, tail 输出精度))`)——单节点结构有 `scan_register`/`eval_expr*` 入口,**融合结构只在 GPU `end_expr` 执行时才算出签名** ⇒ 否则 f16 下复合结构只剩 V0/`#s`/`#x` 三种载体,拿不到 `#xxxx` 特化与其 `#b` 批量变体。两条坑:① 运行期**组键必须带精度身份**——批量变体的元素类型是编译期定死的(f16 槽走 `float16_t` 的 buffer reference),同组混签名会把 f16 缓冲按 f32 读;② 取实例缓冲必须按 `t.precision()` 选槽位(`gpu_tensor()` 的默认模板实参是 F32,f16 张量会命中"无 P 精度存储"断言)。 -- **库外使用者:`nn_enable_gpu_fusion( MAIN <含 main 的源>)`**(`CMakeLists.txt`):使用者在自己的层头里写 `dsl::compute` + 在 CMake 加这一行 → 自动生成**该目标专属**的 `fused_registry.hpp` 并加进它的 include path。机制 = 收集器由**库内收集逻辑**(`tools/scan_exprs.cpp`:锚点 + dry-run + 模型 pass + 显式登记)**加上本目标的全部 TU**(`-DNN_EXPR_SCAN` 编译,让使用者的调用点自登记)组成。**⚠ 必须保留库内收集逻辑**:99 个结构里只有 17 个来自编译期锚点、82 个来自 dry-run/模型 pass,"纯锚点收集器"会漏库自身的结构。**⚠ include 顺序有语义**:`${NNF_OUT_DIR}` 必须排在 `${CMAKE_BINARY_DIR}/generated` 之前(后者含库自身注册表与手写原语 shader 嵌入头),否则 `__has_include("fused_registry.hpp")` 会解析到库的那一份、使用者的自定义结构全部闭合世界报错。样例见 `examples/fusion_custom_layer*`(**库内目标**形态;函数本身定义在本仓 `CMakeLists.txt` 的 `if(Vulkan_FOUND)` 内,且仓库无 `install()`/export——真正**树外**工程要复用它需先做 install/export,见 `docs/todo/18-roadmap.md` E2)。 +- **库外使用者:`nn_enable_gpu_fusion( MAIN <含 main 的源>)`**(`CMakeLists.txt`):使用者在自己的层头里写 `dsl::compute` + 在 CMake 加这一行 → 自动生成**该目标专属**的 `fused_registry.hpp` 并加进它的 include path。机制 = 收集器由**库内收集逻辑**(`tools/scan_exprs.cpp`:锚点 + dry-run + 模型 pass + 显式登记)**加上本目标的全部 TU**(`-DNN_EXPR_SCAN` 编译,让使用者的调用点自登记)组成。**⚠ 必须保留库内收集逻辑**:99 个结构里只有 17 个来自编译期锚点、82 个来自 dry-run/模型 pass,"纯锚点收集器"会漏库自身的结构。**⚠ include 顺序有语义**:`${NNF_OUT_DIR}` 必须排在 `${CMAKE_BINARY_DIR}/generated` 之前(后者含库自身注册表与手写原语 shader 嵌入头),否则 `__has_include("fused_registry.hpp")` 会解析到库的那一份、使用者的自定义结构全部闭合世界报错。样例见 `examples/fusion_custom_layer*`(**库内目标**形态;函数本身定义在本仓 `CMakeLists.txt` 的 `if(Vulkan_FOUND)` 内,且仓库无 `install()`/export——真正**树外**工程要复用它需先做 install/export,见 `docs/internal/18-roadmap.md` E2)。 - **端到端验收(库外 + f16 分派)**:`build/fusion_custom_layer_example.exe` 实测两种**自研算子形态**:①逐元素 `exp(|x|·α)/(√|y|+α)`;②归一化形态 `rsqrt(col_reduce_sum(x)·inv + ε)`(= 库内 LayerNorm/RMSNorm 的 `std_inv` 同形,`raxis=1`、`viewkinds=[0,8]`,属库里"只有执行 Layer 才拿得到"的那一类)。两者都只用**锚点**(自定义层没有 dry-run)→ 都命中并跑通 ⇒ `nn_enable_gpu_fusion` 对常见自定义层可靠。实测值:CPU f32 `0.6712035`(差 0);**GPU f32(V0)`0.6712036`(差 5.96e-08)**;**GPU f16(V1 运行期精度分派)`0.6708984`(差 3.05e-04,f16 舍入内)**;归一化形态 GPU f16 `1.2246094`。含 rparams ⇒ native16 谓词不通过 ⇒ f16 命中必然是 `key#x`;注册表若漏了它就是闭合世界硬报错,"跑通"本身即断言。**残余不确定性**:库内确有 25 条结构只有执行 Layer/模型才拿得到(锚点的符号实例 `Expr{}` 与运行期实例折叠结果不同);实测的两种自定义形态不在其中,但无法先验排除。若使用者的自定义层遇到闭合世界报错,下一步是给 `nn_enable_gpu_fusion` 加 `COLLECT ` 钩子(由使用者提供"跑一遍自己的层"的收集函数,等价于库内的模型 pass)。 - **库是 header-only,多 TU 必须可链接**:头里的类外定义一律要 `inline`(曾漏 `GpuBuffer::~GpuBuffer` → ≥2 个 TU 的程序链接期 duplicate symbol,`examples/fusion_custom_layer*` 抓到)。 - **IR-D emitter 抽象**(`expr_emitter.hpp`):把后端代码生成从 GLSL 专用抽象为 emitter 接口(一份 canonical IR → 多后端代码),`--list-backends` 可列出注册后端。目前仅 `glsl` 后端注册(无 `CpuEmitter`/`CudaEmitter` 实现)。 - 手写原语 shader 在 `shaders/*.comp`(matmul、matmul_tiled、matmul_gemv、batched_matmul、reduce、elementwise_v2、transpose、gather、scatter_add、rearrange_3d、im2col、col2im、group_reduce、scan_prefix_outer、scan_suffix_outer、scan_prefix_outer_gen、scan_suffix_outer_gen(gen = 通用 dk 版,dk>64 后端走它)、outer_col、cast),构建期 glslc 编译并嵌入 C++ 头文件;多数 shader 另用 `-DNN_SHADER_F16=1` 编一份 f16 变体(`NN_ETYPE=float16_t`,f32 分支留在 `#else`)。 -- IR 优化 pass(canonicalize/CSE/寄存器分配)见 `expr_opt.hpp`,设计文档 `docs/todo/03-ir-optimization.md`(IR-C 图融合的当前形态见 §7;历史取舍记录归档在 `docs/history/history.md`)。 +- IR 优化 pass(canonicalize/CSE/寄存器分配)见 `expr_opt.hpp`,设计文档 `docs/internal/03-ir-optimization.md`(IR-C 图融合的当前形态见 §7;历史取舍记录归档在 `docs/history/history.md`)。 ## 8. 训练循环范式(写新入口时照抄) @@ -354,7 +354,7 @@ auto report = NN_UNWRAP(session.train_step( - `Scalar = float`;`BLOCK_SIZE = 64`(matmul 分块,b_block 栈预算 64KB);`PARALLEL_THRESHOLD = 524288`(自适应并行阈值,由 `nn::parallel_for_blocks/parallel_for_samples` 门控)。 - 不使用 `-ffast-math`(保 NaN/Inf,训练稳定性)。 -## 10. 高频坑(Top 8,详见 `docs/todo/08-pitfalls-and-lessons.md`) +## 10. 高频坑(Top 8,详见 `docs/contributors/pitfalls.md`) 1. **布局混用**:position-major vs batch-major → 跨样本串扰、loss 平台期。改序列代码先确认列序约定。 2. **GPU 双存储影子一致性**:CPU/GPU 双存储是分布式状态机问题;GPU-resident 路径已禁用,走 staging(每次算子往返 PCIe)。 @@ -362,16 +362,19 @@ auto report = NN_UNWRAP(session.train_step( 4. **TDR/设备死亡**:`VK_ERROR_DEVICE_LOST` 不可重试(存 checkpoint 退出);`VK_TIMEOUT` 可减半 batch 重试。 5. **缓存 key 冲突**:naive 位域/组合 key 会撞车,用强哈希(FNV-1a)或双字段。 6. **零拷贝 reshape 的 CPU/GPU 语义差异**:CPU 分支 reshape 需复制数据,GPU 保持零拷贝。 -7. **内存爆炸**:"所有出现位置"类索引随输入线性膨胀、大词表 one-hot 物化都会把内存吃到几十 GB 级。先做内存预算(历史量级见 `docs/todo/08-pitfalls-and-lessons.md`)。 +7. **内存爆炸**:"所有出现位置"类索引随输入线性膨胀、大词表 one-hot 物化都会把内存吃到几十 GB 级。先做内存预算(历史量级见 `docs/contributors/pitfalls.md`)。 8. **gradcheck 必须先 forward** 填充 `input_cache_` 再 backward,否则空缓存崩溃。 ## 11. 文档索引(docs/,按类别子目录组织) > **总入口 `docs/README.md`**:规定每个子目录写给谁看。一句话分册定位—— -> **`introduction` / `usage` / `development` 写给调用者;`todo/` 与 `history/history.md` 写给项目开发者**。 -> **`docs/development/` 的读者是"库使用者 / 扩展者"(在库之上写代码),不是改库的人**; -> 项目内部的设计 / 路线图 / 盘点 / 规范 / 踩坑 / 故障 / 整改全在 **`docs/todo/`**。 -> 2026-10-11 的结构整理记录(哪些迁走 / 并入 history / 删除)见 `docs/README.md` §3。 +> **`introduction` / `usage` / `development` 写给调用者;`contributors/` 写给贡献者/维护者/agent; +> `internal/` 与 `history/history.md` 写给项目开发者**。 +> 项目内部的设计 / 路线图 / 盘点 / 故障 / 整改在 **`docs/internal/`**; +> **长期规范与治理**(C++ 规范 / 踩坑 / 文档规范 / 发布规则)在 **`docs/contributors/`**。 +> 写文档前必读 `docs/contributors/documentation-standard.md`(头部模板 / 状态词 / 编号制度 / +> 历史性记载禁令);改文档后必跑 `python scripts/doc_audit.py`。 +> 文档结构的历次整理记录统一在 `docs/history/history.md`。 ### 总档 @@ -396,43 +399,53 @@ auto report = NN_UNWRAP(session.train_step( | 文档 | 何时读 | |------|--------| | `development/README.md` | 本分册定位与索引(明确"写给调用者") | -| `development/cpp-api-manual.md` | **全功能 C++ API 手册(库使用者首选)**:错误宏 / 引擎 / 张量 / 精度 / DSL / 层与 Model / 模型工厂 / 损失 / 优化器 / 训练循环 / 模型文件 / 数据集 / 分词器 / 生成 / 剖析,每节带可粘贴代码片段;§0 有"我要做什么 → 看哪节"表 | -| `development/cmake-integration.md` | **接入与构建**:`add_subdirectory`/`FetchContent`、门面目标 `neuralnet::nn` 传递内容、全部构建开关(`NN_ENABLE_GPU`/`NN_BUILD_APPS`/`NN_ENABLE_TESTS`/`NN_ENABLE_PCH`/`NN_ENABLE_NATIVE`/`NN_ENABLE_PROBES`/`NN_COMPILER_LAUNCHER`)、GPU 语义、`nn_enable_gpu_fusion(target MAIN [OUT_DIR ...])`、本仓构建/测试、跨平台、故障排查 | -| `development/write-a-custom-layer.md` | **写自定义层的指南**(P1-6):完整示例(实测过数值梯度检查 + 训练收敛)+ 七条接入契约 + 精度槽声明 + 可复制的梯度自检片段 + GPU 检查清单 + 常见编译错误对照。背景实测见 `development/20` | -| `development/01-compute-engine-development.md` | **扩展引擎原语**:接口详解、CPU/GPU 实现模式、添加新原语的完整步骤 | +| `development/02-cpp-api-manual.md` | **全功能 C++ API 手册(库使用者首选)**:错误宏 / 引擎 / 张量 / 精度 / DSL / 层与 Model / 模型工厂 / 损失 / 优化器 / 训练循环 / 模型文件 / 数据集 / 分词器 / 生成 / 剖析,每节带可粘贴代码片段;§0 有"我要做什么 → 看哪节"表 | +| `development/01-cmake-integration.md` | **接入与构建**:`add_subdirectory`/`FetchContent`、门面目标 `neuralnet::nn` 传递内容、全部构建开关(`NN_ENABLE_GPU`/`NN_BUILD_APPS`/`NN_ENABLE_TESTS`/`NN_ENABLE_PCH`/`NN_ENABLE_NATIVE`/`NN_ENABLE_PROBES`/`NN_COMPILER_LAUNCHER`)、GPU 语义、`nn_enable_gpu_fusion(target MAIN [OUT_DIR ...])`、本仓构建/测试、跨平台、故障排查 | +| `development/03-write-a-custom-layer.md` | **写自定义层的指南**(P1-6):完整示例(实测过数值梯度检查 + 训练收敛)+ 七条接入契约 + 精度槽声明 + 可复制的梯度自检片段 + GPU 检查清单 + 常见编译错误对照。背景实测见 `development/09-custom-layer-ergonomics.md` | +| `development/04-compute-engine-development.md` | **扩展引擎原语**:接口详解、CPU/GPU 实现模式、添加新原语的完整步骤 | | `development/05-mixed-precision.md` | **多精度语义契约(写层 / 选 profile 必读)**:Precision 类型系统、类型化存储、分派、`PrecisionProfile`(param/compute/stable/optimizer)、实测结论与已知数值限制(§12) | -| `development/06-rapt-algorithm.md` | **线性注意力(RLA → RAPT → RLA-2)**:直观理解 + 数学定义 + 扫描原语工程落地 + 训练显存开关 | -| `development/20-custom-layer-ergonomics.md` | **写自定义层的实测报告**:库外使用者视角的接入契约、7 个摩擦点(是 `write-a-custom-layer.md` 的背景证据,不是操作指南) | +| `development/08-rapt-algorithm.md` | **线性注意力(RLA → RAPT → RLA-2)**:直观理解 + 数学定义 + 扫描原语工程落地 + 训练显存开关 | +| `development/09-custom-layer-ergonomics.md` | **写自定义层的实测报告**:库外使用者视角的接入契约、7 个摩擦点(是 `03-write-a-custom-layer.md` 的背景证据,不是操作指南) | -### 内部工作区(docs/todo/,**给项目开发者**) +### 贡献者规范(docs/contributors/,**给贡献者 / 维护者 / agent**) -索引与定位见 `docs/todo/README.md`。逐篇: +| 文档 | 何时读 | +|------|--------| +| `contributors/documentation-standard.md` | **文档规范**:分册职责 / 编号制度 / 单篇模板(读者·一句话结论·状态)/ 代码示例标注 / 历史性记载禁令 / 机器审查口径。**写任何文档前读** | +| `contributors/cpp-standards.md` | **C++ 开发规范全文**(内存管理 / 模块隔离 / 高性能 / 错误处理 / 注释)——改代码前读 | +| `contributors/pitfalls.md` | **踩坑警示录,改代码前读**:分级 bug 与跨领域根因模式;踩新坑先补这里 | +| `contributors/release-policy.md` | **版本号·分支·发布治理(三条红线)**:**发布须由人提出(agent 不得擅自发布)**、`dev` 不写版本号、发布只在 `main` | +| `contributors/release-requirements.md` | **大版本发布要求**(`1.x.y → 1.(x+1).0`):端到端训练 / 发布文档 / 完整 ctest + Debug / 多编译器矩阵 | + +### 内部工作区(docs/internal/,**给项目开发者**) + +索引与定位见 `docs/internal/README.md`。逐篇: | 文档 | 何时读 | |------|--------| -| `todo/00-code-review-remediation.md` | **2026-10-11 代码审查整改立项台账**:审查发现逐条立项(现象/证据/根因/方案/验收/优先级)。接手整改前先读本文 | -| `todo/02-operator-fusion.md` | **算子融合全篇(当前形态与设计约束):IR 扩展(归约语义)→ 表达式录制 → matmul 参与 IR 融合 → 跨 kernel 自动融合(一期 M1-M7 + 二期 S1-S5/S7;分期实施流水与否决方案见 `docs/history/history.md`)** | -| `todo/03-ir-optimization.md` | IR 优化(现行 IR-A/B/C/D;**IR-C 图融合为现行能力——当前形态与融合规则见 AGENTS §7,历史取舍归档在 `docs/history/history.md`**) | -| `todo/04-memory-optimization.md` | 显存优化:L1 激活重计算(梯度检查点)/ L2 内存池整块归还(均已实施);L3 远期 | -| `todo/08-pitfalls-and-lessons.md` | **踩坑警示录,改代码前读** | -| `todo/10-development-standards.md` | C++ 编码规范全文 | -| `todo/12-compute-engine-inventory.md` | **引擎接口盘点(复现:`bench/doc_inventory.ps1`):52 个 virtual 方法、Layer 直调 32 个(基础设施/数据搬运/状态扫描/fold 执行(自登记)/IR-C 录制段开合/三值打包/张量形变/精度落盘/RL 行带适配)、两套 CPU 求值机制(DSL 模板 + IR 解释器)、ctest 64 个注册(无 Vulkan 树 62);演进记录见 `docs/history/history.md`** | -| `todo/14-f16-stable-gpu-loss-frozen.md` | **故障报告(2026-09-26;2026-10-13 ✅ 已修/根因订正):GPU `stable=f16` 训练 loss 打印冻结(权重不冻结)——真因 = CE 的 (1,1) loss 归约按 `stable=f16` 落盘溢出,非回读链;触发矩阵、测试覆盖缺口、证据与复现** | -| `todo/17-unified-tensor-engine.md` | **统一 Tensor/ComputeEngine/MemoryPool 底层架构总纲(2026-09-30 裁定;M1-M6 全部已实施 2026-09-30,仅 M7 未立项):访问不变量(Tensor 存储私有、一切经引擎,已立为铁律 #11)、InitSpec 声明式初始化、批量 read/write、Matrix 降级为宿主 I/O 载体(L2+ 禁用 = 铁律 #12)、内存池契约统一、`import` 跨设备拉取、Layer 删每调用 engine 形参(M6 段 C,Loss/DSL/辅助对象保留形参见 §8);吸收原 15 未实施的 P2-P6(改期 M1-M7)。立项前先读本文件 + §5 分期 + §8** | -| `todo/18-roadmap.md` | **未来方向路线图 + 未完成项裁定台账(2026-10-01,13 号清单的承接者):RL 主线 ✅(2026-10-23)+ P0-P4 分期(P4 = 持续优化方向,2026-10-14 立项)、13 号逐条裁定(做/条件触发/不做)、触发式立项条件、非目标、门禁与验收口径。查"某件事该不该做、做到什么算完成、避免重复立项"时读本文;**执行排序不在本文**(见 `todo/27-execution-plan.md`)** | -| `todo/27-execution-plan.md` | **执行计划(优先级象限,2026-10-15):RL-0…RL-2b 已完成并从执行表移出;其余象限是后续 backlog。想知道"下一个先做哪个"读它;裁定去 18 号,本文只排顺序、不产生新裁定** | -| `todo/31-rl-training-primitives.md` | **RL 与可组合训练基础设施(2026-10-23 ✅ 已实施)**:issue #23 是能力下界;公共语义 = `NamedTensorSet`/`OutputSchema`、schema 化 experience、policy-objective 组件、通用 `TrainingGroupSession` 与可替换编排;实现/门禁见 §11,使用指南见 `usage/06-reinforcement-learning.md` | -| `todo/19-unified-dataset.md` | **统一数据集格式与加载(`.nndataset`/`.nnvocab`/KVRecord v2,2026-10-05 设计定稿、阶段一~三已实施):裁决记录、KVRecord v2 规范、文件布局、`nn::Dataset`/`dataset_gen`/`dataset_convert`/模型 v6 分期落地与兼容迁移。接数据集相关任务前读本文** | -| `todo/21-quantized-weights.md` | **三值(1.58-bit)量化权重与 BitLinear(2026-10-09 设计定稿 → 2026-10-10 **P1 已实施**,分支 `dev/t1_58`):`Precision::T1_58` + `Layer::precision_support()`(按槽声明、`init` 期校验)+ `BitLinear`(量化 forward / STE backward);含 Lumina-Engine `TQ1_0` 参考实现拆解、`§4.9` 实现与设计的差异、`§8` 架构图、`§10` 提交清单。**已裁定**:尺度 = absmean + per-row(absmax 只剩 0.13~1.29 bit 信息,实测见 `research/ternary_scale/`)、打包 = `TQ1_0` 编码 + 行级块、命名 `T1_58` / CLI 无别名 / 层名 `BitLinear`、D3 = (a)+(b)、D5 = ③(P1 只覆盖 MLP;GPT 侧由 P1.5 补齐,RAPT/ViT 仍拒绝);**仍待定** D6(P2 行步长/对齐)。前置证据 `research/ternary_ste/`**;验收 `src/t1_58_test.cpp`(+`--gpu` 变体) | -| `todo/22-bitnet-2b4t-architecture.md` | **BitNet b1.58 2B4T 的结构对齐(2026-10-10 立项 + **S1/S2/S3 三步已实施并提交**,分支 `dev/t1_58`):三项结构差距 = SubLN / GQA / tied embedding,均为**可选开关、默认关**。**已裁定**:SubLN 封装在子层内部(`AttentionBase`/`FeedForward` 的可选 `unique_ptr`,**不是** `NormType` 新值、**不是** block 的第三个 norm)、类型跟随 `norm_type`;GQA 头映射 = `kv = h/(n_head/n_head_kv)`(llama.cpp FA 与 HF `repeat_kv` 互证)+ 显式展开 K/V 头(前向 `gather_rows` / 反向 `scatter_add_rows`,fold 与 AOT 注册表零改动);tied embedding 在 `GPTModel` 内一个开关(梯度**累加**进 `grad_token_emb_`);**不加 CLI 预设**(GUI 留待以后);`ModelSpec` 追加 `subln`/`n_head_kv`/`tie_embeddings` 三键(缺键 = 旧语义,不升 MODEL_VERSION)。**验收 `src/bitnet_struct_test.cpp`(+`--gpu`)**:GQA 退化与 MHA 逐位一致、GQA↔按块映射复制成 MHA 前向差 0、tied 梯度累加差 0;102 上全量 ctest 30/30。**实施记录见本文 §10**。**待定**:FFN 激活 ReLU²(需确认官方 `hidden_act`;llama.cpp 对 gated squared relu `GGML_ABORT`,无对拍)、GQA in-kernel 版(P2)、HF 权重转换器。**结构侧**与 21 号(权重侧 `T1_58`/`BitLinear`)是两条正交的腿** | -| `todo/23-library-design-cleanup-and-model-file-roles.md` | **库级违规设计清理(2026-10-11 **已实施**):模型文件角色 + 参数形态协议 + 引擎能力体系**(范围 = **整个库**,不只三值)。三轮裁决要点:① 参数级 `kind`(Dense / TernaryLatent / TernaryPacked2 / TernaryPacked3 / 预留 int8);② **不引入**可训练/不可训练状态;③ 能力谓词 = 具体引擎私有、**不得进基类**、不作对外标签、只作内部分发(设备不支持走引擎内降级/报错),能力**信息**走**统一对外查询通道**(`describe()`);④ 文件角色拆开:**`.nnmodel`**(推理,`.bin` 接替者)与 **`.nnckpt`**(含训练参数,`--save-interval` 写它);⑤ 热路径审查(基类能力分支 + `eval_expr` 每次求值双份归因 → 编译期标签 / init 期常量 / 引擎内就地回退);⑥ `sub_layers()` 与 NNQT 独立格式、`--export-deploy` 等标签**全部删除**(`BitLinear` 的 f16 稠密 A/B 开关保留)。**§3 待裁决已定**:`EngineInfo` 结构体 + `text()`、接口名 `describe()`;`.nnmodel` 不留 latent;旧 `.bin` 只读不写、不提供转换工具。落地验收见 21 §4.15 与 `src/model_roles_test.cpp` | -| `todo/24-f16-training-defects.md` | **f16 训练缺陷台账**:全 f16 NaN / loss 冻结 / `--f16` 降速;立项 F1–F7(F5 ✅ 已可训练;F6 = 真 f16 Plan B;F7 = 标准 `--f16` Plan A) | -| `todo/25-release-requirements.md` | **大版本发布必做清单**(`1.x.y → 1.(x+1).0`):端到端模型训练测试 / 发布文档 / 完整 ctest + Debug 构建 / 四组「编译器 × 标准库」矩阵 | -| `todo/26-f16-speedup-plan.md` | **f16 提速与两套 f16 计划**:Plan A = 标准 `--f16`(AMP 式,推荐默认);Plan B = 全流程真 f16(零转换门禁),§8 分列 | -| `todo/28-lifecycle-v3.md` | **生命周期 v3(✅ 已随 v1.10.0 发布)**:删 `EngineId`/`stamp_`/`adopt`/`bound`,设备域从存储派生;改生命周期 / Tensor / 引擎绑定前读 | -| `todo/29-session-architecture.md` | Session 层所有权设计:Model + Optimizer 同生共死、`InferenceSession` / 通用 `TrainingGroupSession` 占位;训练状态归属由 30 号修订 | -| `todo/30-training-session-step.md` | **TrainingSession 单步协议(✅ 随 v1.11.0 发布)**:micro-batch 入、内置梯度累积、global batch 归一化、`batch_size` = 理论 batch;改训练入口前读 | -| `todo/33-version-branch-and-release-policy.md` | **版本号·分支·发布治理**:`v1..<漏洞修复>` 规则、**发布版本号必须由人提出(agent 不得擅自发布)**、`dev` 不写版本号、发布只在 `main` | +| `internal/00-code-review-remediation.md` | **2026-10-11 代码审查整改立项台账**:审查发现逐条立项(现象/证据/根因/方案/验收/优先级)。接手整改前先读本文 | +| `internal/02-operator-fusion.md` | **算子融合全篇(当前形态与设计约束):IR 扩展(归约语义)→ 表达式录制 → matmul 参与 IR 融合 → 跨 kernel 自动融合(一期 M1-M7 + 二期 S1-S5/S7;分期实施流水与否决方案见 `docs/history/history.md`)** | +| `internal/03-ir-optimization.md` | IR 优化(现行 IR-A/B/C/D;**IR-C 图融合为现行能力——当前形态与融合规则见 AGENTS §7,历史取舍归档在 `docs/history/history.md`**) | +| `internal/04-memory-optimization.md` | 显存优化:L1 激活重计算(梯度检查点)/ L2 内存池整块归还(均已实施);L3 远期 | +| `contributors/pitfalls.md` | **踩坑警示录,改代码前读** | +| `contributors/cpp-standards.md` | C++ 编码规范全文 | +| `internal/12-compute-engine-inventory.md` | **引擎接口盘点(复现:`bench/doc_inventory.ps1`):52 个 virtual 方法、Layer 直调 32 个(基础设施/数据搬运/状态扫描/fold 执行(自登记)/IR-C 录制段开合/三值打包/张量形变/精度落盘/RL 行带适配)、两套 CPU 求值机制(DSL 模板 + IR 解释器)、ctest 64 个注册(无 Vulkan 树 62);演进记录见 `docs/history/history.md`** | +| `internal/14-f16-stable-gpu-loss-frozen.md` | **故障报告(2026-09-26;2026-10-13 ✅ 已修/根因订正):GPU `stable=f16` 训练 loss 打印冻结(权重不冻结)——真因 = CE 的 (1,1) loss 归约按 `stable=f16` 落盘溢出,非回读链;触发矩阵、测试覆盖缺口、证据与复现** | +| `internal/17-unified-tensor-engine.md` | **统一 Tensor/ComputeEngine/MemoryPool 底层架构总纲(2026-09-30 裁定;M1-M6 全部已实施 2026-09-30,仅 M7 未立项):访问不变量(Tensor 存储私有、一切经引擎,已立为铁律 #11)、InitSpec 声明式初始化、批量 read/write、Matrix 降级为宿主 I/O 载体(L2+ 禁用 = 铁律 #12)、内存池契约统一、`import` 跨设备拉取、Layer 删每调用 engine 形参(M6 段 C,Loss/DSL/辅助对象保留形参见 §8);吸收原 15 未实施的 P2-P6(改期 M1-M7)。立项前先读本文件 + §5 分期 + §8** | +| `internal/18-roadmap.md` | **未来方向路线图 + 未完成项裁定台账(2026-10-01,13 号清单的承接者):RL 主线 ✅(2026-10-23)+ P0-P4 分期(P4 = 持续优化方向,2026-10-14 立项)、13 号逐条裁定(做/条件触发/不做)、触发式立项条件、非目标、门禁与验收口径。查"某件事该不该做、做到什么算完成、避免重复立项"时读本文;**执行排序不在本文**(见 `internal/27-execution-plan.md`)** | +| `internal/27-execution-plan.md` | **执行计划(优先级象限,2026-10-15):RL-0…RL-2b 已完成并从执行表移出;其余象限是后续 backlog。想知道"下一个先做哪个"读它;裁定去 18 号,本文只排顺序、不产生新裁定** | +| `internal/31-rl-training-primitives.md` | **RL 与可组合训练基础设施(2026-10-23 ✅ 已实施)**:issue #23 是能力下界;公共语义 = `NamedTensorSet`/`OutputSchema`、schema 化 experience、policy-objective 组件、通用 `TrainingGroupSession` 与可替换编排;实现/门禁见 §11,使用指南见 `usage/06-reinforcement-learning.md` | +| `internal/19-unified-dataset.md` | **统一数据集格式与加载(`.nndataset`/`.nnvocab`/KVRecord v2,2026-10-05 设计定稿、阶段一~三已实施):裁决记录、KVRecord v2 规范、文件布局、`nn::Dataset`/`dataset_gen`/`dataset_convert`/模型 v6 分期落地与兼容迁移。接数据集相关任务前读本文** | +| `internal/21-quantized-weights.md` | **三值(1.58-bit)量化权重与 BitLinear(2026-10-09 设计定稿 → 2026-10-10 **P1 已实施**,分支 `dev/t1_58`):`Precision::T1_58` + `Layer::precision_support()`(按槽声明、`init` 期校验)+ `BitLinear`(量化 forward / STE backward);含 Lumina-Engine `TQ1_0` 参考实现拆解、`§4.9` 实现与设计的差异、`§8` 架构图、`§10` 提交清单。**已裁定**:尺度 = absmean + per-row(absmax 只剩 0.13~1.29 bit 信息,实测见 `research/ternary_scale/`)、打包 = `TQ1_0` 编码 + 行级块、命名 `T1_58` / CLI 无别名 / 层名 `BitLinear`、D3 = (a)+(b)、D5 = ③(P1 只覆盖 MLP;GPT 侧由 P1.5 补齐,RAPT/ViT 仍拒绝);**仍待定** D6(P2 行步长/对齐)。前置证据 `research/ternary_ste/`**;验收 `src/t1_58_test.cpp`(+`--gpu` 变体) | +| `internal/22-bitnet-2b4t-architecture.md` | **BitNet b1.58 2B4T 的结构对齐(2026-10-10 立项 + **S1/S2/S3 三步已实施并提交**,分支 `dev/t1_58`):三项结构差距 = SubLN / GQA / tied embedding,均为**可选开关、默认关**。**已裁定**:SubLN 封装在子层内部(`AttentionBase`/`FeedForward` 的可选 `unique_ptr`,**不是** `NormType` 新值、**不是** block 的第三个 norm)、类型跟随 `norm_type`;GQA 头映射 = `kv = h/(n_head/n_head_kv)`(llama.cpp FA 与 HF `repeat_kv` 互证)+ 显式展开 K/V 头(前向 `gather_rows` / 反向 `scatter_add_rows`,fold 与 AOT 注册表零改动);tied embedding 在 `GPTModel` 内一个开关(梯度**累加**进 `grad_token_emb_`);**不加 CLI 预设**(GUI 留待以后);`ModelSpec` 追加 `subln`/`n_head_kv`/`tie_embeddings` 三键(缺键 = 旧语义,不升 MODEL_VERSION)。**验收 `src/bitnet_struct_test.cpp`(+`--gpu`)**:GQA 退化与 MHA 逐位一致、GQA↔按块映射复制成 MHA 前向差 0、tied 梯度累加差 0;102 上全量 ctest 30/30。**实施记录见本文 §10**。**待定**:FFN 激活 ReLU²(需确认官方 `hidden_act`;llama.cpp 对 gated squared relu `GGML_ABORT`,无对拍)、GQA in-kernel 版(P2)、HF 权重转换器。**结构侧**与 21 号(权重侧 `T1_58`/`BitLinear`)是两条正交的腿** | +| `internal/23-library-design-cleanup-and-model-file-roles.md` | **库级违规设计清理(2026-10-11 **已实施**):模型文件角色 + 参数形态协议 + 引擎能力体系**(范围 = **整个库**,不只三值)。三轮裁决要点:① 参数级 `kind`(Dense / TernaryLatent / TernaryPacked2 / TernaryPacked3 / 预留 int8);② **不引入**可训练/不可训练状态;③ 能力谓词 = 具体引擎私有、**不得进基类**、不作对外标签、只作内部分发(设备不支持走引擎内降级/报错),能力**信息**走**统一对外查询通道**(`describe()`);④ 文件角色拆开:**`.nnmodel`**(推理,`.bin` 接替者)与 **`.nnckpt`**(含训练参数,`--save-interval` 写它);⑤ 热路径审查(基类能力分支 + `eval_expr` 每次求值双份归因 → 编译期标签 / init 期常量 / 引擎内就地回退);⑥ `sub_layers()` 与 NNQT 独立格式、`--export-deploy` 等标签**全部删除**(`BitLinear` 的 f16 稠密 A/B 开关保留)。**§3 待裁决已定**:`EngineInfo` 结构体 + `text()`、接口名 `describe()`;`.nnmodel` 不留 latent;旧 `.bin` 只读不写、不提供转换工具。落地验收见 21 §4.15 与 `src/model_roles_test.cpp` | +| `internal/24-f16-training-defects.md` | **f16 训练缺陷台账**:全 f16 NaN / loss 冻结 / `--f16` 降速;立项 F1–F7(F5 ✅ 已可训练;F6 = 真 f16 Plan B;F7 = 标准 `--f16` Plan A) | +| `contributors/release-requirements.md` | **大版本发布必做清单**(`1.x.y → 1.(x+1).0`):端到端模型训练测试 / 发布文档 / 完整 ctest + Debug 构建 / 四组「编译器 × 标准库」矩阵 | +| `internal/26-f16-speedup-plan.md` | **f16 提速与两套 f16 计划**:Plan A = 标准 `--f16`(AMP 式,推荐默认);Plan B = 全流程真 f16(零转换门禁),§8 分列 | +| `internal/28-lifecycle-v3.md` | **生命周期 v3(✅ 已随 v1.10.0 发布)**:删 `EngineId`/`stamp_`/`adopt`/`bound`,设备域从存储派生;改生命周期 / Tensor / 引擎绑定前读 | +| `internal/29-session-architecture.md` | Session 层所有权设计:Model + Optimizer 同生共死、`InferenceSession` / 通用 `TrainingGroupSession` 占位;训练状态归属由 30 号修订 | +| `internal/30-training-session-step.md` | **TrainingSession 单步协议(✅ 随 v1.11.0 发布)**:micro-batch 入、内置梯度累积、global batch 归一化、`batch_size` = 理论 batch;改训练入口前读 | +| `contributors/release-policy.md` | **版本号·分支·发布治理**:`v1..<漏洞修复>` 规则、**发布版本号必须由人提出(agent 不得擅自发布)**、`dev` 不写版本号、发布只在 `main` | ### 使用类(docs/usage/,**给调用者**) @@ -452,19 +465,19 @@ auto report = NN_UNWRAP(session.train_step( ### 已知问题 -- **GPU `stable=f16` 训练 loss 打印冻结(✅ 2026-10-13 已修,原判断已订正)**:真因**不是** loss 回读链,而是 **CE 的 `(1,1)` loss 归约输出按 `stable=f16` 落盘溢出**(`Σ ≈ -log(vocab)·N` 超 65504 → inf → NaN;旧报告里的 `4.0137 ≈ 65504/num_valid` 是饱和表现)。修法 = `compute_loss.hpp` 稀疏(`fused_forward_sparse_`)与稠密两条链的 `(1,1)` reduce 输出**恒 `Precision::F32`**。实测(850M):`seq256/b32` 由 `inf` → `9.0056→8.6922`;`stable=f16` 120 步无 NaN。回归门禁见 `docs/todo/14-f16-stable-gpu-loss-frozen.md` 与 24 号 §3.1。推荐路径仍是 `--f16`(stable/optimizer=f32)。 -- **f16 两套计划(2026-10-18)**:**Plan A = 标准 `--f16`(参考 PyTorch AMP)**——`--f16`(param/compute=f16,stable/optimizer=f32)是推荐默认,补动态 loss scaling / master weights;**Plan B = 全流程真 f16**——四字段全 f16,支持 f16 计算的设备全程零 f16↔f32 转换,不支持时只由引擎在算子内部隐式转换(Layer/DSL/CLI 零手写 cast)。F5 后四字段全 f16 已可训练,但 CE 标量仍是 F32 补丁、matmul/归约仍有 f32 累加、native16 未全覆盖,**不等于真 f16**。细则见 `docs/todo/26-f16-speedup-plan.md` §8.A/§8.B。 +- **GPU `stable=f16` 训练 loss 打印冻结(✅ 2026-10-13 已修,原判断已订正)**:真因**不是** loss 回读链,而是 **CE 的 `(1,1)` loss 归约输出按 `stable=f16` 落盘溢出**(`Σ ≈ -log(vocab)·N` 超 65504 → inf → NaN;旧报告里的 `4.0137 ≈ 65504/num_valid` 是饱和表现)。修法 = `compute_loss.hpp` 稀疏(`fused_forward_sparse_`)与稠密两条链的 `(1,1)` reduce 输出**恒 `Precision::F32`**。实测(850M):`seq256/b32` 由 `inf` → `9.0056→8.6922`;`stable=f16` 120 步无 NaN。回归门禁见 `docs/internal/14-f16-stable-gpu-loss-frozen.md` 与 24 号 §3.1。推荐路径仍是 `--f16`(stable/optimizer=f32)。 +- **f16 两套计划(2026-10-18)**:**Plan A = 标准 `--f16`(参考 PyTorch AMP)**——`--f16`(param/compute=f16,stable/optimizer=f32)是推荐默认,补动态 loss scaling / master weights;**Plan B = 全流程真 f16**——四字段全 f16,支持 f16 计算的设备全程零 f16↔f32 转换,不支持时只由引擎在算子内部隐式转换(Layer/DSL/CLI 零手写 cast)。F5 后四字段全 f16 已可训练,但 CE 标量仍是 F32 补丁、matmul/归约仍有 f32 累加、native16 未全覆盖,**不等于真 f16**。细则见 `docs/internal/26-f16-speedup-plan.md` §8.A/§8.B。 - **不存在的 CLI 参数**:`--tdr-retry`/`--max-tdr-retries` 与 `mnist_train --osc-guard`/`--osc-window`/`--osc-threshold`(**均已移除**:前两者从未实现,后三者属"帮助声明了、解析分支不存在"的幽灵选项,已从帮助/控制器/GUI 三层清除,详见 `docs/history/history.md`「GUI / CLI 参数一致性清理」)。 - **`text_train --model zipt` 启动即中止(未修)** → **已随 ZiPT 整体移除而消失**:AttnZip/ZiPT 已从主线移除(`--model zipt` 现在直接报"未知模型架构"并给出迁移提示),代码保留在 **`legacy/zipt` 分支**。**恢复前提(两条同时满足)**:① **算法层**——压缩向量必须因果(压缩器只能看当前位置之前的内容);② **代码层**——实现质量对齐 RAPT/GPT(支持 `forward_recompute` 梯度检查点与 activation offload、CLI/序列化/测试齐备)。裁决依据见 `docs/history/history.md`「ZiPT 移除」条。已移除的 API:`ZiPTModel`/`ZiPTBlock`/`CrossAttention`、`build_zipt_model*`/`make_zipt_spec`/`ZiPTConfig`/`ZIPT_MEMORY_TOKENS`、`ModelSpec::is_zipt()` 与 `memory_tokens`/`window` 字段、CLI `--model zipt`/`--window`/`--memory-tokens`、`zipt_test`;`ModelType` 的 6 号枚举保留为 `Reserved_ZiPT` 占位,用于对旧 `.bin`(type=6)给出明确错误。 ### 已交付能力(速览) -> **只列"能力名 + 关键不变量",不含数字/过程**——每项的实测收益、A/B 数字、锚值变化与取舍**全部归档在 `docs/history/history.md`**,需要"为什么这么改 / 旧数字"时再去查。设计稿在 `docs/todo/`。 +> **只列"能力名 + 关键不变量",不含数字/过程**——每项的实测收益、A/B 数字、锚值变化与取舍**全部归档在 `docs/history/history.md`**,需要"为什么这么改 / 旧数字"时再去查。设计稿在 `docs/internal/`。 - **表达式 DSL + AOT 融合**(`expr_dsl.hpp`/`expr_spec.hpp`/`expr_graph.hpp`):Layer 用 `dsl::compute*` 写数学,CPU 模板路径直接求值、GPU 折成 `ExprSpec` 按 `expr_spec_key` 查预编译 shader(闭合世界,未命中硬报错)。 - **IR-C 图融合**(`expr_graph.hpp` + `begin_expr/end_expr` + `dsl::start_expr/end_expr`):P1 链 / P2 写穿多输出,**已接入 `Adam::step`/`AdamW::step`**;P3 跨链批量派发(`NN_IRC_NO_BATCH=1` A/B、`NN_IRC_TRACE=1` 观测)。混精度下的未登记复合结构**逐成员降级派发**(可观测,非错误),未登记**单节点**仍硬报错。全 f32 逐形态 GPU 对拍(`fused_gpu_test`)与图融合端到端(`expr_fuse_test`,多输出逐位 err=0)为回归锁。 -- **三值权重 `T1_58` / `BitLinear`**(`precision.hpp` + `compute_layer_bitlinear.hpp`):**离散化不是舍入**、不进提升序、P1 里**不是存储精度**(只作 `param` 槽声明 + 层能力集合取值);`BitLinear` = 打包权重 + `matmul_q`(训练/解码同一条路)。CLI `--precision-param t1_58` 与预设 `--t1_58` 均存在(词法唯一 `t1_58`;预设是"整份 profile 快捷方式")。MLP 与 GPT 已接线;**RAPT / ViT 明确拒绝**。**续训入口(P1-7)**:三值 `.nnmodel` 用 `WeightLoadIntent::Trainable` 按文件 τ 反量化成 f32 latent(`L = trit·τ·K/n` = 量化器不动点)⇒ SFT / QAT 可续训;推理侧仍走默认 `Inference` 部署只读态。结构开关(**默认关**):SubLN / GQA(`n_head_kv`,块映射)/ tied embedding / ReLU²,见 `docs/todo/22`。 -- **BitNet b1.58 2B4T 结构开关**:SubLN(子层内部,非 `NormType` 新值)/ GQA(`n_head_kv`,块映射 `kv=h/(n_head/n_head_kv)`,训练路径 `ExprViewKind::HeadGroup` 不展开 K/V)/ tied embedding(head 复用 `token_emb_`,`dW` 累加)/ ReLU²(`ReLU2GLU`)。`ModelSpec` 追加 `subln`/`n_head_kv`/`tie_embeddings`(缺键 = 旧语义,不升版本)。见 `docs/todo/22`。 +- **三值权重 `T1_58` / `BitLinear`**(`precision.hpp` + `compute_layer_bitlinear.hpp`):**离散化不是舍入**、不进提升序、P1 里**不是存储精度**(只作 `param` 槽声明 + 层能力集合取值);`BitLinear` = 打包权重 + `matmul_q`(训练/解码同一条路)。CLI `--precision-param t1_58` 与预设 `--t1_58` 均存在(词法唯一 `t1_58`;预设是"整份 profile 快捷方式")。MLP 与 GPT 已接线;**RAPT / ViT 明确拒绝**。**续训入口(P1-7)**:三值 `.nnmodel` 用 `WeightLoadIntent::Trainable` 按文件 τ 反量化成 f32 latent(`L = trit·τ·K/n` = 量化器不动点)⇒ SFT / QAT 可续训;推理侧仍走默认 `Inference` 部署只读态。结构开关(**默认关**):SubLN / GQA(`n_head_kv`,块映射)/ tied embedding / ReLU²,见 `docs/internal/22`。 +- **BitNet b1.58 2B4T 结构开关**:SubLN(子层内部,非 `NormType` 新值)/ GQA(`n_head_kv`,块映射 `kv=h/(n_head/n_head_kv)`,训练路径 `ExprViewKind::HeadGroup` 不展开 K/V)/ tied embedding(head 复用 `token_emb_`,`dW` 累加)/ ReLU²(`ReLU2GLU`)。`ModelSpec` 追加 `subln`/`n_head_kv`/`tie_embeddings`(缺键 = 旧语义,不升版本)。见 `docs/internal/22`。 - **多精度**:`Precision`/`PrecisionProfile{param,compute,stable,optimizer}`;f16 走基类 NVI 边界 cast + 引擎 in-kernel f16 变体 + op-level f16 GEMM(`-DNN_SHADER_F16=1` 编第二份 SPIR-V);`--f16` = `{param:F16, compute:F16, stable:F32, optimizer:F32}`。语义契约 `docs/development/05`。 - **推理采样截断**(`SamplingConfig` + `sample_next_token_`,CPU 侧 host 采样):temperature / top-k / top-p(核采样,保留集内重新归一化)/ 重复惩罚(可选 `repeat_window`)/ 固定种子(`has_seed`);顺序固定 = 重复惩罚 → 温度 → top-k → top-p → softmax → 采样/贪心,**全部关闭时与旧路径逐位一致**(`sampling_test` 锁:下标 + 概率向量 + RNG 消耗序);`text_infer` 暴露 `--top-k`/`--top-p`/`--repeat-penalty`/`--repeat-window`/`--seed`(同 seed 同 prompt ⇒ 同输出)。 - **多轮对话闭环**(P0-5 尾项,2026-10-16):prompt 构建唯一真源 = `Tokenizer::chat_prompt`(`BOS<|system|>…` 模板 + 末轮 user 补 `<|assistant|>` + 超 `seq_len` 时**按一问一答整轮丢弃**,system 块与末轮恒保留);**"上下文不丢"的可验证形式 = 第 N 轮的 prompt 以第 N-1 轮为逐 token 前缀**。三条使用路径:`--interactive`(进程内累积,助手轮用生成的原 token 回灌)/ `--turn :`(历史由调用方自带,末条必须 user;合法形状 = 交替、user 起头)+ `--reply-out `(回复落盘 → GUI 取回复不解析日志)/ GUI「GPT 推理」页的「💬 发送(多轮)」+「🧹 清空对话」(`ChatSession` 持有历史,**无状态协议**:每轮把整段历史交回 CLI ⇒ 每轮都能改采样参数)。门禁 `chat_prompt_test`(模板/前缀不变式/截断/纯文本回退 + 真实 CLI 子进程端到端)+ `bench/gui_cli_audit.py` 第 [7] 节(Python 侧参数面)。 @@ -478,10 +491,10 @@ auto report = NN_UNWRAP(session.train_step( - **注意力单 fold kernel**:`FoldSpec` 分块流式(S 不物化),**掩码 `AttnMaskKind` × 位置偏置** 两正交维度。 - **CNN 全引擎化**:`im2col`/`col2im` + `rearrange_3d`,无 PCIe 往返。 - **分词器**:保序并行 `encode`(`set_encode_threads`,任意并行度逐字节一致)+ 零堆分配合并 + `encode_docs_parallel`。 -- **统一数据集**:KVRecord v2 / `.nnvocab`(旧 JSON 不直读,`dataset_convert vocab` 迁移)/ `.nndataset`(`nn::Dataset` 只读类,词表/掩码/test 子集随数据集);**P2b 起样本概念显式**——存储单位 = doc,训练单位 = sample(`dataset_samples.hpp` 的 `TextSampleSet`,文本 = 滑动窗口;`step` 是 `ceil(样本数/batch)` 派生量),数据集可经 `text_trainer.hpp` 直接接入训练工厂。`text_train` 位置参数是 ``(`--vocab`/`--test-file`/`--loss-scope`/`--no-cache` 已移除)。见 `docs/todo/19`。 -- **模型文件角色(v8)**:一份格式两种角色——`*.nnmodel`(推理,三值层写打包形态 base-3 1.6 bpw)与 `*.nnckpt`(训练断点,写 f32 latent + 训练状态段);参数级 `kind`(参数形态协议)+ **载入意图** `WeightLoadIntent`(`Inference` 部署只读 / `Trainable` 反量化 warm start,P1-7);`--resume` 两种角色都收(`.nnckpt` = 断点续训、`.nnmodel` = warm start)。见 `docs/todo/23`。 +- **统一数据集**:KVRecord v2 / `.nnvocab`(旧 JSON 不直读,`dataset_convert vocab` 迁移)/ `.nndataset`(`nn::Dataset` 只读类,词表/掩码/test 子集随数据集);**P2b 起样本概念显式**——存储单位 = doc,训练单位 = sample(`dataset_samples.hpp` 的 `TextSampleSet`,文本 = 滑动窗口;`step` 是 `ceil(样本数/batch)` 派生量),数据集可经 `text_trainer.hpp` 直接接入训练工厂。`text_train` 位置参数是 ``(`--vocab`/`--test-file`/`--loss-scope`/`--no-cache` 已移除)。见 `docs/internal/19`。 +- **模型文件角色(v8)**:一份格式两种角色——`*.nnmodel`(推理,三值层写打包形态 base-3 1.6 bpw)与 `*.nnckpt`(训练断点,写 f32 latent + 训练状态段);参数级 `kind`(参数形态协议)+ **载入意图** `WeightLoadIntent`(`Inference` 部署只读 / `Trainable` 反量化 warm start,P1-7);`--resume` 两种角色都收(`.nnckpt` = 断点续训、`.nnmodel` = warm start)。见 `docs/internal/23`。 - **错误处理宏族**:传播 `NN_TRY`/`NN_TRY_MSG`/`NN_TRY_CHECK`、解包+终止 `NN_UNWRAP(expr[, "语境"])`(**语义 = unwrap,不是 assert**;旧名 `NN_CHECK`/`NN_EASY_CHECK` 保留为等价别名)、解包+退出码 `NN_EXIT(expr, code[, "语境"])`、错误源 `NN_FAIL("msg")`。手写形态已全量迁宏(残留 0,门禁 `doc_inventory.ps1` §5 基线 0)。 -- **RL 与可组合训练(2026-10-23,RL-0…RL-2b ✅)**:`TensorSchema`/`NamedTensorSet`/`GradientBundle`;`Model::forward_named/backward_named` + `OutputBundleLayer`,`RowBandPacking` 仅作旧单 Tensor ABI 适配,ModelSpec 可往返 schema/packing;`ExperienceSchema`/`TensorRecord`/`PolicyBatchView` + GAE/return/group transform;可替换 `PolicyDistribution`(首版 categorical)与 REINFORCE/PPO/GRPO preset;`TrainingGroupSession` 管具名 trainable/readonly role;`RLTrainingPipeline` 固定 `rollout→buffer→sample→update` 并可恢复 seed/计数。新增 RL 内联表达式必须纳入 `scan_exprs` 闭合世界。详见 `docs/usage/06-reinforcement-learning.md` 与 `docs/todo/31-rl-training-primitives.md`。 +- **RL 与可组合训练(2026-10-23,RL-0…RL-2b ✅)**:`TensorSchema`/`NamedTensorSet`/`GradientBundle`;`Model::forward_named/backward_named` + `OutputBundleLayer`,`RowBandPacking` 仅作旧单 Tensor ABI 适配,ModelSpec 可往返 schema/packing;`ExperienceSchema`/`TensorRecord`/`PolicyBatchView` + GAE/return/group transform;可替换 `PolicyDistribution`(首版 categorical)与 REINFORCE/PPO/GRPO preset;`TrainingGroupSession` 管具名 trainable/readonly role;`RLTrainingPipeline` 固定 `rollout→buffer→sample→update` 并可恢复 seed/计数。新增 RL 内联表达式必须纳入 `scan_exprs` 闭合世界。详见 `docs/usage/06-reinforcement-learning.md` 与 `docs/internal/31-rl-training-primitives.md`。 - **CPU 性能**:DSL 模板向量化/并行、`dsl::compute_into` 零分配原地更新、分块 GEMM(`BLOCK_SIZE=64`)。 - **Vulkan 多设备选择**:`--gpu` / `NN_VULKAN_DEVICE`(`cli/cli_gpu_option.hpp`)。 @@ -495,7 +508,7 @@ auto report = NN_UNWRAP(session.train_step( ### 融合二期状态与 IR 编码约束(改融合/IR 代码前必读) -二期范围 = S1-S5、S7(S6 自动窗口不接线;见 `docs/todo/02-operator-fusion.md`,分期流水见 `docs/history/history.md`)。 +二期范围 = S1-S5、S7(S6 自动窗口不接线;见 `docs/internal/02-operator-fusion.md`,分期流水见 `docs/history/history.md`)。 1. **运行时值禁进表达式常量池**(进 `expr_spec_key` 会破坏闭合世界):`scale` 折进 Q(forward `scale_inplace` + backward 补乘)、`inv_num_valid` 后置 `scale_inplace`。 2. **BatchCol 视图要求 `(1, BH*seq)`**(doc_ids 按 (b,h) 块重复),`(1, batch*seq)` 会越界。 diff --git a/CMakeLists.txt b/CMakeLists.txt index c72b3ab..7aeb3da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -675,7 +675,7 @@ if(NN_BUILD_APPS OR NN_ENABLE_TESTS) nn_add_executable(layer_lifetime_test src/layer_lifetime_test.cpp) list(APPEND NN_TEST_TARGETS layer_lifetime_test) - # ── P0 生命周期契约负例(docs/todo/28 §5 P0)────────────────────────── + # ── P0 生命周期契约负例(docs/internal/28 §5 P0)────────────────────────── # 覆盖:ExprSegment 强引用(录制段内丢外部引擎句柄仍可 end)、 # ActivationOffloader 状态机(未 import 的重复 export = fail-fast; # discard 作废通道)与精度门(slab 恒 f32 ⇒ 非 F32 激活拒绝)、 @@ -683,11 +683,11 @@ if(NN_BUILD_APPS OR NN_ENABLE_TESTS) nn_add_executable(lifetime_contract_test src/lifetime_contract_test.cpp) list(APPEND NN_TEST_TARGETS lifetime_contract_test) - # -- P2a: TrainingSession (Model + Optimizer 同生共死, docs/todo/29) -- + # -- P2a: TrainingSession (Model + Optimizer 同生共死, docs/internal/29) -- nn_add_executable(training_session_test src/training_session_test.cpp) list(APPEND NN_TEST_TARGETS training_session_test) - # ── RL 公共基础:有序 tensor schema / 具名张量 / 梯度包(docs/todo/31 §3) + # ── RL 公共基础:有序 tensor schema / 具名张量 / 梯度包(docs/internal/31 §3) nn_add_executable(tensor_schema_test src/tensor_schema_test.cpp) list(APPEND NN_TEST_TARGETS tensor_schema_test) @@ -729,7 +729,7 @@ if(NN_BUILD_APPS OR NN_ENABLE_TESTS) src/rl_training_integration_test.cpp) list(APPEND NN_TEST_TARGETS rl_training_integration_test) - # ── F1:危险精度组合启动期告警(仅警告,不拒绝;docs/todo/24 §2.3)──── + # ── F1:危险精度组合启动期告警(仅警告,不拒绝;docs/internal/24 §2.3)──── # [1][2] 头文件函数组合矩阵(含 all=f16)单测;[3] 子进程跑 text_train/ # mnist_train,捕获 stderr 断言告警出现 + 退出码不变;二进制缺失 → 77 = SKIP nn_add_executable(cli_precision_warning_test src/cli_precision_warning_test.cpp) @@ -1101,7 +1101,7 @@ if(Vulkan_FOUND) # # ⚠ 收集器**必须保留库内收集逻辑**:实测 84 个结构里只有 13 个来自 # 编译期锚点,71 个来自 dry-run/模型 pass(见 docs/history/history.md 与 - # docs/todo/02)。纯锚点收集器会漏掉库自身的结构。 + # docs/internal/02)。纯锚点收集器会漏掉库自身的结构。 # # ── 树外可用性(CMake 函数作用域)──────────────────────────────────── # CMake 函数体在**调用方作用域**求值:消费方在自己的 CMakeLists 里调用 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f59b4cf..68fb93b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ > 本文写给**不是本仓作者**的人:想用库、报 bug、提 PR、加层/加原语、写文档、或把一份实验结果放进 `research/`。 > 只回答「我怎么参与」。**项目自身的开发规范**(14 条铁律、分层依赖、门禁口径、踩坑)在 -> [`AGENTS.md`](AGENTS.md) 与 [`docs/todo/10-development-standards.md`](docs/todo/10-development-standards.md); +> [`AGENTS.md`](AGENTS.md) 与 [`docs/contributors/cpp-standards.md`](docs/contributors/cpp-standards.md); > 文档分册定位(哪篇写给谁看)在 [`docs/README.md`](docs/README.md)。 --- @@ -11,13 +11,13 @@ | 你想做什么 | 从这里开始 | |-----------|-----------| -| 用库写自己的模型/训练 | [`docs/development/cpp-api-manual.md`](docs/development/cpp-api-manual.md)、[`docs/usage/`](docs/usage/) | -| 把库嵌进自己的 CMake 工程 | [`docs/development/cmake-integration.md`](docs/development/cmake-integration.md)、[`docs/usage/05-consume-as-library.md`](docs/usage/05-consume-as-library.md) | -| 写自己的层 | [`docs/development/write-a-custom-layer.md`](docs/development/write-a-custom-layer.md) | -| 扩展引擎原语 / 改 GPU 后端 | [`docs/development/01-compute-engine-development.md`](docs/development/01-compute-engine-development.md) + `AGENTS.md` §7 | +| 用库写自己的模型/训练 | [`docs/development/02-cpp-api-manual.md`](docs/development/02-cpp-api-manual.md)、[`docs/usage/`](docs/usage/) | +| 把库嵌进自己的 CMake 工程 | [`docs/development/01-cmake-integration.md`](docs/development/01-cmake-integration.md)、[`docs/usage/05-consume-as-library.md`](docs/usage/05-consume-as-library.md) | +| 写自己的层 | [`docs/development/03-write-a-custom-layer.md`](docs/development/03-write-a-custom-layer.md) | +| 扩展引擎原语 / 改 GPU 后端 | [`docs/development/04-compute-engine-development.md`](docs/development/04-compute-engine-development.md) + `AGENTS.md` §7 | | **改本仓的代码** | [`AGENTS.md`](AGENTS.md)(**先读 §5 铁律与 §10 高频坑**) | -| 看"下一步该做什么" | [`docs/todo/18-roadmap.md`](docs/todo/18-roadmap.md) | -| 提发布 / 定版本号 | [`docs/todo/33-version-branch-and-release-policy.md`](docs/todo/33-version-branch-and-release-policy.md)(**版本号必须由人提出,agent 不得擅自发布**;`dev` 不写版本号,发布只在 `main`)+ [`docs/todo/25-release-requirements.md`](docs/todo/25-release-requirements.md) | +| 看"下一步该做什么" | [`docs/internal/18-roadmap.md`](docs/internal/18-roadmap.md) | +| 提发布 / 定版本号 | [`docs/contributors/release-policy.md`](docs/contributors/release-policy.md)(**版本号必须由人提出,agent 不得擅自发布**;`dev` 不写版本号,发布只在 `main`)+ [`docs/contributors/release-requirements.md`](docs/contributors/release-requirements.md) | | 看"为什么当初这么改" | [`docs/history/history.md`](docs/history/history.md)(全仓唯一历史归档) | --- @@ -49,7 +49,7 @@ cmake -B build -G Ninja && cmake --build build # 默认 Release cmake -B build -G Ninja -DNN_ENABLE_TESTS=ON && cmake --build build && ctest --test-dir build ``` -常用开关(完整列表见 [`docs/development/cmake-integration.md`](docs/development/cmake-integration.md)): +常用开关(完整列表见 [`docs/development/01-cmake-integration.md`](docs/development/01-cmake-integration.md)): | 开关 | 默认 | 用途 | |------|------|------| @@ -69,7 +69,7 @@ ctest --test-dir build -R gradcheck # 只跑匹配的 ``` **本地必须跑**:CI 目前只做「构建 + 打包可执行文件」(见 §6),**不跑 ctest**—— -那是 [`docs/todo/18-roadmap.md`](docs/todo/18-roadmap.md) 里 P0-1 的待办。所以测试是你自己的门禁。 +那是 [`docs/internal/18-roadmap.md`](docs/internal/18-roadmap.md) 里 P0-1 的待办。所以测试是你自己的门禁。 改到下面这些区域时,请把对应专项测试一起跑(都在 ctest 里): @@ -77,7 +77,7 @@ ctest --test-dir build -R gradcheck # 只跑匹配的 |---------|--------| | 引擎原语 / 张量 | `*_test`(含 `f16_precision_test`、`write_epoch_test`) | | 训练/反向 | 各 `gradcheck*`、`*_train_test` | -| GPU 后端 / DSL 融合 | 带 `--gpu` 的变体(见 [`docs/todo/12-compute-engine-inventory.md`](docs/todo/12-compute-engine-inventory.md) 的清单) | +| GPU 后端 / DSL 融合 | 带 `--gpu` 的变体(见 [`docs/internal/12-compute-engine-inventory.md`](docs/internal/12-compute-engine-inventory.md) 的清单) | | 三值 / BitLinear | `bitnet_struct_test`、`ternary_*`、`adam_quant_test` | | 序列化 / 数据集 | `train_state_test`、`model_roles_test`(容器格式本体已下沉子仓,见下) | | 子仓(`extern/{base,threadpool,kvrecord,dataset,tokenizer}`) | 进入子仓目录独立构建 + ctest(见各子仓 README「构建与测试」);主仓 ctest 不再包含子仓单测 | @@ -105,7 +105,7 @@ NN_VULKAN_DEVICE=850M ./build/test/bitnet_struct_test --gpu # 显式选卡 ### 3.2 代码风格 -风格规则写在 [`docs/todo/10-development-standards.md`](docs/todo/10-development-standards.md) §8 +风格规则写在 [`docs/contributors/cpp-standards.md`](docs/contributors/cpp-standards.md) §8 (命名 / 缩进 4 空格 / include 顺序 / 注释语言),机器可读版本是同目录的 [`.clang-format`](.clang-format)。 ```bash @@ -151,12 +151,12 @@ clang-format -i path/to/new_file.hpp 其他历史分支命名(`feat/`、`fix/`、`docs/` 等)已废止。文档类改动可直接在 `main` 提 PR。 - **版本号与发布规则**(正文与真源表见 [`docs/todo/33-version-branch-and-release-policy.md`](docs/todo/33-version-branch-and-release-policy.md)): + **版本号与发布规则**(正文与真源表见 [`docs/contributors/release-policy.md`](docs/contributors/release-policy.md)): ① 版本号格式 `v1..<漏洞修复>`(位定义见 [`docs/release-notes/README.md`](docs/release-notes/README.md) §1),**版本权威 = `git tag`**; ② **`dev` 及其上的功能分支从不写版本号**——不 bump `project(VERSION ...)`、不建 release note 册、不打 tag;定档与发布**只发生在 `main`**; ③ **发布版本号必须由人提出并明确给出**,agent(AI 编码助手)不得自行决定版本号或执行发布动作(`git tag` / `gh release` 等)。 -2. **一次 PR 一件事**。大改动请先在 issue/讨论里对齐设计——本仓有「先写设计稿进 `docs/todo/`, - 裁定后再实施」的习惯(`docs/todo/` 就是项目开发者的工作区)。 +2. **一次 PR 一件事**。大改动请先在 issue/讨论里对齐设计——本仓有「先写设计稿进 `docs/internal/`, + 裁定后再实施」的习惯(`docs/internal/` 就是项目开发者的工作区)。 3. 提交前自查: ```bash cmake --preset dev && cmake --build --preset dev && ctest --preset dev # 测试必须绿(当前口径:无 Vulkan 62 项 / 开 GPU 64 项) @@ -176,9 +176,9 @@ clang-format -i path/to/new_file.hpp **基线对照**工具:看**你改动的那几行**有没有新增 E,别指望整仓绿。要让它成为可执行门禁,得先给 这些 C 边界补 `// nn-allow: <原因>` 豁免(脚本支持该机制,当前全仓 0 处豁免)——那是独立的一批改动, 不在功能 PR 里顺手做。 - Windows 侧另有 `pwsh -File bench/doc_align_audit.ps1`(文档 ↔ 代码对齐审计: - 文件/符号/CLI/数字/测试名)与 `bench/doc_inventory.ps1`(引擎接口盘点 + L2 分层门禁), - 需要 PowerShell 7,改了文档或引擎接口时跑。 + 改了文档必跑 `python scripts/doc_audit.py`(文档 ↔ 代码对齐 + 文档规范审计,跨平台; + `--report` 另生成代码示例人工复核清单)。Windows 侧另有 `pwsh -File bench/doc_inventory.ps1` + (引擎接口盘点 + L2 分层门禁,需要 PowerShell 7),改了引擎接口时跑。 4. PR 描述里写:**动机 → 改了什么 → 怎么验证的 → 影响面/兼容性**(模型文件格式、CLI 参数、 数值结果是否有变化)。破坏性变更请附迁移说明。 @@ -215,25 +215,32 @@ clang-format -i path/to/new_file.hpp **大版本发布**(版本号 `1.x.y → 1.(x+1).0`)在 CI 门禁之上还有一份必做清单——端到端模型训练测试 (这类测试**不进默认 ctest**)、发布文档、完整 ctest + **Debug** 构建、多编译器 × 标准库矩阵—— -见 [`docs/todo/25-release-requirements.md`](docs/todo/25-release-requirements.md)。 +见 [`docs/contributors/release-requirements.md`](docs/contributors/release-requirements.md)。 --- ## 7. 文档贡献 -分册定位只有一条总则([`docs/README.md`](docs/README.md)): -**除 `todo/` 与 `history/history.md` 外,`docs/` 下的文档都是写给"库外的人"的。** +**规范正文在 [`docs/contributors/documentation-standard.md`](docs/contributors/documentation-standard.md)** +(分册职责 / 编号制度 / 单篇模板 / 代码示例标注 / 历史性记载禁令 / 审查口径),写任何文档前先读。 +要点速览: | 目录 | 读者 | 收什么 | |------|------|--------| -| `docs/introduction/` `docs/usage/` | 调用者 | 总览、教程 | +| `docs/introduction/` `docs/usage/` | 调用者 | 总览、教程(编号 = 阅读顺序,连续不留洞) | | `docs/development/` | **调用者**(扩展库的人) | 接入、API 手册、写自定义层、精度契约 | -| `docs/todo/` | 项目开发者 | 设计稿、路线图、盘点、规范、踩坑、整改 | -| `docs/history/history.md` | 项目开发者 | 全仓唯一历史归档(演进/勘误/被否决方案/A-B 数字) | - -一句话判断:**这篇文档的读者是"库外的人"还是"改库的人"?** 后者进 `todo/`。 - -顺手能做的:文档里的 CLI 参数、文件路径、符号名请与代码核对(`bench/doc_align_audit.ps1` 就是干这个的)。 +| `docs/contributors/` | 贡献者 / 维护者 / agent | 长期规范与治理(无编号主题名) | +| `docs/internal/` | 项目开发者 | 设计稿、路线图、盘点、故障、整改(编号 = 稳定 ID,新增续最大号) | +| `docs/history/history.md` | 项目开发者 | 全仓**唯一**历史归档(演进/勘误/被否决方案/A-B 数字) | + +- **头部模板强制**:每篇必须有 `> **读者**:` / `> **一句话结论**:` / `> **状态**:` + (词表:现行 / 冻结 / TODO / 转发页 / 已归档)。 +- **历史性记载禁令**:`history/` 之外(含代码注释)不得写"xxx 已在 commit xxx 修复"式叙事, + 一律改写为当前事实。 +- **登记义务**:新增/删除文档必须同步分册 README + `docs/README.md` 两处索引。 + +**改完文档必跑** `python scripts/doc_audit.py`(文件/链接、CLI 参数、nn:: 符号、头部模板、 +索引登记、历史性记载、代码示例清单八类检查;`--report` 生成代码示例人工复核清单)。 --- diff --git a/README.md b/README.md index 97777e3..9f31e33 100644 --- a/README.md +++ b/README.md @@ -1,347 +1,162 @@ -# neuralnet.cpp - -一个从零实现的 C++26 神经网络库,支持 CPU/GPU 双后端、多层 Transformer、GPT 语言模型训练与推理。 - -## 许可证 - -本项目采用 [GNU Lesser General Public License v3.0](LICENSE)(LGPL-3.0,全文包含 GPL-3.0 条款),版权归 © 2026 EthanPeng-2048 所有。你可以自由使用、修改、分发本项目,闭源应用也可以链接本库;但对**本库本身**的修改必须以本许可证继续开源,分发时需保留版权声明并附带许可证文本。 - -> **数据集说明**:`scripts/` 下的下载脚本仅负责从第三方来源拉取数据(如 TinyStories、OpenWebText、中文 wiki 等),这些数据集各自拥有独立的许可证,不随本项目代码的 LGPL 许可分发。使用时请自行遵守相应数据集的许可条款。 - -## 🤖 AI 工具致谢 - -本项目的部分代码由 AI 辅助生成。当前使用(且目前限于)以下 AI 工具: - -- **DeepSeek V4 系列** -- **DeepSeek V4.1 系列** -- **Mi Mimo v2.5 系列** -- **Mi Mimo v2.6 系列** -- **Qwen3.8 系列** -- **VS Code Copilot** -- **ChatGPT Codex** - -> AI 仅作为辅助工具,所有代码的所有权与最终版权归本项目作者(EthanPeng-2048)所有,不影响上述 LGPL 许可证的效力。 - -## 📚 文档 +
-| 文档 | 说明 | -|------|------| -| [架构设计](docs/introduction/01-architecture.md) | 项目分层架构、引擎化设计、数据流、模块详解 | -| [性能优化](docs/introduction/02-performance.md) | 自适应并行、线程池、缓存分块、GPU 加速、算子融合等 | -| [算法解析](docs/introduction/03-algorithm-reference.md) | 每个 Layer/Loss/Optimizer 的数学原理与原语分解 | -| [创新设计](docs/introduction/04-innovative-designs.md) | 引擎化、AOT 融合、多精度等创新全景 | -| [C++ API 手册](docs/development/cpp-api-manual.md) | **库使用者首选**:引擎/张量/精度/层/模型/损失/优化器/训练/模型文件/数据集/分词器/生成,每节带代码片段 | -| [构建集成](docs/development/cmake-integration.md) | 把库接进自己的 CMake 工程:接入两行、全部构建开关、GPU 语义、自研算子融合注册 | -| [写自定义层](docs/development/write-a-custom-layer.md) | 自定义层的完整示例 + 接入契约 + 数值梯度自检 + GPU 检查清单 | -| [计算引擎开发](docs/development/01-compute-engine-development.md) | ComputeEngine 接口详解、实现模式、添加新原语 | -| [多精度计算](docs/development/05-mixed-precision.md) | f16/混合精度语义契约:Precision 类型系统、PrecisionProfile、已知数值限制 | -| [线性注意力](docs/development/06-rapt-algorithm.md) | RLA → RAPT → RLA-2 概览 + GPU 扫描原语落地;详细定义见 [research/rla](research/rla/README.md) | -| [写自定义层](docs/development/20-custom-layer-ergonomics.md) | 库外使用者视角的接入契约与实测摩擦点 | -| [快速上手:构建模型](docs/usage/01-quickstart-model.md) | ComputeEngine/Layer/Model 三件套使用教程 | -| [快速上手:训练与推理](docs/usage/02-quickstart-train-infer.md) | MNIST/GPT 训练推理命令行 + C++ API 示例 + GUI 操作指南 | -| [计算引擎使用](docs/usage/03-compute-engine-usage.md) | 张量操作、矩阵运算、表达式融合 | -| [训练包](docs/usage/04-train-package.md) | 用 `.nnpkg` 打包超参+训练集,跨设备一键复现训练 | -| [作为库嵌入](docs/usage/05-consume-as-library.md) | 把本库嵌进自己的工程(`neuralnet::nn` 门面 / FetchContent) | -| [强化学习与可组合训练](docs/usage/06-reinforcement-learning.md) | 具名多输出、GAE、REINFORCE/PPO/GRPO、多模型 Session 与 rollout pipeline | -| [线程安全契约](docs/usage/07-thread-safety.md) | 每个对象的并发口径矩阵 + 服务化下游设计模板 | -| [研究档案索引](research/README.md) | **可引用的实验结论** + 算法定义基线与研究 TODO(MNIST / f16 / 三值 / RLA):证据、重跑命令与边界 | -| [参与本项目](CONTRIBUTING.md) | 给非作者的入口:构建、测试、代码规范、提 PR、CI 口径 | - -> **文档分册定位**:`introduction` / `usage` / `development` 写给**调用者**; -> 项目内部的设计 / 路线图 / 盘点 / 规范 / 踩坑 / 故障 / 整改在 [`docs/todo/`](docs/todo/README.md); -> 历史归档在 [`docs/history/history.md`](docs/history/history.md)。**总索引见 [`docs/README.md`](docs/README.md)。** -> `research/` 是可引用的研究档案归口:实测结论、算法定义基线与明确标注的 TODO(索引见 [`research/README.md`](research/README.md)), -> 参与方式/门禁见 [`CONTRIBUTING.md`](CONTRIBUTING.md)。 - -## 项目结构 + + + neuralnet.cpp logo + -``` -neuralnet.cpp/ -├── CMakeLists.txt -├── README.md -├── docs/ -│ ├── README.md ← 文档总索引与分册定位 -│ ├── history/history.md ← 全仓唯一历史归档 -│ ├── introduction/ ← 介绍类(调用者) -│ │ ├── 01-architecture.md ← 架构设计文档 -│ │ ├── 02-performance.md ← 性能优化文档 -│ │ ├── 03-algorithm-reference.md ← 算法解析参考 -│ │ └── 04-innovative-designs.md ← 创新设计全景 -│ ├── development/ ← 开发类(**调用者**:扩展/接入库) -│ │ ├── cpp-api-manual.md ← 全功能 C++ API 手册 -│ │ ├── cmake-integration.md ← 接入与构建(CMake / 开关 / GPU / 融合注册) -│ │ ├── write-a-custom-layer.md ← 写自定义层指南 -│ │ ├── 01-compute-engine-development.md ← 引擎开发指南(加新原语) -│ │ ├── 05-mixed-precision.md ← 多精度语义契约 -│ │ ├── 06-rapt-algorithm.md ← RLA / RAPT / RLA-2 算法 -│ │ └── 20-custom-layer-ergonomics.md ← 写自定义层实测报告 -│ ├── usage/ ← 使用类(调用者) -│ ├── 01-quickstart-model.md ← 模型构建教程 -│ ├── 02-quickstart-train-infer.md ← 训练推理教程 -│ ├── 03-compute-engine-usage.md ← 引擎使用指南 -│ ├── 04-train-package.md ← .nnpkg 训练包 -│ ├── 05-consume-as-library.md ← 作为库嵌入自己的工程 -│ └── 06-reinforcement-learning.md ← RL 与可组合训练基础设施 -│ └── todo/ ← 内部工作区(**项目开发者**:设计/路线图/盘点/规范/踩坑/故障/整改) -├── gui.py ← 图形化操作界面 (CustomTkinter) -├── include/neuralnet.cpp/ -│ ├── nn.hpp ← 统一入口头文件 -│ ├── core_config.hpp ← 自适应并行、BLOCK_SIZE -│ ├── compute_tensor.hpp ← 统一跨设备张量 -│ ├── compute_engine.hpp ← 引擎抽象接口 -│ ├── compute_cpu_engine.hpp ← CPU 引擎 -│ ├── compute_gpu_engine.hpp ← GPU 引擎 (Vulkan) -│ ├── compute_layer.hpp ← Layer 聚合头 -│ ├── compute_layer_{base,mlp,conv,softmax,attention,feedforward,transformer,gpt,rapt}.hpp ← 各层域 -│ ├── compute_loss.hpp ← 损失函数 -│ ├── compute_optimizer.hpp ← 优化器 (SGD/Adam/AdamW/Muon) -│ ├── model_container.hpp ← Model 容器 -│ ├── model_spec.hpp ← 架构描述 -│ ├── model_serialization.hpp ← 二进制序列化 -│ ├── model_keyvalue_record.hpp ← 自描述键值记录 -│ ├── domain_mnist.hpp ← MNIST 模型工厂 -│ ├── domain_gpt.hpp ← GPT 模型工厂 -│ ├── domain_tokenizer.hpp ← 分词器 -│ ├── algebra_matrix.hpp ← 矩阵类 -│ ├── algebra_ops.hpp ← 逐元素算子定义(DSL 复用) -│ ├── algebra_span.hpp ← Span 抽象 -│ ├── core_threadpool.hpp ← 全局线程池 -│ ├── core_errors.hpp ← Result -│ ├── core_assert.hpp ← 断言宏 -│ ├── core_file.hpp ← 文件工具 -│ ├── core_observer_ptr.hpp ← 观察者指针 -│ └── backend/ ← GPU 后端 (Vulkan) -├── src/ -│ ├── mnist_train.cpp ← MNIST 训练 -│ ├── mnist_infer.cpp ← MNIST 推理 -│ ├── text_train.cpp ← GPT 文本训练 -│ ├── text_infer.cpp ← GPT 文本推理 -│ ├── tokenizer_train.cpp ← 分词器训练 -│ ├── tokenizer_infer.cpp ← 分词器推理 -│ ├── dataset_gen.cpp ← 数据集生成(文本+词表 → .nndataset) -│ ├── dataset_convert.cpp ← 旧格式转换(JSON 词表 → .nnvocab 等) -│ └── gpu_test.cpp ← GPU 后端测试 -├── datasets/ ← 训练数据 -├── pretrained/ ← 预训练模型 -├── research/ ← 可引用的研究档案(定义 / 结论 + 证据 + 重跑命令 + 边界 / TODO) -├── scripts/ ← 数据处理/训练辅助脚本 -├── shaders/ ← GPU Compute Shader -├── compare_with_torch/ ← PyTorch 对比实现 -├── CMakePresets.json ← 预设构建(cmake --preset dev / portable / cpu / probes ...) -├── CONTRIBUTING.md ← 给非作者的参与入口 -└── CODE_OF_CONDUCT.md ← 行为准则 -``` +# neuralnet.cpp -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/EthanPeng-2048/neuralnet.cpp) +**从零实现的 C++26 神经网络库**——不依赖 PyTorch/CUDA,CPU 与 Vulkan GPU 双后端, +覆盖 MLP 到 GPT 的训练与推理全流程,header-only,可两行嵌进你自己的工程。 -## 依赖 +[![CMake (Clang, C++26)](https://github.com/neuralnet-cpp-dev/neuralnet.cpp/actions/workflows/cmake-single-platform.yml/badge.svg)](https://github.com/neuralnet-cpp-dev/neuralnet.cpp/actions/workflows/cmake-single-platform.yml) +[![C++26](https://img.shields.io/badge/C%2B%2B-26-00599C?logo=c%2B%2B&logoColor=white)](https://en.cppreference.com/w/cpp/26) +[![Vulkan](https://img.shields.io/badge/GPU-Vulkan%20Compute-AC162C?logo=vulkan&logoColor=white)](https://www.khronos.org/vulkan/) +[![License: LGPL v3](https://img.shields.io/badge/license-LGPL--3.0-blue.svg)](LICENSE) -- **编译器**: 任意支持 C++26 的编译器(Clang / GCC / MSVC 均可) -- **C++ 标准**: C++26 -- **构建工具**: CMake ≥ 3.30 + Ninja -- **GUI** (可选): Python 3.10+,customtkinter(`pip install customtkinter`),Pillow(`pip install Pillow`) +[快速开始](#-快速-start) · [为什么选它](#为什么选它) · [它不做什么](#它不做什么) · [文档](#文档) · [参与](#参与) -## 构建与运行 +
-### 克隆(含子仓 submodule) +--- -本仓自 v1.13.0 起把 core / threadpool / kvrecord / dataset / tokenizer 拆为 -独立子仓(`extern/` 下的嵌套 submodule)。**克隆必须递归初始化**,否则 -`extern/*/include` 为空、编译时报 `neuralnet.cpp/core_errors.hpp` 等头找不到: +## 🚀 快速开始 ```bash git clone --recurse-submodules git@github.com:neuralnet-cpp-dev/neuralnet.cpp.git -# 已 clone 但漏了子仓时补救: -git submodule update --init --recursive -``` - -### 构建 C++ 项目 - -```powershell -cmake -B build -G Ninja +cd neuralnet.cpp +cmake --preset dev && cmake --build --preset dev # 需要 CMake ≥3.30 + Ninja + C++26 编译器 ``` -### 准备数据 - -- MNIST 数据:从 [Releases](https://github.com/EthanPeng-2048/neuralnet.cpp/releases) - 下载 `mnist_data` 压缩包,解压到 `datasets/mnist_data/`(`train.csv` / `test.csv`) -- 文本语料:使用 `scripts/` 下的 `download_*.py` 脚本下载 -- GPT 训练数据统一为 **`.nndataset`**(token/词表/loss 掩码/test 子集都在生成期定好, - 见 `docs/todo/19-unified-dataset.md`): - - ```powershell - ./build/tokenizer_train corpus.txt --vocab-size 10000 --output my_bpe.nnvocab - ./build/dataset_gen corpus.txt --vocab my_bpe.nnvocab -o corpus.nndataset - ``` - -### 运行训练 +训练你的第一个模型(MNIST,默认数据目录 `datasets/mnist_data/`): ```bash -# 从头开始训练 MLP(默认: 10轮, 学习率0.001, 批大小64, Adam优化器) -./build/mnist_train - -# 训练 Transformer 模型 -./build/mnist_train --arch transformer --epochs 20 +./build/dev/mnist_train --gpu --epochs 10 # GPU 训练(无 GPU 去掉 --gpu) +./build/dev/mnist_infer my_digit.csv --model mnist_model.nnmodel +``` -# 从已有模型恢复训练 -./build/mnist_train --resume pretrained/mnist_model.bin +把它当库用——三行核心代码构建一个 MLP: -# 自定义参数 -./build/mnist_train --epochs 20 --lr 0.001 --batch-size 32 --optimizer adam --save my_model.bin +```cpp +#include -# 支持的优化器: sgd / sgd_momentum / adam -./build/mnist_train --optimizer sgd_momentum +auto engine = nn::CpuEngine::create(); // GPU: nn::GpuBackend::shared() +nn::Model model(*engine); +model.add(784, 128); // add(args...) 返回 Result, +model.add(); // 构造后自动 init(engine) +model.add(128, 10); +auto pred = model.forward(input); // engine 在 Model 内自动传递 ``` -### 运行推理 - -推理入口接受单张 CSV(`784` 像素一行);随机试一张自己画/导出的图即可, -GUI 自带的手写板也能直接识别。 +
+准备训练数据(MNIST / 文本语料) -```bash -# 指定模型文件(架构由模型内自描述的 spec 决定,无需再传类型) -./build/mnist_infer my_digit.csv --model mnist_model.bin --topk 3 +- MNIST:从 [Releases](https://github.com/EthanPeng-2048/neuralnet.cpp/releases) 下载 + `mnist_data` 压缩包,解压到 `datasets/mnist_data/`(`train.csv` / `test.csv`)。 +- 文本语料:`scripts/` 下的 `download_*.py` 脚本;GPT 训练数据统一为 `.nndataset`: -# 显示 Top-5 预测结果 -./build/mnist_infer my_digit.csv --topk 5 + ```bash + ./build/dev/tokenizer_train corpus.txt --vocab-size 10000 --output my_bpe.nnvocab + ./build/dev/dataset_gen corpus.txt --vocab my_bpe.nnvocab -o corpus.nndataset + ./build/dev/text_train corpus.nndataset --gpu + ``` -# 调试模式:显示像素矩阵 -./build/mnist_infer my_digit.csv --show-pixels -``` +
-### 🖥️ 图形化界面 (GUI) +
+克隆后 extern/ 为空? -基于 CustomTkinter 的全功能图形化界面,覆盖 MNIST 训练/推理、GPT 训练/推理、分词器训练/推理,无需记忆命令行参数。 +v1.13.0 起 core / threadpool / kvrecord / dataset / tokenizer 是 `extern/` 下的嵌套 submodule。 +已 clone 但漏了子仓时补救: ```bash -# 启动 GUI -python gui.py +git submodule update --init --recursive ``` -> **前提**: 需要先构建 C++ 项目(`cmake -B build -G Ninja`),GUI 会调用 `build/` 目录下的可执行文件。 +
-#### GUI 功能一览 +## 为什么选它 -| Tab | 功能 | -|-----|------| -| 🏋️ **MNIST 训练** | MNIST 模型训练:MLP / Transformer 架构、超参数调节、恢复训练、学习率调度(fixed / cosine)、GPU 加速、评估样本数;实时 loss / acc 曲线 | -| 🔍 **MNIST 推理** | MNIST 图片推理 + 图片查看:推理某张图片自动显示该图、Top-K 置信度条形图、目录翻页导航;内置 ✍️ **手写板**,鼠标书写数字即刻识别 | -| 📝 **GPT 训练** | GPT 语言模型训练:位置编码(learned / sinusoidal / alibi)、激活(GeLU / SwiGLU)、归一化(LayerNorm / RMSNorm)、梯度累积、滑动窗口 stride、学习率调度(fixed / cosine / step_cosine)、TDR 防护、梯度裁剪;实时 loss 曲线 | -| 💬 **GPT 推理** | GPT 文本生成:温度 / top-k / top-p / 重复惩罚 / 种子、**多轮对话(上下文不丢)**、单次生成、Token ID 调试输出 | -| 🔤 **分词器训练** | 训练 BPE / CharBPE 分词器,配置词表大小和最小合并频率 | -| 🔡 **分词器推理** | 分词器编码/解码测试,支持文本编码、ID 解码、文件编码 | - -#### GUI 操作流程 - -**MNIST 训练:** -1. 选择数据集目录(默认 `datasets/mnist_data`)和模型保存路径 -2. 配置超参数:轮数、学习率、批大小、优化器(`sgd`/`adam`/`adamw`/`muon`) -3. 选择模型类型:`mlp`(自定义层维度)或 `transformer`(模型维度/头数/层数/FFN/Patch) -4. 可选:恢复训练、GPU 加速、学习率调度、振荡抑制 -5. 点击 **"▶ 开始训练"**,日志面板实时输出,下方曲线图绘制 loss / accuracy -6. 训练中可随时点击 **"⏹ 停止"** 终止 +| 亮点 | 说明 | +|------|------| +| **从零实现,全程可读** | 计算引擎、表达式 DSL、AOT kernel 融合、Vulkan 后端、BPE 分词器、训练循环全部自研——想搞懂"框架底层发生了什么",每一层都有源码与文档 | +| **CPU / Vulkan GPU 双后端** | 同一套模型代码切换后端;GPU 侧表达式录制 → AOT 融合单 kernel;f16 混合精度 | +| **C++26 header-only** | 单一聚合头 `nn.hpp`;`FetchContent` / `add_subdirectory` 两行接入;零手动内存管理 | +| **训练 + 推理闭环** | MLP / CNN / ViT / Transformer / GPT;SGD/Adam/AdamW/Muon;`.nnpkg` 训练包跨设备复现;GUI 图形界面 | +| **RL 与可组合训练** | GAE、REINFORCE/PPO/GRPO、具名多输出、多模型 Session 与可替换 rollout pipeline | +| **严谨的工程口径** | 数值梯度自检、CPU/GPU 位级一致门禁、可引用的研究档案(每个结论带证据 + 重跑命令 + 边界,见 [`research/`](research/README.md)) | -**MNIST 推理:** -1. 选择训练好的模型文件(`.bin`),设置 Top-K 与 GPU -2. 选择单张 CSV 图片或包含多张图片的目录 -3. 点击 **"🔍 推理当前图片"** → 自动显示该图片 + Top-K 置信度条形图;目录模式可用 **上一张 / 下一张** 翻页浏览(已推理过的图片会缓存预测) -4. 点击 **"▶ 推理整个目录"** 可批量推理并逐个自动显示 -5. **手写板模式**:在白色画布上书写数字 → 点击 **"🔍 识别手写数字"**,即刻得到预测 +## 它不做什么 -**GPT 训练:** -1. 选择 `.nndataset` 数据集文件(由 `dataset_gen` 生成;词表/loss 掩码/test 子集随数据集) -2. 配置模型架构(维度/头数/层数/FFN)和位置编码 -3. 点击 **"▶ 开始训练"**,实时显示 loss 曲线 +诚实设定边界,避免不匹配的预期: -**GPT 推理:** -1. 选择模型文件(v4+ 自动使用内嵌词表),模型未嵌入时指定 `.nnvocab` 词表;设置采样参数(温度 / top-k / top-p / 重复惩罚 / 种子) -2. 单次生成:输入提示文本,点击 **"▶ 生成文本"** -3. **多轮对话**:输入这一轮的话,点击 **"💬 发送(多轮)"** —— 每轮把整段历史交给 CLI, - 连续 N 轮上下文不丢("对话记录"面板显示历史与轮数);**"🧹 清空对话"** 开新一场对话; - 系统提示用「系统提示(多轮对话)」框设置 +- **不做分布式训练**——单机单卡/CPU 为主,没有多机多卡、模型并行或流水线并行; +- **不追吞吐排名**——与 PyTorch 的 f32 训练吞吐差距约 2.1×(见 [基准报告](docs/benchmarks/2026-10-06-vulkan-vs-torch.md)), + 本项目的价值在**可读、自研、可嵌入**,不是 benchmark 榜单; +- **不是 Python 生态替代品**——没有 autograd 图、没有 pip 包、不兼容 ONNX/checkpoint 格式生态; +- **GPU 只走 Vulkan**——不做 CUDA/Metal 后端;部分精度路径(全 f16 训练)有已知数值限制, + 现状见 [`research/`](research/README.md) 与 [多精度文档](docs/development/05-mixed-precision.md)。 -**分词器训练/推理:** -- 训练:选择文本文件 → 设置类型(`bpe`/`charbpe`)和词表大小 → 点击训练 -- 推理:选择词表 → 输入文本或 ID → 选择编码/解码 → 点击执行 +## 文档 -## 网络结构 +**总索引见 [`docs/README.md`](docs/README.md)**(按读者分册)。最常去的入口: -支持三种模型架构(通过 `--arch mlp|transformer|cnn` 切换,实现见 `domain_mnist.hpp`);下面详述 MLP 与 Transformer(CNN 见 `--cnn-*` 系列参数): +| 我想… | 去看 | +|-------|------| +| 跑通训练/推理(CLI + GUI) | [docs/usage/02-quickstart-train-infer.md](docs/usage/02-quickstart-train-infer.md) | +| 用 C++ API 写自己的模型 | [docs/development/02-cpp-api-manual.md](docs/development/02-cpp-api-manual.md) | +| 把库嵌进自己的工程 | [docs/development/01-cmake-integration.md](docs/development/01-cmake-integration.md) | +| 了解架构与数据流 | [docs/introduction/01-architecture.md](docs/introduction/01-architecture.md) | +| 引用本仓的实测结论 | [research/README.md](research/README.md) | -归一化分两维,两者默认 **`auto`(= 按架构取最合适,4 epoch A/B 实测,见 `docs/history/history.md`)**:**类型** `--norm auto|layernorm|rmsnorm|batchnorm`(auto:MLP/ViT = layernorm、CNN = batchnorm)与**挂载位置** `--norm-place auto|none|conv|head|both|final`(auto:CNN = `conv`、ViT = `final`;`conv`/`head`/`both` 属 CNN、`final` 属 ViT;MLP 的挂载位置由结构固定,只接受 `none`/`auto`)。**旧模型文件没有 `norm_place` 键 → 读回 `none`**:参数布局与旧实现逐位一致,旧 checkpoint 仍可加载。 +## 依赖 -### MLP(默认) +| 组件 | 要求 | +|------|------| +| 编译器 | 任意 C++26 编译器(Clang / GCC / MSVC 均可;CI 主矩阵 = Clang) | +| 构建 | CMake ≥ 3.30 + Ninja(预设:`cmake --preset dev` 等,见 [CMakePresets.json](CMakePresets.json)) | +| GPU(可选) | Vulkan SDK;无 GPU 用 `--preset cpu` 纯 CPU 构建 | +| GUI(可选) | Python 3.10+ + `pip install customtkinter pillow` | -归一化层可通过 `--norm` 切换(`auto` → MLP 默认 LayerNorm): +
+项目结构 ``` -输入 (784) -→ Linear(784 → 512) + Norm + GeLU -→ Linear(512 → 256) + Norm + GeLU -→ Linear(256 → 128) + Norm + GeLU -→ Linear(128 → 64) + Norm + GeLU -→ Linear(64 → 10) -→ CrossEntropy Loss (含 Softmax) +neuralnet.cpp/ +├── include/neuralnet.cpp/ ← header-only 库(nn.hpp 统一聚合入口;backend/ = Vulkan 后端) +├── src/ ← 可执行入口:mnist/text 训练与推理、tokenizer、数据集工具 +├── shaders/ ← GPU compute shader(AOT 融合产物 + 手写原语) +├── docs/ ← 文档总索引(docs/README.md):usage / development / contributors / internal / history +├── research/ ← 可引用的研究档案(定义基线 / 实测结论 / 明确标注的 TODO) +├── gui.py ← 图形化操作界面(CustomTkinter) +├── extern/ ← 子仓:core / threadpool / kvrecord / dataset / tokenizer +├── datasets/ · pretrained/ ← 训练数据 · 预训练模型 +├── scripts/ · bench/ · compare_with_torch/ ← 数据脚本 · 基准测试 · torch 对拍 +└── CMakePresets.json ← 预设构建(dev / portable / cpu / probes ...) ``` -- `LayerNorm`:按特征维归一化(GPT-2 风格,默认) -- `RMSNorm`:无均值、更轻量(LLaMA 风格) -- `BatchNorm`:按 batch 维归一化,训练时更新 running 统计、推理时使用 +
-### Transformer(ViT-like) +## 参与 -``` -输入 (784) — 展平的 28×28 图像 -→ PatchEmbedding: 28×28 → 16 个 7×7 patch → 投影到 d_model=64 -→ TransformerEncoder ×2 层: - ├── MultiHeadAttention(d_model=64, heads=4) - ├── LayerNorm + FeedForward(d_model=64 → d_ff=128 → 64) - └── 残差连接 + 位置编码 -→ [--norm-place final] 归一化(默认开:编码器末端的 final norm,池化之前) -→ 池化 (seq_len → 1) -→ Linear(64 → 10) -→ CrossEntropy Loss (含 Softmax) -``` +- **用库遇到问题**:提 issue,附最小复现与构建环境(编译器版本 + preset)。 +- **想贡献代码**:入口是 [CONTRIBUTING.md](CONTRIBUTING.md)(构建、测试口径、PR 自查清单); + 改代码前先读 [C++ 开发规范](docs/contributors/cpp-standards.md) 与 [踩坑警示录](docs/contributors/pitfalls.md)。 +- **维护者**:@EthanPeng-2048。发布与版本号规则见 [release-policy](docs/contributors/release-policy.md) + (**版本号由人提出,agent 不得擅自发布**)。 +- 所有参与方须遵守 [行为准则](CODE_OF_CONDUCT.md)。 + +## 许可证 -## 提供的组件 +[GNU Lesser General Public License v3.0](LICENSE)(LGPL-3.0,含 GPL-3.0 条款), +© 2026 EthanPeng-2048。闭源应用可以链接本库;对**本库本身**的修改须以本许可证继续开源。 -| 组件 | 说明 | -|------|------| -| `nn::Matrix` | 行主序矩阵,支持并行加/减/乘/转置、预分配缓冲区、`std::span` 访问 | -| `nn::Model` | 网络容器,支持链式 `add()` 构建 | -| `nn::Linear` | 全连接层(含 Xavier 均匀初始化、融合 bias 计算) | -| `nn::ReLU` | ReLU 激活函数 | -| `nn::GeLU` | QuickGeLU 激活函数(`x · σ(1.702x)`) | -| `nn::LayerNorm` | 层归一化(含可学习 γ/β 参数) | -| `nn::Softmax` | Softmax 激活层(数值稳定,含反向传播) | -| `nn::MultiHeadAttention` | 多头注意力层(Transformer 用,`d_model × seq_len` 输入输出) | -| `nn::PositionalEncoding` | 正弦/余弦位置编码(Transformer 用) | -| `nn::MSELoss` | 均方误差损失 | -| `nn::CrossEntropyLoss` | 交叉熵损失(含数值稳定 Softmax,`compute_loss.hpp` 中定义) | -| `nn::SGD` | 随机梯度下降优化器 | -| `nn::SGDWithMomentum` | 动量 SGD 优化器 | -| `nn::Adam` | Adam 优化器(一阶/二阶矩估计) | -| `nn::parallel_for_blocks` / `nn::parallel_for_samples` | 自适应并行分发(`PARALLEL_THRESHOLD = 524288` 门控;旧文档称「SmartPolicy」) | -| `nn::ThreadPool` | 全局单例线程池(懒初始化) | -| `nn::save_model` / `nn::load_model` | 二进制模型序列化 | - -## 📐 开发规范 - -本项目遵循严格的 C++ 开发规范,详见 [开发规范](docs/todo/10-development-standards.md)。 - -### 核心原则 - -1. **零手动内存管理** - 完全消除显式指针操作和手动内存管理 -2. **模块化设计** - 清晰的职责分离,简洁的接口设计 -3. **高性能优先** - 预分配、缓存友好、并行化 -4. **紧跟最新标准** - 始终使用最新的 C++ 标准(当前:C++26) - -### 快速参考 - -| 规范 | 要求 | -|------|------| -| 内存管理 | 禁止 `new`/`delete`,使用 `std::vector`、`std::unique_ptr`、`std::span` | -| 接口设计 | 流式 API、两级访问(安全 + 快速) | -| 性能优化 | 预分配缓冲区、缓存友好分块算法、智能并行化 | -| C++ 标准 | C++26,积极使用 ranges、concepts、std::print 等新特性 | -| 命名规范 | 类名 CamelCase,函数/变量 snake_case,私有成员尾部下划线 | +> **数据集说明**:`scripts/` 的下载脚本仅从第三方拉取数据(TinyStories、OpenWebText、中文 wiki 等), +> 数据集各自持有独立许可证,不随本项目 LGPL 分发,请自行遵守其条款。 + +## 🤖 AI 工具致谢 + +本项目的部分代码由 AI 辅助生成,当前使用:DeepSeek V4 / V4.1、Mi Mimo v2.5 / v2.6、 +Qwen3.8、VS Code Copilot、ChatGPT Codex。AI 仅作为辅助工具,代码所有权与最终版权 +归 EthanPeng-2048,不影响 LGPL 许可证效力。 diff --git a/assets/icon-dark.svg b/assets/icon-dark.svg new file mode 100644 index 0000000..d7a2c9d --- /dev/null +++ b/assets/icon-dark.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icon-light.svg b/assets/icon-light.svg new file mode 100644 index 0000000..9f2d9d2 --- /dev/null +++ b/assets/icon-light.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bench/doc_align_audit.ps1 b/bench/doc_align_audit.ps1 index b0bf0bf..10ac7ea 100644 --- a/bench/doc_align_audit.ps1 +++ b/bench/doc_align_audit.ps1 @@ -39,7 +39,7 @@ $historicalFiles = @('compute_cuda_engine.hpp','compute_cuda_backend.hpp','cuda_ 'offload_primitive_test.cpp','offload_test.cpp','broadcast.comp', 'compute_precision_engine.hpp', # P-1 随 PrecisionEngine 下沉删除 'compute_layer_zipt.hpp','domain_zipt.hpp', # ZiPT 移除(分支 legacy/zipt) - 'ternary_deploy.hpp') # NNQT 独立部署格式,随库级清理(docs/todo/23)删除 + 'ternary_deploy.hpp') # NNQT 独立部署格式,随库级清理(docs/internal/23)删除 # ── [A] 文档引用的文件是否存在 ────────────────────────────────────────── Write-Host '=== [A] 文档引用但仓库中不存在的文件 ===' @@ -170,7 +170,7 @@ $removedFlags = @('--cuda','--tdr-retry','--max-tdr-retries', '--osc-guard','--osc-window','--osc-threshold', '--no-cache','--test-file','--loss-scope', # --export-deploy : NNQT 独立部署格式的导出口,随库级清理 - # (docs/todo/23,2026-10-11)删除 → 文件角色 + # (docs/internal/23,2026-10-11)删除 → 文件角色 # .nnmodel/.nnckpt 取代 '--export-deploy') # 已在 26 §8.B.7 明确标注“计划中、默认关闭、尚未实现”的参数。它们不得出现在 @@ -245,7 +245,7 @@ $missTests = 0 $histTests = 0 # 历史/已并入的测试名(历史交付表中的当时目标名,勿再报警) # zipt_* : 随 ZiPT 移除(历史文档提及属正常) -# ternary_deploy_test : NNQT 部署格式测试,随库级清理(docs/todo/23)删除(并入 model_roles_test) +# ternary_deploy_test : NNQT 部署格式测试,随库级清理(docs/internal/23)删除(并入 model_roles_test) $historicalTests = @('expr_fuse_test','expr_graph_test','expr_spec_test','matmul_fusion_test','offload_primitive_test', 'zipt_test','zipt_gradcheck','zipt_smoke_test','zipt_consistency_test','zipt_doc_test', 'ternary_deploy_test') diff --git a/bench/doc_inventory.ps1 b/bench/doc_inventory.ps1 index 3bfbf9c..90ce2bd 100644 --- a/bench/doc_inventory.ps1 +++ b/bench/doc_inventory.ps1 @@ -1,6 +1,6 @@ # 文档盘点探针:统计 ComputeEngine 接口规模与 Layer 直调算子集合。 # 用法:pwsh -File bench/doc_inventory.ps1 -# 与 docs/todo/12-compute-engine-inventory.md §2 配套(改接口后重跑核对数字)。 +# 与 docs/internal/12-compute-engine-inventory.md §2 配套(改接口后重跑核对数字)。 $ErrorActionPreference = 'Stop' $root = Split-Path $PSScriptRoot -Parent $eng = Join-Path $root 'include\neuralnet.cpp\compute_engine.hpp' @@ -29,7 +29,7 @@ $unused = $uv | Where-Object { $calls -notcontains $_ } Write-Output "not layer-called: $($unused.Count)" Write-Output ($unused -join ', ') -# 4) L2+ 分层审计:Matrix 降级(docs/todo/17 §4.6 / §5 M4;AGENTS.md 铁律 #12) +# 4) L2+ 分层审计:Matrix 降级(docs/internal/17 §4.6 / §5 M4;AGENTS.md 铁律 #12) # 规则:Layer / Loss / Optimizer / Model(L2 计算路径)头文件中—— # [硬] 不得出现 Matrix / MatrixT 类型(不持有、不构造、不交换) # [硬] 不得出现 Matrix 型 I/O 动词 from_matrix / to_matrix / copy_from diff --git a/bench/gui_cli_audit.py b/bench/gui_cli_audit.py index 1c6ccb9..dcefeab 100644 --- a/bench/gui_cli_audit.py +++ b/bench/gui_cli_audit.py @@ -62,7 +62,7 @@ # 不再需要套一个 stdin 循环(进程内的历史 GUI 也拿不到) # --t1_58 : 三值预设的**别名**(等价 --precision-param t1_58);GUI 的 # "精度预设"下拉填的是 precision_param 字段,三条命令在 -# docs/todo/21 §4.10 里已声明等价,故此处不算缺口 +# docs/internal/21 §4.10 里已声明等价,故此处不算缺口 INTENTIONAL_GAPS = {"--interactive", "--t1_58"} diff --git a/docs/README.md b/docs/README.md index 1653d25..65d9811 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,8 +1,11 @@ # 文档总索引与分册定位 -> 本文件是 `docs/` 的**总入口**:规定每个子目录**写给谁看**,并给出全部文档的一行索引。 -> 一句话总则:**除 `todo/` 与 `history/history.md` 外,`docs/` 下的文档都是写给调用者的**; -> `todo/` 与 `history/history.md` 是项目开发者的内部工作区。 +> **读者**:找任何一篇文档在哪的人(调用者与项目参与者共用入口)。 +> **一句话结论**:`docs/` 按读者分册——调用者看 `introduction`/`usage`/`development`, +> 贡献者看 `contributors/`,改库的人看 `internal/`,查历史看 `history/`。 +> **状态**:现行。 +> 分册职责与编号制度的**规范正文**在 [`contributors/documentation-standard.md`](contributors/documentation-standard.md); +> 本文只做索引。 ## 1. 分册定位(写给谁看) @@ -11,30 +14,31 @@ | `introduction/` | 读者 / 调用者 | 架构、性能、算法、创新设计的总览 | 当前状态 | | `usage/` | 调用者 | 用现成能力:CLI、C++ API、GUI、`.nnpkg`、作为库嵌入 | 当前状态 | | `development/` | **调用者(库使用者 / 扩展者)** | **在库之上写代码**:CMake 接入与全功能 C++ API 手册、写自定义层、扩展引擎原语、精度语义契约、算法与原语的对应 | 当前状态 | -| `todo/` | **项目开发者** | 项目自身的工作:设计稿、路线图、盘点、规范、踩坑、故障报告、审查整改立项 | 当前状态(设计+进度) | +| [`contributors/`](contributors/README.md) | **贡献者 / 维护者 / agent** | 长期规范与治理:C++ 规范、踩坑警示录、**文档规范**、发布规则 | 长期真源 | +| `internal/` | **项目开发者** | 项目自身的工作:设计稿、路线图、盘点、故障报告、审查整改立项 | 当前状态(设计+进度) | | `history/history.md` | 项目开发者 | 全仓**唯一**历史归档:演进记录 / 已修复勘误 / 被否决方案 / 性能 A/B | 历史 | | `benchmarks/` | 项目开发者 / 评估者 | 对外性能对比基准报告(Vulkan vs CUDA / Torch) | 采集时的实测 | | `release-notes/` | 调用者 | 版本变更说明(破坏性变更 + 迁移指南 + 验收基线) | 版本发布时 | | [`../research/`](../research/README.md) | **想引用实测结论或核对算法基线的人**(含库外) | 一次研究一个子目录:定义 / 结论 / 证据 / **重跑命令** / 适用边界 | 研究档案(结果与明确标注的 TODO 分开) | -### 1.1 `development/` 的定位(明确约定) +> **一句话总则**:`docs/` 下按"读者是谁"分册;贡献者规则住 `contributors/`, +> 项目内部台账住 `internal/`,历史住 `history/`,其余都是写给调用者的。 -**`docs/development/` 是给调用者的**——即"拿着这个库去开发自己东西"的人:写自定义层、 -扩展引擎原语、接入 GPU 融合、选精度策略。它**不是**项目开发者的工作区: +### 1.1 `development/` 的定位 -- 项目内部的设计稿、路线图、盘点、规范、踩坑、故障报告、审查整改 → `docs/todo/`; -- 已落地的演进过程、被否决方案、旧数字 → `docs/history/history.md`。 +**给调用者**——"拿着这个库去开发自己东西"的人:写自定义层、扩展引擎原语、接入 GPU 融合、 +选精度策略。编号 = 阅读顺序(01→09,连续不留洞)。 -判断标准一句话:**这篇文档的读者是"库外的人"还是"改库的人"?** 库外的放 -`development/`(或 `usage/`),改库的放 `todo/`。组件式设计文档即使被源码注释引用, -也仍属 `todo/`(源码注释引用内部设计稿是正常的)。 +### 1.2 `contributors/` 的定位 -### 1.2 `todo/` 的定位 +**给向本仓贡献的人**:长期有效的规范与治理规则(编码规范 / 踩坑 / 文档规范 / 发布规则)。 +`CONTRIBUTING.md` 与 `AGENTS.md` 对本分册**只留摘要与指针**,规则正文以本分册为准。 -`docs/todo/` = **项目开发者的内部工作区**,按"一件事一篇"存档:设计(含未实施部分)、 -路线图与裁定、现状盘点、编码规范、踩坑记录、未修故障、以及针对代码审查/评审的**整改立项**。 -这里的文档允许带进度状态(✅ 已实施 / ⏳ 待做),但不承载"当前是什么"以外的历史叙事—— -历史叙事一律进 `history/history.md`。 +### 1.3 `internal/` 的定位 + +**项目开发者的内部工作区**,按"一件事一篇"存档:设计(含未实施部分)、路线图与裁定、 +现状盘点、未修故障、整改立项。**编号 = 稳定台账 ID**(新增接最大号,永不重排)。 +允许带进度状态(✅ 已实施 / ⏳ 待做),但不承载历史叙事——历史叙事一律进 `history/history.md`。 ## 2. 索引 @@ -61,38 +65,42 @@ ### development/(给调用者) +按阅读顺序;本分册完整索引见 [`development/README.md`](development/README.md)。 + | 文档 | 何时读 | |------|--------| -| [`README.md`](development/README.md) | 本分册定位与索引(含入门路径建议) | -| [`cpp-api-manual.md`](development/cpp-api-manual.md) | **全功能 C++ API 手册**:错误宏 / 引擎 / 张量 / 精度 / DSL / 层与 Model / 工厂 / 损失 / 优化器 / 训练循环(含 `TextTrainer`)/ 模型文件 / 数据集(`Dataset` + `TextSampleSet`)/ 分词器 / 生成 / 剖析(每节带代码片段) | -| [`cmake-integration.md`](development/cmake-integration.md) | 接入与构建:`add_subdirectory`/`FetchContent`、全部构建开关、GPU 语义、`nn_enable_gpu_fusion`、跨平台、故障排查 | -| [`write-a-custom-layer.md`](development/write-a-custom-layer.md) | 写自己的层:完整示例(实测过梯度检查)+ 接入契约 + 精度槽声明 + 梯度自检 + GPU 清单 | -| [`01-compute-engine-development.md`](development/01-compute-engine-development.md) | 扩展引擎原语:接口全解 + CPU/GPU 实现模式 + 加新原语的完整步骤 | +| [`01-cmake-integration.md`](development/01-cmake-integration.md) | 接入与构建:`add_subdirectory`/`FetchContent`、全部构建开关、GPU 语义、`nn_enable_gpu_fusion`、跨平台、故障排查 | +| [`02-cpp-api-manual.md`](development/02-cpp-api-manual.md) | **全功能 C++ API 手册**:错误宏 / 引擎 / 张量 / 精度 / DSL / 层与 Model / 工厂 / 损失 / 优化器 / 训练循环 / 模型文件 / 数据集 / 分词器 / 生成 / 剖析(每节带代码片段) | +| [`03-write-a-custom-layer.md`](development/03-write-a-custom-layer.md) | 写自己的层:完整示例(实测过梯度检查)+ 接入契约 + 精度槽声明 + 梯度自检 + GPU 清单 | +| [`04-compute-engine-development.md`](development/04-compute-engine-development.md) | 扩展引擎原语:接口全解 + CPU/GPU 实现模式 + 加新原语的完整步骤 | | [`05-mixed-precision.md`](development/05-mixed-precision.md) | 多精度语义契约(写层/选 profile 必读)+ 实测限制 | -| [`06-rapt-algorithm.md`](development/06-rapt-algorithm.md) | 线性注意力(RLA → RAPT → RLA-2)算法 + 扫描原语落地 | -| [`07-vulkan-backend-map.md`](development/07-vulkan-backend-map.md) | Vulkan 后端结构地图(维护者):调用链 / 所有权 / 依赖方向 / 扩展步骤 | -| [`08-object-lifetimes.md`](development/08-object-lifetimes.md) | 对象生命周期契约 v3 转发页(唯一真源 = `09`:设备域从存储派生 / 入口逐操作数检查 / `import` 是唯一跨域入口) | -| [`09-engine-ownership.md`](development/09-engine-ownership.md) | **生命周期 v3 唯一真源**:设备域模型、入口域检查、backend/GpuBuffer 生命周期、失败语义、迁移清单与性能口径 | -| [`20-custom-layer-ergonomics.md`](development/20-custom-layer-ergonomics.md) | 写自定义层的**实测报告**:接入契约与 7 个摩擦点(库外使用者视角) | - -### todo/(给项目开发者) - -见 [`todo/README.md`](todo/README.md) 的完整索引。要点: - -- `todo/00-code-review-remediation.md` — **2026-10-11 代码审查整改立项台账**(本批新增)。 -- `todo/18-roadmap.md` — **"某件事该不该做"的唯一入口**(裁定台账 + 验收口径 + 现状实测;不含执行计划)。 -- `todo/27-execution-plan.md` — **执行计划(优先级象限)**:"下一个先做哪个"。 -- `todo/31-rl-training-primitives.md` — **当前 RL 主线与通用训练基础设施**:具名多输出、schema 化 - experience、可组合 policy objectives、`TrainingGroupSession` 与可替换编排(issue #23 是能力下界; - f16 / 训练性能项暂缓)。**2026-10-23 ✅ 已实施并随 `v1.12.0` 发布**;调用指南见 - `usage/06-reinforcement-learning.md`。 -- `todo/12` / `todo/17` / `todo/19` / `todo/21` / `todo/22` / `todo/23` — 现行设计/盘点。 -- `todo/28` / `todo/29` / `todo/30` — **生命周期 v3 / Session 层 / TrainingSession 单步协议** - (P2a/P2b 已随 `v1.10.0` 发布;30 号于 2026-10-22 冻结 micro-batch、梯度累积与 global-batch 归一化边界,随 `v1.11.0` 发布)。 -- `todo/24` / `todo/25` — f16 训练缺陷台账 / **大版本发布要求**(`1.x.y → 1.(x+1).0`)。 -- `todo/10` / `todo/08` — **C++ 开发规范全文** / **踩坑警示录**(改代码前读)。 -- `todo/33` — **版本号·分支·发布治理**:版本号规则、**发布须由人提出(agent 不得擅自发布)**、 - `dev` 不写版本号、发布只在 `main`。 +| [`06-vulkan-backend-map.md`](development/06-vulkan-backend-map.md) | Vulkan 后端结构地图:调用链 / 所有权 / 依赖方向 / 扩展步骤 | +| [`07-engine-ownership.md`](development/07-engine-ownership.md) | **生命周期 v3 唯一真源**:设备域模型、入口域检查、backend/GpuBuffer 生命周期、失败语义、迁移清单 | +| [`08-rapt-algorithm.md`](development/08-rapt-algorithm.md) | 线性注意力(RLA → RAPT → RLA-2)算法 + 扫描原语落地;定义基线见 [`../research/rla/`](../research/rla/README.md) | +| [`09-custom-layer-ergonomics.md`](development/09-custom-layer-ergonomics.md) | 写自定义层的**实测报告**:接入契约与 7 个摩擦点(库外使用者视角) | + +### contributors/(给贡献者 / 维护者 / agent) + +本分册完整索引见 [`contributors/README.md`](contributors/README.md)。要点: + +- [`contributors/documentation-standard.md`](contributors/documentation-standard.md) — **文档规范**:分册职责、编号制度、单篇模板、代码示例标注、机器审查口径。**写任何文档前读**。 +- [`contributors/cpp-standards.md`](contributors/cpp-standards.md) — **C++ 开发规范全文**(改代码前读)。 +- [`contributors/pitfalls.md`](contributors/pitfalls.md) — **踩坑警示录**(改代码前读;踩新坑先补这里)。 +- [`contributors/release-policy.md`](contributors/release-policy.md) — **版本号·分支·发布治理**:**发布须由人提出(agent 不得擅自发布)**、`dev` 不写版本号、发布只在 `main`。 +- [`contributors/release-requirements.md`](contributors/release-requirements.md) — **大版本发布要求**(`1.x.y → 1.(x+1).0`)。 + +### internal/(给项目开发者) + +见 [`internal/README.md`](internal/README.md) 的完整索引。要点: + +- `internal/18-roadmap.md` — **"某件事该不该做"的唯一入口**(裁定台账 + 验收口径 + 现状实测;不含执行计划)。 +- `internal/27-execution-plan.md` — **执行计划(优先级象限)**:"下一个先做哪个"。 +- `internal/31-rl-training-primitives.md` — **RL 主线与通用训练基础设施**(2026-10-23 ✅ 已随 `v1.12.0` 发布);调用指南见 `usage/06-reinforcement-learning.md`。 +- `internal/00-code-review-remediation.md` — 2026-10-11 代码审查整改立项台账。 +- `internal/12` / `17` / `19` / `21` / `22` / `23` — 现行设计/盘点。 +- `internal/28` / `29` / `30` — 生命周期 v3 / Session 层 / TrainingSession 单步协议(已随 `v1.10.0`/`v1.11.0` 发布)。 +- `internal/02` / `03` / `04` / `26` — 融合/IR/显存/f16 提速计划。 +- `internal/14` / `24` — 已修故障报告 / f16 训练缺陷台账。 ### 总档 @@ -105,50 +113,8 @@ | [`../CMakePresets.json`](../CMakePresets.json) | 预设构建(`cmake --preset dev` 等)——见 CONTRIBUTING §1 | | [`benchmarks/2026-09-25-vulkan-vs-cuda.md`](benchmarks/2026-09-25-vulkan-vs-cuda.md) | Vulkan 后端 vs CUDA(torch)基准 | | [`benchmarks/2026-10-06-vulkan-vs-torch.md`](benchmarks/2026-10-06-vulkan-vs-torch.md) | 第二轮复测 | -| `release-notes/v1.5.0.md` … `v1.13.0.md` | 版本变更说明,覆盖 v1.5.0 → v1.13.0 的全部 tag(`v1.5.1` / `v1.6.1` / `v1.7.1` / `v1.8.0` 为 2026-10-18 补写;`v1.10.0-rc0` / `v1.10.0-rc0.1` 为正式版前的预发布候选记录;**大版本发布要求**见 [`todo/25-release-requirements.md`](todo/25-release-requirements.md)) | - -## 3. 2026-10-11 文档整理记录 - -本仓库的文档在 2026-10-11 做过一次结构性整理,原则 =「`development/` 只留调用者文档; -项目开发者文档进 `todo/`;历史进 `history/history.md`」。逐项: - -**迁移到 `docs/todo/`**(原 `docs/development/`,文件名与编号不变):`02` `03` `04` `08` -`10` `12` `14` `17` `18` `19` `21` `22` `23`。 - -**整篇并入 `docs/history/history.md`**(内容已由后继文档承接,正文保留在 history 文末归档节): -`15-computeengine-refresh.md`、`16-computeengine-p0-inventory.md`。 - -**删除**:`13-refactor-backlog.md`——2026-10-01 起就只是 16 行的重定向 stub, -正文早在 `history/history.md` 与 `todo/18-roadmap.md`。 - -**保留在 `docs/development/`(并重定义其读者为"调用者")**:`01` `05` `06` `20`。 - -**新增**:`docs/README.md`(本文件)、`docs/todo/README.md`、`docs/development/README.md`、 -`docs/todo/00-code-review-remediation.md`(审查整改立项)。 - -**同日第二轮(补"调用者能否不读源码用全库"的缺口)**:`docs/development/` 新增三篇 -用户向文档——`cpp-api-manual.md`(全功能 C++ API 手册)、`cmake-integration.md` -(接入与构建全解)、`write-a-custom-layer.md`(写自定义层指南,含实测过梯度检查的示例层)。 -三篇均通过符号/文件/CLI 参数三重自审(对齐 `bench/doc_align_audit.ps1` 的 [A][D][E] 口径), -其中示例层的代码片段经真实编译 + 数值梯度检查实跑验证。`development/20` 的 -悬空样例引用(`examples/custom_layer_*` 已不在仓库)一并订正。 - -整理前 `docs/development/` 共有 20 篇文档,其中多数是"一件事只用几次"的内部设计/盘点稿—— -这正是本次把它们从面向用户的分册里移出的原因。 - -## 4. 2026-10-11 对外入口补全(第二轮) - -第一轮解决"文档写给谁看",第二轮补"**非作者怎么进得来**"。逐项: - -| 增加 | 作用 | -|------|------| -| [`../CONTRIBUTING.md`](../CONTRIBUTING.md) | 给非作者的统一入口:构建(preset)、测试口径、代码规范、提交信息写法、PR 自查清单、CI 实际做什么(**含"CI 不跑 ctest"这一事实**)、文档/研究怎么贡献 | -| [`../CODE_OF_CONDUCT.md`](../CODE_OF_CONDUCT.md) | 社区行为准则(Contributor Covenant 2.1 改编)+ 本仓特有的"技术讨论对事不对人"约定 | -| [`../CMakePresets.json`](../CMakePresets.json) | 预设构建:`release` / `dev` / `debug` / `portable` / `cpu` / `probes`(+ build/test/workflow preset)。**只描述口径,不改变 CMakeLists 默认值** | -| [`../.clang-format`](../.clang-format) + [`../.editorconfig`](../.editorconfig) + [`../.gitattributes`](../.gitattributes) | 把 §8 的风格规则变成机器可读;全仓 LF。⚠ 定位是**目标风格 + 增量工具**(`git clang-format`),**不是整仓重排脚本**——对全仓整体格式化会改约 41% 的行,见 history 的「代码风格可执行化」条 | -| [`../research/README.md`](../research/README.md) 重写 | 从"目录表"升级为**可引用结论索引**:每条给 结论(带数字与样本量)/ 证据 / 重跑命令 / **边界**,并写明"怎么引用、怎么新增一份研究" | +| `release-notes/v1.5.0.md` … `v1.13.0.md` | 版本变更说明,覆盖 v1.5.0 → v1.13.0 的全部 tag(**大版本发布要求**见 [`contributors/release-requirements.md`](contributors/release-requirements.md)) | -同时修掉的构建问题:**ccache 与共享 PCH 互斥**(Clang 侧缺 `sloppiness=pch_defines,time_macros` -与 `-fno-pch-timestamp`)导致 40+ 个目标的编译全部不可缓存——已修,单个 TU 从 30.2s 降到 0.11s -(命中缓存;全量重建 13m26s → 58.8s)。归因与实测见 [`history/history.md`](history/history.md) 的「ccache × 共享 PCH」条, -口径与复现见 [`development/cmake-integration.md`](development/cmake-integration.md) §8。 +> 历次文档整理的记录(2026-10-11 两轮、2026-11 第三轮)统一在 +> [`history/history.md`](history/history.md);文档规范正文见 +> [`contributors/documentation-standard.md`](contributors/documentation-standard.md)。 diff --git a/docs/benchmarks/2026-09-25-vulkan-vs-cuda.md b/docs/benchmarks/2026-09-25-vulkan-vs-cuda.md index 2b1b7dc..e7773de 100644 --- a/docs/benchmarks/2026-09-25-vulkan-vs-cuda.md +++ b/docs/benchmarks/2026-09-25-vulkan-vs-cuda.md @@ -17,7 +17,7 @@ | Layer(f32,fwd+bwd,large 组) | gpt_block 95.2 ms | 44.8 ms | torch 快 2.1× | | 训练稳定性(lr=1e-3 实测) | **f32 5 epoch 健康收敛(09-26 采集;09-25 采集为 NaN 发散)**;f16+`stable=f16` **loss 打印冻结**(见 §2.5 与 14 号报告) | fp16/fp32 全程稳定 | f32 打平;f16 存在缺陷 | -三个反直觉发现(§2.4、§2.5、§3.3):① torch 在 40HX 上该模型的 **fp16 路径比 fp32 慢 3.3×(病态)**;② nn 的 **f16 比 f32 慢 17%**(118.4 vs 101.0 ms;09-25 采集为 f16≈f32≈117 ms),且 `stable=f16` 下 **loss 打印冻结而权重照常更新**(2026-09-26 发现,`docs/todo/14-f16-stable-gpu-loss-frozen.md`);③ nn f32 显存 **3069 MiB**(09-25 采集 5743,差 −47%)——峰值强相关于精度,见 §2.3。 +三个反直觉发现(§2.4、§2.5、§3.3):① torch 在 40HX 上该模型的 **fp16 路径比 fp32 慢 3.3×(病态)**;② nn 的 **f16 比 f32 慢 17%**(118.4 vs 101.0 ms;09-25 采集为 f16≈f32≈117 ms),且 `stable=f16` 下 **loss 打印冻结而权重照常更新**(2026-09-26 发现,`docs/internal/14-f16-stable-gpu-loss-frozen.md`);③ nn f32 显存 **3069 MiB**(09-25 采集 5743,差 −47%)——峰值强相关于精度,见 §2.3。 --- @@ -92,7 +92,7 @@ ### 2.5 训练稳定性(按采集日期如实记录) - **nn f32(09-26 采集)**:短测 3 epoch 与长测 5 epoch **全程健康收敛**(短测 avg 7.38→5.93→5.28;长测 4.62→2.76),无 NaN。09-25 采集记录为「f16/f32 均 ~100–2000 步发散 NaN」;两者的差异归于 09-25 之后的提交窗口,未逐个二分。 -- **nn f16 + `stable=f16`(09-26 采集到的缺陷)**:loss **打印冻结**——step 5–45 恒 4.0137、跨 epoch/跨数据集/跨进程逐位相同;同时**权重照常更新**(同进程跨 epoch 模型快照 63% 参数字节不同)。定性矩阵:触发器 = `stable=f16`(GPU 特有,CPU 同配置健康);`--f16` 推荐 profile(stable/optimizer=f32)实测健康;`optimizer=f16` 单独即爆炸(= 下条已知数值限制)。**测试全绿与该缺陷并存**(覆盖缺口:GPU+stable=f16 无自动化用例)。详见 `docs/todo/14-f16-stable-gpu-loss-frozen.md`。 +- **nn f16 + `stable=f16`(09-26 采集到的缺陷)**:loss **打印冻结**——step 5–45 恒 4.0137、跨 epoch/跨数据集/跨进程逐位相同;同时**权重照常更新**(同进程跨 epoch 模型快照 63% 参数字节不同)。定性矩阵:触发器 = `stable=f16`(GPU 特有,CPU 同配置健康);`--f16` 推荐 profile(stable/optimizer=f32)实测健康;`optimizer=f16` 单独即爆炸(= 下条已知数值限制)。**测试全绿与该缺陷并存**(覆盖缺口:GPU+stable=f16 无自动化用例)。详见 `docs/internal/14-f16-stable-gpu-loss-frozen.md`。 - **nn 四字段全 f16 的缺陷表现(按采集日期)**:09-25 采集为「epoch1 活 → epoch2 发散 -nan」(= 05 文档 §12.5「stable=F16 时 CE 链 ~200 步 NaN」);09-26 采集为「epoch1 起即静默冻结」——冻结是静默出错(NaN 反而会暴露),风险等级更高。 - **torch fp16**:默认 `eps=1e-8` 在 fp16 中表示为 0,稀疏 embedding 零梯度行 `0/0=NaN`,**必须 `eps=1e-4`** 后稳定(实测 3 epoch 平稳下降)。 - **nn optimizer=f16 语义(本报告口径,以代码为准)**:`compute_optimizer.hpp:51-53` 注释明确状态张量按 `p_.optimizer` 创建(默认 F32;全 f16 profile 按字面取 F16,"用户显式选择全 f16 时不予阻拦,只如实报告数值表现")。09-25 采集条目记的「`--precision-optimizer f16` 不改变 Adam 状态精度(m/v 恒 f32)」与当前代码不符,以本条为准。定性矩阵 case c(optimizer=f16, stable=f32)loss 爆炸至 1.8e7 即为该语义的实测表现(与 05 文档 §12.5「optimizer=F16 时 Adam 的 v≈g²~1e-10 下溢→更新爆炸」一致)。故 nn `--f16`(推荐 profile)实际语义 = 参数/激活 f16 + stable/optimizer **f32**;四字段全 f16 = 含爆炸/冻结双重风险的实验性组合。 @@ -232,7 +232,7 @@ --epochs 3 --optimizer adam --lr 0.001 --gpu=40HX ` --save-interval 0 --log-interval 100000 -# nn 训练 —— 全 f16(实验性;loss 打印冻结,仅计时/显存有效,见 docs/todo/14-*.md) +# nn 训练 —— 全 f16(实验性;loss 打印冻结,仅计时/显存有效,见 docs/internal/14-*.md) # 追加: --precision-param f16 --precision-compute f16 --precision-stable f16 --precision-optimizer f16 # nn 训练 —— 推荐 f16 profile(实测健康): 追加 --f16 diff --git a/docs/benchmarks/2026-10-06-vulkan-vs-torch.md b/docs/benchmarks/2026-10-06-vulkan-vs-torch.md index 889788d..a0494fb 100644 --- a/docs/benchmarks/2026-10-06-vulkan-vs-torch.md +++ b/docs/benchmarks/2026-10-06-vulkan-vs-torch.md @@ -171,7 +171,7 @@ | torch fp16 forward | 47.64 ms | 8.55 ms | **不复现** | | nn 全 f16 | 比 f32 慢 17%、loss 打印冻结 | 与 f32 持平、loss `-nan` | 表现变化,**两者都不可用** | -**不复现项的处理**:本报告如实记录新值,并保留旧值供追溯;未对旧结论做"勘误",因为差异未二分(旧环境不可复现)。`docs/todo/14-f16-stable-gpu-loss-frozen.md` 记录的 nn 全 f16 缺陷仍成立,且本轮新增一种表现形态(epoch1 起 `-nan`)。 +**不复现项的处理**:本报告如实记录新值,并保留旧值供追溯;未对旧结论做"勘误",因为差异未二分(旧环境不可复现)。`docs/internal/14-f16-stable-gpu-loss-frozen.md` 记录的 nn 全 f16 缺陷仍成立,且本轮新增一种表现形态(epoch1 起 `-nan`)。 --- diff --git a/docs/contributors/README.md b/docs/contributors/README.md new file mode 100644 index 0000000..b6465fc --- /dev/null +++ b/docs/contributors/README.md @@ -0,0 +1,39 @@ +# contributors/ —— 贡献者与仓库作者规范 + +> **本分册写给向本仓贡献的人**:提 PR 的外部贡献者、仓库维护者、AI 编码助手(agent)。 +> 与相邻分册的分工:**调用者**(拿库写自己东西的人)看 [`../usage/`](../usage/) 与 +> [`../development/`](../development/);**项目内部设计/台账**看 [`../internal/`](../internal/); +> 历史归档在 [`../history/history.md`](../history/history.md)。 +> +> 一句话判断:**这篇规则管的是"怎么参与本仓的开发与治理",还是"怎么用这个库"?** +> 前者住这里,后者住 `usage/` / `development/`。 +> **读者**:向本仓贡献代码的人(含维护者与 AI 编码助手)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 + +## 这里的文档怎么组织 + +- **长期真源**:本分册放的是**长期有效的规范与治理规则**,不是一次性台账。 + 临时性的设计稿/整改立项进 [`../internal/`](../internal/)。 +- **别处只留引用**:`CONTRIBUTING.md`、`AGENTS.md` 等入口文档对本分册**只留摘要与指针**, + 规则正文一律以这里为准(避免同一规则多处维护、互相漂移)。 +- **无编号主题名**:本分册文档用主题名(`cpp-standards.md`),不用数字编号—— + 编号制度见 [`documentation-standard.md`](documentation-standard.md) §1。 + +## 索引 + +| 文档 | 何时读 | +|------|--------| +| [`documentation-standard.md`](documentation-standard.md) | **文档规范**:分册职责、编号制度、单篇模板(读者/结论/状态)、代码示例与 API 标注、状态词表、机器审查口径。**写任何文档前读** | +| [`cpp-standards.md`](cpp-standards.md) | **C++ 开发规范**:内存管理 / 模块隔离 / 高性能 / 错误处理 / 注释——改代码前读 | +| [`pitfalls.md`](pitfalls.md) | **踩坑警示录**:分级 bug 与跨领域根因模式——改代码前读;**踩了新坑先补这里再修代码** | +| [`release-policy.md`](release-policy.md) | **版本号·分支·发布治理(三条红线)**:`v1..<漏洞修复>`、**发布版本号必须由人提出(agent 不得擅自发布)**、`dev` 不写版本号、发布只在 `main`。定版本号 / 发版 / 改分支策略前读 | +| [`release-requirements.md`](release-requirements.md) | **大版本发布要求**(`1.x.y → 1.(x+1).0`):端到端模型训练测试 / 发布文档 / 完整 ctest + Debug 构建 / 多编译器 × 标准库矩阵 | + +## 相关(相邻分册 / 总档) + +| 想去哪 | 文档 | +|--------|------| +| 提 PR / 构建测试口径 | [`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) | +| AI 开发速览 | [`../../AGENTS.md`](../../AGENTS.md) | +| 总索引与分册定位 | [`../README.md`](../README.md) | +| 项目内部设计 / 台账 | [`../internal/README.md`](../internal/README.md) | diff --git a/docs/todo/10-development-standards.md b/docs/contributors/cpp-standards.md similarity index 98% rename from docs/todo/10-development-standards.md rename to docs/contributors/cpp-standards.md index 91050b2..7e89aee 100644 --- a/docs/todo/10-development-standards.md +++ b/docs/contributors/cpp-standards.md @@ -1,6 +1,7 @@ # C++ 开发规范 -> **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 +> **读者**:向本仓贡献代码的人(含 AI 编码助手)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 > 本文档定义 neuralnet.cpp 项目的开发规范,旨在确保代码质量、可维护性和高性能。 @@ -833,6 +834,10 @@ if constexpr (std::is_same_v) { ## 10. 文档与注释规范 +> **历史性记载禁令**:代码注释与文档一律不得写"xxx 已在 commit `abc1234` 修复"式叙事; +> 注释只描述**当前行为与约束**,变更过程归 [`../history/history.md`](../history/history.md)。 +> 全文见 [`documentation-standard.md`](documentation-standard.md) §3.4(机器审查 [H] 类兜底)。 + ### 10.1 注释风格 ```cpp diff --git a/docs/contributors/documentation-standard.md b/docs/contributors/documentation-standard.md new file mode 100644 index 0000000..9727dd7 --- /dev/null +++ b/docs/contributors/documentation-standard.md @@ -0,0 +1,170 @@ +# 文档规范 + +> **读者**:往本仓写/改任何文档的人(含 AI 编码助手)。本分册定位见 [`README.md`](README.md)。 +> 关联:[`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) §7(文档贡献入口)、 +> [`../README.md`](../README.md)(分册定位与全仓索引)、机器审查 = `scripts/doc_audit.py`。 +> **状态**:现行。 + +## 0. 一句话 + +**每篇文档必须回答四件事——写给谁(读者)、结论是什么(一句话)、现在算不算数(状态)、 +内容怎么标注(代码示例/API 符号/术语);写完必须登记进索引,机器审查(`doc_audit.py`)全绿才算完。** + +## 1. 分册职责与编号制度 + +### 1.1 分册职责(读者矩阵) + +| 分册 | 读者 | 写什么 | +|------|------|--------| +| `introduction/` `usage/` `development/` | **调用者**(拿库写自己东西的人) | 当前状态:总览、教程、API 手册、扩展指南 | +| `internal/` | **项目开发者**(改库的人) | 设计稿、路线图、盘点、缺陷台账、整改立项 | +| `contributors/` | **贡献者/维护者/agent** | 长期规范与治理:编码规范、踩坑、文档规范、发布规则 | +| `history/` | 项目开发者 | 全仓**唯一**历史归档:演进、勘误、被否决方案、旧数字 | +| `release-notes/` | 调用者 | 版本变更说明(随 tag 一册) | +| `benchmarks/` | 评估者 | 对外性能基准报告(采集时的实测) | +| `../research/` | 想引用结论/核对定义的人 | 研究档案:定义基线 / 实测结论 / 明确标注的 TODO | + +判断口径:**"这篇内容是描述产品,还是约束参与方式?"** 描述产品按调用者分册放; +约束参与方式进 `contributors/`;一次性台账进 `internal/`;已成历史的进 `history/`。 + +### 1.2 编号制度(两种语义,按分册区分) + +| 编号语义 | 适用 | 规则 | +|----------|------|------| +| **稳定台账 ID** | `internal/` | 编号=文档唯一 ID,**新增接当前最大号,永不重排**;缺号是历史正常痕迹,不需要解释性重排 | +| **阅读顺序** | `introduction/` `usage/` `development/` | 编号=建议阅读顺序,**必须连续**(01、02、03…不留洞);新增文档要么排进顺序重排编号,要么无主题名(仅限"独立参考手册"性质) | +| **无编号主题名** | `contributors/` `research//` | 长期真源用主题名(`cpp-standards.md`);编号不携带信息就不编号 | + +- 历史编号文件(`development/04-…` 等)已按阅读顺序重排(2026-11-XX);此后 `development/` + 新增文档接续最大号并保持语义顺序。 +- 转发页("本文只是指针,真源在 X")**原则上不建**;确有旧链接需要兜底时才建,且必须在 + 首屏标注唯一真源。 + +## 2. 单篇模板(强制) + +每篇 `docs/**/*.md`(豁免见 §2.2)**首屏必须有引用块头部**,三要素齐全: + +```markdown +# 文档标题 + +> **读者**:<一句话>。本分册定位见 [`README.md`](README.md)(或分册入口); +> 历史归档在 [`../history/history.md`](../history/history.md)。 +> **一句话结论**:<本文最重要的一件事,带数字/命令/边界,不写空话>。 +> **状态**:现行 +``` + +### 2.1 状态词表(封闭集合,审查器校验) + +| 状态 | 含义 | +|------|------| +| `现行` | 内容描述当前代码/规则,随代码同步维护 | +| `冻结` | 内容描述一个不再演进但仍然成立的现状(附冻结日期与原因) | +| `TODO` | 内容含未实施设计/未执行实验;**不得被引用为已有证据** | +| `转发页` | 本文只是指针;唯一真源在文内给出 | +| `已归档` | 历史快照,不再维护(正文应迁去 `history/`,此状态仅用于来不及迁的过渡期) | + +### 2.2 豁免 + +`history/history.md`(历史归档,按时间叙事)、`release-notes/v*.md`(随 tag 冻结)、 +`benchmarks/*.md`(采集时快照)豁免头部模板;其余一律适用(含本文件)。 + +## 3. 内容标注(机器审查的对象) + +### 3.1 事实三分(写作纪律) + +| 类别 | 写法要求 | +|------|----------| +| **机械事实** | 可由代码/实测直接验证;涉及符号/命令/数字的写法须通过 §4 审查 | +| **设计意图** | 用"设计上/意图是/为了…"明示,不得写成效果 | +| **未验证主张** | 效果类主张("更快""更强")**必须**给出指向:实测→`../research/` 条目;未测→标 `TODO` 并指向实验计划 | + +教训来源:`development/08-rapt-algorithm.md` 曾把设计意图写成效果结论("只检索语义相关 +Token"),2026-11 整改时按本条重写。 + +### 3.2 代码示例(三类角色,info string 标注) + +C++ 代码块的 fence info string 必须声明**角色**: + +| 标注 | 含义 | 要求 | +|------|------|------| +| ```` ```cpp example api ```` | 演示公开 API 的可编译示例 | 出现的每个 API 符号必须真实存在且签名匹配(审查器 F 类核对) | +| ```` ```cpp snippet ```` | 概念片段(省略上下文/错误处理,不可直接编译) | 片段内的 API 符号仍必须存在 | +| ```` ```cli ```` | 命令行示例 | 每个 `--flag` 必须在对应可执行文件的解析代码中存在(审查器 D 类核对) | + +- 其他语言同理:`python` / `bash` / `cmake` 块标 `` snippet ``(默认)或 `` example ``。 +- **无标注 = 默认 `snippet`**(审查器允许省略,但 `api` 角色必须显式声明)。 +- 审查器会**提取全部代码块生成复核清单**(`build/doc_audit/code_examples_report.md`), + 按文件/行号列出每段的角色与引用符号核对结果;**符号对得上不等于逻辑对**,示例改动后 + 须人工过一遍清单。 + +### 3.3 API 符号 + +- 本仓公开符号一律反引号包裹:`` `nn::Model` ``、`` `ComputeEngine::forward` ``; + 不用引号、不裸写。审查器对 `nn::*` 及文档中反引号类名做符号表核对(审查器 E 类)。 +- 提到**已删除**的符号/文件/CLI 参数时,须同句写出"已删除/已移除"字样(审查器识别否定语境, + 不报残留)。 + +### 3.4 历史性记载禁令(唯一归档 = `history/`) + +**除 `history/history.md` 外,任何文档与代码注释一律不得出现历史性记载**—— +如"xxx 已在 commit `abc1234` 修复"、"2026-10-13 的溢出修复"、"该参数于某日被删除"。 +写法一律改写为**当前事实**:"当前行为是什么、约束是什么";变更过程、修复日期、 +被删对象的来龙去脉 → [`../history/history.md`](../history/history.md)。 + +**时点记录文档豁免**(它们本身就是记录,按版本/采集时点冻结): +`history/` 本体、`release-notes/v*.md`、`benchmarks/*.md`、`research/` 报告、 +`contributors/release-requirements.md` 的实跑记录节。 + +允许的两类边界写法: +- **状态标记**:台账里的 `✅ 已实施(2026-10-20)` 是进度状态,不是叙事(`internal/` 允许); +- **兼容性契约**:"与旧 checkpoint 参数布局逐位一致""缺键不回落"描述的是**当前行为** + 对旧文件的承诺,不是历史;但不得展开"当初为什么、当时怎么改"。 + +### 3.5 术语 + +- 统一用**代码里的名字**称物:类型名/文件名/CLI 参数名照抄代码,不自造别名。 +- 中英混排规则:专有名词(Vulkan、RoPE、GPT)保留原文;通用技术词首次出现给中英对照, + 后文统一用中文。 + +## 4. 索引与生命周期义务 + +1. **登记义务**:新增/删除 `docs/**/*.md` 必须同步两处——分册 `README.md` 索引 + + [`../README.md`](../README.md) 总索引(审查器 E 类核对,漏登记即 FAIL)。 +2. **归档义务**:演进叙事("当初为什么、旧数字、被否决方案")一律进 + [`../history/history.md`](../history/history.md);索引/规范/台账文件里**不得**承载叙事段落。 + **历史性记载禁令见 §3.4**:`history/` 之外(含代码注释)不得出现 + "已在 commit xxx 修复"式记载(引述禁令本身不计);机器审查 [H] 类兜底。 +3. **同步义务**:改了 API/CLI/文件名,同 PR 内更新引用它的文档(审查器 A/D/E/F 类兜底)。 +4. **引用口径**:引用本仓结论/规范时**连出处一起引用**(文档名 + 章节),不转述。 + +## 5. 机器审查(`scripts/doc_audit.py`) + +```bash +python scripts/doc_audit.py # 全量检查,FAIL 时 exit 1 +python scripts/doc_audit.py --report # 另生成 build/doc_audit/code_examples_report.md 代码示例复核清单 +``` + +| 类 | 检查项 | 失败级别 | +|----|--------|----------| +| A | 文档引用的文件/链接目标存在(历史白名单豁免已删文件) | FAIL | +| B | 已删除符号无正向残留(识别"已删除"否定语境) | FAIL | +| C | 数字型断言(N 个 virtual / N/N 绿)披露待核 | WARN | +| D | `--flag` 在代码中存在(外部工具/已删/计划中三张白名单) | FAIL | +| E | 头部模板齐全 + 状态词合法 + **索引登记**(分册 README + 总索引) | FAIL | +| F | `nn::` 符号与反引号类名在 `include/`/`src/` 存在;测试名在 CMake/src 存在 | FAIL | +| G | 代码示例清单:提取全部代码块 → 复核报告(角色标注 + 符号核对) | FAIL(标注违规)/ 报告供人工复核 | +| H | **历史性记载**:`history/` 之外的 commit hash 引用、"已在…修复"、日期+变更动作叙事(§3.4;示例行以 `` 豁免) | FAIL | + +- 白名单(历史文件/已删符号/外部 CLI/历史测试名)维护在脚本顶部,**带注释说明每一项的来历**。 +- 本地口径:改文档必跑;CI 口径见 [`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) §5。 +- 旧 `bench/doc_align_audit.ps1` 的 A–F 类检查已并入本脚本并扩展(G 类新增);ps1 保留至 + Windows 侧迁移到 Python 为止,两者口径以本文件为准。 + +## 6. 历史整理记录 + +- 2026-10-11:第一轮整理——`development/` 只留调用者文档,项目开发者文档进 `todo/`, + 历史进 `history/`;新增本仓 `docs/README.md` 总索引。 +- 2026-11(本规范):第二轮整理——`todo/` 更名 `internal/`(并剥离长期规范);新增 + `contributors/` 分册与本规范;`development/` 编号按阅读顺序重排;新增 + `scripts/doc_audit.py`(含代码示例复核清单);根 README 改写为项目介绍。 + 详细逐项见 [`../history/history.md`](../history/history.md)。 diff --git a/docs/todo/08-pitfalls-and-lessons.md b/docs/contributors/pitfalls.md similarity index 98% rename from docs/todo/08-pitfalls-and-lessons.md rename to docs/contributors/pitfalls.md index aab9ec8..6a29020 100644 --- a/docs/todo/08-pitfalls-and-lessons.md +++ b/docs/contributors/pitfalls.md @@ -1,6 +1,7 @@ # 踩坑警示录(Pitfalls & Lessons) -> **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 +> **读者**:向本仓贡献代码的人(含 AI 编码助手)——**改代码前必读**。本分册定位见 [`README.md`](README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 > 本文档汇总项目开发至今踩过的所有坑,按严重度分级,提炼跨领域的根因模式,并提供开发活动的防坑清单。**每次踩新坑,先补充到本文档,再修复代码。** @@ -76,7 +77,7 @@ - **症状**:`add_inplace` 断言失败 `lhs=(seq,d_model) rhs=(seq*d_model,1)`。 - **根因**:`Tensor::reshape()` 是零拷贝视图:共享 `cpu_data_` 只改 Tensor 元数据 `rows_/cols_`,但 CPU 引擎的 `add_inplace` 用底层 `Matrix` 实际 shape 检查 → 不一致。 -- **当前行为**:CPU 分支 reshape 复制数据到新 shape;GPU 分支保持零拷贝(buffer+count 无 shape)。(M1 起公共入口为 `ComputeEngine::reshape`,实现同一份;原 `Tensor::reshape` 私有化,docs/todo/17 §3 D10) +- **当前行为**:CPU 分支 reshape 复制数据到新 shape;GPU 分支保持零拷贝(buffer+count 无 shape)。(M1 起公共入口为 `ComputeEngine::reshape`,实现同一份;原 `Tensor::reshape` 私有化,docs/internal/17 §3 D10) - **教训**:**任何"零拷贝视图 + 后端无关"的 Tensor 操作,CPU 与 GPU 语义天然不同**。排查 `add_inplace` 断言:先怀疑 reshape 后共享 Matrix 参与运算。 ### 3.3 缓存 key 冲突:哈希碰撞与位域溢出 @@ -392,8 +393,8 @@ GPU-resident 单算子对、链式错;attn batch=1 对、batch=2 错;gradche ## 8. 相关文档 -- `10-development-standards.md`(同目录)— 分层职责规范("每层只能负责每层的事") +- `cpp-standards.md`(同目录)— 分层职责规范("每层只能负责每层的事") - `../introduction/01-architecture.md` — 架构分层 -- `06-rapt-algorithm.md` — 线性注意力家族(RLA / RAPT / RLA-2)的设计与工程约束 +- `08-rapt-algorithm.md` — 线性注意力家族(RLA / RAPT / RLA-2)的设计与工程约束 (原 `07-zipt-algorithm.md` 已随 AttnZip 移除,见 `docs/history/history.md`) - `../usage/04-train-package.md` — 训练包格式 diff --git a/docs/todo/33-version-branch-and-release-policy.md b/docs/contributors/release-policy.md similarity index 87% rename from docs/todo/33-version-branch-and-release-policy.md rename to docs/contributors/release-policy.md index a6a55bb..f9e8601 100644 --- a/docs/todo/33-version-branch-and-release-policy.md +++ b/docs/contributors/release-policy.md @@ -1,13 +1,14 @@ -# 33 — 版本号、分支与发布治理规范 +# 版本号、分支与发布治理规范 -> **读者**:项目开发者与 AI 编码助手(agent)。本分册定位见 [`README.md`](README.md); +> **读者**:项目维护者 / 发布者与 AI 编码助手(agent)。本分册定位见 [`README.md`](README.md); > 历史归档在 [`../history/history.md`](../history/history.md)。 > 关联:[`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) §4(分支模型表 / 提 PR)、 > [`../release-notes/README.md`](../release-notes/README.md) §1(版本号格式与位定义全文)、 -> [`25-release-requirements.md`](25-release-requirements.md)(大版本必做清单)、 -> [`18-roadmap.md`](18-roadmap.md) §2(**git tag 是版本权威**)。 +> [`release-requirements.md`](release-requirements.md)(大版本必做清单)、 +> [`18-roadmap.md`](../internal/18-roadmap.md) §2(**git tag 是版本权威**)。 > > `AGENTS.md` 与 `CONTRIBUTING.md` 对本文**只留引用**;三条规则的正文以本文为准。 +> **状态**:现行。 ## 0. 三条规则(正文见 §1–§3) @@ -44,7 +45,7 @@ - `git tag` / `git push --tags` / `gh release create|edit|publish`; - 改 `CMakeLists.txt` 的 `project(VERSION ...)` 为新的定档值; - 在 `docs/release-notes/` 新建 `v*.md` **定稿**(草案可写,但必须标注"未定档")。 -3. **人发出指令后 agent 只是执行者**:可按 [`25-release-requirements.md`](25-release-requirements.md) +3. **人发出指令后 agent 只是执行者**:可按 [`release-requirements.md`](release-requirements.md) 清单代跑,但执行**前**须复述将用的版本号与动作清单并得到确认;号与内容不一致时**停下报告**, 不得自行改号或"顺手"发版。 4. **清单全绿 ≠ 可发布**:必做项全部就绪也不产生发布权——没有人的定档指令就不发。 @@ -74,7 +75,7 @@ |---|---| | 版本号格式 / 位定义 / rc / 勘误细则 | [`../release-notes/README.md`](../release-notes/README.md) §1 | | 分支模型(分支表与流转) | [`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) §4 | -| 版本号·分支·发布治理(本文三条规则) | 本文(`docs/todo/33-version-branch-and-release-policy.md`) | -| 大版本发布必做清单 | [`25-release-requirements.md`](25-release-requirements.md) | -| 版本权威与现状实测 | `git tag`;[`18-roadmap.md`](18-roadmap.md) §2 | +| 版本号·分支·发布治理(本文三条规则) | 本文(`docs/contributors/release-policy.md`) | +| 大版本发布必做清单 | [`release-requirements.md`](release-requirements.md) | +| 版本权威与现状实测 | `git tag`;[`18-roadmap.md`](../internal/18-roadmap.md) §2 | | 发布范围 / 主题 / 迁移指南 | [`../release-notes/`](../release-notes/) 每版一册 | diff --git a/docs/todo/25-release-requirements.md b/docs/contributors/release-requirements.md similarity index 92% rename from docs/todo/25-release-requirements.md rename to docs/contributors/release-requirements.md index 1fef40c..6a187c9 100644 --- a/docs/todo/25-release-requirements.md +++ b/docs/contributors/release-requirements.md @@ -1,10 +1,10 @@ -# 25 — 版本发布要求(大版本必做清单) +# 版本发布要求(大版本必做清单) -> **读者**:项目维护者 / 发布者。本分册定位见 [`README.md`](README.md); -> 历史归档在 [`../history/history.md`](../history/history.md)。 -> 关联:[`18-roadmap.md`](18-roadmap.md)(**git tag 是版本权威**); -> [`24-f16-training-defects.md`](24-f16-training-defects.md)(F2 的端到端全 f16 训练归口本清单第 1 项); -> [`33-version-branch-and-release-policy.md`](33-version-branch-and-release-policy.md)(**发布须由人提出、agent 不得擅自发布;`dev` 不写版本号、发布只在 `main`**——清单全绿也不等于可发版)。 +> **读者**:项目维护者 / 发布者。本分册定位见 [`README.md`](README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> 关联:[`18-roadmap.md`](../internal/18-roadmap.md)(**git tag 是版本权威**); +> [`24-f16-training-defects.md`](../internal/24-f16-training-defects.md)(F2 的端到端全 f16 训练归口本清单第 1 项); +> [`release-policy.md`](release-policy.md)(**发布须由人提出、agent 不得擅自发布;`dev` 不写版本号、发布只在 `main`**——清单全绿也不等于可发版)。 +> **状态**:现行。 ## 0. 适用范围 @@ -12,13 +12,13 @@ 小版本 / 修订号升级(`1.x.y → 1.x.(y+1)`)不强制走本清单,按常规 PR 门禁(构建 + `ctest` + 文档审计)即可。 **版本权威**:`git tag`;`CMakeLists.txt` 的 `project(... VERSION ...)` 与之对齐 -(口径见 [`18-roadmap.md`](18-roadmap.md) §2)。发布说明落在 `docs/release-notes/`。 +(口径见 [`18-roadmap.md`](../internal/18-roadmap.md) §2)。发布说明落在 `docs/release-notes/`。 ## 1. 必做项(大版本发布前逐条完成) | # | 项目 | 要求 | 证据(记入 release note 或 PR) | |---|---|---|---| -| 1 | **端到端模型训练测试** | 至少一条**真实规模**训练跑通且健康(loss 收敛、无 NaN / 无冻结、权重确实移动),并覆盖关键配方(f16 / 三值 / GPU 视当期改动而定)。**这类测试不进默认 ctest**(见 §2),只在本清单实跑一次。**注(2026-10-13)**:`stable=f16` 的「loss 冻结/inf」根因已修([`24`](24-f16-training-defects.md) §3.1 = CE 的 (1,1) 归约按 f16 落盘溢出),故本项的「无冻结」判据现对 `stable=f16` 也可测;**注(2026-10-14)**:`optimizer=f16` 的 NaN 根因(Adam 二阶矩在 f16 下下溢为 0)已修([`24`](24-f16-training-defects.md) §4.6 = 优化器状态缩放),故**四字段全 f16 现已可训练**(实测 GPU 500 步 6.05→4.05 无 NaN),本项的「无 NaN/无冻结、权重确实移动」判据对全 f16 同样适用;**注(2026-10-18)**:`26` 号 §8 分两套计划——**Plan A 标准 `--f16`** 的发布门禁是与 f32/PyTorch AMP 同量级、无 NaN;**Plan B 真 f16** 的额外门禁是 capable 设备零转换 / incapable 仅引擎内转换 / 多模型/多设备/长跑。R5 通过前本项只证明“可训练”,不等于“真 f16 可转正”。启动期精度告警(F1)继续作为"显式实验档"的提示保留 | 训练命令 + 步数 + loss 起止值(必要时轨迹)+ 产物 | +| 1 | **端到端模型训练测试** | 至少一条**真实规模**训练跑通且健康(loss 收敛、无 NaN / 无冻结、权重确实移动),并覆盖关键配方(f16 / 三值 / GPU 视当期改动而定)。**这类测试不进默认 ctest**(见 §2),只在本清单实跑一次。**注(2026-10-13)**:`stable=f16` 的「loss 冻结/inf」根因已修([`24`](../internal/24-f16-training-defects.md) §3.1 = CE 的 (1,1) 归约按 f16 落盘溢出),故本项的「无冻结」判据现对 `stable=f16` 也可测;**注(2026-10-14)**:`optimizer=f16` 的 NaN 根因(Adam 二阶矩在 f16 下下溢为 0)已修([`24`](../internal/24-f16-training-defects.md) §4.6 = 优化器状态缩放),故**四字段全 f16 现已可训练**(实测 GPU 500 步 6.05→4.05 无 NaN),本项的「无 NaN/无冻结、权重确实移动」判据对全 f16 同样适用;**注(2026-10-18)**:`26` 号 §8 分两套计划——**Plan A 标准 `--f16`** 的发布门禁是与 f32/PyTorch AMP 同量级、无 NaN;**Plan B 真 f16** 的额外门禁是 capable 设备零转换 / incapable 仅引擎内转换 / 多模型/多设备/长跑。R5 通过前本项只证明“可训练”,不等于“真 f16 可转正”。启动期精度告警(F1)继续作为"显式实验档"的提示保留 | 训练命令 + 步数 + loss 起止值(必要时轨迹)+ 产物 | | 2 | **发布文档** | 落 `docs/release-notes/v1.(x+1).0.md`:发布范围(上一 tag → 本 tag)、主题、**破坏性变更 + 迁移指南**、验收基线 | release-note 文件 | | 3 | **完整 ctest + Debug 构建** | `Debug` 配置下构建并跑**完整 ctest**、全绿(需 GPU 的用例按退出码 77 记 skip);Release 全套 ctest 同样绿 | `cmake --preset debug`(或 `-DCMAKE_BUILD_TYPE=Debug -DNN_ENABLE_TESTS=ON`)+ `ctest` 输出 | | 4 | **多编译器 × 标准库编译测试** | 至少 **4 组**「编译器 × 标准库」**各自全新构建 + ctest**:clang + libc++、g++ + libstdc++、clang + MSVC STL、cl.exe + MSVC STL。MSVC 必须带 `/Zc:preprocessor`(已写进 `CMakeLists.txt` 的目录级与接口选项) | 每组 configure / build / ctest 结果(口径见 `AGENTS.md` §2) | @@ -29,13 +29,13 @@ ctest 是 CI **每次 push 都跑**的默认门禁,要求**分钟级**跑完 耗时远超该预算,塞进 ctest 会拖垮 CI 并诱发超时 flaky。故按耗时分层: - **默认门禁(ctest)** 只放**廉价**断言——组合矩阵、数值不变量、单步 / 短链轨迹(见 - [`24`](24-f16-training-defects.md) F2); + [`24`](../internal/24-f16-training-defects.md) F2); - **端到端训练**(含全 f16 可用性核对)归口**本清单第 1 项**,在大版本发布时实跑一次。 ## 3. 与常规门禁的关系 - 常规 PR 门禁(构建 + `ctest` + `NN_BIND_DEBUG=1 ctest` + 文档审计)见 - [`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) §6 与 [`18-roadmap.md`](18-roadmap.md) §8。 + [`../../CONTRIBUTING.md`](../../CONTRIBUTING.md) §6 与 [`18-roadmap.md`](../internal/18-roadmap.md) §8。 - 本清单是**超集**:大版本在常规门禁之上,再要求第 1 项(端到端训练)与第 4 项(多编译器矩阵)。 ## 4. 2026-10-18 发布前实跑记录(v1.9.0 发布态复验) @@ -245,7 +245,7 @@ seq_len=64 / batch=8`,每种配方 **20 step**,GPU: ## 8. 2026-10-23 `v1.11.0` 发布实跑记录 -> 测试对象 = `bc37df3`(`feat(session)!`:TrainingSession 单步协议与 global/micro batch 语义,docs/todo/30)。 +> 测试对象 = `bc37df3`(`feat(session)!`:TrainingSession 单步协议与 global/micro batch 语义,docs/internal/30)。 > 同步方式:`git bundle` → 102 上的临时独立检出(不触碰既有工作区)。 > 口径:`NN_ENABLE_NATIVE=OFF` 可移植基线;GPU = **NVIDIA CMP 40HX / Vulkan SDK 1.4.350**(原生设备自动选卡)。 diff --git a/docs/development/cmake-integration.md b/docs/development/01-cmake-integration.md similarity index 99% rename from docs/development/cmake-integration.md rename to docs/development/01-cmake-integration.md index c3bc5f5..4f3d77b 100644 --- a/docs/development/cmake-integration.md +++ b/docs/development/01-cmake-integration.md @@ -5,6 +5,7 @@ > > 消费方的最小接入也可以看 [`../usage/05-consume-as-library.md`](../usage/05-consume-as-library.md); > 本文是**完整版**:全部构建开关、GPU 语义、自研算子融合注册、跨平台与故障排查。 +> **状态**:现行。 --- diff --git a/docs/development/cpp-api-manual.md b/docs/development/02-cpp-api-manual.md similarity index 98% rename from docs/development/cpp-api-manual.md rename to docs/development/02-cpp-api-manual.md index 16d718c..d58edab 100644 --- a/docs/development/cpp-api-manual.md +++ b/docs/development/02-cpp-api-manual.md @@ -8,6 +8,7 @@ > 引擎原语、张量 I/O、表达式 DSL 的**逐条细节**在 > [`../usage/03-compute-engine-usage.md`](../usage/03-compute-engine-usage.md)(下称「引擎手册」), > 本文只做速查与交叉引用,不重复。 +> **状态**:现行。 --- @@ -15,7 +16,7 @@ | 我要做的事 | 看 | |---|---| -| 把库嵌进我的 CMake 工程(add_subdirectory / FetchContent) | §2 + [`cmake-integration.md`](cmake-integration.md) + [`../usage/05-consume-as-library.md`](../usage/05-consume-as-library.md) | +| 把库嵌进我的 CMake 工程(add_subdirectory / FetchContent) | §2 + [`01-cmake-integration.md`](01-cmake-integration.md) + [`../usage/05-consume-as-library.md`](../usage/05-consume-as-library.md) | | 创建引擎、开 GPU | §3 | | 创建 / 读写张量、上传下载数据 | §4(细节见引擎手册 §3–§6) | | 打开 `--f16` / 三值权重那样的精度配置 | §5 | @@ -31,8 +32,8 @@ | 剖析性能、看环境变量开关 | §16 | | 查错误处理宏、断言宏 | §17 | | 写自己的 CLI / 用底层工具(文件、哈希、线程池) | §19 | -| 写一个**自己的层** | §18 + [`write-a-custom-layer.md`](write-a-custom-layer.md) | -| 往引擎里**加一个新原语** | [`01-compute-engine-development.md`](01-compute-engine-development.md) | +| 写一个**自己的层** | §18 + [`03-write-a-custom-layer.md`](03-write-a-custom-layer.md) | +| 往引擎里**加一个新原语** | [`04-compute-engine-development.md`](04-compute-engine-development.md) | | 多精度的语义契约(写层必读) | [`05-mixed-precision.md`](05-mixed-precision.md) | > **两条最容易踩的铁律**:① 一切张量的创建 / 读写 / reshape **必须经 `ComputeEngine`** @@ -147,7 +148,7 @@ SPIR-V 嵌入头目录、Vulkan 链接与 shader 生成顺序。嵌入时 `NN_BU `NN_ENABLE_GPU` 默认 `AUTO`。自研 `nn::dsl::compute` 表达式要一行 `nn_enable_gpu_fusion(...)` 才进 GPU 闭合世界。 -> **完整版(全部构建开关、GPU 语义、融合注册、故障排查)见 [`cmake-integration.md`](cmake-integration.md)**; +> **完整版(全部构建开关、GPU 语义、融合注册、故障排查)见 [`01-cmake-integration.md`](01-cmake-integration.md)**; > 消费方视角的精简版见 [`../usage/05-consume-as-library.md`](../usage/05-consume-as-library.md)。 --- @@ -158,7 +159,7 @@ SPIR-V 嵌入头目录、Vulkan 链接与 shader 生成顺序。嵌入时 `NN_BU `Tensor` 不保存引擎身份(设备域从存储派生);不再需要“引擎最后析构”的调用约定。 ⚠ 但这**不覆盖**优化器与模型的顺序:`Optimizer` 的参数/梯度是 Model 内 Tensor 的非拥有引用,**优化器必须先于 Model 销毁**(否则 `step()` UAF); -用 `nn::TrainingSession` 统一拥有两者可结构性避免([`todo/29`](../todo/29-session-architecture.md))。 +用 `nn::TrainingSession` 统一拥有两者可结构性避免([`internal/29`](../internal/29-session-architecture.md))。 ```cpp // ① CPU(默认,无额外依赖) @@ -290,7 +291,7 @@ nn::profile_f32(); // 全 F32(默认) nn::profile_f16(); // Plan A 标准 --f16:param=F16, compute=F16, stable=F32, optimizer=F32 nn::profile_t1_58(); // --t1_58:param=T1_58(其余三槽 = profile_f16) nn::profile_master_weights(); // Plan A 的 AMP master-weights 形态:f32 主权重 + f16 计算 + f32 稳定/优化器 -nn::profile_all_f16(); // Plan B 真 f16:四槽全 F16;F5 后可训练,但 native16/零转换尚未完成,见 todo/26 §8 +nn::profile_all_f16(); // Plan B 真 f16:四槽全 F16;F5 后可训练,但 native16/零转换尚未完成,见 internal/26 §8 ``` 两种用法: @@ -377,7 +378,7 @@ nn::Tensor z = NN_UNWRAP(nn::dsl::compute(engine, > > 一元函数(`exp`/`log`/`sqrt`/`tanh` 等 7 个 + 一元负号)、视图 / 广播 / 归约的**完整清单** > 与 5 个陷阱见引擎手册 §8。GPU 侧:库内层的融合 shader 构建期已生成;**自研表达式** -> 需一行 CMake 注册(见 §2 / [`cmake-integration.md`](cmake-integration.md)),否则运行期硬报错。 +> 需一行 CMake 注册(见 §2 / [`01-cmake-integration.md`](01-cmake-integration.md)),否则运行期硬报错。 --- @@ -1040,7 +1041,7 @@ nn::prof::dump(stdout); // 进程结束前打表(stage / op / GPU / per- | `NN_VULKAN_DEVICE` / `NN_VULKAN_NO_16BIT_ALU` / `NN_VULKAN_NO_TIMELINE` | GPU 设备与特性逃生阀 | | `NN_POOL_BLOCK_MB` / `NN_POOL_LADDER_MAX_MB` / `NN_NO_EARLY_REAP` / `NN_CPU_PAUSE` / `NN_GPU_PROFILE` | 内存池 / 调度 A/B | -> 探针门语义(哪些算探针、默认为什么不编译)见 [`cmake-integration.md`](cmake-integration.md)。 +> 探针门语义(哪些算探针、默认为什么不编译)见 [`01-cmake-integration.md`](01-cmake-integration.md)。 --- @@ -1063,11 +1064,11 @@ nn::prof::dump(stdout); // 进程结束前打表(stage / op / GPU / per- ## 18. 写自己的层 / 加新原语(去哪读) - **写自定义层**(`Layer` 子类:`init_impl` NVI、参数注册、精度槽声明、缓存契约、 - GPU checklist、梯度自检)→ [`write-a-custom-layer.md`](write-a-custom-layer.md)。 + GPU checklist、梯度自检)→ [`03-write-a-custom-layer.md`](03-write-a-custom-layer.md)。 - **给引擎加新原语**(CPU / GPU 两后端实现、shader、AOT 闭合世界注册)→ - [`01-compute-engine-development.md`](01-compute-engine-development.md)。 + [`04-compute-engine-development.md`](04-compute-engine-development.md)。 - **多精度语义契约(写层前必读)** → [`05-mixed-precision.md`](05-mixed-precision.md)。 -- **线性注意力家族算法** → [`06-rapt-algorithm.md`](06-rapt-algorithm.md)。 +- **线性注意力家族算法** → [`08-rapt-algorithm.md`](08-rapt-algorithm.md)。 --- diff --git a/docs/development/write-a-custom-layer.md b/docs/development/03-write-a-custom-layer.md similarity index 98% rename from docs/development/write-a-custom-layer.md rename to docs/development/03-write-a-custom-layer.md index 39ce14a..b37e2e2 100644 --- a/docs/development/write-a-custom-layer.md +++ b/docs/development/03-write-a-custom-layer.md @@ -1,12 +1,13 @@ # 写一个自己的层(自定义 Layer 指南) > **读者**:调用者(库使用者)。想在内置层之外加自己的结构时读本文。 -> 背景实测报告(接入契约、7 个摩擦点的库外视角)见 [`20-custom-layer-ergonomics.md`](20-custom-layer-ergonomics.md); +> 背景实测报告(接入契约、7 个摩擦点的库外视角)见 [`09-custom-layer-ergonomics.md`](09-custom-layer-ergonomics.md); > 引擎原语清单见 [`../usage/03-compute-engine-usage.md`](../usage/03-compute-engine-usage.md); > 多精度语义契约见 [`05-mixed-precision.md`](05-mixed-precision.md)。 > > 本文的三步路径与示例层**经实测**:示例 `LowRankAdapter` 通过数值梯度检查 > (`max|num−an| = 4.7e-06`)并能训练收敛(`loss 0.0615 → 0.000116`,50 步 Adam)。 +> **状态**:现行。 --- @@ -152,7 +153,7 @@ public: > **输出形状可省**:上例的 `dsl::compute(engine, expr, rows, cols, P)` 可写成 > `dsl::compute(engine, expr, P)` —— 输出网格由表达式推导(逐元素/广播/归约视图/ -> matmul 段各按广播规则合并,口径见 [`cpp-api-manual.md`](cpp-api-manual.md) §6)。 +> matmul 段各按广播规则合并,口径见 [`02-cpp-api-manual.md`](02-cpp-api-manual.md) §6)。 > 推导不出的网格(如裸广播向量)会返回错误并提示改用显式形式,不会猜形状; > 两种写法在同一表达式上**结果逐位一致**(库内 6 处调用点已改为省略形式)。 diff --git a/docs/development/01-compute-engine-development.md b/docs/development/04-compute-engine-development.md similarity index 98% rename from docs/development/01-compute-engine-development.md rename to docs/development/04-compute-engine-development.md index 4f848f7..1e9aec1 100644 --- a/docs/development/01-compute-engine-development.md +++ b/docs/development/04-compute-engine-development.md @@ -1,7 +1,8 @@ # 计算引擎开发指南 > **读者**:调用者(库使用者 / 扩展者)——本分册定位见 [`README.md`](README.md)。 -> 项目内部的设计 / 路线图 / 盘点在 [`../todo/`](../todo/),历史在 [`../history.md`](../history/history.md)。 +> 项目内部的设计 / 路线图 / 盘点在 [`../internal/`](../internal/),历史在 [`../history.md`](../history/history.md)。 +> **状态**:现行。 > 面向想要理解或修改计算引擎实现的开发者。本文覆盖 ComputeEngine 接口全解、CPU / GPU 实现模式、以及添加新原语的完整方法。 @@ -107,7 +108,7 @@ engine.end_batch(); // 提交并等待 ``` > **接口分层(NVI,P-1/P1 之后)**:引擎的**公共入口全部非虚**——承载边界 cast -> (f16 抬 f32 算→按 P 落回,15 §4.1)、`bind_check_`(设备域检查,docs/todo/28 §4.3) +> (f16 抬 f32 算→按 P 落回,15 §4.1)、`bind_check_`(设备域检查,docs/internal/28 §4.3) > ;**引擎实现侧是 protected 的虚 `*_impl`**。 > 下文各"原语"清单列出的就是引擎需要实现的 `*_impl` 签名;调用方(Layer/测试) > 永远调用**同名公共入口**(不带 `_impl`)。 @@ -253,10 +254,10 @@ auto rg = dsl::compute(engine, // > 归约视图给输入整网格、`grouped_reduce(t,R)` 给 `(rows/R, cols)`、matmul 段给 > `(batch·M, N)`、标量/索引叶/稀疏与批视图中性);**冲突、不可推导或全无贡献者一律 > 报错**并提示改用显式形式(不猜形状)。`dsl::compute_reduce(engine, expr[, P])` 同理 -> (它要的是**输入网格**)。细则见 [`cpp-api-manual.md`](cpp-api-manual.md) §6。 +> (它要的是**输入网格**)。细则见 [`02-cpp-api-manual.md`](02-cpp-api-manual.md) §6。 > 理由:DSL 与逐元素算子能力完全重叠,且天然融合为单 kernel。 -> 引擎原语盘点见 `../todo/12-compute-engine-inventory.md`; +> 引擎原语盘点见 `../internal/12-compute-engine-inventory.md`; > 逐元素算子收敛的历史演进记录见 `docs/history/history.md`。 ### 9. 数据操作原语 @@ -360,7 +361,7 @@ auto rg = dsl::compute(engine, // **形状约定**:batch-major `i = b*seq+t`;头 (b,h) 行块起点 `r0=(b*H+h)*d_k`;K/V/P/R(X/Y)`(B·H·d_k, seq)`、D `(B·H·d_k², seq)`、A0/B0 `(H·d_k, d_k)`;boundary `(1, B·seq)`(1=文档起点);空参数用 (1,1) dummy + bool 标志(规避 0 字节 GPU buffer);`d_k ≤ 64`(GPU MAX_DK);标量块 s/r 头内逐行重复(实现写全部行,调用方读任一行)。 -**使用方**:`ReLULinearAttention`(RAPT 层)——shader 只含"带状态的顺序归约 + matvec 读出 / 外积",算法(L2 分母 / ReLU 门控 / 梯度公式 / 文档重置)全部由 Layer 用原语组合表达(见 `06-rapt-algorithm.md` §4)。 +**使用方**:`ReLULinearAttention`(RAPT 层)——shader 只含"带状态的顺序归约 + matvec 读出 / 外积",算法(L2 分母 / ReLU 门控 / 梯度公式 / 文档重置)全部由 Layer 用原语组合表达(见 `08-rapt-algorithm.md` §4)。 ### 12. 内存统计与回收(M5,17 §4.5) diff --git a/docs/development/05-mixed-precision.md b/docs/development/05-mixed-precision.md index b57ced2..e6519a3 100644 --- a/docs/development/05-mixed-precision.md +++ b/docs/development/05-mixed-precision.md @@ -2,19 +2,19 @@ > **读者**:调用者(库使用者 / 扩展者)——本分册定位见 [`README.md`](README.md)。 > 本文的语义契约章节(§7.2)与实测限制章节(§12)是写给"要选精度 / 要写层"的人的; -> 项目内部的路线图 / 盘点在 [`../todo/`](../todo/),历史在 [`../history.md`](../history/history.md)。 +> 项目内部的路线图 / 盘点在 [`../internal/`](../internal/),历史在 [`../history.md`](../history/history.md)。 -> **状态**:Phase 1(存储类型化 / cast / f16 GEMM / 类型化 Tensor)与 Phase 2(f16 边界 cast +> **状态**:现行(Phase 1 存储类型化 / cast / f16 GEMM / 类型化 Tensor 与 Phase 2 f16 边界 cast >(**P-1 已下沉为 `ComputeEngine` 基类 NVI 入口**,原 `PrecisionEngine` 装饰器已删除,见 > `docs/history/history.md「15 号归档」` §4.1)+ DSL/Layer/Loss/Optimizer 全链精度接线 + **in-kernel f16 带类型变体(逐元素 / > 归约 / matmul 段 / fold)** + **op-level f16 GEMM**)均为**当前实现**;当前 `--f16` 实测峰值显存 > 低于 f32(§12.11)。当前状态、实测结论与已知问题见 **§12**;各轮实施过程与 A/B 流水见 > `docs/history/history.md`。 > **2026-10-18 口径更新**:F5 之后四字段全 f16(`profile_all_f16()`)已可训练;「全流程真 f16」 -> 作为独立目标恢复为活跃计划([`../todo/26-f16-speedup-plan.md`](../todo/26-f16-speedup-plan.md) §8)。 +> 作为独立目标恢复为活跃计划([`../internal/26-f16-speedup-plan.md`](../internal/26-f16-speedup-plan.md) §8)。 > 本文 §9.4 / §12.5 中「不可训练」的旧结论只适用于 **F5 之前**。 > **范围**:f16 + f32(bf16 / f64 仅枚举占位)。 -> **配套**:`01-compute-engine-development.md`(引擎开发)、`../usage/03-compute-engine-usage.md`(引擎使用)、`08-pitfalls-and-lessons.md`(踩坑)。 +> **配套**:`04-compute-engine-development.md`(引擎开发)、`../usage/03-compute-engine-usage.md`(引擎使用)、`../contributors/pitfalls.md`(踩坑)。 ## 目录 @@ -269,13 +269,13 @@ P = F32:参考即自身,不舍入(= 现状行为) | 数据操作(clone/slice/gather…) | 按 P 字节拷贝 | 按 P 字节拷贝 | 同左(`supports_native_data_move()` 对 f16 直接放行,无边界 cast) | > 上表是**当前实现**;真 f16 计划要求 capable 设备取消 f32 累加与任何 f16↔f32 转换,见 -> [`../todo/26-f16-speedup-plan.md`](../todo/26-f16-speedup-plan.md) §8。 +> [`../internal/26-f16-speedup-plan.md`](../internal/26-f16-speedup-plan.md) §8。 ### 7.4 f16 GEMM(计算侧主收益点) 定义(Q4 特化):**f16 输入、f32 累加、f16 输出(round-half-to-even)**。当前实现: -> **口径区分(2026-10-18)**:本节描述**当前实现**;[`../todo/26-f16-speedup-plan.md`](../todo/26-f16-speedup-plan.md) +> **口径区分(2026-10-18)**:本节描述**当前实现**;[`../internal/26-f16-speedup-plan.md`](../internal/26-f16-speedup-plan.md) > §8 的“全流程真 f16”是更高目标——支持 f16 计算的设备要求取消 f16↔f32 转换(包括 f32 累加), > 累加误差改用 f16 分块/补偿方案。不要把本节的“f32 累加”当作真 f16 的验收口径。 @@ -391,7 +391,7 @@ loss = ce.forward_sparse(engine, logits, labels, mask, vocab, - 优化器更新算子全部显式:参数更新 P = `param`(in-place,存储不变),状态更新 P = `optimizer`。 - **per-layer 覆盖 = Phase 2**:`p_` 本就是每层成员,改成员即覆盖(如末层 head 强制 F32),纯增量。 - CLI 入口的 `--f16` 标志 = `profile_f16()` = **{param=F16, compute=F16, stable=F32, optimizer=F32}**(§9.4"f16 存储"行);`text_train`/`mnist_train` 另有 `--precision-param/compute/stable/optimizer` 逐字段覆盖,`mem_probe` 有 `--f16` / `--f16-all`。master-weights 配方 {param=F32, compute=F16, stable=F32, optimizer=F32} 对应 `profile_master_weights()`。 -- **精度预设(2026-10-10 新增)**:CLI `--t1_58` = `profile_t1_58()` = **{param=T1_58, compute=F16, stable=F32, optimizer=F32}** —— 定义上就是 `profile_f16()` 把 `param` 换成三值(另三槽在同一函数里派生 → 不可能与 `--f16` 漂移),即"**其他默认 f16,模型参数 1.58**"。三值只描述**权重**(`T1_58` 不是存储精度),落地点是 `BitLinear`,见 `docs/todo/21-quantized-weights.md` §4.10。 +- **精度预设(2026-10-10 新增)**:CLI `--t1_58` = `profile_t1_58()` = **{param=T1_58, compute=F16, stable=F32, optimizer=F32}** —— 定义上就是 `profile_f16()` 把 `param` 换成三值(另三槽在同一函数里派生 → 不可能与 `--f16` 漂移),即"**其他默认 f16,模型参数 1.58**"。三值只描述**权重**(`T1_58` 不是存储精度),落地点是 `BitLinear`,见 `docs/internal/21-quantized-weights.md` §4.10。 ### 9.4 典型配方 @@ -409,9 +409,9 @@ loss = ce.forward_sparse(engine, logits, labels, mask, vocab, 四字段全 F16 在 **F5(2026-10-14)后已可训练**:Adam 状态缩放 `S=4096` 把 m/v 移出 f16 下溢区, CE 的 `(1,1)` loss 标量归约当前恒 F32(见 §12.5)——这是 F5 的数值补丁,**与真 f16 的零转换目标 冲突**,R2 要改成 f16 安全归约;tiny GPT 20 步与 GPU 500 步记录见 -[`../todo/24-f16-training-defects.md`](../todo/24-f16-training-defects.md) §4.6。但它仍是**实验配方**: +[`../internal/24-f16-training-defects.md`](../internal/24-f16-training-defects.md) §4.6。但它仍是**实验配方**: 长跑质量、全模型覆盖与一键 CLI 预设尚未完成,产品化计划见 -[`../todo/26-f16-speedup-plan.md`](../todo/26-f16-speedup-plan.md) §8。不要把「F5 前不可训练」的 +[`../internal/26-f16-speedup-plan.md`](../internal/26-f16-speedup-plan.md) §8。不要把「F5 前不可训练」的 旧结论当作当前事实。同理 `--t1_58` 只把 **param** 换成三值(`T1_58` 只描述权重、不是存储精度): compute/stable/optimizer 与 `--f16` 逐字段相同;字面"四槽全 f16 + 三值权重"= `--t1_58 --precision-stable f16 --precision-optimizer f16`。 @@ -536,15 +536,15 @@ compute/stable/optimizer 与 `--f16` 逐字段相同;字面"四槽全 f16 + 5. tensor core f16 FMA GEMM(当前实现用 f32 累加,§7.4;真 f16 目标要求 f16 累加/分块补偿,见 §12.13)。 6. f64(若出现需求)。 7. **动态 loss scaling(GradScaler 语义)**——Plan A 的标准项(§12.13 A1.1);F5 的 optimizer state scaling 不能替代它。Plan B 可复用为数值缓解技术。 -8. **全流程真 f16(四槽全 F16)产品化**——F5 已关闭「能不能训练」,本项关闭「支持 f16 的设备能不能全程零转换、全模型、可发布地训练」:一键 `--f16-all`、零转换普查、native16 全覆盖、logits/CE 融合、全模型/全设备长跑与质量基线。细则见 [`../todo/26-f16-speedup-plan.md`](../todo/26-f16-speedup-plan.md) §8(R0–R6)。 +8. **全流程真 f16(四槽全 F16)产品化**——F5 已关闭「能不能训练」,本项关闭「支持 f16 的设备能不能全程零转换、全模型、可发布地训练」:一键 `--f16-all`、零转换普查、native16 全覆盖、logits/CE 融合、全模型/全设备长跑与质量基线。细则见 [`../internal/26-f16-speedup-plan.md`](../internal/26-f16-speedup-plan.md) §8(R0–R6)。 ### 12.4 已知限制(显式,写入用户预期) -1. **当前无训练循环 loss scaling(Plan A A1.1 补)**:f16 范围 65504,f16 matmul 输出 / 大归约可能溢出 inf。`stable = F32` 把 softmax / LayerNorm 移出 f16 是第一道防线;训练侧应监控 inf/nan。**注**:CE 的 (1,1) loss 标量归约输出当前**恒 F32**(2026-10-13 的溢出修复)。这是 F5 的数值补丁,**不是真 f16 的终态**:真 f16 计划(todo/26 §8.B)要求用 per-token 平均/分块缩放把它改回 f16 安全归约。 +1. **当前无训练循环 loss scaling(Plan A A1.1 补)**:f16 范围 65504,f16 matmul 输出 / 大归约可能溢出 inf。`stable = F32` 把 softmax / LayerNorm 移出 f16 是第一道防线;训练侧应监控 inf/nan。**注**:CE 的 (1,1) loss 标量归约输出当前**恒 F32**。这是 F5 的数值补丁,**不是真 f16 的终态**:真 f16 计划(internal/26 §8.B)要求用 per-token 平均/分块缩放把它改回 f16 安全归约。 2. **CPU f16(无 f16 ISA)省内存不省时间**(逐元素 decode/encode 开销)。 3. **跨设备 f16 容差内相等,不字节一致**(§11.2)——不要写"CPU f16 与 GPU f16 逐字节对拍"的测试。 4. **bf16 / f64 未实现**,使用 → 清晰报错。 -5. **全流程真 f16 仍是实验配方**:F5 后 `optimizer=f16` 可训练,但 `|g| ≳ 0.0625` 时 `v` 会溢出 f16(实践配 `--max-norm`);`stable=f16` 的 softmax / Norm 尾数与长跑质量仍待 R2 硬化;当前 matmul/归约/CE 仍有 f32 累加或 F32 标量,**不满足真 f16 的零转换门禁**;RAPT f16 另有已知 NaN([`../todo/18-roadmap.md`](../todo/18-roadmap.md) §3.1 C11)。产品化门禁见 [`../todo/26-f16-speedup-plan.md`](../todo/26-f16-speedup-plan.md) §8。 +5. **全流程真 f16 仍是实验配方**:F5 后 `optimizer=f16` 可训练,但 `|g| ≳ 0.0625` 时 `v` 会溢出 f16(实践配 `--max-norm`);`stable=f16` 的 softmax / Norm 尾数与长跑质量仍待 R2 硬化;当前 matmul/归约/CE 仍有 f32 累加或 F32 标量,**不满足真 f16 的零转换门禁**;RAPT f16 另有已知 NaN([`../internal/18-roadmap.md`](../internal/18-roadmap.md) §3.1 C11)。产品化门禁见 [`../internal/26-f16-speedup-plan.md`](../internal/26-f16-speedup-plan.md) §8。 --- @@ -565,16 +565,16 @@ compute/stable/optimizer 与 `--f16` 逐字段相同;字面"四槽全 f16 + **机制结论(当前有效)** - **边界 cast 的代价**:适配层对**每个**未命中变体的算子把 f16 入参抬成 f32 副本(再按 P 落回)。被 k 个算子读取的张量要 k 份 f32 副本——典型是 `(vocab, batch·seq)` 量级的 logits 被 loss 链读 4~6 次。**LM head 计算精度固定为 `stable`(F32)** → logits 与 f32 基线同构、loss 链零 cast。结论:**边界 cast 只能拿"存储减半",拿不到"峰值下降"**(训练峰值由 transient 决定)——这是 in-kernel f16(§12.6 起)的存在理由;变体命中时不再走该路径(§11.1 三条路径)。 -- **数值结论(当前)**:GPU 上 `profile_f16`(param+compute f16)与 f32 **轨迹一致**——同初值/同超参 3.4776→3.1822 vs 3.4776→3.1803,最大相对偏差 **6e-4**(§7.2 语义成立)。**四字段全 f16(`profile_all_f16`)在 F5 前不可训练**:`optimizer=F16` 时 Adam 的 v≈g²~1e-10 下溢到 0 → 更新爆炸(loss 7.9→3.6e4);两者同时 f16 时 loss 恒定(更新被 f16 舍入吃光)。**F5(2026-10-14)后已可训练**:Adam 状态缩放 `S=4096` 把 m/v 移出下溢区(更新量数学不变),tiny GPT 20 步与 GPU 500 步记录见 [`../todo/24-f16-training-defects.md`](../todo/24-f16-training-defects.md) §4.6。CLI `--f16` 仍是安全默认 = `profile_f16()` = {param:F16, compute:F16, stable:F32, optimizer:F32}(§9.4);四字段全 f16 的产品化见 [`../todo/26-f16-speedup-plan.md`](../todo/26-f16-speedup-plan.md) §8。 - **订正(2026-10-13)**:原记的「`stable=F16` 时 CE 链 ~200 步 NaN」**根因是 CE 的 (1,1) loss 归约按 `stable=f16` 落盘溢出**(大 token 数下 Σ≈ -log(vocab)·N 超 f16 上限 65504 → ±inf,进而 NaN),当时的修复是 `compute_loss.hpp` 两条链的 (1,1) 归约输出**恒 F32**。该补丁让训练健康(GPU 120 步、6.9→5.76),但**它是真 f16 的已知偏差**:R2 要改成 per-token 平均/分块缩放的 f16 安全归约,不能把 F32 标量当作永久例外。`optimizer=F16` 的爆炸当时不在本修范围,后由 **F5(2026-10-14)的 Adam 状态缩放**修复。详见 [`../todo/24-f16-training-defects.md`](../todo/24-f16-training-defects.md) §2.1/§3.1/§4.6。 -- **外部数值鲁棒性方案(2026-10-18)**:SR / GradientStabilizer / ECO / Unit Scaling / Peri-LN / 低精度 attention 的 `δ` 修复已列入真 f16 计划;其中 **SR / GradientStabilizer / ECO / attention `δ` 修复进入 R2.5**(SR/ECO 需局部 f32 临时量,按 **B-Mem** 口径不产生 f32 持久态),**Unit Scaling 与 Peri-LN 是模型级 R5.x 实验**。证据、边界与落地门禁见 [`../todo/26-f16-speedup-plan.md`](../todo/26-f16-speedup-plan.md) §8.B.7。 +- **数值结论(当前)**:GPU 上 `profile_f16`(param+compute f16)与 f32 **轨迹一致**——同初值/同超参 3.4776→3.1822 vs 3.4776→3.1803,最大相对偏差 **6e-4**(§7.2 语义成立)。**四字段全 f16(`profile_all_f16`)在 F5 前不可训练**:`optimizer=F16` 时 Adam 的 v≈g²~1e-10 下溢到 0 → 更新爆炸(loss 7.9→3.6e4);两者同时 f16 时 loss 恒定(更新被 f16 舍入吃光)。**F5(2026-10-14)后已可训练**:Adam 状态缩放 `S=4096` 把 m/v 移出下溢区(更新量数学不变),tiny GPT 20 步与 GPU 500 步记录见 [`../internal/24-f16-training-defects.md`](../internal/24-f16-training-defects.md) §4.6。CLI `--f16` 仍是安全默认 = `profile_f16()` = {param:F16, compute:F16, stable:F32, optimizer:F32}(§9.4);四字段全 f16 的产品化见 [`../internal/26-f16-speedup-plan.md`](../internal/26-f16-speedup-plan.md) §8。 + **订正(2026-10-13)**:原记的「`stable=F16` 时 CE 链 ~200 步 NaN」**根因是 CE 的 (1,1) loss 归约按 `stable=f16` 落盘溢出**(大 token 数下 Σ≈ -log(vocab)·N 超 f16 上限 65504 → ±inf,进而 NaN),当时的修复是 `compute_loss.hpp` 两条链的 (1,1) 归约输出**恒 F32**。该补丁让训练健康(GPU 120 步、6.9→5.76),但**它是真 f16 的已知偏差**:R2 要改成 per-token 平均/分块缩放的 f16 安全归约,不能把 F32 标量当作永久例外。`optimizer=F16` 的爆炸当时不在本修范围,后由 **F5(2026-10-14)的 Adam 状态缩放**修复。详见 [`../internal/24-f16-training-defects.md`](../internal/24-f16-training-defects.md) §2.1/§3.1/§4.6。 +- **外部数值鲁棒性方案(2026-10-18)**:SR / GradientStabilizer / ECO / Unit Scaling / Peri-LN / 低精度 attention 的 `δ` 修复已列入真 f16 计划;其中 **SR / GradientStabilizer / ECO / attention `δ` 修复进入 R2.5**(SR/ECO 需局部 f32 临时量,按 **B-Mem** 口径不产生 f32 持久态),**Unit Scaling 与 Peri-LN 是模型级 R5.x 实验**。证据、边界与落地门禁见 [`../internal/26-f16-speedup-plan.md`](../internal/26-f16-speedup-plan.md) §8.B.7。 - 边界 cast 期的分阶段实测 A/B 与探针数据(f32 3069 MiB / f16 4124 MiB 等)见 `docs/history/history.md`;**当前峰值数字见 §12.11**。 **已知问题(当前)** 1. **CPU 侧 f16 全模型训练发散(已修复)**(双根因与验证见 §12.12);`f16_precision_test` 对应的容忍分支已改为硬失败。 2. 边界 cast 的 transient 膨胀(见上):**未命中变体的算子**仍走该路径,剩余归因与下一步见 §12.8 / §12.11。 -3. RAPT / CNN 的 f16 接线已完成(P2-3);剩余覆盖问题不是“未传 P”,而是 RAPT f16 的已知 NaN([`../todo/18-roadmap.md`](../todo/18-roadmap.md) §3.1 C11)与长跑质量验证。 +3. RAPT / CNN 的 f16 接线已完成(P2-3);剩余覆盖问题不是“未传 P”,而是 RAPT f16 的已知 NaN([`../internal/18-roadmap.md`](../internal/18-roadmap.md) §3.1 C11)与长跑质量验证。 4. `--activation-offload` 下 f16 激活写入 slab 前被抬为 f32(正确,但该份激活不再减半)。 --- @@ -784,7 +784,7 @@ matmul 段 / 归约 / 目标传递三类变体落地后的同窗交错实测(f 扫描 + `compute_into` 预绑定失败打印 + `accumulate`/`eval_into`/`prepare` 异常打印。 - profile 单字段矩阵(f16_precision_test `NN_F16_DEBUG=1`):param/compute/stable/CLI 四组均收敛且贴合 f32;`optimizer=F16` 的旧发散已由 F5 的 Adam 状态缩放修复 - (§12.5 / todo/24 §4.6),与本节两个缺陷无关。 + (§12.5 / internal/24 §4.6),与本节两个缺陷无关。 - ctest 全绿(含新增断言);`text_train --f16` CPU 可正常训练。 --- @@ -814,7 +814,7 @@ matmul 段 / 归约 / 目标传递三类变体落地后的同窗交错实测(f | f16 累加 / 归约 | ❌ matmul / reduce / fold / CE 仍存在 f32 累加器;真 f16 要求 native16 全链或分块/补偿实现 | | 原生 f16 ALU 覆盖 | ❌ `#a` 仍排除 fold/matmul/reduce;真 f16 要求覆盖全部计算结构 | | 无 `shaderFloat16` 设备 | 🟡 允许转换,但只能由引擎在算子内部隐式完成;尚未建立 Layer/DSL 零 cast 的自动门禁 | -| RAPT f16 | 🟡 仍有已知 NaN(todo/18 §3.1 C11),R5 前必须关闭 | +| RAPT f16 | 🟡 仍有已知 NaN(internal/18 §3.1 C11),R5 前必须关闭 | **“全流程真 f16”的定义(Plan B)**:`{param, compute, stable, optimizer}` 四槽全 F16 覆盖从张量进入引擎到 输出离开引擎的整条计算图。**设备支持 f16 计算时,全程不允许任何 f16↔f32 转换**:native16 覆盖 @@ -827,7 +827,7 @@ f16;数据集 token/id 是整数;只有日志/调试打印这类宿主展示 → A2 PyTorch AMP 长跑验收;**Plan B** = R0 口径统一 → R1 `--f16-all` 预设 → R2 零转换普查与真 f16 数值硬化 → R3 logits/CE 融合(先补 CE backward 扫描)→ R4 native16 全覆盖(核心门禁)→ R5 全模型/ 全设备覆盖 → R6 转正。完整验收矩阵与旧结论(S0/S1/S2/S5)的处理见 -[`../todo/26-f16-speedup-plan.md`](../todo/26-f16-speedup-plan.md) §8。 +[`../internal/26-f16-speedup-plan.md`](../internal/26-f16-speedup-plan.md) §8。 > 一句话:**F5 关闭了“能不能训练”;Plan A 关闭“标准混合精度能不能稳定可用”, > Plan B 关闭“支持 f16 的设备能不能全程零转换、全模型可发布”**。 diff --git a/docs/development/07-vulkan-backend-map.md b/docs/development/06-vulkan-backend-map.md similarity index 98% rename from docs/development/07-vulkan-backend-map.md rename to docs/development/06-vulkan-backend-map.md index 2bb4d21..d8517a2 100644 --- a/docs/development/07-vulkan-backend-map.md +++ b/docs/development/06-vulkan-backend-map.md @@ -3,6 +3,8 @@ > 面向"第一次读后端代码"的人:先建立调用链与所有权模型,再动手改。 > 本文只描述**当前代码**与**已确定的重构方向**;每一步的提交信息(`git log`) > 是该刀的范围与验收记录。 +> **读者**:调用者(库使用者 / 扩展者)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 ## 1. 为什么需要这张图 diff --git a/docs/development/09-engine-ownership.md b/docs/development/07-engine-ownership.md similarity index 93% rename from docs/development/09-engine-ownership.md rename to docs/development/07-engine-ownership.md index 89dbd92..20f72ad 100644 --- a/docs/development/09-engine-ownership.md +++ b/docs/development/07-engine-ownership.md @@ -3,10 +3,12 @@ > 适用范围:`ComputeEngine`、`GpuBackend`、`CpuEngine` / `GpuEngine`、`Layer`、 > `Model`、`Optimizer`、`TrainingSession`、`Tensor`、`ExprGraph` / `ExprSegment`。 > -> **本文是生命周期契约的唯一真源**(v3,2026-10-20 落地,随 `v1.10.0` 正式发布;预发布候选为 `v1.10.0-rc0`)。 -> [`08-object-lifetimes.md`](08-object-lifetimes.md) 已降为 3 行转发。设计与审计证据见 -> [`todo/28-lifecycle-v3.md`](../todo/28-lifecycle-v3.md);Session 层见 -> [`todo/29-session-architecture.md`](../todo/29-session-architecture.md)。 +> **本文是生命周期契约的唯一真源**(v3,2026-10-20 落地,随 `v1.10.0` 正式发布; +> 预发布候选为 `v1.10.0-rc0`;原转发页 `08-object-lifetimes.md` 已随 2026-11 文档重构删除)。 +> 设计与审计证据见 [`internal/28-lifecycle-v3.md`](../internal/28-lifecycle-v3.md); +> Session 层见 [`internal/29-session-architecture.md`](../internal/29-session-architecture.md)。 +> **读者**:调用者(库使用者 / 扩展者)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 ## 1. 一句话 diff --git a/docs/development/08-object-lifetimes.md b/docs/development/08-object-lifetimes.md deleted file mode 100644 index 63a2433..0000000 --- a/docs/development/08-object-lifetimes.md +++ /dev/null @@ -1,8 +0,0 @@ -# 对象生命周期契约(v3:设备域模型) - -> 本页是转发页。**唯一真源 = [`09-engine-ownership.md`](09-engine-ownership.md)** -> (v3,2026-10-20 落地,随 `v1.10.0` 正式发布;预发布候选为 `v1.10.0-rc0`)。 -> -> v2 的"Tensor 保存 8 字节 `EngineId` + `stamp_`/`adopt`/`bound`/`NN_BIND_DEBUG`" -> 模型已删除:设备域**从存储派生**,入口逐操作数检查,`import` / `to_matrix` 是仅有的 -> 跨域通道。设计与审计见 [`todo/28-lifecycle-v3.md`](../todo/28-lifecycle-v3.md)。 diff --git a/docs/development/06-rapt-algorithm.md b/docs/development/08-rapt-algorithm.md similarity index 97% rename from docs/development/06-rapt-algorithm.md rename to docs/development/08-rapt-algorithm.md index 2835fbe..5852a9b 100644 --- a/docs/development/06-rapt-algorithm.md +++ b/docs/development/08-rapt-algorithm.md @@ -1,10 +1,11 @@ # 线性注意力家族:RLA / RAPT / RLA-2 与 GPU 落地 > **读者**:调用者(库使用者 / 扩展者)——本分册定位见 [`README.md`](README.md)。 -> 项目内部的设计 / 路线图 / 盘点在 [`../todo/`](../todo/),历史在 [`../history.md`](../history/history.md)。 +> 项目内部的设计 / 路线图 / 盘点在 [`../internal/`](../internal/),历史在 [`../history.md`](../history/history.md)。 > **详细研究基线**:RLA-2/RAPT 的完整公式、复杂度、实现映射和事实/假设边界见 > [`../../research/rla/01-what-is-rla.md`](../../research/rla/01-what-is-rla.md);效果实验尚为 > [`../../research/rla/02-rla-effectiveness.md`](../../research/rla/02-rla-effectiveness.md) 的 TODO。 +> **状态**:现行。 > **30 秒了解 RAPT**:标准 Transformer 注意力要算 L×L 的分数矩阵,序列翻倍、开销翻四倍。 > RAPT 走**线性注意力**路线:利用矩阵结合律,先把历史键值"汇总"成一个固定大小的 @@ -203,7 +204,7 @@ CPU 实现**逐位一致**(门禁 `scan_bitwise_test`)。**dk ≤ 32 走窄 本项目**不存在单一 "flash-attn" kernel**——FlashAttention 的核心思想(online softmax + 不物化 S) 由注意力 forward 的**单 fold kernel 分块流式**实现(`FoldSpec`:QKᵀ/掩码/online softmax/ΣwV 逐 -`EXPR_FOLD_BLOCK=128` 块完成,S 矩阵绝不物化,见 `08-pitfalls-and-lessons.md` §4 与 +`EXPR_FOLD_BLOCK=128` 块完成,S 矩阵绝不物化,见 `../contributors/pitfalls.md` §4 与 `compute_layer_attention.hpp` 头注释)。掩码变体(Plain/Causal/Alibi/Doc/AlibiDoc)经 `FoldSpec` 登记,漏登记即 GPU 闭合世界硬报错。backward 为 R/X 表达式 + 3 个 `batched_matmul`。 @@ -225,6 +226,6 @@ RAPT 与 GPT 同档支持三种开关: `ReLULinearAttention` 在 checkpoint 模式下不写任何 backward 缓存(Qp/Kp/V_re/Q_normed/K_normed/逐头 1/rms),backward 缺缓存直接报错而非拿空张量算梯度;`activation_cache()` 列出全部本层缓存 + 4 个子层缓存(offload 完整覆盖)。 -**坑**:复合层 override `forward_recompute` 必须调用**虚函数** `set_checkpoint_mode` 关闭子层——基类默认实现只改本块标志位,子层缓存不重建,表现为"stride=1 能过、stride=2 过不了"(见 `08-pitfalls-and-lessons.md` 模式 H)。 +**坑**:复合层 override `forward_recompute` 必须调用**虚函数** `set_checkpoint_mode` 关闭子层——基类默认实现只改本块标志位,子层缓存不重建,表现为"stride=1 能过、stride=2 过不了"(见 `../contributors/pitfalls.md` 模式 H)。 **验收**:`rapt_test` 内含 `rapt_checkpoint`(stride∈{1,2} vs 全存基线逐位一致,max_abs=0);`rapt_offload_test`(GPU-only)同样逐位一致。 diff --git a/docs/development/20-custom-layer-ergonomics.md b/docs/development/09-custom-layer-ergonomics.md similarity index 94% rename from docs/development/20-custom-layer-ergonomics.md rename to docs/development/09-custom-layer-ergonomics.md index d3244e8..e29a494 100644 --- a/docs/development/20-custom-layer-ergonomics.md +++ b/docs/development/09-custom-layer-ergonomics.md @@ -2,17 +2,17 @@ > **读者**:调用者(库使用者 / 扩展者)——本分册定位见 [`README.md`](README.md)。 > 本文是"库外使用者"视角的实测报告:写自定义层时**必须**满足的接入契约与已知摩擦点。 -> 报告登记的问题项由 [`../todo/18-roadmap.md`](../todo/18-roadmap.md) 承接;历史在 [`../history.md`](../history/history.md)。 +> 报告登记的问题项由 [`../internal/18-roadmap.md`](../internal/18-roadmap.md) 承接;历史在 [`../history.md`](../history/history.md)。 -> **状态**:实测报告 · 基准版本 v1.7.0(`f20532b`)· 环境:本机 CPU(clang++,Debug) +> **状态**:冻结(实测报告 · 基准版本 v1.7.0 · 环境:本机 CPU clang++ Debug,不再随代码更新) > **方法**:以"库外使用者"身份**只写新文件、不改库内任何代码**,从零实现一个自定义层 > 并把它训起来;记录全部编译失败、契约误解与"必须回读源码才能确定"的点。 > **证据(快照)**:本次实测用的 `examples/custom_layer_lowrank.hpp`(层,157 行)+ > `examples/custom_layer_train.cpp`(数值梯度检查 + MNIST 训练,277 行)+ `CMakeLists.txt` > 的 `custom_layer_example` 目标——**这三个产物已不在仓库中**(随 `examples/` 目录整理移除)。 -> **要写层请看 [`write-a-custom-layer.md`](write-a-custom-layer.md)**:它给出自包含、可复制、 +> **要写层请看 [`03-write-a-custom-layer.md`](03-write-a-custom-layer.md)**:它给出自包含、可复制、 > 且经数值梯度检查实测通过的层模板与契约清单;本文退化为它的背景证据与摩擦点清单。 -> **关联**:`docs/todo/18-roadmap.md` X6(本文登记的问题项);X2/P2-4 是数据侧的同类"使用者视角"缺口。 +> **关联**:`docs/internal/18-roadmap.md` X6(本文登记的问题项);X2/P2-4 是数据侧的同类"使用者视角"缺口。 > **写作纪律**:行号取自实测;坐标系为 `文件:行`,行号漂移后以符号名为准。 --- @@ -53,7 +53,7 @@ out = x + scale · (B · h) B: (dim, rank) B 初始化为 0 ⇒ 初始为 > Debug(`-O0`)下的 118 ms/step 不代表性能,仅证明路径正确。 > 复现(快照期的命令,该目标与源文件已不在仓库): > `cmake --build build --target custom_layer_example && ./build/custom_layer_example`; -> 当前可复现的等价物是 [`write-a-custom-layer.md`](write-a-custom-layer.md) §3 的梯度自检片段。 +> 当前可复现的等价物是 [`03-write-a-custom-layer.md`](03-write-a-custom-layer.md) §3 的梯度自检片段。 --- @@ -125,7 +125,7 @@ error: ignoring return value of function declared with 'nodiscard' attribute `NN_UNWRAP(try_create_tensor(...))` 转发(失败即终止,不再是"返回空 Tensor 让调用方查 `valid()`")。因此本文 §4 的顾虑("改动波及全部 Layer 与测试")不成立:迁移是**增量**的, 旧写法继续编译;想要结构化错误就用 `try_create_tensor`。判据与验收见 -`docs/todo/00-code-review-remediation.md` 的 RV-02 卡(负例在 `tensor_precision_test [5]`)。 +`docs/internal/00-code-review-remediation.md` 的 RV-02 卡(负例在 `tensor_precision_test [5]`)。 ### 2.3 无"写自定义层"文档,四条契约全靠读源码(严重度:高) @@ -229,7 +229,7 @@ CPU 上写完即可跑;切 GPU 需要额外在 CMake 加 `nn_enable_gpu_fusion | # | 动作 | 成本 | 消解的问题 | |---|---|---|---| -| R1 | 新增"写自定义层"指南(层骨架模板 + gradcheck 片段 + 契约清单 + GPU checklist)——**已落地**在 `docs/development/write-a-custom-layer.md`(原计划路径 `docs/usage/06-…`,改置 `development/` 以符合分册定位) | 小 | 2.1 / 2.2 / 2.3 / 2.5 / 2.7 | +| R1 | 新增"写自定义层"指南(层骨架模板 + gradcheck 片段 + 契约清单 + GPU checklist)——**已落地**在 `docs/development/03-write-a-custom-layer.md`(原计划路径 `docs/usage/06-…`,改置 `development/` 以符合分册定位) | 小 | 2.1 / 2.2 / 2.3 / 2.5 / 2.7 | | R2 | `Layer::init` NVI 处加精度自检(`profile.param == F16` ⇒ `parameters()` 全为 F16 存储) | 小 | 2.4(同时为 C7 提供自动门禁) | | R3 | 提供公共梯度检查工具(或至少在 R1 的文档里给可复制的 60 行) | 小–中 | 2.6 | | R4 | `quickstart` 首屏加一句"`NN_UNWRAP` 是 unwrap 不是断言";可选新增 `NN_UNWRAP` 别名 | 小 | 2.1 | diff --git a/docs/development/README.md b/docs/development/README.md index ce85f2d..058e126 100644 --- a/docs/development/README.md +++ b/docs/development/README.md @@ -1,8 +1,12 @@ # development/ —— 面向调用者的开发文档 -> **本分册写给调用者(库使用者 / 扩展者)**,不是项目开发者的工作区。 -> 内部设计稿、路线图、盘点、规范、踩坑、故障报告、审查整改一律在 [`../todo/`](../todo/); -> 历史叙事在 [`../history.md`](../history/history.md)。 +> **读者**:调用者(库使用者 / 扩展者),不是项目开发者。 +> **一句话结论**:从接入构建、全套 C++ API 到扩展(自定义层/引擎原语/融合算子)的开发文档, +> 按 01→09 的阅读顺序编号。 +> **状态**:现行。 +> 内部设计稿、路线图、盘点、故障报告、审查整改在 [`../internal/`](../internal/); +> 贡献者规范在 [`../contributors/`](../contributors/README.md); +> 历史叙事在 [`../history/history.md`](../history/history.md)。 ## 这里的文档解决什么问题 @@ -18,25 +22,23 @@ ## 索引 -**入门路径建议**:先读 [`cpp-api-manual.md`](cpp-api-manual.md) §0 的「我要做什么 → 看哪节」表, -按任务跳到对应章节;要改构建就再读 [`cmake-integration.md`](cmake-integration.md)。 +**入门路径建议**:先读 [`02-cpp-api-manual.md`](02-cpp-api-manual.md) §0 的「我要做什么 → 看哪节」表, +按任务跳到对应章节;要改构建就再读 [`01-cmake-integration.md`](01-cmake-integration.md)。 | 文档 | 何时读 | |------|--------| -| [`cpp-api-manual.md`](cpp-api-manual.md) | **全功能 C++ API 手册**(首选):错误处理宏、引擎、张量、精度、DSL、层与 Model、模型工厂、损失、优化器、训练循环、模型文件、数据集、分词器、生成、剖析——每节带代码片段 | -| [`cmake-integration.md`](cmake-integration.md) | **接入与构建**:`add_subdirectory`/`FetchContent`、全部构建开关、GPU 语义、`nn_enable_gpu_fusion`、本仓构建/测试、跨平台、故障排查 | -| [`write-a-custom-layer.md`](write-a-custom-layer.md) | **写自己的层**:完整示例(实测通过数值梯度检查)+ 七条接入契约 + 精度槽声明 + 可复制的梯度自检 + GPU 检查清单 + 常见编译错误 | -| [`01-compute-engine-development.md`](01-compute-engine-development.md) | 想**扩展引擎**(加新原语)而不只是使用它:`ComputeEngine` 接口全解、CPU/GPU 实现模式、加原语的完整步骤 | +| [`01-cmake-integration.md`](01-cmake-integration.md) | **接入与构建**:`add_subdirectory`/`FetchContent`、全部构建开关、GPU 语义、`nn_enable_gpu_fusion`、本仓构建/测试、跨平台、故障排查 | +| [`02-cpp-api-manual.md`](02-cpp-api-manual.md) | **全功能 C++ API 手册**:错误处理宏、引擎、张量、精度、DSL、层与 Model、模型工厂、损失、优化器、训练循环、模型文件、数据集、分词器、生成、剖析——每节带代码片段 | +| [`03-write-a-custom-layer.md`](03-write-a-custom-layer.md) | **写自己的层**:完整示例(实测通过数值梯度检查)+ 七条接入契约 + 精度槽声明 + 可复制的梯度自检 + GPU 检查清单 + 常见编译错误 | +| [`04-compute-engine-development.md`](04-compute-engine-development.md) | 想**扩展引擎**(加新原语)而不只是使用它:`ComputeEngine` 接口全解、CPU/GPU 实现模式、加原语的完整步骤 | | [`05-mixed-precision.md`](05-mixed-precision.md) | 多精度**语义契约**(f16 的 P 精度算术、`PrecisionProfile{param/compute/stable/optimizer}`)+ 当前实测结论与已知数值限制(§12) | -| [`06-rapt-algorithm.md`](06-rapt-algorithm.md) | 线性注意力家族(RLA / RAPT / RLA-2):直观理解 + 数学定义 + 扫描原语工程落地 | -| [`07-vulkan-backend-map.md`](07-vulkan-backend-map.md) | **维护者视角**:Vulkan 后端的调用链、所有权、依赖方向,以及"加一个算子/pipeline 要改哪几处" | -| [`08-object-lifetimes.md`](08-object-lifetimes.md) | **维护者视角**:v3 转发页(唯一真源 = `09`:设备域从存储派生 / 入口域检查 / 跨域迁移清单) | -| [`09-engine-ownership.md`](09-engine-ownership.md) | **生命周期 v3 唯一真源**:设备域从存储派生、入口域检查、backend weak 缓存、失败语义、迁移清单与性能口径 | -| [`20-custom-layer-ergonomics.md`](20-custom-layer-ergonomics.md) | 自定义层的**实测报告**(库外使用者视角):7 个摩擦点、逐条坐标。写层前读 [`write-a-custom-layer.md`](write-a-custom-layer.md),本文是它的背景证据 | +| [`06-vulkan-backend-map.md`](06-vulkan-backend-map.md) | **维护者视角**:Vulkan 后端的调用链、所有权、依赖方向,以及"加一个算子/pipeline 要改哪几处" | +| [`07-engine-ownership.md`](07-engine-ownership.md) | **生命周期 v3 唯一真源**:设备域从存储派生、入口域检查、backend weak 缓存、失败语义、迁移清单与性能口径 | +| [`08-rapt-algorithm.md`](08-rapt-algorithm.md) | 线性注意力家族(RLA / RAPT / RLA-2):直观理解 + 数学定义 + 扫描原语工程落地;详细定义基线见 [`../../research/rla/`](../../research/rla/README.md) | +| [`09-custom-layer-ergonomics.md`](09-custom-layer-ergonomics.md) | 自定义层的**实测报告**(库外使用者视角):7 个摩擦点、逐条坐标。写层前读 [`03-write-a-custom-layer.md`](03-write-a-custom-layer.md),本文是它的背景证据 | -> **命名约定**:带数字前缀的文件沿用历史设计稿编号(`01` / `05` / `06` / `20`); -> 新增的**使用类文档**改用描述性文件名(`cpp-api-manual` / `cmake-integration` / -> `write-a-custom-layer`),避免与已归档的编号混淆。 +> **编号制度**:本分册编号 = 建议阅读顺序,**连续不留洞**(文档规范见 +> [`../contributors/documentation-standard.md`](../contributors/documentation-standard.md) §1.2)。 ## 相关(相邻分册) @@ -47,7 +49,7 @@ | 跑现成 CLI / GUI 训练推理 | [`../usage/02-quickstart-train-infer.md`](../usage/02-quickstart-train-infer.md) | | 写 RL / PPO / GRPO 或自定义 rollout | [`../usage/06-reinforcement-learning.md`](../usage/06-reinforcement-learning.md) | | 看**数据流/AOT 融合**的整体设计 | [`../introduction/01-architecture.md`](../introduction/01-architecture.md)、[`../introduction/04-innovative-designs.md`](../introduction/04-innovative-designs.md) | -| 融合/IR 的**内部设计**(改库才需要) | [`../todo/02-operator-fusion.md`](../todo/02-operator-fusion.md)、[`../todo/03-ir-optimization.md`](../todo/03-ir-optimization.md) | +| 融合/IR 的**内部设计**(改库才需要) | [`../internal/02-operator-fusion.md`](../internal/02-operator-fusion.md)、[`../internal/03-ir-optimization.md`](../internal/03-ir-optimization.md) | > ⚠ 本分册的文档同样受仓库写作纪律约束:**只描述当前状态**;演进过程、被否决方案、 > 旧数字一律在 [`../history.md`](../history/history.md)。 diff --git a/docs/history/history.md b/docs/history/history.md index d0b3b4e..86ffcc5 100644 --- a/docs/history/history.md +++ b/docs/history/history.md @@ -8,10 +8,10 @@ 类型标注:bug 根因 / 否决方案 / 性能 A/B / 删除清单 / 演进记录 / 覆盖缺口。 > **2026-10-11 文档整理说明**:`docs/development/` 的定位改为**面向调用者**(库使用者 / -> 扩展者)的开发文档,原其中的内部设计 / 路线图 / 盘点 / 规范类文档已迁至 `docs/todo/`; +> 扩展者)的开发文档,原其中的内部设计 / 路线图 / 盘点 / 规范类文档已迁至 `docs/internal/`; > 其中 `15-computeengine-refresh.md`、`16-computeengine-p0-inventory.md` 两篇**整篇并入本文件** >(见文末「docs/development 15 · 16」归档节),`13-refactor-backlog.md`(早先已降级为重定向 stub) -> 已删除——其内容本就在本文件与 `docs/todo/18-roadmap.md`。本文中出现的 +> 已删除——其内容本就在本文件与 `docs/internal/18-roadmap.md`。本文中出现的 > 「原位置 docs/development/NN…」字样均为**迁移前**路径,勿当现行路径。 ## 目录 @@ -104,7 +104,7 @@ expr_opt / expr_registry / expr_spec)「历史状态类注释」摘录。整 "一组代表值覆盖任意形状"在真实注册表上成立。 - **边界**:登记表仍由"掩码清单"驱动(C++ 无反射)——新增掩码种类要在 X 宏加一项,但枚举与 登记表**同源展开**,因此"加了枚举忘了登记"这一漏项形态已不可能出现;GQA 比本身是运行期 - vp 参数(不进 key),登记 kv_ratio=2 一条即覆盖任意 `n_rep`(docs/todo/22 §3.2 P2)。 + vp 参数(不进 key),登记 kv_ratio=2 一条即覆盖任意 `n_rep`(docs/internal/22 §3.2 P2)。 ## `dsl::compute` / `compute_reduce` 无形状重载(P4-4 ②,2026-10-15) @@ -221,7 +221,7 @@ expr_opt / expr_registry / expr_spec)「历史状态类注释」摘录。整 - **顺带修的 header-only 缺陷**:`backend/compute_vk_backend.hpp` 的 `GpuBuffer::~GpuBuffer()` 类外定义**缺 `inline`** → 任何 ≥2 个 TU 的程序链接期 `duplicate symbol`(样例两 TU 复现)。已加 `inline`。这条此前从未暴露,因为库自身的可执行目标都是单 TU。 - **GPU 端到端验收(本轮补齐)**:样例原先只验 CPU——而 CPU 走模板求值、与注册表无关,等于**没验到本 PR 的核心机制**。补上 GPU 后实测:CPU f32 `0.6712035`(差 0);GPU f32(V0)`0.6712036`(差 5.96e-08);**GPU f16(V1 运行期精度分派)`0.6708984`(差 3.05e-04,f16 舍入内)**。该表达式含 rparams ⇒ `expr_prec_sig_native16` 谓词不通过 ⇒ f16 那一跑命中的必然是 `key#x` 分派 shader;注册表若漏它就是闭合世界硬报错,"跑通"本身即断言。 - **CMake include 顺序有语义(踩坑)**:`nn_enable_gpu_fusion` 起初只把 `${NNF_OUT_DIR}` 加进目标,样例 GPU 初始化报 `matmul SPIR-V bytecode not embedded`——手写原语 shader 的嵌入头在 `${CMAKE_BINARY_DIR}/generated`;但该目录**同时含库自身的 `fused_registry.hpp`**。最终把两者都加、且 `${NNF_OUT_DIR}` **排在前面**(`__has_include` 取第一个匹配),否则使用者的自定义结构全部闭合世界报错。已写进 AGENTS §7。 -- **已注册为常驻 ctest(round 17)**:样例的目标原先只由默认构建覆盖编译(运行时断言需手工跑),会静默腐化。现已 `add_test(fusion_custom_layer_example)` + `SKIP_RETURN_CODE 77`(无 Vulkan 设备时跳过)——它是**库外使用者形态的 AOT 融合端到端门禁**。ctest 总数 19 → **20**(18 个测试目标 + `cnn_test_gpu` + 本样例;`AGENTS.md` §12 与 `docs/todo/12` 的当前数字已同步)。 +- **已注册为常驻 ctest(round 17)**:样例的目标原先只由默认构建覆盖编译(运行时断言需手工跑),会静默腐化。现已 `add_test(fusion_custom_layer_example)` + `SKIP_RETURN_CODE 77`(无 Vulkan 设备时跳过)——它是**库外使用者形态的 AOT 融合端到端门禁**。ctest 总数 19 → **20**(18 个测试目标 + `cnn_test_gpu` + 本样例;`AGENTS.md` §12 与 `docs/internal/12` 的当前数字已同步)。 ## AOT 融合分支代码审核与本轮修复(2026-10-01,round 20) @@ -240,7 +240,7 @@ expr_opt / expr_registry / expr_spec)「历史状态类注释」摘录。整 - **删除的死物**:`prec_manifest` 形参(回填工作流残留)、`ExprRegistry::contains`(无调用点)、`fusion_anchor_touch`(**实测删除后库外样例的 2 条自定义结构仍被锚点登记**——registry 84 → 86 不变,说明该 TU 靠"包含头文件"即可)、`std::exit(1)`(改 `return false`,与同函数其余错误路径一致)、`scan_exprs` 里重复 4 次的 matmul trans 登记(转置不进 key 后 4 份折叠成 1 条)、AGENTS 里 4 处有争议的 `ctest 19/19`。 - **简化/去重**:`glsl_vp_slot()` 取代 6 处逐字重复的"按视图序累计 vp 槽"(漂移 = 读写错位 push constant);`scan_register()` 取代 3 个 dsl 入口各写一遍的锚点+折叠+校验+登记;`is_fusable`/`fused_vec_width_for` 取代生成/发射/元数据三循环各写一遍的判据;`expr_variant_out_f16()` 取代 4 处"分派变体按运行期签名、其余按变体身份";f16 双 `float16_t()` 冗余转换删除;`EXPR_PREC_ALU_SUFFIX` 常量取代 3 处硬编码 `"#a"`;`tool_env_flag()` 取代两份 `_dupenv_s` 样板。 - **检测口径收紧**:`expr_prec_sig_in_f16` 先与 `EXPR_PREC_SIG_INPUT_MASK` 相与(否则哨兵 `0x00020000` 的 bit17 会被读成"第 17 个输入是 f16",改 `EXPR_MAX_INPUTS` 即踩雷);分发查询改用 `reg.keys` 而非重建集合;`--list-backends` 排序(铁律 8)。 -- **文档纠偏**(本轮统一):AGENTS §7/§12、`docs/todo/02/05/18`、`docs/usage/03` 中"运行期永不 miss""`[prec][miss]` 已删除""bin v9 变体段""`gen_fused` 产物""ctest 19""12040 次分派"等表述全部改写为当前事实;`docs/development/05` §12.7 改为**历史机制**(明确标注已删除),§12.10 ③ 标注为 V0 时代口径。 +- **文档纠偏**(本轮统一):AGENTS §7/§12、`docs/internal/02/05/18`、`docs/usage/03` 中"运行期永不 miss""`[prec][miss]` 已删除""bin v9 变体段""`gen_fused` 产物""ctest 19""12040 次分派"等表述全部改写为当前事实;`docs/development/05` §12.7 改为**历史机制**(明确标注已删除),§12.10 ③ 标注为 V0 时代口径。 - **验收(本机 Debug+Ninja+clang)**:build 零告警(`-Werror`);**ctest 21/21**;`NN_BIND_DEBUG=1 ctest` 全绿;**CPU 字节锚 `6f8849f14da23110` / GPU dev2 锚 `8ef51b2927253c50` 逐位不变**(GLSL 文本改动全部数值等价);库外样例端到端值不变(CPU f32 `0.6712035`、GPU f32 `0.6712036`、GPU f16 `0.6708984`、归一化 f16 `1.2246094`);`scan_exprs` 结构数 **84**(例 86)不变;`NN_PREC_TRACE` 分派日志 12040 → **6022**、distinct 仍 24(20 `#x` + 4 `#a`);`L2-VIOLATIONS: 0`、`doc_align_audit` A/D/E/F 可行动项 0。 - **教训**:这一轮 9 条真缺陷里有 4 条的形态是同一个——**同一份知识被写在两个地方、靠注释维持同步**(谓词 vs key、创建侧 vs 写入侧 PC 长度、f16 视图名 vs 子串替换、目标编译条件 vs 收集器)。"能简化的简化"在本仓的直接收益就是**消掉这些同步点**;剩下两条(trace 先打后查、测试假通过)则是"**测量/断言必须先证明它能失败**"的同一个教训的延续(round 15/19 已各记一次)。 @@ -523,7 +523,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## P-C2-7 / P0-5 计划项标签摘除(原位置 include/neuralnet.cpp/compute_layer_attention.hpp:392、440、697、742、791、810) - 类型:修复叙事 -- 内容:原注释多处带"(P-C2-7 正确性修复)""(P0-5:从 Q/K 重算 W…)""P-C2-7 起 m/l 也不缓存""(P-C2-7:旧 softmax.backward 分支不保留)"等计划项/修复标签。P0-5 在 docs 中无对应条目(悬空引用);P-C2-7 的演进叙事已完整记录于 `docs/todo/02-operator-fusion.md`(§关键算法状态横幅、§注意力 M6→S7→P-C2-7)。头文件注释改为直接陈述当前行为:forward 恒单 fold 路径、W/m/l/attn 均不缓存、`recompute_W_` 内部 softmax 单表达式归一化、反向走 R/X 路径。 +- 内容:原注释多处带"(P-C2-7 正确性修复)""(P0-5:从 Q/K 重算 W…)""P-C2-7 起 m/l 也不缓存""(P-C2-7:旧 softmax.backward 分支不保留)"等计划项/修复标签。P0-5 在 docs 中无对应条目(悬空引用);P-C2-7 的演进叙事已完整记录于 `docs/internal/02-operator-fusion.md`(§关键算法状态横幅、§注意力 M6→S7→P-C2-7)。头文件注释改为直接陈述当前行为:forward 恒单 fold 路径、W/m/l/attn 均不缓存、`recompute_W_` 内部 softmax 单表达式归一化、反向走 R/X 路径。 ## recompute_W_ 裸 matmul 的 dry-run 覆盖(原位置 include/neuralnet.cpp/compute_layer_attention.hpp:458) - 类型:bug 根因 @@ -575,7 +575,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ① `AttnScoreMask` 族(`PlainScoreMask` / `CausalScoreMask` / `CausalDocScoreMask`,**只做掩码**)——每种掩码语义一个类,各自实现类级常量 `mask_kind()`、`prepare()`、`append_fold_inputs()`、`masked_scores()`(反向 DSL 文本);由 `AttentionBase::make_score_mask_()` 在**配置期**(构造 / `set_doc_ids`)工厂化选定,forward/backward 各只做一次虚调用。文档掩码的"有/无"是运行期数据,其裁定落在 `set_doc_ids` 这一**配置调用**里(模式不变时零开销),不再是每步 forward 的判断。 **后续同一轮内又把 ALiBi 偏置从掩码策略里摘出去**:原 `CausalAlibiScoreMask` / `CausalAlibiDocScoreMask` 两个类把"掩码"和"位置偏置"融成同一条 select,掩码工厂因此必须查询 `pos_->has_score_bias()`。现在掩码族只保留三个纯掩码类,位置偏置由 `PositionEncoder::apply_score_bias()` 在 backward 的"掩码之后、softmax 之前"独立叠加(forward 仍融在同一个 fold kernel 内,由 `make_fold_attn_o` 的正交第二入参 `bool score_bias` 表达)。`expr::FoldAttnMask`(5 值融合枚举)随之改为 `expr::AttnMaskKind{Plain,Causal,CausalDoc}` + `bool score_bias`,`scan_exprs` 登记块改为 3×2 组合循环(跳过不存在的 "Plain + 偏置"),掩码策略类由 5 个降为 3 个。 ② `PositionEncoder` 族(新文件 `compute_position_encoding.hpp`)——`RotaryEmbedding` 从 attention 头迁出、由 `RopePositionEncoder` 持有;`use_rope_` 布尔消失,Q/K 旋转改走策略对象(非 RoPE 策略 = 恒等 no-op)。`PositionEncoder` 基类按**注入点**分三组(嵌入侧 `apply/apply_step/backward`、Q/K 侧 `apply_qk/apply_qk_step/set_position_offset`、分数侧 `has_score_bias/prepare_score_bias/apply_score_bias/apply_bias_step`),`Learned/Sinusoidal` 走嵌入侧、`RoPE` 走 Q/K 侧、`ALiBi` 走分数侧、`NoPositionEncoder` 恒等——各子类只覆写自己那组,其余继承基类 no-op。 - ③ **⚠ 拆开时踩到的坑(`row()` 的批内语义)**:ALiBi 的偏置项原来是 `batch_mod(slopes, H) * (col − row)`,`row()` 是"批内行号"、其分解来自**同一 ExprSpec 里的 matmul 段**(`MatmulSpec.batch`)——旧实现把它融在掩码表达式里,那个表达式恰好含 `dsl::matmul(..., BH)`,所以正确。拆成独立一步后 spec 里没有 matmul → batch 退化为 1 → `row()` 变**全局行号** → 偏置静默错值(探针实测 |偏置| 达 27,理论界 (seq−1)·m_0≈7),`attn_test` 的 alibi+doc gradcheck 立刻失败。修法:把 `(col − row)` 换成**`(rows,1)` 行表 + `dsl::row_broadcast`**(按全局行号直读,与网格分解无关)——`AlibiPositionEncoder::prepare_score_bias` 建两张 O(B·H·seq) 行表(每行斜率 `m_{h(row)}` 与批内位置 `row % seq`),`apply_score_bias` 用 `leaf(S) + rb(slope_row) * (col() − rb(pos_row))`。该坑已写进 `AGENTS.md` §7 的告警与 `docs/todo/02` §IR 扩展。 + ③ **⚠ 拆开时踩到的坑(`row()` 的批内语义)**:ALiBi 的偏置项原来是 `batch_mod(slopes, H) * (col − row)`,`row()` 是"批内行号"、其分解来自**同一 ExprSpec 里的 matmul 段**(`MatmulSpec.batch`)——旧实现把它融在掩码表达式里,那个表达式恰好含 `dsl::matmul(..., BH)`,所以正确。拆成独立一步后 spec 里没有 matmul → batch 退化为 1 → `row()` 变**全局行号** → 偏置静默错值(探针实测 |偏置| 达 27,理论界 (seq−1)·m_0≈7),`attn_test` 的 alibi+doc gradcheck 立刻失败。修法:把 `(col − row)` 换成**`(rows,1)` 行表 + `dsl::row_broadcast`**(按全局行号直读,与网格分解无关)——`AlibiPositionEncoder::prepare_score_bias` 建两张 O(B·H·seq) 行表(每行斜率 `m_{h(row)}` 与批内位置 `row % seq`),`apply_score_bias` 用 `leaf(S) + rb(slope_row) * (col() − rb(pos_row))`。该坑已写进 `AGENTS.md` §7 的告警与 `docs/internal/02` §IR 扩展。 ④ **所有权按注入点划分(谁拥有 = 谁负责)**:`PosEncodingType` 的分发收敛为两个工厂,同一策略类型只在一个工厂里实做、在另一个里映射为恒等—— · 模型侧 `make_embedding_position_encoder(type, d_model, seq_len)`(Learned/Sinusoidal 实做),由 `GPTModel`/`ZiPTModel`/`RAPTModel` 持有并在 `apply`/`apply_step` 里施加; · 注意力侧 `make_attention_position_encoder(type, d_k, num_heads)`(RoPE/ALiBi 实做),由 `CausalSelfAttention`/`ReLULinearAttention` **自持**(`AttentionBase::install_position_encoder`),在 `apply_qk`/`apply_score_bias` 上取数。 @@ -642,7 +642,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## 「文档 22」悬空引用(原位置 include/neuralnet.cpp/compute_layer_rapt.hpp:35、411) - 类型:删除清单(指向不存在文档的引用) -- 内容:注释引用「与原版 RLA 的关键差异(§3 文档 22)」「稳定数值分布…(文档 22 §4.3)」,但仓库内无"文档 22"编号;两处改指现存的 `docs/development/06-rapt-algorithm.md`(§3 家族演进即 RLA vs RLA-2 差异表,防神经元死亡 / RMSNorm 前置一并记录在该节)。RLA-2 与原版 RLA 的差异列表本身是当前算法定义,保留。 +- 内容:注释引用「与原版 RLA 的关键差异(§3 文档 22)」「稳定数值分布…(文档 22 §4.3)」,但仓库内无"文档 22"编号;两处改指现存的 `docs/development/08-rapt-algorithm.md`(§3 家族演进即 RLA vs RLA-2 差异表,防神经元死亡 / RMSNorm 前置一并记录在该节)。RLA-2 与原版 RLA 的差异列表本身是当前算法定义,保留。 ## "迁 dsl::…(原 engine.xxx)"与 dispatch 计数对照(原位置 conv.hpp:191、229、235、244、427;mlp.hpp:142;rapt.hpp:118、174、238-239、683、688-689、713-714、831-832、845、878-880) - 类型:迁移叙事 / 性能 A/B @@ -710,7 +710,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 GPU ctest 55/55(`NN_VULKAN_DEVICE=850M`);`layer_lifetime_test` 覆盖 EngineId 8B、Tensor 晚于引擎析构、Layer/Model/Optimizer 保活、跨引擎拒绝; `NN_GPU_LIFETIME_FULL=1` 额外验证 GpuBuffer 晚于 GpuEngine/backend 析构。 - 设计与迁移清单见 `docs/development/09-engine-ownership.md`。 + 设计与迁移清单见 `docs/development/07-engine-ownership.md`。 - **2026-10-18 发布前补漏:GPU f16 回退边界 cast 的 EngineId stamp**:`NN_BIND_DEBUG=1` 全量 GPU ctest 暴露 `f16_writeback_probe` / `f16_precision_test` / `rapt_test_f16_gpu` 三例失败,首个点位是 `ComputeEngine::cast` 的未绑定输入。根因是 GPU 引擎在无原生 f16 @@ -723,13 +723,13 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 - 类型:覆盖缺口 → 修复(构建期扫描补记) - 内容:`scan_exprs` 模式下的 CPU `end_expr` 只做了 `global_registry().add(k.spec)`(登记**结构** V0),没有登记**融合 kernel 的运行期精度签名**——单节点结构的签名由 `dsl::compute` 的 `scan_register` 与引擎 `eval_expr*` 入口按真实张量精度登记,而**融合结构只在 GPU 的 `end_expr` 执行时才算出签名**。后果:`--f16` 下复合结构只有 V0/`#s`/`#x` 三种载体 ⇒ ① 拿不到 `key#xxxx` 静态特化(回落带 `prec` 三元的 `#x`);② 拿不到 `key#xxxx#b` 批量变体(即便 `#b` 已对每个静态签名变体发射)。修法 = 在 scan 的 `end_expr` 里对 `members.size() > 1` 的 kernel 用**与运行期同源**的口径补记 `add_variant(k.spec, expr_prec_sig_make(输入张量 f16 位图, k.prec == F16))`(等价于运行期 `expr_prec_sig_of(d.ins, out.precision())`;内部依赖输入未绑定张量 → 该槽按 f32 记,纯逐元素复合的成员引用经寄存器直替、不进 views,故正常构图下每槽都是外部输入)。生效后 Adam 复合结构拿到 `#10004` + `#10004#b`;实测(40HX/f16/b64/20 步,配对 `329f8f1` vs `5bb6a51`):`[ir-c][degrade]` 70 → 0/步、优化器派发 138.7 → 8.55 calls/步(−94%)、优化器 host 阶段 −34%,但端到端墙钟在 GPU-bound(忙率 95.5%)下无可见收益。**边界**:只覆盖 scan 真跑过的 profile(f32 + `--f16`),其它显式组合仍按设计回落降级(构建期 2^4 精度枚举不可取)。 -## 代码审查整改批 RV-06/09/10/11/13 与 CI 真跑测试(2026-10-12;证据坐标 docs/todo/00-code-review-remediation.md) +## 代码审查整改批 RV-06/09/10/11/13 与 CI 真跑测试(2026-10-12;证据坐标 docs/internal/00-code-review-remediation.md) - 类型:bug 根因 + 结构收敛 + 门禁 - 内容:① **RV-06 前置去红**:`NN_BIND_DEBUG=1 ctest` 原为红(`t1_58_test` / `ternary_gemm_test` / `model_roles_test` 三例在 `cast` 处报 "unbound input into engine")——根因是 `matmul_q_impl`(CPU 与 GPU 两份)在边界 cast 回退里:CPU 递归调用 impl 后、GPU 用静态工厂 `Tensor::from_gpu` 造输出后,都直接调**公共** `cast`(内含 `bind_check_`)而产物尚未 stamp。两处改为 `cast(adopt(std::move(x)), P)`(`adopt` = 基类 protected 的库内 stamp 通道,与 M6 的 `to_prec` 修法同款);本机 Release+CPU `NN_BIND_DEBUG=1 ctest` 由 37/40 转 **40/40**。CI 侧新增一轮 `NN_BIND_DEBUG=1 ctest` 作为默认门禁。② **RV-09**:环境变量读取收敛到新 `core_env.hpp`(`nn::detail::{env_flag_raw,env_string_raw,env_int_raw}` + 探针门包装;`getenv`/`_dupenv_s` 只此一处、探针门关时恒 false 且不求值);`dsl::env_flag` 的"任意非空即真"一并对齐为"0 = 关"。③ **RV-10**:BitLinear `quantize_weights_` 与 `ternary_pack::code_of` 的判据注释精确化(严格 `|W|>0.5τ`、半值归零;与 `RoundClip` 的唯一差异在等值点),不改算法。④ **RV-11**:`precision.hpp` 加 `static_assert` 冻结"枚举值 ↔ 序列化 tag"两张映射 + `precision_from_tag(precision_tag(p))==p` 往返(改一处即编译失败)。⑤ **RV-13**:`nn::Expression` / `nn::BoolExpression` 概念从 `expr_dsl.hpp` 移到 L1 的 `algebra_span.hpp`(`expr_dsl` 经 `algebra_matrix → algebra_span` 传递可见)。另(roadmap P0-1):CI 配置加 `-DNN_ENABLE_TESTS=ON` 并在 Linux/Windows 各跑 `ctest --output-on-failure`,打包补齐 `dataset_gen`/`dataset_convert`(应用入口 6 → 8)。**仍 Open**:RV-05、RV-07、RV-08、RV-12、RV-14(RV-05/14 需 GPU 提权环境;RV-07/08 为需单独提交并逐步过三件套的重构;RV-12 仅设计评估)。 - GPU 实测补充(2026-10-12,NVIDIA CMP 40HX @ ethan@192.168.1.102,Windows + clang++,Debug,GPU 启用):`ctest` **42/42**、`NN_BIND_DEBUG=1 ctest` **42/42**(全部 GPU 用例真跑、零 skip)。同批带出的 Windows 可移植性缺陷:`src/assert_always_test.cpp` 的裸 `std::fopen` 在 clang++ + MSVC STL + `-Werror` 下编译失败(正是 CI 的 Windows 配置,此前不编测试故未暴露)→ 改 `_MSC_VER` 下 `fopen_s`。 -## 代码审查整改批 RV-07/RV-08:算子分派收敛 + VK 后端拆分(2026-10-12;证据坐标 docs/todo/00-code-review-remediation.md) +## 代码审查整改批 RV-07/RV-08:算子分派收敛 + VK 后端拆分(2026-10-12;证据坐标 docs/internal/00-code-review-remediation.md) - 类型:结构收敛(纯重构,零行为变化) - 内容:① **RV-07**:同一个 `ExprOp` 的分派原先散在约 9 处(CPU 引擎 3 处 switch + `expr_spec` 语义校验 + `expr_opt` 常量折叠 + GLSL emitter 6 处)。新增 `expr_op_table.hpp` 作**唯一真源**——以 `nn::ops::*::apply` 为 CPU 语义,每算子一行元数据(元数 / 归约标志 / 可折叠 / 一元·二元标量函数指针 / GLSL 发射形态 + 符号 + 向量比较内建名),末尾 `consteval` 断言强制与 `expr_spec` 的 `expr_instr_num_operands`/`expr_op_is_reduce`/`expr_op_reduces_cols` 逐项一致。CPU 三处 switch、`expr_eval_const_fold` switch、emitter 的 `glsl_binary_op`/`glsl_unary_op` 与 6 处指令发射块全部改为查表(新增 `glsl_alu_expr` 单一发射器,`b`/`c` 惰性回调)。**新增一个逐元素算子只需表里一行**。② **RV-08**:42 个 `get_*_spirv()` 的手写 `#ifdef` 函数体 + 42 个 `#define NN_*_SPV_EMBEDDED` 删除,改为文件头探测块把字节码函数绑到 `NN_SPV_FN_` + `NN_SPV_GETTER_LIST` X 宏一次展开(新增 shader 只改探测块与列表各一处,调用点零改)。`GpuBackend`(成员体 ~5375 行)拆为 4 个**片段**文件 `backend/compute_vk_backend_{destroy,frame,pipelines,ops}.inc`,由主文件在 class 体内**按序** `#include`(片段不可单独编译)——主文件 6397 → **1055 行**。 - 验收:CPU `ctest` 40/40;**融合 shader 字节锚**用「RV-07 前 / 后」两侧源码各编 `scan_exprs` 生成后 `diff -rq` → 805 个产物(`fused_registry.hpp` + 402 组 `.comp`/`.spv`)**零差异**;拆分的正确性用脚本比对「主文件头 + 4 片段 + 尾」与拆分前文件**逐行相同**;40HX(102)全量构建 + `ctest` **42/42**、`NN_BIND_DEBUG=1 ctest` **42/42**;`bench/doc_inventory.ps1`(`L2-VIOLATIONS: 0`/`HANDWRITTEN-RESIDUE: 0`)与 `bench/doc_align_audit.ps1` 均 exit 0。**仍 Open**:RV-05、RV-12、RV-14。 @@ -761,7 +761,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## CE 稀疏/稠密路径引用已删除原语(原位置 include/neuralnet.cpp/compute_loss.hpp:274、277、332) - 类型:删除清单 -- 内容:注释曾引用 `col_softmax_denom`、`col_softmax_sparse_forward`(M5 期 op-level 原语,已随 S7 删除,见 docs/todo/02 §"S7 删除 M4-M6")以及"融合原语不可用(如 CUDA 未对齐返回未实现)"的 CUDA 例子(CUDA 后端已整体移除)。当前实现为 S7 IR 组合(col_max 原语 + denom/loss_vec/grad 表达式);labels 以 (1,total) 浮点打包,前置条件 vocab_size ≤ 2^24,失败直接透传错误。整改后注释改为当前结构 + 当前前置条件。 +- 内容:注释曾引用 `col_softmax_denom`、`col_softmax_sparse_forward`(M5 期 op-level 原语,已随 S7 删除,见 docs/internal/02 §"S7 删除 M4-M6")以及"融合原语不可用(如 CUDA 未对齐返回未实现)"的 CUDA 例子(CUDA 后端已整体移除)。当前实现为 S7 IR 组合(col_max 原语 + denom/loss_vec/grad 表达式);labels 以 (1,total) 浮点打包,前置条件 vocab_size ≤ 2^24,失败直接透传错误。整改后注释改为当前结构 + 当前前置条件。 ## CpuEngine::matmul_with_bias 覆盖前的 GPU host 往返(原位置 include/neuralnet.cpp/compute_cpu_engine.hpp:673) - 类型:bug 根因 / 性能 A/B @@ -805,24 +805,24 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## 统一总纲 M1:Tensor 访问收口——存储私有化 + reshape 引擎化 + 库外全迁(2026-09-30,原位置 compute_tensor.hpp 公共面、compute_engine.hpp 新增 reshape、expr_dsl.hpp 求值出口、model_serialization.hpp save f16 分支、src 9 测试文件 + text_train.cpp:756 + tools/scan_exprs.cpp) - 类型:演进记录 / 性能 A/B -- 内容:M1(方案见 docs/todo/17 §4.1/§5 M1 行;commits `3d76478` 库外全迁、`c8f308f` 访问收口)分两段落地。① **私有化**:`Tensor` 的静态直构工厂(`from_matrix`×2/`cpu`×3/`cpu_uninitialized`/`from_gpu`×2)、存储构造、访问器(`cpu_matrix`×2/`cpu_shared`/`gpu_tensor`×2/`gpu_shared`)、`reshape` 全部转 private;friend 集 = `ComputeEngine/CpuEngine/GpuEngine` + 新增 `detail::TensorAccess`(前向声明于文件头、定义于尾部;`nn::dsl` 内 `using TensorAccess` 别名,eval_cpu 出口/扫描占位/求值叶子共 **19 处**改道)。公共面收敛为形状/精度/设备查询、`bound()/engine()`、`valid()`、`shape_str()`——绕过引擎 = 编译错误(铁律 #11 新立于 AGENTS §5)。② **`ComputeEngine::reshape`(D10)**:`bind_check_` + `stamp_` + 元素数不匹配返回 Result 错误(原 NN_ASSERT 升级);`Tensor::reshape` 实现保留为私有成员供引擎调用(逻辑零搬移)。③ **库外全迁(D7,不留过渡期)**:`test_common.hpp` 新增 `upload/download` 助手(Result 失败 NN_ASSERT 兜底),`make_tensor`(48 调用点)/`check_close`(18 调用点)签名加 engine 首参;9 个测试文件读路径一律 download 值接收(防 `auto&` 悬垂)、写路径一律"本地 Matrix 写好 → upload 回传"(rng 消耗顺序逐位保持,断言/容差/打印原字节);`fused_gpu_test` 双引擎对拍 32 个输入张量 cpu/gpu 各上传一份(出生绑定检查下跨引擎喂食 = 硬错误,逼出拆分);`text_train.cpp:756` CPU/GPU 分支合一走 `engine.to_matrix`;`scan_exprs.cpp` 的 `scan_tensor` 收编为 dry_run lambda 内 `engine.create_tensor(rows,cols,g_scan_prof.compute)`(60 处调用点零改动,出生绑定与 dry-run 引擎一致)。④ **model_serialization save_model f16 分支**:CPU 直读 `cpu_matrix` 删除,CPU/GPU 统一经 `engine.to_matrix` 下载再转 f16 落盘(f16→f32→f16 往返精确,v5 字节不变)。⑤ `tensor_precision_test` 按引擎 I/O 重写:`cpu_shared` 别名断言随私有化取消(无公共等价物)、新增 reshape 元素数不匹配拒绝用例。**教训**:旧审计 pattern `cpu_matrix\s*\(` 漏掉**模板形态** `cpu_matrix()`——`model_serialization.hpp:550` 即此形态漏网,审计须用裸词 `\.cpu_matrix`。**验收**(本机 Debug+Ninja+clang):build 122/122;ctest 20/20;`gpu_stability_probe --steps 20` hash=`6f8849f14da23110` 与 M1 前基线**逐位一致**;scan 双 hash 不变(`expr_specs.bin`=bdc3a442…a58360、`fused_registry.hpp`=7a10412c…);库外 grep 旧 API 零命中(编译期强制成立)。**性能 A/B(配对裁决)**:首轮 --all 单点对拍显 feedforward fwd/train +6~7%——但基线采集期并发了子代理语法编译且为单样本;按配对方法重建 pre-M1 对照二进制(git worktree @ HEAD~2 独立构建 layer_bench),feedforward/swiglu/linear 各 4 轮 pre/post 交错:**分布重叠、方向混合**(feedforward train 中位 3229.7ms vs 3228.3ms,swiglu train 均值 10.28 vs 10.46,linear 落在彼此散布内),无系统性回退;附带实测本机 Debug layer_bench 单点 run-to-run 摆动可达 ±25%(linear fwd 0.537~0.860ms),单点不可裁决——机制上 M1 只动冷路径与调用点层(`cpu_get_ptr` 热循环零变化)。四子代理并行迁移 + 主线统一构建的分工可行(子代理仅做 `-fsyntax-only` 与 %TEMP% 单 TU 运行,不碰 cmake)。 +- 内容:M1(方案见 docs/internal/17 §4.1/§5 M1 行;commits `3d76478` 库外全迁、`c8f308f` 访问收口)分两段落地。① **私有化**:`Tensor` 的静态直构工厂(`from_matrix`×2/`cpu`×3/`cpu_uninitialized`/`from_gpu`×2)、存储构造、访问器(`cpu_matrix`×2/`cpu_shared`/`gpu_tensor`×2/`gpu_shared`)、`reshape` 全部转 private;friend 集 = `ComputeEngine/CpuEngine/GpuEngine` + 新增 `detail::TensorAccess`(前向声明于文件头、定义于尾部;`nn::dsl` 内 `using TensorAccess` 别名,eval_cpu 出口/扫描占位/求值叶子共 **19 处**改道)。公共面收敛为形状/精度/设备查询、`bound()/engine()`、`valid()`、`shape_str()`——绕过引擎 = 编译错误(铁律 #11 新立于 AGENTS §5)。② **`ComputeEngine::reshape`(D10)**:`bind_check_` + `stamp_` + 元素数不匹配返回 Result 错误(原 NN_ASSERT 升级);`Tensor::reshape` 实现保留为私有成员供引擎调用(逻辑零搬移)。③ **库外全迁(D7,不留过渡期)**:`test_common.hpp` 新增 `upload/download` 助手(Result 失败 NN_ASSERT 兜底),`make_tensor`(48 调用点)/`check_close`(18 调用点)签名加 engine 首参;9 个测试文件读路径一律 download 值接收(防 `auto&` 悬垂)、写路径一律"本地 Matrix 写好 → upload 回传"(rng 消耗顺序逐位保持,断言/容差/打印原字节);`fused_gpu_test` 双引擎对拍 32 个输入张量 cpu/gpu 各上传一份(出生绑定检查下跨引擎喂食 = 硬错误,逼出拆分);`text_train.cpp:756` CPU/GPU 分支合一走 `engine.to_matrix`;`scan_exprs.cpp` 的 `scan_tensor` 收编为 dry_run lambda 内 `engine.create_tensor(rows,cols,g_scan_prof.compute)`(60 处调用点零改动,出生绑定与 dry-run 引擎一致)。④ **model_serialization save_model f16 分支**:CPU 直读 `cpu_matrix` 删除,CPU/GPU 统一经 `engine.to_matrix` 下载再转 f16 落盘(f16→f32→f16 往返精确,v5 字节不变)。⑤ `tensor_precision_test` 按引擎 I/O 重写:`cpu_shared` 别名断言随私有化取消(无公共等价物)、新增 reshape 元素数不匹配拒绝用例。**教训**:旧审计 pattern `cpu_matrix\s*\(` 漏掉**模板形态** `cpu_matrix()`——`model_serialization.hpp:550` 即此形态漏网,审计须用裸词 `\.cpu_matrix`。**验收**(本机 Debug+Ninja+clang):build 122/122;ctest 20/20;`gpu_stability_probe --steps 20` hash=`6f8849f14da23110` 与 M1 前基线**逐位一致**;scan 双 hash 不变(`expr_specs.bin`=bdc3a442…a58360、`fused_registry.hpp`=7a10412c…);库外 grep 旧 API 零命中(编译期强制成立)。**性能 A/B(配对裁决)**:首轮 --all 单点对拍显 feedforward fwd/train +6~7%——但基线采集期并发了子代理语法编译且为单样本;按配对方法重建 pre-M1 对照二进制(git worktree @ HEAD~2 独立构建 layer_bench),feedforward/swiglu/linear 各 4 轮 pre/post 交错:**分布重叠、方向混合**(feedforward train 中位 3229.7ms vs 3228.3ms,swiglu train 均值 10.28 vs 10.46,linear 落在彼此散布内),无系统性回退;附带实测本机 Debug layer_bench 单点 run-to-run 摆动可达 ±25%(linear fwd 0.537~0.860ms),单点不可裁决——机制上 M1 只动冷路径与调用点层(`cpu_get_ptr` 热循环零变化)。四子代理并行迁移 + 主线统一构建的分工可行(子代理仅做 `-fsyntax-only` 与 %TEMP% 单 TU 运行,不碰 cmake)。 ## 统一总纲 M2:声明式初始化——InitSpec + Layer::init 迁移 + RNG 收编(2026-09-30,原位置 compute_engine.hpp 张量工厂区、compute_layer_{mlp,conv,gpt,zipt,rapt,transformer}.hpp 的 init 函数、src/gpu_stability_probe.cpp) - 类型:演进记录 / 性能 A/B -- 内容:M2(方案见 docs/todo/17 §4.4/§5 M2 行)分三段落地(commits `8bd6bd5` 核心、`4492098` 层迁移、文档段随后)。① **`InitSpec` + 四参 `create_tensor`**(compute_engine.hpp):`Kind{Uninitialized,Zero,Constant,Uniform,Normal}` + 工厂(分布类 **seed 必填** = U1 裁定,层传 `kInitSeed=42`);四参 `create_tensor(rows,cols,P,spec)` 为公共非虚 NVI——Zero/Uninitialized 走既有 `create_tensor_impl`(Zero 另补 `zero()`),分布类 = 引擎内 host 生成后 `from_matrix` 上传(D6 策略调用方不可见):`fill_host_` 用 mt19937_64,种子 = splitmix64(spec.seed × 引擎内创建序号 `init_seq_` 混流)——**同 seed 不同张量不撞流**(否则 GPT 同形状多层 Linear/注意力投影会互为镜像);3 参 `create_tensor` 保持既有纯分配语义不动作(初值要什么显式走 InitSpec,零仍可显式 `zero`)。② **Layer::init 全迁**(6 头文件 25 处):Linear/Conv2D 权重 `uniform(-limit,limit)`(层算 limit、引擎填数)、bias/梯度缓冲 `zero`、LayerNorm `gamma=1/beta=0`、RMSNorm `gamma=1`、GPT/ZiPT/RAPT token_emb `normal(0,0.02)`、LearnedPositionEncoder `normal(0,0.02)`(`AdditivePositionEncoder::init_` 入参 Matrix→Tensor,Sinusoidal 公式路径改走 `from_matrix`)、CrossAttention 记忆查询 P `uniform`、TransformerEncoder `ones_row_` `constant(1)`;mlp/conv 的 `thread_local rng_` 删除、init 侧 `random_device` 清零。**精度口径逐点保持**:conv/zipt/rapt 原 `from_matrix` 默认 F32 → create_tensor 显式 F32,gpt/norm 原 `p_.param` 照传——不借机改 profile。③ **裁定不迁(运行期随机性,17 §1 表已注)**:`generate()` 采样 RNG(gpt:954/zipt:1041/rapt:1461)、`text_train.cpp:1270` 数据洗牌 RNG——均非 init。④ **探针新增 `--init-hash` 模式**(gpu_stability_probe):6 类模型(mnist_mlp/cnn/mnist_transformer/gpt/zipt/rapt)建后即哈希(不覆写),输出 `INIT1/INIT2` 固定前缀行供跨进程 diff;默认模式头注释更新——init 已确定性化后,覆写保留是为了**隔离 init 变量**、只测后端执行确定性。 +- 内容:M2(方案见 docs/internal/17 §4.4/§5 M2 行)分三段落地(commits `8bd6bd5` 核心、`4492098` 层迁移、文档段随后)。① **`InitSpec` + 四参 `create_tensor`**(compute_engine.hpp):`Kind{Uninitialized,Zero,Constant,Uniform,Normal}` + 工厂(分布类 **seed 必填** = U1 裁定,层传 `kInitSeed=42`);四参 `create_tensor(rows,cols,P,spec)` 为公共非虚 NVI——Zero/Uninitialized 走既有 `create_tensor_impl`(Zero 另补 `zero()`),分布类 = 引擎内 host 生成后 `from_matrix` 上传(D6 策略调用方不可见):`fill_host_` 用 mt19937_64,种子 = splitmix64(spec.seed × 引擎内创建序号 `init_seq_` 混流)——**同 seed 不同张量不撞流**(否则 GPT 同形状多层 Linear/注意力投影会互为镜像);3 参 `create_tensor` 保持既有纯分配语义不动作(初值要什么显式走 InitSpec,零仍可显式 `zero`)。② **Layer::init 全迁**(6 头文件 25 处):Linear/Conv2D 权重 `uniform(-limit,limit)`(层算 limit、引擎填数)、bias/梯度缓冲 `zero`、LayerNorm `gamma=1/beta=0`、RMSNorm `gamma=1`、GPT/ZiPT/RAPT token_emb `normal(0,0.02)`、LearnedPositionEncoder `normal(0,0.02)`(`AdditivePositionEncoder::init_` 入参 Matrix→Tensor,Sinusoidal 公式路径改走 `from_matrix`)、CrossAttention 记忆查询 P `uniform`、TransformerEncoder `ones_row_` `constant(1)`;mlp/conv 的 `thread_local rng_` 删除、init 侧 `random_device` 清零。**精度口径逐点保持**:conv/zipt/rapt 原 `from_matrix` 默认 F32 → create_tensor 显式 F32,gpt/norm 原 `p_.param` 照传——不借机改 profile。③ **裁定不迁(运行期随机性,17 §1 表已注)**:`generate()` 采样 RNG(gpt:954/zipt:1041/rapt:1461)、`text_train.cpp:1270` 数据洗牌 RNG——均非 init。④ **探针新增 `--init-hash` 模式**(gpu_stability_probe):6 类模型(mnist_mlp/cnn/mnist_transformer/gpt/zipt/rapt)建后即哈希(不覆写),输出 `INIT1/INIT2` 固定前缀行供跨进程 diff;默认模式头注释更新——init 已确定性化后,覆写保留是为了**隔离 init 变量**、只测后端执行确定性。 - **计划内字节变化(17 §6 例外,新锚已立)**:原 random_device 播种站点与 seed-42 站点的 RNG 流(改引擎序号派生)字节全变。新锚(2026-09-30,两次独立进程逐字节):`gpu_stability_probe --init-hash` 六模型 hash = mnist_mlp `a22e807ee05ec3ac` / cnn `4020958a14160bbd` / mnist_transformer `04a72d865624042a` / gpt `8efa936ac5c8c9b2` / zipt `f90bf8c8783c2f89` / rapt `b037632f75b7159c`;`mnist_train` 三架构(`--epochs 1 --max-samples 512 --batch-size 64 --shuffle-steps false`)双进程 loss 序列 + 模型文件逐字节一致(模型 SHA256:mlp `B596BB19…85A1`、cnn `19A29E0B…6FE7`、transformer `5D533039…2ADA`,仅墙钟行不同)。**反例定位**:`text_train` 双跑 loss 不等(9.0546 vs 9.0566)→ 根因 `text_train.cpp:1270` `mt19937_64{random_device{}()}` 数据洗牌——M2 前即存在、与 init 无关(init 已确定性后它成为 text_train 跨进程差异的唯一来源),范围外未修;要 text_train 全链路复现需另立 --seed 类开关。 - **验收**(本机 Debug+Ninja+clang):build 122/122 零告警;ctest 20/20;`gpu_stability_probe --steps 20` hash=`6f8849f14da23110` **与 M1 锚点逐位一致**(该探针覆写 init,证明后端执行路径零变化);scan 双 hash 不变(`expr_specs.bin`=bdc3a442…a58360、`fused_registry.hpp`=7a10412c…);`--init-hash` 两进程 `INIT1` 行全同 + 进程内两轮 PASS;`NN_BIND_DEBUG=1` mnist 冒烟零诊断。**性能 A/B(配对 + 逆序复测)**:pre 基线 = git worktree @ M1 HEAD(735594d)独立构建 layer_bench,同窗交错;feedforward 正序 4 轮 fwd/train POST 中位 +3.0%/+2.9%,**逆序 4 轮(POST 先跑)复测差异依旧**(+3.1%/+3.5%)→ 排除运行顺序热偏置,为 Debug(-O0) 二进制重排/内联漂移级小差(M2 未改动任何热路径语义,init 仅建模时执行一次);swiglu fwd/train ±2% 分布重叠;linear 分布交叉重叠(已知单点 ±25% 方差,M1 记录在案)。全部 < ±6% 验收带,**无系统性回退**。 ## 统一总纲 M3:批量读写 API——read/write/get_index/set_index 落地 I/O 分组(2026-09-30,原位置 compute_engine.hpp I/O 分组区、src 10 个 gradcheck/一致性测试文件、src/gpu_stability_probe.cpp) - 类型:演进记录 / 附带缺陷修复 -- 内容:M3(方案见 docs/todo/17 §4.3 D3/D9、U2;commits `e0338d9` 核心、`4977a29` 探针、`3ddb13c` 测试迁移)分三段落地。① **`compute_engine.hpp` I/O 分组区**:`from_matrix/to_matrix/read/write/get_index/set_index` 六动词同组成文(D9:保留 `from_matrix/to_matrix` 原名,15 P2 的 `to_host/from_host` 改名随之取消);新增 **基类非虚模板** `read(const Tensor&, span)` / `write(Tensor&, span)`(不进 49 virtual 骨架)——`read` 统一经 `to_matrix`(GPU 分支自带 `end_batch`→`wait_in_flight`→新帧,即"隐含 flush+同步"),`write` 宿主直写既有存储、GPU 走 `copy_from` 既有 drain 语义(F16 目标 = f32 上传 + `cast_into` 写回原存储),二者都**覆盖既有存储、不替换对象**(沿 `copy_into` 红线);`get_index/set_index` 为语法糖(宿主直读写零往返,GPU = 整张批量往返,明确不给热循环承诺)。② **U2 精确匹配**:span 元素类型须与 `t.precision()` 严格一致(`float`↔F32、`nn::f16`↔F16)——元素类型非 float/f16 或 `read` 的 T 为 const = `static_assert` 编译期报错,精度错配/元素数不符/越界 = `Result` 运行期错误;`write` 形参用 `span` 而非 `span`(模板实参推导中 `const T` 无法匹配非 const span,推导失败),静态断言按去 cv 后元素类型校验。`read` 对 f16 存储升 f32 后按 T 落回(RHE,往返位不变)。③ **调用约定成文**(17 §7-1/§7-4、铁律 #6):read 隐含 flush、写入张量须存活到 `end_batch()` 之后;逐 step loss 回读继续走 `submit_scalar_readback` 快路。④ **测试迁移**(10 文件):gradcheck 扰动-恢复、CPU→GPU 权重同步等 **f32 路径 `copy_from` → `write`**;f16 专项(`f16_cpu_probe`/`f16_precision_test`/`f16_writeback_probe`)**保留 `copy_from`**——其语义就是 f32 Matrix → f16 的转换填充(RHE),正是 U2 精确匹配下 `write` 不承担的转换入口,故两动词分工成文而非并吞。 +- 内容:M3(方案见 docs/internal/17 §4.3 D3/D9、U2;commits `e0338d9` 核心、`4977a29` 探针、`3ddb13c` 测试迁移)分三段落地。① **`compute_engine.hpp` I/O 分组区**:`from_matrix/to_matrix/read/write/get_index/set_index` 六动词同组成文(D9:保留 `from_matrix/to_matrix` 原名,15 P2 的 `to_host/from_host` 改名随之取消);新增 **基类非虚模板** `read(const Tensor&, span)` / `write(Tensor&, span)`(不进 49 virtual 骨架)——`read` 统一经 `to_matrix`(GPU 分支自带 `end_batch`→`wait_in_flight`→新帧,即"隐含 flush+同步"),`write` 宿主直写既有存储、GPU 走 `copy_from` 既有 drain 语义(F16 目标 = f32 上传 + `cast_into` 写回原存储),二者都**覆盖既有存储、不替换对象**(沿 `copy_into` 红线);`get_index/set_index` 为语法糖(宿主直读写零往返,GPU = 整张批量往返,明确不给热循环承诺)。② **U2 精确匹配**:span 元素类型须与 `t.precision()` 严格一致(`float`↔F32、`nn::f16`↔F16)——元素类型非 float/f16 或 `read` 的 T 为 const = `static_assert` 编译期报错,精度错配/元素数不符/越界 = `Result` 运行期错误;`write` 形参用 `span` 而非 `span`(模板实参推导中 `const T` 无法匹配非 const span,推导失败),静态断言按去 cv 后元素类型校验。`read` 对 f16 存储升 f32 后按 T 落回(RHE,往返位不变)。③ **调用约定成文**(17 §7-1/§7-4、铁律 #6):read 隐含 flush、写入张量须存活到 `end_batch()` 之后;逐 step loss 回读继续走 `submit_scalar_readback` 快路。④ **测试迁移**(10 文件):gradcheck 扰动-恢复、CPU→GPU 权重同步等 **f32 路径 `copy_from` → `write`**;f16 专项(`f16_cpu_probe`/`f16_precision_test`/`f16_writeback_probe`)**保留 `copy_from`**——其语义就是 f32 Matrix → f16 的转换填充(RHE),正是 U2 精确匹配下 `write` 不承担的转换入口,故两动词分工成文而非并吞。 - **附带缺陷修复(16 §7-2 根因,P0 遗留未决项收口)**:`gpu_stability_probe` GPU 模式首个 `vkCreateBuffer` 即 "Invalid device" 崩溃——根因 = `GpuBackend::instance()` 只是惰性单例,Vulkan 设备须显式 `backend.initialize()` 才建立,探针 `make_engine` 漏调(`cli_engine_factory` 与全部 GPU 测试入口都会调它,这正是 16 §7-2 当时记的"差异在探针路径"那一处),首个 buffer 拿到 VK_NULL_HANDLE 即崩。修复 = 探针建引擎前补 `initialize()`(空 selector 仍按 显式 > `NN_VULKAN_DEVICE` > 自动打分 选卡)。修复后 GPU 档位首次可测:Windows 本机 **dev2 `8ef51b2927253c50`、dev0 `47977edc71a21a20`、dev4 `01b7192bd15a59d9`** 进程内两轮 + 跨进程两次启动 loss/hash **逐字节一致** → D9 的 GPU 验收档位在本机坐实为**逐字节**;dev1(MESA/D3D12 转译)初始化即报 DXIL container 校验错误、exit=2,为设备级不可用(非探针/库问题,另记)。 - **探针新增 `--io-roundtrip` 模式**(M3 专属验收,GPU 模式即 staging 验收):三用例 = `f32_roundtrip`(写后读回 + `read` vs `to_matrix` 交叉对拍)、`f16_roundtrip`(f16 精确匹配与 RHE 往返)、`batch_window`(铁律 #6:录制窗口内 write → read → `end_batch` → 复读值不变),另覆盖索引往返、越界、U2 错配错误路径;输出 `RESULT io_cases=3 io_failures=0 verdict=PASS`。 - **验收**(本机 Debug+Ninja+clang):build 全绿零告警;ctest 20/20;`--io-roundtrip` CPU + GPU(dev2)三用例全 PASS;`gpu_stability_probe --steps 20` hash=`6f8849f14da23110` **与 M1/M2 锚点逐位一致**(I/O 组为纯新增、未动任何计算路径);scan 双 hash 不变(`expr_specs.bin`=bdc3a442…a58360、`fused_registry.hpp`=7a10412c…)。 ## 统一总纲 M4:Matrix 降级收口——L2+ 禁用 + span 宿主桥 + 分层审计(2026-09-30,原位置 compute_layer_{attention,base,conv,gpt,rapt,transformer,zipt}.hpp、compute_loss.hpp、compute_optimizer.hpp、compute_engine.hpp 尾部、bench/doc_inventory.ps1) - 类型:演进记录 / 新增裁定(D11、U5) -- 内容:M4(方案见 docs/todo/17 §4.6、§5 M4 行)分四段落地。 +- 内容:M4(方案见 docs/internal/17 §4.6、§5 M4 行)分四段落地。 ① **先立审计再迁移(编译器/grep 驱动)**:`bench/doc_inventory.ps1` 新增第 [4] 节——它本就枚举 L2 文件集(`compute_layer*.hpp` + `compute_loss.hpp` + `compute_optimizer.hpp` + `model_container.hpp`),逐行剥离 `//` 与块注释(行内状态机处理跨行注释)后匹配三类:`Matrix`/`MatrixT` 类型(**硬**)、`from_matrix/to_matrix/copy_from`(**硬**,签名即含 Matrix)、宿主桥动词(**披露**,只计数不判违规);末行输出 `L2-VIOLATIONS: N`(验收口径 0)。**首跑违规模基线 = 77 条(32 处 `Matrix` 类型 + 45 处 Matrix 型 I/O 动词),分布在 10 个头文件**。 ② **D11 裁定(新增到 17 §3,10 项 → 11 项)**:17 §4.3 原字面"from_matrix/to_matrix/read/write 只准出现在 I/O/测试代码"在 L2 上**不可执行**——层确实需要生成索引/位置/掩码类辅助数据,而引擎没有 arange / RoPE 表 / 斜率表这类生成原语(要严格执行得先加原语,超 M4 范围)。裁定把禁令本体收窄为**`Matrix` 类型**(数据格式统一的可审计判据):Matrix 型三动词随之在 L2 全禁,span/标量级作为受控宿主桥保留(判据 = 不引入 Matrix 即不破坏统一),大批量 I/O 仍归 I/O 层。U5 同时裁定:审计落点 = 扩展 `doc_inventory.ps1`,不另建脚本。 ③ **宿主桥三个自由函数**(`compute_engine.hpp` 尾部 `namespace detail`,0 虚表项、0 新原语):`upload_span(engine, rows, cols, P, span) -> Result`(= `from_matrix` 的 span 形态;f16 目标按 `f16{float}` RHE,与 CPU `from_matrix_impl` 的 `dst[i] = src[i]` 同一条舍入路径)、`download_span(engine, t, span)`(= `to_matrix(t, F32)`:f16 存储先升 f32 再落,升 cast 精确无损)、`download_vector(engine, t)`(取值便捷形态)。三者内部只调 M3 的批量 `write/read`(GPU staging、隐含 flush 照旧),不进 49 virtual 骨架。 @@ -831,14 +831,14 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 - **验收**(本机 Debug+Ninja+clang):① **审计零违规**:`L2-VIOLATIONS: 0`,`host_bridge_uses: 41`(披露);② build 122/122 零告警;③ ctest 20/20;④ **字节零变化**(迁移是纯载体替换:`Matrix(rows,cols)` 与 `std::vector(n)` 同为零填充、行主序 flat 下标 = `at_unchecked(r,c)`、f16 转换同一条 RHE 路径)——CPU `--steps 20` hash=`6f8849f14da23110`、GPU dev2 `8ef51b2927253c50` **均与迁移前逐位一致**;⑤ scan 双 hash 不变(`expr_specs.bin`=bdc3a442…a58360、`fused_registry.hpp`=7a10412c…)——`scan_exprs` 的 dry-run 走 Layer forward,表达式文本未动;⑥ **layer_bench 配对 A/B**(pre = `git worktree add` @ 48189d4 独立构建 layer_bench,feedforward/swiglu/linear 各 4 轮 PRE/POST 交错,`--iter 4`):feedforward fwd/train **-1.2%/-1.6%**、linear +1.4%/-4.2%、swiglu fwd -6.2%/train +0.2%——swiglu fwd 为 0.38–0.47ms 亚毫秒项、PRE 自身极差即 ±10%,全部落在 ±6% 噪声带且方向混合,**无系统性回退**;⑦ `doc_align_audit.ps1` A/D/E/F 可行动项全 0、`virtual_in_engine` 仍 50。 - **连带数字更新**:doc 12 的"Layer 直调 23 → **21**"(`from_matrix`/`to_matrix` 退出 L2;宿主桥是自由函数,不进 `engine.(` 统计口径)与"其余 26 → 28",§2.2 顺带修正 P-1 遗留的陈旧行 `cast_into/copy_into 仅 compute_precision_engine.hpp 内部`(该文件已删,实际调用方 = 基类 NVI 边界 cast + 引擎互调 + `write` 的 f16 目标)。AGENTS.md 新立**铁律 #12**(L2+ 禁用 Matrix + 宿主桥 + 审计口径),§3 审计表登记 `doc_inventory.ps1` 第 [4] 节。 -## 统一总纲 M5:内存池契约统一——无池引擎 pool_stats 补齐(2026-09-30,原位置 algebra_matrix.hpp 顶部账本与 MatrixT 分配/释放路径、compute_engine.hpp 基类 pool_stats/release_idle_pool_blocks 注释、docs/todo/04-memory-optimization.md) +## 统一总纲 M5:内存池契约统一——无池引擎 pool_stats 补齐(2026-09-30,原位置 algebra_matrix.hpp 顶部账本与 MatrixT 分配/释放路径、compute_engine.hpp 基类 pool_stats/release_idle_pool_blocks 注释、docs/internal/04-memory-optimization.md) - 类型:演进记录 - 内容:M5(方案见 17 §4.5 / §5 M5 行)按"统一的是**接口与语义**、不是实现(D5)"落地,两段: ① **宿主直配账本 `nn::HostAllocLedger`**(`algebra_matrix.hpp` 顶部,L1):`live_blocks/live_bytes/peak_bytes/total_blocks/total_bytes` 五个 `std::atomic`,全程 `memory_order_relaxed`,**只在分配/释放路径记账,元素热循环零参与**;峰值用 load + CAS 循环(只在变大时写)。全进程唯一实例由 `inline` 函数内静态对象提供(header-only,跨翻译单元同一地址)。 ② **`MatrixT` 三处释放出口收口**:分配在 `allocate_()` 成功后 `on_alloc(n * sizeof(element))`;释放统一走新增私有 `release_storage_()`(记账 + `data_.reset()` + `size_=0`),**析构 / 移动赋值 / `resize()`** 三处调用——移动赋值与 `resize` 原本是"直接覆盖 `data_`"的隐式释放,若只挂析构会漏记(账本越走越偏)。移动构造把源 `size_` 置 0(原实现已有),不重复记账。 ③ **`ComputeEngine::pool_stats()` 基类默认实现**:由返回空串改为返回 `direct{ blocks=<活分配数> live_bytes=<> peak_bytes=<> total_blocks=<> total_bytes=<> }`(单位字节,key 显式带 `_bytes` 避免与 GPU 的 `total=..MB` 混淆);`GpuEngine` 的 `persist{…} transient{…} pending=…` override 不动。`release_idle_pool_blocks()` 保持 no-op,但把理由("直配无整块可归还,语义成立")写进 `compute_engine.hpp` 注释与 `04-memory-optimization.md`——M4 之前那句"CPU 为 no-op/返回空"的口径一并更正(history 的同名旧条目已加后注)。 - **未做(保持 U3)**:CPU 真内存池是独立优化立项,需先分配剖析量化 DSL 临时张量热点;本期只补契约不改分配策略,`Matrix` 仍是 `std::unique_ptr` 直配。 -- **验收**(本机 Debug+Ninja+clang):① **两引擎 `pool_stats` 非空且口径已文档化**(17 §4.5 + `04-memory-optimization.md` + `01-compute-engine-development.md`)——`NN_MEM_STATS=1 text_train` 实测抓取:CPU `engine-init` 全 0 → `model-built` `direct{ blocks=44 live_bytes=9168512 peak_bytes=9168512 total_blocks=56 … }` → `optimizer-created` `blocks=88 live_bytes=18337024 …`(随生命周期单调反映),GPU dev2 `persist{blocks=5 allocs=12 total=1028MB …} transient{…} pending=0MB` 照旧;② build 122/122 零告警;③ ctest 20/20;④ CPU `--steps 20` hash=`6f8849f14da23110` **与 M1–M4 锚点逐位一致**(账本只读计数,不进任何数值路径);⑤ scan 双 hash 不变;⑥ `--io-roundtrip` CPU + GPU(dev2) 三用例全 PASS;⑦ L2 审计仍 `L2-VIOLATIONS: 0`;⑧ **layer_bench 配对 A/B**(pre = `git worktree add` @ d28c899 独立构建,feedforward/swiglu/linear 各 4 轮 PRE/POST 交错 `--iter 4`):feedforward fwd/train **+0.3%/+1.1%**(分配最密集的算例,说明 relaxed 原子开销不可测)、swiglu fwd -5.7%/train +0.1%、linear fwd -3.0%/train **-13.0%**(POST 更快;linear 单点方差 M1/M2 已记录在案 ±25%,且两组分布交叉),**方向混合、无系统性回退**。 +- **验收**(本机 Debug+Ninja+clang):① **两引擎 `pool_stats` 非空且口径已文档化**(17 §4.5 + `04-memory-optimization.md` + `04-compute-engine-development.md`)——`NN_MEM_STATS=1 text_train` 实测抓取:CPU `engine-init` 全 0 → `model-built` `direct{ blocks=44 live_bytes=9168512 peak_bytes=9168512 total_blocks=56 … }` → `optimizer-created` `blocks=88 live_bytes=18337024 …`(随生命周期单调反映),GPU dev2 `persist{blocks=5 allocs=12 total=1028MB …} transient{…} pending=0MB` 照旧;② build 122/122 零告警;③ ctest 20/20;④ CPU `--steps 20` hash=`6f8849f14da23110` **与 M1–M4 锚点逐位一致**(账本只读计数,不进任何数值路径);⑤ scan 双 hash 不变;⑥ `--io-roundtrip` CPU + GPU(dev2) 三用例全 PASS;⑦ L2 审计仍 `L2-VIOLATIONS: 0`;⑧ **layer_bench 配对 A/B**(pre = `git worktree add` @ d28c899 独立构建,feedforward/swiglu/linear 各 4 轮 PRE/POST 交错 `--iter 4`):feedforward fwd/train **+0.3%/+1.1%**(分配最密集的算例,说明 relaxed 原子开销不可测)、swiglu fwd -5.7%/train +0.1%、linear fwd -3.0%/train **-13.0%**(POST 更快;linear 单点方差 M1/M2 已记录在案 ±25%,且两组分布交叉),**方向混合、无系统性回退**。 ## 统一总纲 M6 段 A/B:15 D6/D7/D8 落地 + NN_BIND_DEBUG 门禁 + ensure_gpu→import(2026-09-30,原位置 model_serialization.hpp v5 加载分支、model_container.hpp set_engine、compute_engine.hpp(matmul_with_bias_impl 默认体 / to_prec / bind_error_ / 新增 import 与 import_impl)、expr_dsl.hpp 归约向量 F16 分支、compute_gpu_engine.hpp ensure_gpu) - 类型:演进记录 / 新增引擎契约 / 门禁化 @@ -867,7 +867,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 - **性能 A/B(配对 + 逆序复测,M2 同款方法)**:pre = `git worktree add` @ `4ce5884` 独立构建 layer_bench,feedforward/swiglu/linear 各 4 轮 PRE/POST 交错:feedforward fwd/train **+4.1%/+4.5%**、swiglu -0.7%/+0.9%、linear fwd **+8.5%**/train +3.8%(linear fwd 为 0.8ms 亚毫秒项)。**逆序复测**(POST 先跑,3 轮):feedforward **-0.7%/+0.4%**、linear +5.6%/-6.9% → 正序的 +4% 系**运行窗口/机器状态**(同窗 PRE 绝对值本身较上一轮高约 18%)与 -O0 二进制重排所致,**方向混合、无系统性回退**。 ## CE 的 (1,1) loss 归约输出恒 F32——修 `stable=f16` 溢出(2026-10-13,原位置 include/neuralnet.cpp/compute_loss.hpp 的 `softmax_cols_`/`forward`(步骤4+5)/`fused_forward_sparse_`) -- 类型:bug 根因 / 已修复勘误([`docs/todo/24`](../todo/24-f16-training-defects.md) §2.1/§3.1/§5 的 F2/F3;[`docs/todo/14`](../todo/14-f16-stable-gpu-loss-frozen.md)) +- 类型:bug 根因 / 已修复勘误([`docs/internal/24`](../internal/24-f16-training-defects.md) §2.1/§3.1/§5 的 F2/F3;[`docs/internal/14`](../internal/14-f16-stable-gpu-loss-frozen.md)) - 内容:`CrossEntropyLoss` 的两条链都把最终 **(1,1) loss 和**按 `p_.stable` 落盘。该标量 = 跨 `batch×seq` 的 log_prob 求和(≈ `-log(vocab)·token 数`),**大 token 数下必然超 f16 上限 65504**:部分硬件溢出为 ±inf,部分饱和为 f16 max。**这就解释了 14 号台账的 GPU `stable=f16`「loss 恒 4.0137」**——`4.0137 ≈ 65504/num_valid`,饱和值与权重/数据无关,故「跨 epoch/数据集/进程逐位相同」;原报告归因的「loss 回读链(`cast`/异步槽位读陈旧)」**被否定**(`ce_fusion_test` 的「异步标量回读 vs 同步下载」用例、迭代 24 轮 > 槽位 8,持续通过)。**修法**:两条链的 (1,1) 归约 `Precision::F32`(归约内部本就恒 f32 累加,输出改 F32 即得正确值;调用方随后本就 `cast` 到 F32 回读,等于顺手去掉一次 cast)。**触发范围 = 大 token 数**(本机 GPU 实测:`seq128×b8`=1024 token 健康;`seq256×b32`=8192 token 时 `stable=f16` 打印 `inf`、`stable=f32` 正常 9.0→8.7;修复后 `stable=f16` 9.0056→8.6922 正常下降)。 - **不变量**:f16 存储的**聚合标量**(跨 N 个元素求和、量级 ∝ N)不得按 f16 落盘;f16 只适合量级有界的逐元素/归一化中间量(`col_sum`/`log_softmax`/`lse` 保持 `p_.stable` 不变)。`optimizer=f16` 的爆炸(Adam 二阶矩下溢)与四字段全 f16 的数值性冻结**不属本修**——仍由 24 §2.3 的启动期告警覆盖(F1),根治留给 F5。 - **验收**:本机 CPU(build-ab,Release+tests)ctest **41/41**;本机 GPU(build/gpu,Release+tests+probes+850M/Intel)ctest **43/43**(含全部 `*_gpu` 变体与 `ce_fusion_test`)。新增回归:`f16_precision_test` 的 profile 组合矩阵(补 `all=f16` 行、提为默认门禁、CPU+GPU 都跑)+ `test_ce_loss_stable_f16_no_overflow`(`C=100,N=20000`,CPU/GPU 实测 `f32 5.1876 = stable=f16 5.1876`)。 @@ -922,9 +922,9 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## 失效文档链接清理(原位置 core_file.hpp:13/:42、model_serialization.hpp:24/:82、algebra_matrix.hpp:41/:43/:746、core_config.hpp:47) - 类型:删除清单 -- 内容:docs/17-pointer-audit.md、docs/23-mixed-precision.md、docs/development/11-cpu-performance-diagnosis.md、DEVELOPMENT_STANDARDS.md、src/bench_thresholds.cpp 均已删除或改名;对应链接改指 docs/todo/10-development-standards.md、docs/development/05-mixed-precision.md,或去掉文件名只留实测结论(blocked 优于 naive、并行阈值 524288 标定表等实测数据保留)。 +- 内容:docs/17-pointer-audit.md、docs/23-mixed-precision.md、docs/development/11-cpu-performance-diagnosis.md、DEVELOPMENT_STANDARDS.md、src/bench_thresholds.cpp 均已删除或改名;对应链接改指 docs/contributors/cpp-standards.md、docs/development/05-mixed-precision.md,或去掉文件名只留实测结论(blocked 优于 naive、并行阈值 524288 标定表等实测数据保留)。 -## 错误处理宏族落地:NN_UNWRAP / NN_EXIT / NN_TRY_MSG / NN_FAIL(2026-10-05,原位置 include/neuralnet.cpp/core_errors.hpp 的 NN_TRY 段、AGENTS.md §5 铁律 #1、CMakeLists.txt 测试块、docs/todo/12 / 18、docs/usage/05 的 ctest 计数行) +## 错误处理宏族落地:NN_UNWRAP / NN_EXIT / NN_TRY_MSG / NN_FAIL(2026-10-05,原位置 include/neuralnet.cpp/core_errors.hpp 的 NN_TRY 段、AGENTS.md §5 铁律 #1、CMakeLists.txt 测试块、docs/internal/12 / 18、docs/usage/05 的 ctest 计数行) - 类型:演进记录 - **背景(被替代的手写形态与实测量)**:全仓 `return std::unexpected(...)` 共 **1205** 处 —— 其中**纯传播** `return std::unexpected(r.error())` **628** 处(`NN_TRY`/`NN_TRY_CHECK` 此前只覆盖 **392** 处:L2 已收敛,其余散在 backend/engine/src/tools)、**错误源头** `return std::unexpected(Error{...})` **518** 处、`src/` 里 `if (!r) { std::cerr << ...; return 1/false; }` 形态 **374** 处(**全仓唯一没有任何宏覆盖的语义**)。原宏族只解决"传播",解包与失败退出两类全靠手写,也正是"作为库易用性"评估里排第一的摩擦源。 - **新宏族(三种语义 + 一个糖)**:`NN_TRY` / `NN_TRY_CHECK`(传播,展开与手写逐字等价);`NN_TRY_MSG(decl, "语境", expr)`(传播并把语境前缀进 `Error.message`);`NN_UNWRAP(expr[, "语境"])`(解包 + 终止,别名 `NN_UNWRAP_1`,接受 `Result` / `Result` / `bool` 三形态);`NN_EXIT(expr, code[, "语境"])`(解包 + `std::exit(code)`,CLI 参数错误保住退出码);`NN_FAIL("msg")`(错误源头糖)。 @@ -972,7 +972,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## BPE encode 保序并行(原位置 include/neuralnet.cpp/domain_tokenizer_{base,bpe,charbpe}.hpp 的 encode) - 类型:演进记录 / 性能 A/B -- 内容:`encode` 从「单线程顺序处理整段文本」改为 `encode_segments_`:按空白串起点(`find_safe_splits`)分段 → 各段经全局线程池并发编码 → **按段下标升序拼接**。正确性依据(已作为当前契约写进代码注释):安全切分点对 BPE/CharBPE 的预分词**必然是 chunk 边界**、标记不含空白故不会被切断、预分词与合并都是 chunk 局部操作,因此任意并行度与顺序执行逐字节一致(铁律 #8)。文本 < 256 KiB(`PARALLEL_ENCODE_MIN_BYTES`)或找不到切分点时回退顺序路径;新增 `Tokenizer::set_encode_threads`(0=自动/1=顺序/>1=指定)。实测 8 MiB 多样文本 `encode` 0.93s → 0.134s(32 线程,7.0x;本机 32 核,2026-10-01)。此前「BPE 不能并行」的结论只适用于训练期合并循环(见 `docs/todo/08` §4.2)。 +- 内容:`encode` 从「单线程顺序处理整段文本」改为 `encode_segments_`:按空白串起点(`find_safe_splits`)分段 → 各段经全局线程池并发编码 → **按段下标升序拼接**。正确性依据(已作为当前契约写进代码注释):安全切分点对 BPE/CharBPE 的预分词**必然是 chunk 边界**、标记不含空白故不会被切断、预分词与合并都是 chunk 局部操作,因此任意并行度与顺序执行逐字节一致(铁律 #8)。文本 < 256 KiB(`PARALLEL_ENCODE_MIN_BYTES`)或找不到切分点时回退顺序路径;新增 `Tokenizer::set_encode_threads`(0=自动/1=顺序/>1=指定)。实测 8 MiB 多样文本 `encode` 0.93s → 0.134s(32 线程,7.0x;本机 32 核,2026-10-01)。此前「BPE 不能并行」的结论只适用于训练期合并循环(见 `docs/internal/08` §4.2)。 ## evaluate_mnist 原始签名否决(cli/cli_mnist_io.hpp:16-18 头注释与 evaluate_mnist 函数注释,整改前行号) - 类型:否决方案 @@ -1065,7 +1065,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 - 类型:演进记录 / 审计缺口收口(P0-2 的 ③⑤ 两项 + 台账漂移回正) - **原状**:① `docs/release-notes/` 缺 `v1.5.1.md`(E3,自 v1.5.1 起就缺); ② `bench/doc_align_audit.ps1` 的 [A] 只扫**反引号里的文件名**,markdown 链接目标不查 —— 实测 - `todo/25-release-requirements.md` 里 `../CONTRIBUTING.md` 指向 `docs/CONTRIBUTING.md`(不存在) + `contributors/release-requirements.md` 里 `../CONTRIBUTING.md` 指向 `docs/CONTRIBUTING.md`(不存在) 这类死链因此长期漏检(E8);③ ctest 计数在 12 号/AGENTS/18 号三处口径不一(47 vs 48), §6 触发清单仍把**已落地**的 IR-C 列为待触发项,26 号进度总览停在"S4 未做 / ≤ f32 未达成"。 - **改动**:① 补写 `docs/release-notes/v1.5.1.md`(依据 `git log/show v1.5.0..v1.5.1` 三个提交与 @@ -1134,7 +1134,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## 悬空文档引用(原位置 tools/scan_exprs.cpp:352、389、359) - 类型:失效链接 -- 内容:注释曾引用不存在的 `docs/14`(S1-S3/S5 章节)与已无对应文档的条目号 `P2-13`。前者改指现存的 `docs/todo/02-operator-fusion.md`(二期 S1-S7 主线);后者改为直接描述现行机制"同 RowMod/RotateHalf 的视图参数处理:不进 key,运行时填充"。`include/neuralnet.cpp/expr_spec.hpp:429` 亦有同款 `P2-13` 悬空引用,不在本次范围内,需另行处理。 +- 内容:注释曾引用不存在的 `docs/14`(S1-S3/S5 章节)与已无对应文档的条目号 `P2-13`。前者改指现存的 `docs/internal/02-operator-fusion.md`(二期 S1-S7 主线);后者改为直接描述现行机制"同 RowMod/RotateHalf 的视图参数处理:不进 key,运行时填充"。`include/neuralnet.cpp/expr_spec.hpp:429` 亦有同款 `P2-13` 悬空引用,不在本次范围内,需另行处理。 --- @@ -1372,52 +1372,52 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 # docs/development 12 · 13 · 08 -> 本文件汇集 docs/todo/12-compute-engine-inventory.md、13-refactor-backlog.md、 +> 本文件汇集 docs/internal/12-compute-engine-inventory.md、13-refactor-backlog.md、 > 08-pitfalls-and-lessons.md 整改中移出的历史叙事(演进流水 / 已修复勘误 / 否决方案 / > 过程性验证数字)。正文只保留当前状态与仍然适用的教训。 -## 2026-09-27 计算类原语全量迁 DSL 横幅(原位置 docs/todo/12-compute-engine-inventory.md 顶部横幅) +## 2026-09-27 计算类原语全量迁 DSL 横幅(原位置 docs/internal/12-compute-engine-inventory.md 顶部横幅) - 类型:演进记录 - 内容:迁移范围——inplace 族 `add_inplace`/`scale_inplace`/`accumulate` → `dsl::compute_into`(10 处:attention/mlp/conv/rapt/transformer/zipt);单 matmul `matmul`/`matmul_with_bias` → `dsl::matmul`(Linear fwd/bwd、Conv gcol、Transformer 池化反传、Muon NS 6 处);归约族 `row_reduce_sum`/`col_reduce_sum`/`col_reduce_max` → `dsl::compute_reduce`(mlp/conv/transformer/loss×4/optimizer×3/rapt);批量 matmul `batched_matmul` 21 处 → `dsl::matmul(..., batch)`(attention backward+forward_step、CrossAttention、ZiPTBlock、rapt forward_step),alpha 经 `dsl::rparam(scale)` 尾链(值不进 key);缺口 A:`grouped_reduce_sum/max` → 新 `ExprViewKind::GroupedReduceSum/Max` 视图(param=R 进 key),MaxPool2D 迁移。结果:Layer 直调 **34 → 23**,10 个计算类原语全部退出 Layer 直调(`bench/doc_inventory.ps1` 复测);ctest 19/19。随迁的三条方法论教训(dry-run 禁止吞错 / alpha 用 rparam / 新 ExprViewKind 落点清单)保留在 12 §2.1 正文(现在式)。 -## 2026-09-19 IR-C 删除横幅 + 2026-09-25 接口数字复核流水(原位置 docs/todo/12-compute-engine-inventory.md 顶部横幅) +## 2026-09-19 IR-C 删除横幅 + 2026-09-25 接口数字复核流水(原位置 docs/internal/12-compute-engine-inventory.md 顶部横幅) - 类型:演进记录 - 内容:① 2026-09-19 横幅:IR-C 部分执行完毕——`expr_graph.hpp`、`ComputeEngine::begin_expr/end_expr`、`dsl::start_expr/end_expr`、`FusedChainLayer`、`Tensor::virtual_tag_` 均已从代码移除;§4.2/§4.3/§5/§8 曾保留为"决策前证据快照"。② 2026-09-25 复核:**58 个 virtual(Phase 2 加入 `cast_into`/`copy_into`/`supports_*`/`eval_expr_*` 等)、Layer/Loss/Optimizer 直调 35 个**;随后 2026-09-26 收敛更新为 **49 virtual / Layer 直调 32**,2026-09-27 迁移后为 **49 virtual / Layer 直调 23**(当前值)。 -## 2026-09-26 §5 遗留物清单收敛记录横幅(原位置 docs/todo/12-compute-engine-inventory.md 顶部横幅) +## 2026-09-26 §5 遗留物清单收敛记录横幅(原位置 docs/internal/12-compute-engine-inventory.md 顶部横幅) - 类型:演进记录 - 内容:① 旧代数 AST 整体移除:`algebra_expr.hpp`、`algebra_compute.hpp`(`nn::compute::apply`)删除,`Expression`/`BoolExpression` 概念迁入 `expr_dsl.hpp`,`Matrix::detail::{apply,binary_apply,binary_apply_inplace}` 死函数删除;② 无根/测试-only 算子全部删除:`axpy_inplace`、`broadcast_row_inplace`、`broadcast_col_inplace`(连带 `shaders/broadcast.comp` 全链)、`elementwise_unary/binary/binary_scalar`、`elementwise_select_scalar_cond`、引擎 `row_reduce_max`、offload B 组 `offload_store/offload_load`、`UnaryOp/BinaryOp/CompareOp` 枚举;③ 数字:引擎 virtual **58 → 49**;CPU 求值机制 **4 → 2**(DSL 模板路径 + IR 解释器);④ 随行清理:`src/test_common.hpp`、死 `activation_cache()` override、重复 `offload_test` 聚合目标(ctest 20 → 19)、`gpt_offload_test` 补 batch 录制包裹。 -## §1 CUDA 移除范围清单(原位置 docs/todo/12-compute-engine-inventory.md §1) +## §1 CUDA 移除范围清单(原位置 docs/internal/12-compute-engine-inventory.md §1) - 类型:删除清单 - 内容:原先约 100 KB 死代码 + 10 处条件分支——删除 `cuda/`(`CMakeLists.txt`/`cuda_kernels.h`/`cuda_kernels.cu`)、`compute_cuda_engine.hpp`、`backend/compute_cuda_backend.hpp`;清除 `compute_tensor.hpp`(6 处 `#ifdef NN_HAS_CUDA`)、`nn.hpp`、`cli/cli_engine_factory.hpp`(`EngineConfig::use_cuda`)、`cli/cli_train_common.hpp`(`--cuda`)、`CMakeLists.txt` 停用段、15 个 `src/*.cpp` 的 `--cuda`/`use_cuda`/`cuda_enabled`、`cli_controllers.py` 的 `--cuda` 传参。历史快照见 git 分支 `legacy/cuda`。 -## §2.2 失效的 2026-09-25 调用方快照行(原位置 docs/todo/12-compute-engine-inventory.md §2.2) +## §2.2 失效的 2026-09-25 调用方快照行(原位置 docs/internal/12-compute-engine-inventory.md §2.2) - 类型:已修复勘误(算子已删,行随之失效) - 内容:`offload_store`/`offload_load`(仅 offload_primitive_test;Layer 用 `offload_save/offload_restore`)、`elementwise_unary`/`elementwise_binary_scalar`/`elementwise_binary`(含 `compute_layer_rapt.hpp:866` Div 生产调用)、`broadcast_row_inplace`(无根)、`broadcast_col_inplace`(仅 f16 测试/layer_bench)、`axpy_inplace`(无根)、`row_reduce_max` 引擎算子(仅适配层转发;Layer 走 `dsl::row_reduce_max` DSL 叶子)、`elementwise_select_scalar_cond`(全仓无调用点)——以上算子已于 2026-09-26 收敛轮从接口删除,当前 49 个 virtual 中不再存在。 -## §3「四套机制」旧表与死/重复叙事(原位置 docs/todo/12-compute-engine-inventory.md §3) +## §3「四套机制」旧表与死/重复叙事(原位置 docs/internal/12-compute-engine-inventory.md §3) - 类型:演进记录 - 内容:机制 1「旧代数 AST `compute::apply(span, expr)`」(`algebra_compute.hpp`/`algebra_expr.hpp`/`Matrix::detail::*`)已于 2026-09-26 整体删除;`eval_cpu` 串行模板分支此前已被并行化+向量化的 `eval_into_span` 取代。原判定:"机制 2 与机制 3 是 DSL 在 CPU 上的两条路(一条内联、一条解释)——收敛后的全部 CPU 求值路径";机制 3(IR 解释器)逐元素 switch 分派 + 归约前缀重放,实测比等价原语慢 1.5–3.8 倍(2026-09-18 诊断实测,原诊断报告已删除,结论数字保留)。 -## §4.2–§4.3 IR-C 盘点原文(原位置 docs/todo/12-compute-engine-inventory.md §4.2、§4.2.1–§4.2.3、§4.3) +## §4.2–§4.3 IR-C 盘点原文(原位置 docs/internal/12-compute-engine-inventory.md §4.2、§4.2.1–§4.2.3、§4.3) - 类型:否决方案 / 演进记录 - 内容:① §4.2 盘点:接口 `compute_engine.hpp:110-111`、录制图 `expr_graph.hpp`(22.5 KB,`ExprGraph`/`recording_graph_owner`);生产调用方无——唯二调用者 `FusedChainLayer`(`compute_layer_mlp.hpp:762-800`,自述"IR-C 演示"层,不被模型工厂使用)与 `tools/scan_exprs.cpp:136-143` + `src/expr_fuse_test.cpp`。② §4.2.1 代数关系:IR-C 是 DSL 同一流水线的阶段 C(IR-A/B `expr_opt.hpp`、IR-C `expr_graph.hpp`、IR-D `expr_emitter.hpp`);原始开发分支时间线 `bf86af2`(08-21 DSL) → `662cb08`(08-22 begin_expr/end_expr) → `36caba4`(08-24 IR-C/D),DSL 先出现、IR-C/D 是同波加入。③ §4.2.2 数据流图:`dsl::compute → ExprSpec → IR-A/B → eval_expr → IR-D`,`begin_expr` 段走 `ExprGraph → fuse_expr_graph`;CPU `eval_expr_impl` 与 GPU `eval_expr` 都先 `canonicalize_expr_spec`。④ §4.2.3 非对称:GPU 真录制 + `execute_fused_graph`,CPU 仅 `NN_EXPR_SCAN` 下动作(普通运行 no-op)→ 接 IR-C 对 CPU 收益为零。⑤ §4.3:`dsl::start_expr/end_expr`(`ExprBlock`)仅被测试使用,随 IR-C 删除。 -- 结论去向:完整取舍与重新立项前提见 `docs/todo/03-ir-optimization.md` §5.3。 +- 结论去向:完整取舍与重新立项前提见 `docs/internal/03-ir-optimization.md` §5.3。 -## §5 遗留物清单历史行(原位置 docs/todo/12-compute-engine-inventory.md §5) +## §5 遗留物清单历史行(原位置 docs/internal/12-compute-engine-inventory.md §5) - 类型:演进记录(已删除/已修复条目) - 内容:~~CUDA 引擎+backend+`cuda/`+10 处 `#ifdef`~~(~100 KB,已移除);旧代数 AST `algebra_expr.hpp`+`algebra_ops.hpp`+`algebra_compute.hpp`(27.6 KB,已删除——注意 `algebra_ops.hpp` 仍在,判定原文含误列);IR-D `CpuEmitter` 残留注释(2026-09-25 已清理,`cpu_emitter.hpp` 已删);`FusedChainLayer`(~60 行,已移除);`begin_expr`/`end_expr`+`expr_graph.hpp`+`Tensor::virtual_tag_`(~24 KB,已移除);`eval_cpu` 串行模板路径(已由并行化 `eval_into_span` 取代);`axpy_inplace`/`broadcast_row_inplace`(原判无根,2026-09-26 已删);`broadcast_col_inplace`(原仅测试/bench,已删);`nn::one_hot`(无调用点且与铁律 9 冲突,已删);`Matrix::multiply_transposed_add_to`(自述死代码,已删);`elementwise_select_scalar_cond`(无调用点,已删);`offload_store`/`offload_load`(原仅测试,已删);`row_reduce_max` 引擎算子(无 Layer 调用点,已删)。 -## §6 差距表旧数字(原位置 docs/todo/12-compute-engine-inventory.md §6) +## §6 差距表旧数字(原位置 docs/internal/12-compute-engine-inventory.md §6) - 类型:演进记录 - 内容:A. Layer 直调算子 ~~35 个~~ → 23(2026-09-27 计算类已全量迁移);B. 求值机制原为 4 套(含旧代数 AST),2026-09-26 起 CPU 只剩 2 套;C. 融合世代:IR-C 已于 2026-09-19 移除(设计无收益点,见 §8.9 与 03 §5.3);D. 死代码:CUDA 全链 ~100 KB、IR-C ~24 KB 已清。 -## §7 演进段(原位置 docs/todo/12-compute-engine-inventory.md §7.2/§7.4/§7.5/§7.6) +## §7 演进段(原位置 docs/internal/12-compute-engine-inventory.md §7.2/§7.4/§7.5/§7.6) - 类型:演进记录 - 内容:① §7.2 类别①原列的 `elementwise_unary/binary/binary_scalar`、`broadcast_row/col_inplace`、`axpy_inplace` 已于 2026-09-26 删除(`add_inplace`/`scale_inplace`/`accumulate`/`zero` 仍在接口)。② §7.4 原文:"保留与 DSL 重复的逐元素路径 → 就是今天 CPU 上'旧代数 AST / DSL 模板 / 解释器'三套并存、层直调 35 个算子的直接来源。"③ §7.5 原"缺三样"中的前两样已完成/已处置:`dsl::compute_into(eng, expr, dst)` 已落地(optimizer/残差/LayerNorm 梯度/CE 梯度已迁移);跨表达式融合(IR-C)判定无收益并移除。④ §7.6 务实路径原文:"先把 §7.2 ① 标记为 legacy 并逐层迁移(LayerNorm/Softmax/Linear/激活先行,optimizer/RLA/offload 放后面)"——该迁移已执行(2026-09-27,见顶部横幅条目)。 -## §8 方案(决策前草案):把 IR-C 吸收进 dsl::compute——全节(原位置 docs/todo/12-compute-engine-inventory.md §8.1–§8.10) +## §8 方案(决策前草案):把 IR-C 吸收进 dsl::compute——全节(原位置 docs/internal/12-compute-engine-inventory.md §8.1–§8.10) - 类型:否决方案 - 内容(精简,保留关键数字与结论):2026-09-18 候选方案,最终未采用;2026-09-19 决定直接删除 IR-C。要点: - §8.1 用户入口 3 → 1:`dsl::compute/compute_reduce/compute_into`(保留)、`dsl::start_expr…end_expr(ExprBlock)`(仅 expr_dsl_test 用)、`engine.begin_expr…end_expr`(仅 FusedChainLayer + scan 用)——后两者删除;收敛不是靠"自动融合",而是靠删除跨表达式融合能力。 @@ -1454,15 +1454,15 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 - 类型:演进记录 - 内容:依据全仓"悬空设计"审计(A/B/C 三档)+ activation offload 只读评估,逐项 build + ctest 验证(**20 → 19 个目标,19/19 全绿**):① A 档死码全删(`elementwise_select_scalar_cond`、`axpy_inplace`、`broadcast_row_inplace`、`nn::one_hot`、`text_train::one_hot_labels`、`Matrix::multiply_transposed_add_to`、`nn::sigmoid·relu`、`ops::Sigmoid·ReLU`);② 新增 `src/test_common.hpp`(`CHECK`/`make_tensor`/`check_close`/`approx`/`dot`/`close_to` 收敛唯一副本,保留聚合编译 `#define main`);③ RAPT `forward_step` 的 `num/den` 除法改 `dsl::compute(engine, leaf/(leaf+Scalar{1e-4}), rows, cols)`,与 `forward` 同构复用已注册 AOT 键;④ 算子收敛(删 `elementwise_unary/binary/binary_scalar`、`broadcast_col_inplace`+`broadcast.comp` 全链、引擎 `row_reduce_max`、`offload_store/load`、`UnaryOp/BinaryOp/CompareOp`;引擎 virtual 58 → 49);⑤ AST 移除(`algebra_expr.hpp`+`algebra_compute.hpp` 删除,`Expression`/`BoolExpression` 迁入 `expr_dsl.hpp`,CPU 求值只剩两套);⑥ offload 评估(保留 A 组生产链、删 B 组 `offload_store/load`+`offload_primitive_test`+重复聚合器;`gpt_offload_test` 补 `begin_batch/end_batch`;CPU/ZiPT 由静默 no-op 改显式警告;帮助文本"互斥"更正为"可混合");⑦ 死 override:`TransformerEncoderLayer`/`ZiPTBlock` 的 `activation_cache()`(20 行)删除。随附五条教训保留在 13 §9 正文(现在式)。 -## 08 §3.5 CUDA obj 不随 Debug/Release 重编(原位置 docs/todo/08-pitfalls-and-lessons.md §3.5) +## 08 §3.5 CUDA obj 不随 Debug/Release 重编(原位置 docs/contributors/pitfalls.md §3.5) - 类型:已失效条目(CUDA 后端已整体移除,坑不再可能触发) - 内容:Debug↔Release 切换后 `cuda_kernels.obj` 的 DEPENDS 只有 .cu,不重编 → `_ITERATOR_DEBUG_LEVEL` 不匹配(clang-cl=2 vs nvcc obj=0)→ lld-link 失败。修复:`-Xcompiler /D_ITERATOR_DEBUG_LEVEL=N` 对齐;切换配置后删 `build\cuda\cuda_kernels.obj` 再重编。教训(若恢复多编译器混合构建仍适用):调试级宏必须在各编译器侧显式对齐。 -## 08 §5 nvcc 行与 §7 CUDA 清单项(原位置 docs/todo/08-pitfalls-and-lessons.md §5 表格、§7 修改构建/工具链) +## 08 §5 nvcc 行与 §7 CUDA 清单项(原位置 docs/contributors/pitfalls.md §5 表格、§7 修改构建/工具链) - 类型:已失效条目 - 内容:① §5 表行"nvcc 12.8 与 MSVC 2026 (v14.51) 不兼容,cudafe++ crash | 构建(CUDA 已停用)| 用 VS 2022 BuildTools;`-allow-unsupported-compiler`"。② §7 "修改构建/工具链"两条:`[x] Debug↔Release 切换清 build/cuda/cuda_kernels.obj`(CUDA 移除后作废)、`[ ] nvcc 编译器版本匹配(12.8 ↔ VS 2022 BuildTools)`。 -## 08 各条目的过程性验证/定位叙事(原位置 docs/todo/08-pitfalls-and-lessons.md §2.5/§3.7/§4.10/§4.12/§6 模式 H) +## 08 各条目的过程性验证/定位叙事(原位置 docs/contributors/pitfalls.md §2.5/§3.7/§4.10/§4.12/§6 模式 H) - 类型:已修复勘误 / 过程叙事(教训本身保留在正文,现在式) - 内容: - §2.5 验证流水:修复前 3 类 VUID 报错 → 强制校验层跑完整 `gpu_test`(256×256/10 迭代)0 条 VUID;`--gpu=AMD` 从"10s 超时失败"变 2s 通过;时间线 / `NN_VULKAN_NO_TIMELINE=1` 回退两路径 + ctest 15/15 全绿。 @@ -1480,7 +1480,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 整改时移出的历史记录。整改原则:正文只记录当前状态、当前机制与仍然适用的结论;本文件保存 被移出的演进流水、分期验收记录、被否决方案与性能 A/B 过程,供追溯用。 -## 两期主线与分期状态横幅(原位置 docs/todo/02-operator-fusion.md 篇首导语) +## 两期主线与分期状态横幅(原位置 docs/internal/02-operator-fusion.md 篇首导语) - 类型:演进记录 - 内容:原文把两期工作串成流水:「一期(M1-M7)用手写 op 级融合原语解决 GPT+Vulkan 训练显存/开销问题; 二期(S1-S7)把 matmul 纳入 IR 融合、实现跨 kernel 自动融合(原规划的图级缓存落地方案已随 IR-C 于 @@ -1579,7 +1579,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 正文教训 1 已按当前写法改写。另:形状无关融合的原始效果记录(扫描条目 24 → 18,RoPE 4×dk 去重) 与教训 5 的「74 条 spec 全生成」计数已从正文移除(计数以构建输出为准)。 -## IR-C(图 IR + begin_expr/end_expr 融合分析)取舍记录(原位置 docs/todo/03-ir-optimization.md §5.3) +## IR-C(图 IR + begin_expr/end_expr 融合分析)取舍记录(原位置 docs/internal/03-ir-optimization.md §5.3) - 类型:取舍记录 / 被否决方案 - 内容:阶段 C 的落地形态 = `expr_graph.hpp`(`ExprGraph`/`fuse_expr_graph`/`recording_graph_owner`/图级缓存) + `ComputeEngine::begin_expr/end_expr` 显式录制 API + `dsl::start_expr/end_expr`(`ExprBlock`) @@ -1725,108 +1725,108 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 # docs/development 01 · 04 · 06 · 07 · 10 · 14 -> 本文件汇集 docs/development/01-compute-engine-development.md、04-memory-optimization.md、 -> 06-rapt-algorithm.md、10-development-standards.md、14-f16-stable-gpu-loss-frozen.md +> 本文件汇集 docs/development/04-compute-engine-development.md、04-memory-optimization.md、 +> 08-rapt-algorithm.md、10-development-standards.md、14-f16-stable-gpu-loss-frozen.md > 整改中移出的历史叙事(演进流水 / 已修复勘误 / 删除清单 / 性能 A/B / 排查过程)。 > 正文只保留当前状态、当前机制与仍然适用的教训;07-zipt-algorithm.md 为纯算法文档,无移出条目。 -## 01 §5 引擎 row_reduce_max 删除注脚(原位置 docs/development/01-compute-engine-development.md §5) +## 01 §5 引擎 row_reduce_max 删除注脚(原位置 docs/development/04-compute-engine-development.md §5) - 类型:删除清单 - 内容:原文「⚠️ 2026-09 收敛:`row_reduce_max`(引擎算子)已删除——按行求最大走 DSL 归约叶子 `dsl::row_reduce_max(...)`(详见 `expr_dsl.hpp`;AGENTS §4.3 有完整删除清单)」。当前做法(按行求最大用 DSL 叶子、归约表达式走 `dsl::compute_reduce`)已保留为正文提示。 -## 01 §6 逐元素/广播算子删除清单与理由(原位置 docs/development/01-compute-engine-development.md §6) +## 01 §6 逐元素/广播算子删除清单与理由(原位置 docs/development/04-compute-engine-development.md §6) - 类型:删除清单 -- 内容:`broadcast_row_inplace`、`broadcast_col_inplace`、`elementwise_unary`、`elementwise_binary`、`elementwise_binary_scalar`、`elementwise_select_scalar_cond`(连同 `UnaryOp`/`BinaryOp`/`CompareOp` 枚举)已全部删除(2026-09 收敛轮)。理由:这些算子在 DSL 落地后已无生产调用方,且与表达式能力完全重复(详见 `todo/12-compute-engine-inventory.md` 顶部收敛横幅与 `13-refactor-backlog.md` §9)。 +- 内容:`broadcast_row_inplace`、`broadcast_col_inplace`、`elementwise_unary`、`elementwise_binary`、`elementwise_binary_scalar`、`elementwise_select_scalar_cond`(连同 `UnaryOp`/`BinaryOp`/`CompareOp` 枚举)已全部删除(2026-09 收敛轮)。理由:这些算子在 DSL 落地后已无生产调用方,且与表达式能力完全重复(详见 `internal/12-compute-engine-inventory.md` 顶部收敛横幅与 `13-refactor-backlog.md` §9)。 -## 01 性能优化节旧 dsl::compute 示例(原位置 docs/development/01-compute-engine-development.md 性能优化 §2) +## 01 性能优化节旧 dsl::compute 示例(原位置 docs/development/04-compute-engine-development.md 性能优化 §2) - 类型:已修复勘误(API 形式过期) - 内容:原文用 lambda + 张量列表形式 `dsl::compute(engine, [](auto a, auto b, auto c){...}, {tensor_a, tensor_b, tensor_c}, rows, cols)`——该重载在代码中不存在。现 API 为 `dsl::compute(eng, expr, rows, cols[, precision])`(expr_dsl.hpp:1317),已按 `dsl::leaf(*a) + dsl::leaf(*b) * dsl::leaf(*c)` 形式改写。 -## 01 Q3 旧答案:通过 UnaryOp/BinaryOp 枚举加激活函数(原位置 docs/development/01-compute-engine-development.md 常见问题 Q3) +## 01 Q3 旧答案:通过 UnaryOp/BinaryOp 枚举加激活函数(原位置 docs/development/04-compute-engine-development.md 常见问题 Q3) - 类型:已修复勘误 - 内容:原文步骤为「1. 在 `UnaryOp` 或 `BinaryOp` 中添加枚举值;2. 在 `CpuEngine` 中实现逐元素运算;3. 在 `GpuEngine` 中实现 shader」——枚举与逐元素引擎算子已删除,该路径不存在。现行答案:在 Layer 内用 DSL 组合表达(`ReLU::forward` = `dsl::max(dsl::leaf(x), Scalar{0})`),引擎/ shader 不认识算法名(铁律 3)。 -## 04 实施进度日期标注与 RAPT 接入旧叙事(原位置 docs/todo/04-memory-optimization.md 背景与目标 §实施进度) +## 04 实施进度日期标注与 RAPT 接入旧叙事(原位置 docs/internal/04-memory-optimization.md 背景与目标 §实施进度) - 类型:演进记录 / 已修复勘误 - 内容:① 原节标题「实施进度(2026-08-22)」及各条目的日期戳(L1 续:RLA/RAPT 接入 2026-09-19)。② 「此前 `set_checkpoint_every`/`set_activation_offload`/`set_flush_interval` 对 RAPT 是静默 no-op,而 CLI 会打印"已启用"」——该缺陷已于 2026-09-19 修复,当前 RAPT 三开关真实生效。③ 「`activation_cache()` 补齐此前遗漏的 4 项(否则 offload 覆盖不全)」——当前已列出全部 7 项层内缓存 + 4 个子层缓存。④ L2 条目中「(CPU no-op;CUDA 已停用)」的 CUDA 提法——CUDA 后端已整体移除(96a3675),当前只写 CPU no-op。⑤ 「新增 rapt_offload_test」「text_train 新增 --checkpoint-every」等"新增"措辞。 -## 04 基准显存 27G vs 29G 的融合 A/B(原位置 docs/todo/04-memory-optimization.md 背景与目标 §基准配置与峰值显存) +## 04 基准显存 27G vs 29G 的融合 A/B(原位置 docs/internal/04-memory-optimization.md 背景与目标 §基准配置与峰值显存) - 类型:性能 A/B - 内容:原文「该配置下训练峰值显存 ≈ 27 GB(已含 M5/M6 融合收益),此前 29 GB(融合前)」;「融合(M4/M5/M6)已把非线性象限(seq² 注意力、vocab×seq 全 softmax)从 ~3× 砍到几近为 0」。现正文只保留 27GB 当前口径与"非线性象限不物化 ≈0"的当前状态。 -## 04 f16 红线修订注脚(原位置 docs/todo/04-memory-optimization.md 现状与根因 §数值精度) +## 04 f16 红线修订注脚(原位置 docs/internal/04-memory-optimization.md 现状与根因 §数值精度) - 类型:演进记录 - 内容:原文「(立项时口径……)(历史红线"不引入 f16"已随混合精度修订。)」。当前事实:本文档数字为 fp32 基线;v1.2.0 起 f16 混合精度见 05-mixed-precision,本文档显存账不适用于 f16 路径。 -## 04 L2 旧问题叙述:内存池永不归还(原位置 docs/todo/04-memory-optimization.md 现状与根因 §内存池碎片化) +## 04 L2 旧问题叙述:内存池永不归还(原位置 docs/internal/04-memory-optimization.md 现状与根因 §内存池碎片化) - 类型:已修复勘误 - 内容:原文「但:从未将整个空 Block 归还 GPU(`blocks_.clear()` 仅在析构时触发),block 底材按需 128MB(或超尺寸单块)申请后不回收 ⇒ 峰值生命周期等于整个进程/测试生命周期」;「算子融合文档将"内存池 first-fit 碎片化 + 永不归还"列为独立跟踪项、不随融合解决」。该问题已由 L2 的 `release_idle_blocks()` / `release_idle_pool_blocks()` 解决(step 边界整块归还);残余风险(step 内仍累积)保留为正文。 -## 04 注意力两趟式旧实现描述(原位置 docs/todo/04-memory-optimization.md 现状与根因 §注意力形态) +## 04 注意力两趟式旧实现描述(原位置 docs/internal/04-memory-optimization.md 现状与根因 §注意力形态) - 类型:演进记录 - 内容:原文「原 `batched_matmul_reduce/max → denom → apply` 两趟式 forward 与 `batched_matmul_softmax_backward_q/kv` backward 重算 W 方案,已被 IR 融合替代(算子融合文档 S7;2026-09-23 起 forward 进一步换单 fold kernel——FoldSpec 分块流式……)」。当前状态(单 fold kernel、S 不落显存、backward 为 R/X 表达式 + batched_matmul)已保留为正文。 -## 04 「已核对(2026-08-24)」审查记录框(原位置 docs/todo/04-memory-optimization.md L2 节) +## 04 「已核对(2026-08-24)」审查记录框(原位置 docs/internal/04-memory-optimization.md L2 节) - 类型:演进记录(结论仍适用,已改写为常设约定) - 内容:原文以「已核对(2026-08-24):中间 Tensor 的归还路径是安全的,无需修改即可维持正确性」开头的审查记录。四条安全约定(延迟销毁 + 录制期全内存屏障、复用前必写满、新增原语必须插 output barrier、期望为 0 必须显式 `zero()`)全部保留为正文「内存池复用安全约定」。 -## 04 旧落地顺序与过期约束(原位置 docs/todo/04-memory-optimization.md 落地顺序建议 / 与既有约束的关系) +## 04 旧落地顺序与过期约束(原位置 docs/internal/04-memory-optimization.md 落地顺序建议 / 与既有约束的关系) - 类型:演进记录 / 已修复勘误 - 内容:① 原落地顺序「1. 先 L1……2. 再 L2……3. 若仍不足 → 立项 L3……」(L1/L2 已完成,现正文改为"L1/L2 已就位,下一步立项 L3")。② 「用训练 step 耗时采样替代(bench 工具已移除)」的 bench 删除提法。③ 原约束「不引入 f16(bf16/fp16)低精度训练」——已过时(f16 混合精度已落地),改为「L1/L2 与精度设置正交,本文档账目为 fp32 口径」。 -## 06 §4 引擎化改造流水(原位置 docs/development/06-rapt-algorithm.md §4 开头) +## 06 §4 引擎化改造流水(原位置 docs/development/08-rapt-algorithm.md §4 开头) - 类型:演进记录 - 内容:原文「2026-09-04 的引擎化改造删掉了 Layer 内的 `scan_forward_/scan_backward_` 纯 CPU 标量循环(PCIe 往返),改为 3 个 op-level 扫描原语,由 Layer 用原语 + 逐元素原语组合表达算法(铁律 3:shader 永不含算法)」。当前状态保留为正文。 -## 06 §4.3 坑 3/坑 4 的历史措辞(原位置 docs/development/06-rapt-algorithm.md §4.3) +## 06 §4.3 坑 3/坑 4 的历史措辞(原位置 docs/development/08-rapt-algorithm.md §4.3) - 类型:已修复勘误 - 内容:① 坑 3 原文「写错则 doc-aware gradcheck 才会暴露(历史已踩过)」。② 坑 4 原文「不能让空张量流进 matmul(旧行为 = 静默算出垃圾梯度)」——旧行为已修复,现行规则(缺缓存立刻硬报错)保留为正文。 -## 06 §4.4 验证基线的演进措辞与失效交叉引用(原位置 docs/development/06-rapt-algorithm.md §4.4) +## 06 §4.4 验证基线的演进措辞与失效交叉引用(原位置 docs/development/08-rapt-algorithm.md §4.4) - 类型:已修复勘误 / 断链修正 -- 内容:① 原标题「验证基线(2026-09-04,GTX 850M)」与表内「max_err 与改造前基线一致」的对照措辞(现直接列 max_err 基线数值)。② 原注「6 处 Vulkan 接线细节沉淀在 `01-compute-engine-development.md`」——01 号文档并无该清单,属失效交叉引用,改为直接指向 `compute_gpu_engine.hpp` 与 `backend/compute_vk_backend.hpp`。 +- 内容:① 原标题「验证基线(2026-09-04,GTX 850M)」与表内「max_err 与改造前基线一致」的对照措辞(现直接列 max_err 基线数值)。② 原注「6 处 Vulkan 接线细节沉淀在 `04-compute-engine-development.md`」——01 号文档并无该清单,属失效交叉引用,改为直接指向 `compute_gpu_engine.hpp` 与 `backend/compute_vk_backend.hpp`。 -## 06 §5 历史:两趟式注意力(已删除)——全节(原位置 docs/development/06-rapt-algorithm.md §5) +## 06 §5 历史:两趟式注意力(已删除)——全节(原位置 docs/development/08-rapt-algorithm.md §5) - 类型:删除清单 / 演进记录 - 内容:S7 的"两趟式多 kernel 注意力"(forward 3 个融合 kernel m→l→W × 4 种掩码变体、backward 3 个,W 物化供复用)已删除——2026-09-24 起注意力 forward 为单 fold kernel 分块流式(QKᵀ/掩码/online softmax/ΣwV 逐 `EXPR_FOLD_BLOCK=128` 块完成,S 矩阵绝不物化)。与传统 Flash Attention 的对照分析(kernel 数量、IO 复杂度、掩码扩展方式)原注「见 git 历史中本节原文」。保留的结论(当前事实)已改写为 §5 正文:本项目不存在单一 flash-attn kernel、fold 流式实现 FlashAttention 核心思想、掩码变体经 FoldSpec 登记漏登记硬报错。 -## 06 §6 RAPT 开关与已修前置缺陷(原位置 docs/development/06-rapt-algorithm.md §6) +## 06 §6 RAPT 开关与已修前置缺陷(原位置 docs/development/08-rapt-algorithm.md §6) - 类型:已修复勘误 - 内容:① 「(2026-09-19 补齐;此前 RAPT 侧是静默 no-op 而 CLI 会打印"已启用")」。② 「已修的两个前置缺陷(不修则静默毁模型):1. `RAPTModel::clear_cache()` 曾清空 `token_emb_`(模型参数)——检查点每块 backward 后都调它,等于毁掉词嵌入。2. `RAPTModel::forward` 曾只在 `doc_ids` 非空时下发文档 id → `set_doc_ids({})` 关不掉文档感知,跨 step 残留边界重置(跨样本串扰)」。③ 「`activation_cache()` ……(Q_normed/K_normed/Q_rms_inv/K_rms_inv 曾漏列 → offload 漏搬,已补)」。④ §3 表格「分数定义:推理/训练曾不一致」措辞(改为"原版缺陷")。 -## 06 §4.2 forward_step 旧原语调用(原位置 docs/development/06-rapt-algorithm.md §4.2) +## 06 §4.2 forward_step 旧原语调用(原位置 docs/development/08-rapt-algorithm.md §4.2) - 类型:已修复勘误(API 过期) - 内容:原文「先更新状态(`batched_matmul(V, Kp, transB)` → `add_inplace(B_state)`;`add_inplace(z_state, Kp)`)→ num = B·q'(batched_matmul)」——2026-09-27 计算类原语迁 DSL 后,Layer 不再直调 `batched_matmul`/`add_inplace`:现为 `dsl::matmul(V, Kp, false, true, H)` + `dsl::compute_into` 原地累加(compute_layer_rapt.hpp:832-848),已按代码现状订正。 -## 10 compute::apply / 代数 AST 移除注脚(原位置 docs/todo/10-development-standards.md §2.6、§4.3.1、§4.3.2) +## 10 compute::apply / 代数 AST 移除注脚(原位置 docs/contributors/cpp-standards.md §2.6、§4.3.1、§4.3.2) - 类型:已修复勘误 - 内容:三处注脚原文——「(旧 `compute::apply(span, expr)` 代数 AST 已于 2026-09 整体移除)」「注:旧 compute::apply 代数 AST 与广播/逐元素算子在 2026-09 已移除」「(旧 compute::apply 代数 AST 已于 2026-09 移除)」。旧规则表表述「Layer 通过 Matrix 语义 API 或 `compute::apply(span, expr)` 表达算法」「上层通过 Matrix API 或 compute::apply 间接享受并行加速」已改为表达式 DSL。 -## 10 目录树中的已删文件行(原位置 docs/todo/10-development-standards.md §5.1) +## 10 目录树中的已删文件行(原位置 docs/contributors/cpp-standards.md §5.1) - 类型:删除清单 - 内容:目录树原有一行「├── (algebra_expr.hpp / algebra_compute.hpp 已于 2026-09 移除)」——文件树只列当前存在的文件,该行已删(`algebra_expr.hpp`/`algebra_compute.hpp` 确已不存在;`Expression`/`BoolExpression` 概念迁入 `expr_dsl.hpp`)。 -## 10 §6.2.4 SmartPolicy 历史说明(原位置 docs/todo/10-development-standards.md §6.2.4) +## 10 §6.2.4 SmartPolicy 历史说明(原位置 docs/contributors/cpp-standards.md §6.2.4) - 类型:已修复勘误 - 内容:原文「历史说明:早期文档把该策略命名为「SmartPolicy」并给出用户可替换 policy 的扩展示例,该类型在代码中从不存在(只有上述自由函数 + 阈值门控),示例已按实际 API 更正」。当前事实(无 policy 类型,只有 `parallel_for_samples`/`parallel_for_blocks` + 阈值门控)保留在代码注释形式的正文中。 -## 10 过期 API 示例批量订正(原位置 docs/todo/10-development-standards.md §2.5、§3.2.4、§4.2.2、§4.3.1、§4.3.4、§5.3.1、§5.3.2、§5.4、§10.2) +## 10 过期 API 示例批量订正(原位置 docs/contributors/cpp-standards.md §2.5、§3.2.4、§4.2.2、§4.3.1、§4.3.4、§5.3.1、§5.3.2、§5.4、§10.2) - 类型:已修复勘误(API 现状订正;原内容与代码现状不符,非单纯演进注脚) - 内容:① §2.5 「遵循隔离」示例 `matrix.apply_relu()`——`Matrix` 无此方法且违反 §2.6 自身铁律(Matrix 不写算法),改为 `add_inplace`/`multiply_to`。② §3.2.4 「避免使用已废弃的 `data_ptr()`」——接口只有 `span()`(algebra_matrix.hpp:194 注明 span 替代所有 data_ptr 场景)。③ §4.2.2 正确示例原为 `compute::apply(x, max(x, Scalar{0}))` 与 `p.binary_apply_inplace(g, lambda)`——分别改为 `dsl::compute` 与 `dsl::compute_into`(与 compute_layer_mlp.hpp ReLU::forward、compute_optimizer.hpp SGD::step 一致)。④ §4.3.1 Matrix API 列表原含 `apply`/`binary_apply`/`binary_apply_inplace` 模板——三者已不存在(`Matrix::detail::apply/binary_apply/binary_apply_inplace` 死函数删除),只留 `reduce/row_reduce/col_reduce/span`。⑤ §4.3.4 「Adam::step 通过 binary_apply_inplace 表达」——现为三个 DSL kernel(K1/K2 dsl::compute + K3 compute_into,RParam 承载偏置校正,compute_optimizer.hpp:304-353)。⑥ §5.3.1 链式 fluent 示例 `model.add(784,64).add()...add()`——`Model::add` 实际返回 `Result`(不可链式),`CrossEntropyLoss` 不是 Layer 不可 add;§5.3.2 原工厂示例返回 `Model&`——均改为实际实现。⑦ §5.4 检查清单「是否支持链式调用?」同步改为 Result 传播检查项。⑧ §10.2 Doxygen 示例 `@throws std::invalid_argument`——与全项目禁异常冲突,改为 Error 返回说明。 -## 10 §7.2 C++ 特性表过期行(原位置 docs/todo/10-development-standards.md §7.2) +## 10 §7.2 C++ 特性表过期行(原位置 docs/contributors/cpp-standards.md §7.2) - 类型:已修复勘误 - 内容:删除三行未使用特性——`std::ranges`(原注「如 ranges::generate Xavier 初始化」,全仓无 ranges::generate)已改为实际用途(ranges::distance/advance 切分并行区间、ranges::sort);`std::views::zip`(原注「优化器参数更新」,全仓无 views::zip——优化器用 dsl::compute_into 逐参数处理);`std::execution::par_unseq`(原注「并行执行策略(矩阵运算)」,全仓无 std::execution,core_config.hpp:64 明言替代 std::execution::par)。`std::expected`/`std::span`/`std::views::iota` 三行保留(经核实仍在使用)。 -## 10 不存在的头文件引用(原位置 docs/todo/10-development-standards.md §8.3、§9.1) +## 10 不存在的头文件引用(原位置 docs/contributors/cpp-standards.md §8.3、§9.1) - 类型:已修复勘误(断链修正) - 内容:① §9.1 标题「基础类型定义(nn_core_config.hpp)」——仓库无 `nn_core_config.hpp`,`Error`/`Result` 定义在 `core_errors.hpp:15-20`。② §8.3 包含顺序示例 `#include `(同上)与第三方库 `#include `(全仓无 fmt 依赖)。③ §5.2.1 注释中「layer.hpp - 层定义」——现名 `compute_layer.hpp`。 -## 14 §4 回归窗口与历史脉络(原位置 docs/todo/14-f16-stable-gpu-loss-frozen.md §4) +## 14 §4 回归窗口与历史脉络(原位置 docs/internal/14-f16-stable-gpu-loss-frozen.md §4) - 类型:演进记录(排查过程流水) - 内容:① 09-24 16:54 bench 原始数据(早于 75255da)同配置行为「epoch1 loss 活(7.40)→ epoch2 发散 -nan」(该配置历史上就不可训练,§12.5 stable=F16 时 CE 链 ~200 步 NaN,但 loss 至少是活的);② 09-26 HEAD `4a12876` 症状变为「epoch1 起即静默冻结」,「冻结比 NaN 更危险」的评述;③ 嫌疑提交清单(`git log 75255da..HEAD`:`eba744d` CPU f16 修复、`200955f` transpose 派发、`3c2b9e8` f16 MSVC 修复、`4c8c58c` 审查修复、`4a12876` 技术债清理;基线若追到 09-24 则 `b4ee2df`/`4cd0616` 也在窗口内)。与 issue #13 P0-② 的对照表为当前有效的事实区分,保留在 §4 正文。 -## 14 证据行号订正(原位置 docs/todo/14-f16-stable-gpu-loss-frozen.md §3、§5、§6) +## 14 证据行号订正(原位置 docs/internal/14-f16-stable-gpu-loss-frozen.md §3、§5、§6) - 类型:已修复勘误(数字订正) - 内容:报告引用的源码行号整体偏移 1–7 行,已按 HEAD `4a12876` 工作区实况订正:`text_train.cpp` 1513→1514(forward_sparse_sum)、1522→1523(cast)、1571→1572(submit_scalar_readback)、1366→1367(harvest 打印)、582→583(实验性注释);`compute_gpu_engine.hpp` 150→146(submit_scalar_readback 定义);`f16_precision_test.cpp` 642-649→639-646(profile 单字段矩阵)、698-702→691-700(main() CPU 块 + NN_F16_DEBUG 门)。缺陷本身未修(HEAD 仍为 4a12876,无修复提交)。 @@ -1850,7 +1850,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## 引擎算子收敛横幅(原位置 docs/introduction/01-architecture.md L2 表下 blockquote) - 类型:删除清单 -- 内容:**2026-09 收敛**:`axpy_inplace`、`broadcast_row_inplace/col_inplace`、`elementwise_unary/binary/binary_scalar`、`elementwise_select_scalar_cond`、引擎 `row_reduce_max`、`offload_store/load` 与 `UnaryOp/BinaryOp/CompareOp` 枚举已全部删除(逐元素/广播/条件选择一律走表达式 DSL),引擎 virtual 58 → 49;逐项清单见 `todo/12-compute-engine-inventory.md` 顶部收敛横幅。 +- 内容:**2026-09 收敛**:`axpy_inplace`、`broadcast_row_inplace/col_inplace`、`elementwise_unary/binary/binary_scalar`、`elementwise_select_scalar_cond`、引擎 `row_reduce_max`、`offload_store/load` 与 `UnaryOp/BinaryOp/CompareOp` 枚举已全部删除(逐元素/广播/条件选择一律走表达式 DSL),引擎 virtual 58 → 49;逐项清单见 `internal/12-compute-engine-inventory.md` 顶部收敛横幅。 ## IR-C 块式融合移除括注(原位置 docs/introduction/01-architecture.md 表达式入口表 `expr_dsl.hpp` 行) - 类型:演进记录 @@ -1954,7 +1954,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## IR-C 移除条目(原位置 docs/introduction/04-innovative-designs.md §6.2) - 类型:演进记录 -- 内容:「**IR-C 图 IR + 融合分析**:~~`begin_expr/end_expr` 录制虚拟寄存器 DAG;逐元素链拼接~~ → **已评估并整体移除(2026-09-19)**……」——正文改写为「不采用」+ 指向 `docs/todo/03-ir-optimization.md` §5.3 的当前表述。 +- 内容:「**IR-C 图 IR + 融合分析**:~~`begin_expr/end_expr` 录制虚拟寄存器 DAG;逐元素链拼接~~ → **已评估并整体移除(2026-09-19)**……」——正文改写为「不采用」+ 指向 `docs/internal/03-ir-optimization.md` §5.3 的当前表述。 ## f32-only 红线修订记录(原位置 docs/introduction/04-innovative-designs.md §7「设计红线(立项时基线,v1.2.0 起修订)」) - 类型:演进记录 @@ -2162,7 +2162,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## 代码风格可执行化:`.clang-format` / `.editorconfig` / `.gitattributes`(2026-10-11) - 类型:演进记录 / 否决方案("整仓 clang-format 重排"被否决) -- 内容:风格规则原本只在 `docs/todo/10-development-standards.md` §8(散文),新增机器可读的 +- 内容:风格规则原本只在 `docs/contributors/cpp-standards.md` §8(散文),新增机器可读的 `.clang-format`。取值是**实测拟合**出来的(对 `include/` 71 个文件跑 `clang-format` 后统计与 原文的行级差异):Allman(函数/类型/控制语句大括号一律另起一行,仓内主流)+ `NamespaceIndentation: None` + `ColumnLimit: 100`(全仓 99% 的行 ≤100 列)+ `ReflowComments: false` + @@ -2174,7 +2174,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 以及少数历史文件带 namespace 缩进)。因此定位为**目标风格 + 增量工具**:推荐 `git clang-format` 只格式化自己的改动行,并在 CONTRIBUTING/文件头明确写"不要在功能 PR 里顺手格式化无关文件"。 - 同批:`.editorconfig`(缩进/行尾/编码/尾随空格)、`.gitattributes`(**全仓 LF**:`scan_exprs` 的 - AOT 键与 KVRecord/日志解析对 `\r` 敏感,见 `docs/todo/08-pitfalls-and-lessons.md` 的 CRLF 条)。 + AOT 键与 KVRecord/日志解析对 `\r` 敏感,见 `docs/contributors/pitfalls.md` 的 CRLF 条)。 - 验收:`.clang-format` 能被 clang-format 23 解析(`--style=file` 退出码 0);`.gitattributes` 落地后 `git status` 无重规范化噪声(工作树本来就全 LF)。 @@ -2192,7 +2192,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## 计算类原语全量迁 DSL(2026-09-27,原位置 AGENTS.md §12「后续提交」第 1 条) - 类型:演进记录 + 教训 -- 内容:Layer 直调 **34 → 23**(`bench/doc_inventory.ps1` 复测),10 类计算原语全部退出 Layer 直调——`add_inplace`/`scale_inplace`/`accumulate`→`dsl::compute_into`(10 处)、`matmul`/`matmul_with_bias`→`dsl::matmul`(Linear/Conv/Transformer/Muon)、`row/col_reduce_*`→`dsl::compute_reduce`(11 处)、`batched_matmul` 21 处→`dsl::matmul(..., batch)`(alpha 用 `*dsl::rparam(scale)` 尾链,累加后乘三端等价);缺口 A:新增 `ExprViewKind::GroupedReduceSum/Max`(`dsl::grouped_reduce_sum/max(t, R)`,R 进 key、glsl_gen 编译期展开、CPU 模板路径独立归约),MaxPool2D 迁移。保留 23 个 = 基础设施/数据搬运(transpose/slice/gather/im2col…)/状态扫描(scan_*/outer_col)/fold 显式登记,与 `docs/todo/12` §7.3 形态一致。ctest 19/19 全绿。 +- 内容:Layer 直调 **34 → 23**(`bench/doc_inventory.ps1` 复测),10 类计算原语全部退出 Layer 直调——`add_inplace`/`scale_inplace`/`accumulate`→`dsl::compute_into`(10 处)、`matmul`/`matmul_with_bias`→`dsl::matmul`(Linear/Conv/Transformer/Muon)、`row/col_reduce_*`→`dsl::compute_reduce`(11 处)、`batched_matmul` 21 处→`dsl::matmul(..., batch)`(alpha 用 `*dsl::rparam(scale)` 尾链,累加后乘三端等价);缺口 A:新增 `ExprViewKind::GroupedReduceSum/Max`(`dsl::grouped_reduce_sum/max(t, R)`,R 进 key、glsl_gen 编译期展开、CPU 模板路径独立归约),MaxPool2D 迁移。保留 23 个 = 基础设施/数据搬运(transpose/slice/gather/im2col…)/状态扫描(scan_*/outer_col)/fold 显式登记,与 `docs/internal/12` §7.3 形态一致。ctest 19/19 全绿。 - 教训①:scan dry-run **禁止 `(void)` 吞错**——ZiPTBlock 的 dry-run 调单参 `forward(x)`(实际返回"用双参"错误)被吞 → **该 dry-run 从未执行真实路径**,存量结构恰好处处有 key 才长期绿,迁移新结构立刻闭合世界硬报错(已修为双参调用 + 失败 abort);**dry-run 长期绿 ≠ 覆盖存在**。 - 教训②:新 `ExprViewKind` 落点清单:枚举+validate(`expr_spec.hpp`)→ SpecBuilder helper+叶子+自由函数+`has_reduction_v=false` 显式特化(`expr_dsl.hpp`)→ `glsl_view_read` case(`expr_glsl_gen.hpp`,R 编译期展开)→ 解释器两处 switch(`compute_cpu_engine.hpp` 形状校验+读取);GPU 侧无 per-view 分派,vec4 白名单/uses_row 排除集自动正确。 @@ -2215,7 +2215,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## IR-C(图 IR / 跨表达式融合)整体移除(原位置 AGENTS.md §12 + §7) - 类型:被否决方案 -- 内容:删除 `expr_graph.hpp`、`compute_engine` 的 `begin_expr/end_expr`、`dsl::start_expr/end_expr`、`FusedChainLayer`、`Tensor::virtual_tag_`。取舍记录正文(五条否证依据、删除项/保留项清单、重新立项前提)见 `docs/todo/03-ir-optimization.md` §5.3(归档正文在 `docs/history.md`)。当前结论保留在 AGENTS §7:**IR-C 未采用,当前没有任何跨表达式录制机制**。 +- 内容:删除 `expr_graph.hpp`、`compute_engine` 的 `begin_expr/end_expr`、`dsl::start_expr/end_expr`、`FusedChainLayer`、`Tensor::virtual_tag_`。取舍记录正文(五条否证依据、删除项/保留项清单、重新立项前提)见 `docs/internal/03-ir-optimization.md` §5.3(归档正文在 `docs/history.md`)。当前结论保留在 AGENTS §7:**IR-C 未采用,当前没有任何跨表达式录制机制**。 ## RLA/RAPT 激活重计算 + offload 接线(2026-09-19,原位置 AGENTS.md §12) @@ -2235,7 +2235,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## 分组归约原语 + 融合 push-constant 缺陷修复(2026-09-20,原位置 AGENTS.md §12) - 类型:已修复勘误 -- 内容:新增 `grouped_reduce_sum/max`(沿行方向按固定长度 R 分组归约),MaxPool2D 因此去掉逐通道 C 次 dispatch → 单次原语;新增 `fused_gpu_test::run_reduce_consts` 回归用例。根因:`run_fused_gpu` 的 push-constant **固定头长度必须逐形态**与生成器 PC 声明一致(逐元素 2 / 逐元素+matmul 5 / 归约 4 / 归约+matmul 6);bug 把"归约但无 matmul"按 **5** 算 → 常量池整体后移一个 uint → **GPU 上"带常量的归约"静默错值而 CPU 正常**(表现为 `col_reduce_sum(select(x == col_broadcast(max), 1, 0))` 恒返回 kk-1 而非真实并列数)。教训:这类"只有 GPU 错"的问题要**先打印生成的 GLSL/IR 再猜成因**。详见 `docs/todo/08-pitfalls-and-lessons.md` §4.10。 +- 内容:新增 `grouped_reduce_sum/max`(沿行方向按固定长度 R 分组归约),MaxPool2D 因此去掉逐通道 C 次 dispatch → 单次原语;新增 `fused_gpu_test::run_reduce_consts` 回归用例。根因:`run_fused_gpu` 的 push-constant **固定头长度必须逐形态**与生成器 PC 声明一致(逐元素 2 / 逐元素+matmul 5 / 归约 4 / 归约+matmul 6);bug 把"归约但无 matmul"按 **5** 算 → 常量池整体后移一个 uint → **GPU 上"带常量的归约"静默错值而 CPU 正常**(表现为 `col_reduce_sum(select(x == col_broadcast(max), 1, 0))` 恒返回 kk-1 而非真实并列数)。教训:这类"只有 GPU 错"的问题要**先打印生成的 GLSL/IR 再猜成因**。详见 `docs/contributors/pitfalls.md` §4.10。 # 训练 step 剖析器(NN_PROFILE,2026-10-06) @@ -2278,12 +2278,12 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 ## 评估分块(CNN 全量评估 OOM 修复,2026-09-20,原位置 AGENTS.md §12) - 类型:已修复勘误 -- 内容:`evaluate_mnist` 新增 `eval_batch`(默认 1000)分块前向 + 每块 `release_idle_pool_blocks()`;`mnist_train` 传 `cfg.batch_size`。根因:CNN/MLP 走 `N = x.cols()` 全量单次 forward,CNN 的 im2col 是 k²·C_in 倍 → 60000 样本需 ~6.4 GB → `vkAllocateMemory failed: -2`(训练步其实只多 130 MB)。见 `docs/todo/08-pitfalls-and-lessons.md` §3.7。 +- 内容:`evaluate_mnist` 新增 `eval_batch`(默认 1000)分块前向 + 每块 `release_idle_pool_blocks()`;`mnist_train` 传 `cfg.batch_size`。根因:CNN/MLP 走 `N = x.cols()` 全量单次 forward,CNN 的 im2col 是 k²·C_in 倍 → 60000 样本需 ~6.4 GB → `vkAllocateMemory failed: -2`(训练步其实只多 130 MB)。见 `docs/contributors/pitfalls.md` §3.7。 ## 复合层 checkpoint 模式坑(原位置 AGENTS.md §12「坑」) - 类型:已修复勘误 -- 内容:复合层 override `forward_recompute` 必须调用**虚函数** `set_checkpoint_mode` 关闭子层;基类默认实现只改本块标志位 → 子层缓存不重建(stride>1 时被上一轮陈旧缓存掩盖,表现为部分 stride 通过)。模式开关(checkpoint/offload/doc-mask)的缓存契约见 `docs/todo/08-pitfalls-and-lessons.md` 模式 H。 +- 内容:复合层 override `forward_recompute` 必须调用**虚函数** `set_checkpoint_mode` 关闭子层;基类默认实现只改本块标志位 → 子层缓存不重建(stride>1 时被上一轮陈旧缓存掩盖,表现为部分 stride 通过)。模式开关(checkpoint/offload/doc-mask)的缓存契约见 `docs/contributors/pitfalls.md` 模式 H。 ## GPU 算子性能优化(2026-09-23;其 BK trade-off 表于 2026-09-24 被同参 A/B 推翻,原位置 AGENTS.md §12) @@ -2555,7 +2555,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 - 内容: **合并说明**:`docs/development/13-refactor-backlog.md` 的未完成项与后续验证口径已迁入 -`docs/todo/18-roadmap.md`(未来方向路线图);13 号文件自 2026-10-01 起只是重定向 stub +`docs/internal/18-roadmap.md`(未来方向路线图);13 号文件自 2026-10-01 起只是重定向 stub (指向 18 与本节),**并于 2026-10-11 文档整理时删除**(内容已全部在 18 号与本文件,无信息丢失)。 本节归档它原有的两类内容——已完成 / 已被吸收的项,与 2026-10-01 裁定"不做"的项。 13 文首「正确性缺陷已在同轮修复」清单、原 §6 误报对照表、原 §9 代码缩减轮执行表**早已归档在本文件** @@ -2563,7 +2563,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 **已完成 / 已被吸收(只记坐标,正文见本文件既有条目)**: -- 13 §10(Tensor 绑定引擎 + 存储多态提案)整体被 `docs/todo/17-unified-tensor-engine.md` +- 13 §10(Tensor 绑定引擎 + 存储多态提案)整体被 `docs/internal/17-unified-tensor-engine.md` 吸收为 M1–M6,并于 2026-09-30 **全部实施**(访问收口 / InitSpec 声明式初始化 / 批量读写 / Matrix 降级 / 内存池契约统一 / `import` + Layer 删 engine 形参);**M7 未立项**。 逐期记录见本文件「统一总纲 M1…M6」诸条。 @@ -2605,7 +2605,7 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 "不机械统一"是唯一安全前提;留待下次动测试公共头时顺带处理。 5. **13 §10「Tensor 抽象基类 + `CPUTensor`/`GPUTensor` 句柄指针化」选型** —— 裁定:**维持否决**。 - 由 `docs/todo/17-unified-tensor-engine.md` §4.2 与 + 由 `docs/internal/17-unified-tensor-engine.md` §4.2 与 `docs/development/15-computeengine-refresh.md` §4 裁定:它要解决的 device 互斥收益与存储多态 重叠,却要 `Result` 203 处指针化 + `span/vector` 元素类型连锁,且**不解决 engine 传参耦合**。 @@ -2619,9 +2619,9 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则 §8(CI 冒烟)、§9 第 5 条(18 号文档记作 §9.5;`gpt_test` 偶发失败待观察:62 次直跑 1 次失败、 日志被覆盖未定位,已列为 18 号文档 P1-4)、§9b 末尾未编号 bullet(`bench/doc_inventory.ps1` 的 `host_bridge_uses` 计数口径未复核,13 与 17 记 41、18 号文档实测 40),以及 §10 吸收后的 **M7**, -其行动项与触发条件见 `docs/todo/18-roadmap.md`。13 原文件中"仍然生效的工程教训"类正文 +其行动项与触发条件见 `docs/internal/18-roadmap.md`。13 原文件中"仍然生效的工程教训"类正文 (§9 前四条约束、§9b 的 `dsl::compute` 无 2 参重载等)属当前状态说明,不在本节归档(避免与 -AGENTS §7、`docs/development/01-compute-engine-development.md` 等现行文档重复)。 +AGENTS §7、`docs/development/04-compute-engine-development.md` 等现行文档重复)。 **「文档坐标已过期」事实记录(2026-10-01 实测,供后续纠偏)**:13 正文中的行数/份数是审查当时快照, 现已过期——`include/neuralnet.cpp/backend/compute_vk_backend.hpp` **5246** 行(13 写 ≈4700; @@ -2633,8 +2633,8 @@ A1 段改动前为 2424)、`include/neuralnet.cpp/compute_cpu_engine.hpp` **23 **ctest 计数(口径已统一,2026-10-01 A4/A5 两轮 + 本次审核)**:审查当时实测 **19** (= 18 个测试目标 + `cnn_test_gpu`),此后 A4 注册 `fusion_custom_layer_example`、A5 接回 `fused_gpu_test` → **20 → 21**(= **19** 个测试目标 + `cnn_test_gpu` + `fusion_custom_layer_example`)。 -`AGENTS.md` §12 与 `docs/todo/18-roadmap.md` §2/§7 已统一写 **21**; -`docs/release-notes/v1.5.0.md` 与 `docs/todo/17-unified-tensor-engine.md` 记的 **20/20** 是 +`AGENTS.md` §12 与 `docs/internal/18-roadmap.md` §2/§7 已统一写 **21**; +`docs/release-notes/v1.5.0.md` 与 `docs/internal/17-unified-tensor-engine.md` 记的 **20/20** 是 **2026-09-30 里程碑当时的计数**(历史值,不回改)。19 / 20 / 21 三个数并存过一阵,根因就是 "是否含 `cnn_test_gpu`"与"后来新增了两个目标"两件互不相关的事叠在一起——**这不构成矛盾**, 但必须写明口径(本次补记)。 @@ -2664,7 +2664,7 @@ A1 段改动前为 2424)、`include/neuralnet.cpp/compute_cpu_engine.hpp` **23 - 类型:演进记录 / 删除清单 / 覆盖缺口 - **背景**:接入一个新数据集要重写一套读取+解析+缓存——六条互不相通的读取路径(MNIST CSV ×2、txt 直读、`.tokcache`、JSON 词表、`.nnpkg`)散落在三个文件里;词表/语料/掩码/缓存四个 - 概念互相纠缠。设计与逐条裁决见 `docs/todo/19-unified-dataset.md`(2026-10-05 对话定稿, + 概念互相纠缠。设计与逐条裁决见 `docs/internal/19-unified-dataset.md`(2026-10-05 对话定稿, 本轮按其 §9 分期落地,分段提交)。 - **阶段一(KVRecord v2 + `.nnvocab`)**:`model_keyvalue_record.hpp` 增 v2 分支——哨兵 `kvrec_version` 自举 v1/v2 分派(无版本字段 = v1,有 = 按版本读)、字段只记 key/类型/文件绝对 @@ -2876,7 +2876,7 @@ A1 段改动前为 2424)、`include/neuralnet.cpp/compute_cpu_engine.hpp` **23 AGENTS / 20 号文档仍在引用,20 号文档同提交还在称 `fusion_custom_layer*` 为 "现有样例")→ 从 `652c53d^` 恢复 5 个文件;`-DNN_ENABLE_TESTS=ON` 此前在 configure 阶段即失败,现恢复可用。 -- 待办(**已于 2026-10-06 随 P2 收官完成**):`docs/todo/02、03、12`、 +- 待办(**已于 2026-10-06 随 P2 收官完成**):`docs/internal/02、03、12`、 `docs/usage/03`、`docs/introduction/04` 中"IR-C 不存在/未采用"的当前状态表述。 --- @@ -3016,7 +3016,7 @@ A1 段改动前为 2424)、`include/neuralnet.cpp/compute_cpu_engine.hpp` **23 # Windows CRT abort() 模态弹窗静音(2026-10-06,用户截图报障) -- 类型:缺陷修复(测试/脚本可用性)+ 工具链坑(已录入 `docs/todo/08` §5) +- 类型:缺陷修复(测试/脚本可用性)+ 工具链坑(已录入 `docs/internal/08` §5) - **现象**:Windows Debug CRT 在 `abort()` 时弹**模态**"Microsoft Visual C++ Runtime Library — Debug Error! abort() has been called (Press Retry to debug the application)" 对话框(用户截图实测,来源 `error_macro_test.exe` 的 abort 负例子进程)。两个要害: @@ -3519,7 +3519,7 @@ A1 段改动前为 2424)、`include/neuralnet.cpp/compute_cpu_engine.hpp` **23 口径见上「kernel 对照」条(用户裁定:`fused_b` 与 `fused@optimizer` 分列, 合计核对)。 -## 库级违规设计清理:模型文件角色 + 参数形态协议 + 引擎能力体系(2026-10-11,docs/todo/23) +## 库级违规设计清理:模型文件角色 + 参数形态协议 + 引擎能力体系(2026-10-11,docs/internal/23) **整改前的原位置**:`include/neuralnet.cpp/compute_engine.hpp`(6 个能力谓词 + 19 处基类 NVI 能力分支)、`compute_layer_base.hpp` 的 `Layer::sub_layers()`、`compute_layer_bitlinear.hpp` @@ -3669,7 +3669,7 @@ F2 的实测瓶颈是**双份归因**(`supports_expr_precision_variant` 每次 > 与 `docs/development/16-computeengine-p0-inventory.md`(P0 盘点报告)的原正文随本次整理 > 从 `docs/development/` 撤下,全文并入本文;两份文档的**已落地成果**(P-1 PrecisionEngine 下沉、 > P1 张量出生绑定)与**未实施部分**(P2-P6)均已由现行总纲 -> `docs/todo/17-unified-tensor-engine.md`(改期 M1-M7,M1-M6 已实施)承接,无信息丢失。 +> `docs/internal/17-unified-tensor-engine.md`(改期 M1-M7,M1-M6 已实施)承接,无信息丢失。 > 以下为原文(标题降一级;正文路径与行号按归档当时版本书写,行号漂移后以符号名为准)。 ## ComputeEngine Refresh —— 详细设计与未决问题 @@ -3988,7 +3988,7 @@ P0 的"字节基线"因此拆成两半:**同设备 pre/post 锚点**(不变 - 方案出处与选型记录:`docs/development/13-refactor-backlog.md` §10(含 §10.8 否决记录; §10.3 第 1 条按本文 4.2 补"库内/库外"脚注)。 -- 引擎接口盘点:`docs/todo/12-compute-engine-inventory.md`。 +- 引擎接口盘点:`docs/internal/12-compute-engine-inventory.md`。 - 精度边界语义(P-1 下沉对象):`docs/development/05-mixed-precision.md` §8/§12。 - 历史归档:`docs/history.md`。 @@ -4202,7 +4202,7 @@ build/gpu_stability_probe --gpu 1 --steps 20 # 指定 GPU # 代码审查整改 批 A/B(RV-01..RV-04,2026-10-11) -来源:`docs/todo/00-code-review-remediation.md`(2026-10-11 外部代码审查的立项台账)。本轮只做 +来源:`docs/internal/00-code-review-remediation.md`(2026-10-11 外部代码审查的立项台账)。本轮只做 **批 A(RV-01、RV-02)+ 批 B(RV-03、RV-04)**,批 C / 批 D 未动。每条的方案与验收口径见该文 对应 RV 卡;这里只留本文件该管的**历史信息**(被替换掉的旧形态、踩到的坑、环境结论)。 @@ -4293,7 +4293,7 @@ INTERFACE 的 `/utf-8` 同处一条命令行 → `cl` 报 **口径说明**:结论是**代码级生命周期分析**,不是"校验层零告警"对拍——本机 `/usr/share/vulkan/explicit_layer.d/` 只有 MESA/INTEL 层,**无 `VK_LAYER_KHRONOS_validation`**。 -复现命令见 `docs/todo/00-code-review-remediation.md` 的 RV-14 卡(审计表 + 分类依据 + 未做项)。 +复现命令见 `docs/internal/00-code-review-remediation.md` 的 RV-14 卡(审计表 + 分类依据 + 未做项)。 # P2-6「绘制节流」半边:画板拖动开销(2026-10-15) @@ -4640,7 +4640,7 @@ E5 记的"任一改动牵动全文件"是真实成本,也是 **P1-2(checkpoi `steps_per_epoch`、测试子集、`eff_seq`、`x/y/loss_mask/flat_targets` 缓冲)一律在 loop 内 派生或经 `TextTrainLoopInput` 传入——不留"一半状态在 src、一半在 header"的缝合线。 4. **角色门禁的错误文案不加语境前缀**(用 `NN_TRY_CHECK` 而非 `NN_TRY_MSG`):该文案是 - 用户可见契约(docs/todo/23 §2.1),逐字保留。 + 用户可见契约(docs/internal/23 §2.1),逐字保留。 5. **探针随循环进 loop 模块**:`NN_NAN_TRACE` 的四个 helper 与 `NN_MEM_STATS` 的 `TextTrainMemProbe` 都只在循环里用;探针门语义不变(默认构建整块不编译、`on` 恒 false、 不求值 `getenv`)。 @@ -4689,7 +4689,7 @@ setup 路径上的错误不再带 `(expr) at file:line`(如需保留可另立 # P1-1(第一刀):`text_train` 的退出码语义——断点写失败不得成功退出(2026-10-15) -**缺陷**(docs/todo/18 §4.2 P1-1 的"退出码语义修正"):`--save-interval` 的 `.nnckpt` +**缺陷**(docs/internal/18 §4.2 P1-1 的"退出码语义修正"):`--save-interval` 的 `.nnckpt` 写失败时旧代码只打印一行 `[ckpt] 保存失败: …` 就继续跑,最后照常 `return 0`——上层 (脚本 / CI / `train_pkg`)看到的是"这轮训练完好",而实际上**断点没落盘**,`--resume` 会拿到旧断点或空文件。 @@ -4721,7 +4721,7 @@ setup 路径上的错误不再带 `(expr) at file:line`(如需保留可另立 # P1-2 设计裁定:`.nnckpt` 训练状态段 + role 语义(2026-10-16) **类型**:演进记录(裁定)+ 否决方案。**状态**:已裁定,未实施(落地见 18 §4.2 P1-2 行 + 门禁 §8.2 第 7 条; -设计正文见 `docs/todo/23` §2.1.1)。 +设计正文见 `docs/internal/23` §2.1.1)。 **背景**:原 P1-2 只写"`.bin` 增加可选优化器状态段(Adam m/v)"。设计讨论中把范围扩到"断点 = 训练的可续点", 并顺带查证出三处**静默错误**(下面的"依据"),它们决定了最终口径。 @@ -4760,7 +4760,7 @@ setup 路径上的错误不再带 `(expr) at file:line`(如需保留可另立 `packed_only_` 部署态,`backward()` 直接报错(`compute_layer_bitlinear.hpp:394`「部署态只读(没有 latent 可更新)」) ⇒ 三值模型的 SFT 需要反量化载入路径(新立 P1-7)。 - **版本号现实**:v7 已被"文件角色"改动占用(`model_serialization.hpp:62`);P1-2 原行写的 `5 → 6` 是过期口径 - (v1.7.0/v1.8.x 时期的"抢号提示")。本轮把 18 号与 `docs/todo/19` 的提示刷新为 **7 → 8**; + (v1.7.0/v1.8.x 时期的"抢号提示")。本轮把 18 号与 `docs/internal/19` 的提示刷新为 **7 → 8**; release note 作为历史文档保留原样(它写的"谁后落地谁顺延"正是已发生的事实)。 **被否决的方案(含否决理由)** @@ -4776,7 +4776,7 @@ setup 路径上的错误不再带 `(expr) at file:line`(如需保留可另立 **连带影响(后续落地时不得漏)** - **反转 P1-1 落地的角色门禁**:`--resume` 由"只认 Checkpoint"改为"Model 也接受(CLI 全权)"。 - 该门禁文案是 P1-1 验收里"**逐字未变**"的用户可见契约(`docs/todo/23` §2.1), + 该门禁文案是 P1-1 验收里"**逐字未变**"的用户可见契约(`docs/internal/23` §2.1), 落地时要同步 `text_train_modules_test` 的"Model 必须被拒"用例与 18 §5 的对应行。 - 禁列校验需要**旗标名**信息(解析层的默认值无法与用户输入区分):`parse_text_train_args` 记录"本进程显式 给出的 A/B 类旗标"名单,恢复路径发现非空即报错(+ 单测覆盖禁列)。 @@ -5222,8 +5222,8 @@ P0-4 的 `install()/find_package` 与 P2-9);剩 13 项 = 部分完成 5(P0 # 生命周期 v3 与 Session 层(v1.10.0,2026-10-20/21) -- 类型:演进记录 / 删除清单 / 设计裁决(**当前契约**以 `docs/development/09-engine-ownership.md` - 与 `docs/todo/28-lifecycle-v3.md`、`docs/todo/29-session-architecture.md` 为准;本条只归档 +- 类型:演进记录 / 删除清单 / 设计裁决(**当前契约**以 `docs/development/07-engine-ownership.md` + 与 `docs/internal/28-lifecycle-v3.md`、`docs/internal/29-session-architecture.md` 为准;本条只归档 「为什么删/为什么这样改」与已否决方案)。 - **原状(v1.9.0)**:`Tensor` 保存 `EngineId` provenance + `stamp_` / `adopt` / `bound` 出生绑定机制 (`core_engine_id.hpp` 83 行;`stamp_` 35 处、`adopt` 18 处、`bind_check_` 42 处、 @@ -5248,7 +5248,7 @@ P0-4 的 `install()/find_package` 与 P2-9);剩 13 项 = 部分完成 5(P0 (`TextTrainer::create` 校验配方 seq_len ↔ 模型 `spec.seq_len`)、P2-1(`--resume` 的 `adopt_resume_state` 之后重新校验精度×offload 组合)、P2-2(空 test 子集恢复打印"样本数: 0"); 其余 P2 记录在 `docs/release-notes/v1.10.0.md` §2.5 / §9。四棵树矩阵与真实数据端到端验收 - 见 `docs/todo/25-release-requirements.md` §7。 + 见 `docs/contributors/release-requirements.md` §7。 - **否决方案**:① 保留 provenance 但"按操作数两两比较 + 补 `this` 比较"(D1 漏点仍在、机制税照付); ② 用 `dynamic_cast` 查具体层类型做形状校验(铁律 #14 禁止);③ 把 offload slab 精度协议化 (本轮选"配置期拒绝"的最短正确路径);④ `Layer::sequence_length()` 全覆盖形状校验 @@ -5288,7 +5288,7 @@ P0-4 的 `install()/find_package` 与 P2-9);剩 13 项 = 部分完成 5(P0 - **动机**:`TrainingSession`(单步)与 `TextTrainer`(文本域驱动)之间没有领域无关 骨架,自定义域从 `train_step` 往上全要自己写(go CLI `go_train_cli.cpp` 达 1456 行, 其中 epoch 循环 / 断点节奏 / lr 接线 / 指标落盘全是与领域无关的重复)。 -- **RFC**:`docs/todo/32-trainer-skeleton-and-openspec.md`,四扩展点统一心智 = +- **RFC**:`docs/internal/32-trainer-skeleton-and-openspec.md`,四扩展点统一心智 = 「虚基类定义契约 + 主仓持基类引用 + 子类注入特化」(TrainState / ModelSpecBase / BatchSource / RunDriver)。 - **阶段 A**:`TrainState` 虚基类化(编解码骨架 + `state_kind`/`write_extra_kv`/ @@ -5345,3 +5345,71 @@ P0-4 的 `install()/find_package` 与 P2-9);剩 13 项 = 部分完成 5(P0 落盘——两者混淆会让"缺 norm_type 键的旧文件"读成 BatchNorm、参数布局错位。 - **验证**:全量构建 0 错误;ctest 70/70(含 spec 往返、旧数值 type 回落、 ZiPT 拒绝、norm_place 错配拦截、三值权重往返、自定义注册表 §8)。 + +## docs/ 文档结构整理(2026-10-11 两轮 + 2026-11 第三轮) + +> 类型:演进记录。本节归档 `docs/README.md` 曾承载的历次整理叙事(2026-11 起索引文件 +> 不再承载叙事,按文档规范归档义务统一放这里)。 + +### 第一轮(2026-10-11):分册按读者划分 + +原则 =「`development/` 只留调用者文档;项目开发者文档进 `internal/`;历史进 `history/`」。逐项: + +- **迁移到 `docs/internal/`**(原 `docs/development/`,文件名与编号不变):`02` `03` `04` `08` + `10` `12` `14` `17` `18` `19` `21` `22` `23`。 +- **整篇并入 `history.md`**(内容已由后继文档承接,正文保留在文末「docs/development 15 · 16」 + 归档节):`15-computeengine-refresh.md`、`16-computeengine-p0-inventory.md`。 +- **删除**:`13-refactor-backlog.md`——2026-10-01 起就只是 16 行的重定向 stub,正文早在本文件 + 与 `internal/18-roadmap.md`。 +- **保留在 `docs/development/`(重定义其读者为"调用者")**:`01` `05` `06` `20`。 +- **新增**:`docs/README.md`(总索引)、`docs/internal/README.md`、`docs/development/README.md`、 + `docs/internal/00-code-review-remediation.md`。 + +整理前 `docs/development/` 共 20 篇,多数是"一件事只用几次"的内部设计/盘点稿。 + +### 第二轮(2026-10-11 同日):对外入口补全 + +第一轮解决"文档写给谁看",第二轮补"非作者怎么进得来": + +| 增加 | 作用 | +|------|------| +| `CONTRIBUTING.md` | 非作者统一入口:构建(preset)、测试口径、代码规范、提交信息、PR 自查、CI 实际做什么(含"CI 不跑 ctest"事实)、文档/研究贡献 | +| `CODE_OF_CONDUCT.md` | 社区行为准则(Contributor Covenant 2.1 改编)+ "技术讨论对事不对人"约定 | +| `CMakePresets.json` | 六个 preset;只描述口径,不改变 CMakeLists 默认值 | +| `.clang-format` / `.editorconfig` / `.gitattributes` | 风格规则机器可读化;定位是目标风格 + 增量工具(`git clang-format`),不是整仓重排(整排会改约 41% 行,见「代码风格可执行化」条) | +| `research/README.md` 重写 | 从目录表升级为可引用结论索引:结论(带数字与 n=)/ 证据 / 重跑命令 / 边界 | + +同日修掉的构建问题:ccache 与共享 PCH 互斥(Clang 侧缺 `sloppiness=pch_defines,time_macros` +与 `-fno-pch-timestamp`)导致 40+ 目标不可缓存——已修,命中缓存的单 TU 30.2s → 0.11s, +全量重建 13m26s → 58.8s(见「ccache × 共享 PCH」条)。 + +### 第三轮(2026-11):规范成文 + 目录重构 + 机器审查升级 + +背景:dev 合入 main 后暂缓版本定档,先做文档重构(**发布规则见 +`docs/contributors/release-policy.md`:定档由人提出**)。逐项: + +- **新增 `docs/contributors/` 分册**(贡献者/维护者/agent 的长期规范与治理): + `cpp-standards.md`(原 `internal/10-development-standards.md`)、`pitfalls.md` + (原 `internal/08-pitfalls-and-lessons.md`)、`release-policy.md`(原 + `internal/33-…`)、`release-requirements.md`(原 `internal/25-…`)、 + `documentation-standard.md`(**新写**:分册职责/编号制度/单篇模板/标注体系/机器审查口径)。 +- **`docs/todo/` 更名 `docs/internal/`**:原名只覆盖"待办"语义,而目录实际承载设计稿/ + 路线图/盘点/故障台账;长期规范剥离至 `contributors/` 后改名。全仓 49 个 md + 代码注释 + (gui.py / CMakeLists / bench / 头文件)中的路径同步改写。 +- **`docs/development/` 编号按阅读顺序重排**(编号=阅读顺序,连续不留洞): + `cmake-integration` → `01`、`cpp-api-manual` → `02`、`write-a-custom-layer` → `03`、 + `01-compute-engine-development` → `04`、`05-mixed-precision` 不变、 + `07-vulkan-backend-map` → `06`、`09-engine-ownership` → `07`、 + `06-rapt-algorithm` → `08`、`20-custom-layer-ergonomics` → `09`; + **删除转发页 `08-object-lifetimes.md`**(3 行指针,真源 = 新 `07-engine-ownership.md`; + 转发页原则上不再建,见文档规范 §1.2)。 +- **编号制度成文**(文档规范 §1.2):`internal/` = 稳定台账 ID(跳号正常、新增续最大号); + 调用者分册 = 阅读顺序(必须连续);`contributors/` = 无编号主题名。 +- **新增 `scripts/doc_audit.py`**:移植并扩展 `bench/doc_align_audit.ps1` 的 A–F 类检查 + (文件/链接存在、已删符号残留、数字断言披露、CLI 参数、头部模板+状态词+索引登记、 + 符号/测试名核对),新增 G 类**代码示例清单**——提取全部代码块生成复核报告 + (`build/doc_audit/code_examples_report.md`),机器核对符号存在性、人工复核逻辑正确性。 + 代码示例按 fence info string 标注角色(`example api` / `snippet` / `cli`)。 +- **根 `README.md` 重写为项目介绍**(此前是文档索引+项目结构+许可证的堆叠): + 定位改为"最吸引人的东西放最前";文档索引职责移交 `docs/README.md`(消除两处重复维护)。 +- **`docs/README.md` 瘦身**:§3/§4 的两轮整理叙事迁入本节;新增 `contributors/` 分册段。 diff --git a/docs/todo/00-code-review-remediation.md b/docs/internal/00-code-review-remediation.md similarity index 99% rename from docs/todo/00-code-review-remediation.md rename to docs/internal/00-code-review-remediation.md index f9c4c4e..9ea0107 100644 --- a/docs/todo/00-code-review-remediation.md +++ b/docs/internal/00-code-review-remediation.md @@ -6,6 +6,7 @@ > **本文作用**:把审查报告里的问题**逐条立项**——先复核(哪些成立、哪些表述有误),再给每项定优先级、证据、 > 根因、方案、验收口径。**接手整改前先读本文**;未完成的"下一步该做什么"仍以 [`18-roadmap.md`](18-roadmap.md) 为准, > 本文是它的**执行细节来源**,两者不重复立项(见 §5)。 +> **状态**:现行。 ## 0. 怎么用本文 @@ -246,7 +247,7 @@ display / beta / state_bufs / half_state)+ `optimizer_table()` / `find_optimiz `EngineId`(不复用、无指针),Tensor 晚于引擎析构也安全。验收:CPU ctest **53/53**、GPU ctest **55/55**(850M);`layer_lifetime_test` 覆盖 Tensor/Layer/Model/Optimizer 保活与跨引擎拒绝, `NN_GPU_LIFETIME_FULL=1` 额外验证 `GpuBuffer` 晚于 `GpuEngine`/backend 析构;设计与迁移清单见 -[`../development/09-engine-ownership.md`](../development/09-engine-ownership.md)。 +[`../development/07-engine-ownership.md`](../development/07-engine-ownership.md)。 ### RV-06 — 绑定不变量与 `NN_BIND_DEBUG`:把调试门升为 CI 门禁 @@ -474,7 +475,7 @@ GPU 侧用 `static_cast(P)` 拼精度签名/报错文本的地方补一致 **现象与证据**:`compute_vk_backend.hpp` 中 `descriptor*` 出现 **199** 处;`pending_destroys_` 只管 **buffer** (延迟销毁),descriptor set / pool 的归还路径(如 `:3595` 附近"只归还描述符集;solo fence/cmd 留待下次复用") -未在文档里闭环,`todo/12` 的盘点也未覆盖。 +未在文档里闭环,`internal/12` 的盘点也未覆盖。 **方案**:一次**只读**专项审计——列表(分配点 / 归还点 / 池重置点),核对"录制期引用"与"归还时机"是否满足**铁律 6**; 产出结论(表格:点位 / 是否可能 use-after-free / 证据)写回本文;发现真缺陷则另立 RV 编号。 diff --git a/docs/todo/02-operator-fusion.md b/docs/internal/02-operator-fusion.md similarity index 99% rename from docs/todo/02-operator-fusion.md rename to docs/internal/02-operator-fusion.md index a882e4f..c2ab560 100644 --- a/docs/todo/02-operator-fusion.md +++ b/docs/internal/02-operator-fusion.md @@ -1,6 +1,7 @@ # 算子融合(Operator Fusion)—— 显存下探与手写算子收敛为 IR 融合 > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 +> **状态**:现行。 > 本文记录算子融合的**当前形态与设计约束**:一期(M1-M7)建立归约语义 IR 与注意力 / 稀疏 CE 的融合结构,二期(S1-S7)把 **matmul 纳入 IR 融合**,让手写融合原语收敛为 IR 表达——**一期的手写融合原语(M4-M6)已不存在,其结构一律由 IR / fold 承载**。两期服务同一目标:减少 GPT+Vulkan 训练显存,同时严格遵循分层铁律。 > @@ -359,7 +360,7 @@ forward = 单 fold kernel(`FoldSpec` 分块流式,见 §关键算法);ba | **M3** | Softmax/LayerNorm/RMSNorm fwd/bwd 的 DSL 归约表达式 + GPU 归约融合 shader(见 §Layer 迁移) | | **M4 / M6** | 手写注意力融合原语——**不存在**;forward 由 fold 承载、backward 由 IR 链承载(见 §关键算法) | | **M5** | 稀疏交叉熵——现为 IR 表达(见 §关键算法) | -| **M7** | "原语可专、不叫算法名"约定(`10-development-standards.md`) | +| **M7** | "原语可专、不叫算法名"约定(`../contributors/cpp-standards.md`) | | **S1–S7** | 二期阶段,见 §二期 S1-S7:手写算子收敛为 IR 融合 | > 分期实施流水、当时验收与被删原语的实施坑见 `docs/history/history.md`。 diff --git a/docs/todo/03-ir-optimization.md b/docs/internal/03-ir-optimization.md similarity index 98% rename from docs/todo/03-ir-optimization.md rename to docs/internal/03-ir-optimization.md index 69aab2e..e92c492 100644 --- a/docs/todo/03-ir-optimization.md +++ b/docs/internal/03-ir-optimization.md @@ -1,10 +1,11 @@ # IR 优化(IR Optimization)—— 为融合算子引入中间表示 > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 +> **状态**:现行。 > 目标:在**不推翻现有 AOT 闭合世界**的前提下,把 `ExprSpec` 从"直通轻量 IR"演进为带优化 pass 的规范 IR,分阶段提升开发便利与代码质量。 > 状态:现行优化链 = **IR-A(canonicalize:DCE/常量折叠/代数化简/稳定重编号)+ IR-B(CSE + 寄存器分配 liveness)+ IR-C(图 IR + `begin_expr/end_expr` 融合分析)+ IR-D(后端 emitter 抽象)**,分别由 `expr_opt.hpp` / `expr_graph.hpp` / `expr_emitter.hpp` 承载;**IR-C 已恢复并通用化(P1 机制 + P2 写穿多输出 + Adam 接线,见 §5.3)**。 -> 关联文档:`02-operator-fusion.md`(算子融合)、`10-development-standards.md`(分层铁律)、`08-pitfalls-and-lessons.md`。 +> 关联文档:`02-operator-fusion.md`(算子融合)、`../contributors/cpp-standards.md`(分层铁律)、`../contributors/pitfalls.md`。 ## 目录 diff --git a/docs/todo/04-memory-optimization.md b/docs/internal/04-memory-optimization.md similarity index 99% rename from docs/todo/04-memory-optimization.md rename to docs/internal/04-memory-optimization.md index ff9bacf..545109c 100644 --- a/docs/todo/04-memory-optimization.md +++ b/docs/internal/04-memory-optimization.md @@ -1,9 +1,10 @@ # 显存优化计划(Memory Optimization)—— GPT + Vulkan/CPU 训练显存下探 > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 +> **状态**:现行。 > 文档状态:**L1 激活重计算(梯度检查点)已实施 / L2 内存池整块归还 + 统计已实施**(L3 远期)。 -> 关联文档:`../todo/02-operator-fusion.md`(算子融合已完成部分,消除 seq² 物化)。 +> 关联文档:`../internal/02-operator-fusion.md`(算子融合已完成部分,消除 seq² 物化)。 ## 目录 diff --git a/docs/todo/12-compute-engine-inventory.md b/docs/internal/12-compute-engine-inventory.md similarity index 99% rename from docs/todo/12-compute-engine-inventory.md rename to docs/internal/12-compute-engine-inventory.md index f1b6b2b..dcee53d 100644 --- a/docs/todo/12-compute-engine-inventory.md +++ b/docs/internal/12-compute-engine-inventory.md @@ -1,6 +1,7 @@ # 计算引擎现状盘点 > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 +> **状态**:现行。 > 本文只记录**当前状态**:引擎接口清单、表达式求值机制、与目标形态的差距。 > 目的:把当前代码里实际并存的计算 API 与遗留物列清楚,作为事实底座;全部结论来自 @@ -10,10 +11,10 @@ > 其余 20 个公开入口只服务 DSL lowering / 序列化 / CLI / 适配层 / 测试,见 §2); > CPU 求值机制 **2 套** > (DSL 模板路径 + IR 解释器,见 §3);ctest **62** 个(**无 Vulkan 树**;GPU 树 **64**,2026-10-30 实测)= -> **51 个测试目标 + 13 个变体/附加**(**完整枚举只写在 `docs/todo/18` §2**, +> **51 个测试目标 + 13 个变体/附加**(**完整枚举只写在 `docs/internal/18` §2**, > 此处不重复以免漂移)。其中 `fused_gpu_test` = 融合 shader **逐形态** GPU 对拍;`expr_graph_test` = IR-C 图融合分析(CPU 12 用例); > `error_macro_test`(错误处理宏族 `NN_UNWRAP`/`NN_EXIT`/`NN_TRY_MSG`/`NN_FAIL`)与 `kvrec_test`/`nnvocab_test`/`dataset_test` -> (统一数据集 KVRecord v2 / `.nnvocab` / `.nndataset`,见 `docs/todo/19`)**已下沉子仓** +> (统一数据集 KVRecord v2 / `.nnvocab` / `.nndataset`,见 `docs/internal/19`)**已下沉子仓** > (2026-10-26 `24e0599`:本体在 `extern/base` / `extern/kvrecord` / `extern/tokenizer` / `extern/dataset` 各自 `tests/`,主仓 ctest 不再注册); > `zipt_test` 随 ZiPT 移除,见 `docs/history/history.md`;`dsl_shape_infer_test` = `dsl::compute`/`compute_reduce` 的**无形状重载**(推导口径 + 负例)。 > @@ -88,7 +89,7 @@ scan_suffix_outer/outer_col——顺序状态机,DSL 无此语义)、`eval_e 注意力组合在 `compute_layer_attention.hpp`,属 AOT 设计而非旁路)、`begin_expr`(IR-C 录制段入口:`Adam::step`/`AdamW::step` 打开图录制,`ExprSegment` 守卫收口)。 **三值打包**(`matmul_q`/`matmul_q_t`/`trit_pack`——`BitLinear` 的打包 GEMM 与打包, -op-level 引擎原语,不进 DSL 闭合世界、无需 scan 登记,见 `docs/todo/21` §4.12)。 +op-level 引擎原语,不进 DSL 闭合世界、无需 scan 登记,见 `docs/internal/21` §4.12)。 **`from_matrix`/`to_matrix` 自 M4 起退出本列**(铁律 #12:L2+ 禁用 Matrix 型 I/O 动词),层自算辅助数据改走 `detail::upload_span/download_span/download_vector` (自由函数,不进 `engine.(` 统计)。) diff --git a/docs/todo/14-f16-stable-gpu-loss-frozen.md b/docs/internal/14-f16-stable-gpu-loss-frozen.md similarity index 99% rename from docs/todo/14-f16-stable-gpu-loss-frozen.md rename to docs/internal/14-f16-stable-gpu-loss-frozen.md index 3aec133..86dfc72 100644 --- a/docs/todo/14-f16-stable-gpu-loss-frozen.md +++ b/docs/internal/14-f16-stable-gpu-loss-frozen.md @@ -1,6 +1,7 @@ # 14 — GPU `stable=f16` 训练 loss 回读冻结 > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 +> **状态**:现行。 > 状态:**✅ 已修复(2026-10-13)——根因订正:不是「loss 回读链」问题,而是 CE 的 (1,1) loss > 归约按 `stable=f16` 落盘溢出(详见 [`24`](24-f16-training-defects.md) §3.1)**。 diff --git a/docs/todo/17-unified-tensor-engine.md b/docs/internal/17-unified-tensor-engine.md similarity index 99% rename from docs/todo/17-unified-tensor-engine.md rename to docs/internal/17-unified-tensor-engine.md index a40b07c..732331a 100644 --- a/docs/todo/17-unified-tensor-engine.md +++ b/docs/internal/17-unified-tensor-engine.md @@ -1,6 +1,7 @@ # 统一 Tensor / ComputeEngine / MemoryPool 底层架构总纲 > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 +> **状态**:现行。 > **本文是新总纲**:吸收并取代 `15-computeengine-refresh.md` 未实施的 P2-P6(本文 §5 分期), > 并对 `13-refactor-backlog.md` §10.8 增补"访问不变量"注脚。历史归档见 `docs/history/history.md`。 @@ -211,7 +212,7 @@ CPU 字节基线 + scan 产物 hash + layer_bench(定义见 §6)。 | **M2** ✅ | **声明式创建/初始化**:`InitSpec` + `Layer::init` 迁移 + RNG 收编 | `create_tensor` NVI 扩展;`compute_layer_*.hpp` 的 init(mlp/conv/gpt/zipt/rapt…) | **四件套全过** + **初值跨进程确定性**:build 122/122 零告警;ctest 20/20;`gpu_stability_probe --init-hash` 六模型两进程 `INIT1` 行全同(**新锚**:mnist_mlp `a22e807ee05ec3ac`、cnn `4020958a14160bbd`、mnist_transformer `04a72d865624042a`、gpt `8efa936ac5c8c9b2`、zipt `f90bf8c8783c2f89`、rapt `b037632f75b7159c`);mnist 三架构(`--shuffle-steps false`)双进程 loss 序列 + 模型文件逐字节一致(**新训练锚**,仅墙钟行异);`--steps 20` hash=`6f8849f14da23110` 与 M1 锚点逐位一致(覆写隔离下后端执行零变化);scan 双 hash 不变(`expr_specs.bin`=bdc3a442…a58360、`fused_registry.hpp`=7a10412c…);layer_bench 配对 4 轮 + feedforward 逆序 4 轮复测均 < ±6% 无系统性回退;`NN_BIND_DEBUG=1` 冒烟零诊断(详见 `docs/history/history.md` M2 条) | | **M3** ✅ | **批量读写 API**:`read/write/get_index/set_index` + I/O 分组审计口径(D9;U2 精确匹配) | `compute_engine.hpp` I/O 分组(基类非虚模板,复用 `to_matrix`/`copy_from`)+ CPU/GPU 两引擎;测试 f32 填充/恢复路径迁 `write`;探针 `--io-roundtrip` | **四件套全过**:build 全绿零告警;ctest 20/20;`gpu_stability_probe --io-roundtrip` CPU + GPU 全过(`f32_roundtrip`/`f16_roundtrip`/`batch_window` 三用例含录制窗口 write→read→end_batch→复读);CPU 字节锚 `--steps 20` hash=`6f8849f14da23110` 不变;scan 双 hash 不变(`expr_specs.bin`=bdc3a442…a58360、`fused_registry.hpp`=7a10412c…);**顺带修复 16 §7-2**(探针漏 `backend.initialize()` 的 GPU 崩溃,根因回填 16 §6/§7)——dev0/dev2/dev4 进程内两轮 + 跨进程 loss/hash 逐字节(详见 `docs/history/history.md` M3 条) | | **M4** ✅ | **Matrix 降级收口**:L2+ 禁用规则成文(铁律 #12)+ D11 宿主桥裁定 + 分层审计脚本(U5) | L2 全量迁移:`compute_layer_{attention,base,conv,gpt,rapt,transformer,zipt}.hpp` + `compute_loss.hpp` + `compute_optimizer.hpp`(45 处 Matrix 型 I/O + 32 处 `Matrix` 类型);`compute_engine.hpp` 尾部新增 `detail::upload_span/download_span/download_vector`(宿主桥,0 虚表项);`bench/doc_inventory.ps1` 新增第 [4] 节 | **审计零违规**(`L2-VIOLATIONS: 0`,宿主桥 41 处仅披露)+ 四件套全过:build 122/122 零告警;ctest 20/20;**CPU 字节锚 `6f8849f14da23110` 与 GPU dev2 `8ef51b2927253c50` 均与迁移前逐位一致**(迁移是纯载体替换,数值路径零改动);scan 双 hash 不变;layer_bench 配对 A/B(pre=HEAD worktree 二进制,feedforward/swiglu/linear 各 4 轮交错):feedforward fwd/train **-1.2%/-1.6%**、linear +1.4%/-4.2%、swiglu fwd -6.2%(0.4ms 亚毫秒级,PRE 自身极差 0.38–0.47ms 即 ±10%)——全部在 ±6% 噪声带内无系统性回退(详见 `docs/history/history.md` M4 条) | -| **M5** ✅ | **内存池契约统一**:无池引擎 `pool_stats` 语义补齐 | `algebra_matrix.hpp`(`HostAllocLedger` + `MatrixT` 分配/释放记账三出口)+ `compute_engine.hpp` 基类默认 `pool_stats` | **两引擎 `pool_stats` 非空且口径文档化**(17 §4.5 + `04-memory-optimization.md` + `01-compute-engine-development.md`):CPU `direct{ blocks/live_bytes/peak_bytes/total_blocks/total_bytes }` 实测随 model-built/optimizer-created 递增(`NN_MEM_STATS=1 text_train` 抓取),GPU `persist{…} transient{…} pending=…` 照旧;`release_idle_pool_blocks` CPU no-op 写明理由。四件套:build 122/122 零告警、ctest 20/20、CPU 锚 `6f8849f14da23110` 与 scan 双 hash 不变、`--io-roundtrip` CPU/GPU 全过、L2 审计仍 0 | +| **M5** ✅ | **内存池契约统一**:无池引擎 `pool_stats` 语义补齐 | `algebra_matrix.hpp`(`HostAllocLedger` + `MatrixT` 分配/释放记账三出口)+ `compute_engine.hpp` 基类默认 `pool_stats` | **两引擎 `pool_stats` 非空且口径文档化**(17 §4.5 + `04-memory-optimization.md` + `04-compute-engine-development.md`):CPU `direct{ blocks/live_bytes/peak_bytes/total_blocks/total_bytes }` 实测随 model-built/optimizer-created 递增(`NN_MEM_STATS=1 text_train` 抓取),GPU `persist{…} transient{…} pending=…` 照旧;`release_idle_pool_blocks` CPU no-op 写明理由。四件套:build 122/122 零告警、ctest 20/20、CPU 锚 `6f8849f14da23110` 与 scan 双 hash 不变、`--io-roundtrip` CPU/GPU 全过、L2 审计仍 0 | | **M6** ✅(三段全落地) | **吸收 15 P2/P3**:**A** = 15 D6/D7/D8 落地 + `NN_BIND_DEBUG` 门禁;**B** = 43 处 `ensure_gpu`→`import`(新增跨设备拉取契约,virtual 48→49);**C** = 删 Layer 每调用 engine 形参(175 打标清单里的 Layer 部分) | 段 A:`model_serialization.hpp`、`model_container.hpp`、`compute_engine.hpp`(D6-3 改纯虚、`to_prec` 补绑定、`bind_error_` 打 stderr)、offload 占位(D8)、`expr_dsl.hpp`;段 B:`compute_engine.hpp` `import/import_impl` + `compute_gpu_engine.hpp` 48 处改名;段 C:`compute_layer_base.hpp`(`engine_` 成员 + `init` NVI + 四虚接口去形参 + `engine_ref()` 带 source_location 诊断)、10 个层头 54 处定义 + 约 200 处调用点、复合层子层 init 补齐、scan/测试补 `init(engine)` | **三段四件套全过**:build 零告警;ctest 20/20 **且 `NN_BIND_DEBUG=1` 同样 20/20(门禁)**;CPU 锚 `6f8849f14da23110` 与 **GPU dev2 锚 `8ef51b2927253c50`** 均逐位不变;`--init-hash` 六模型与 M2 锚全同;scan 双 hash 不变;`--io-roundtrip` CPU/GPU 全过;L2 审计 0;D6-1 round-trip SHA256 逐字节一致(f32/f16 param)。**layer_bench 配对 A/B(pre=worktree 基线)**:正序 feedforward fwd/train +4.1%/+4.5%、**逆序复测 -0.7%/+0.4%**(排除运行顺序偏置,判定为 -O0 二进制重排级小差,同 M2 结论);linear fwd ±8%(0.8ms 亚毫秒、train 反向 -6.9%,M1/M2 已记录该点方差)——**无系统性回退** | | **M7** | (可选后置)15 P5/P6 存储多态 + `as_cpu/as_gpu` | `compute_tensor.hpp` | 第三后端出现前**不立项** | diff --git a/docs/todo/18-roadmap.md b/docs/internal/18-roadmap.md similarity index 93% rename from docs/todo/18-roadmap.md rename to docs/internal/18-roadmap.md index 4772a3a..48b6fc3 100644 --- a/docs/todo/18-roadmap.md +++ b/docs/internal/18-roadmap.md @@ -1,11 +1,12 @@ # 开发路线图与未完成项裁定 > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 > **本文是"下一步该做什么"的唯一入口**:把 13 号清单(原 `docs/development/13-refactor-backlog.md`, > 现归档于 `docs/history/history.md`)的未完成条目与未来 6–12 个月的方向合并为一份可执行的裁定台账。 -> 13 号文档已于 2026-10-11 删除(内容全在本文与 `docs/history/history.md`);已完成项、被否决方案与历史取舍统一归档在 `docs/history/history.md`。 -> 底层契约的已落地部分(统一总纲 M1–M6)见 `docs/todo/17-unified-tensor-engine.md`。 +> 13 号文档已删除(内容全在本文与 `docs/history/history.md`);已完成项、被否决方案与历史取舍统一归档在 `docs/history/history.md`。 +> 底层契约的已落地部分(统一总纲 M1–M6)见 `docs/internal/17-unified-tensor-engine.md`。 > 写作纪律:只写事实与决定;行号取自实测,行号漂移后以符号名为准,未能确证的位置只给文件名、不给行号。 ## 0. 一句话 @@ -21,12 +22,12 @@ | 文档 | 角色 | 何时读 | |---|---|---| | **本文(18)** | 方向 + **未完成项裁定台账**(做 / 条件触发 / 不做 + 验收口径 + 现状实测);**不含执行计划** | 想知道"某件事该不该做、做到什么算完成"时 | -| `docs/todo/27-execution-plan.md` | **执行计划(优先级象限)**:把本文 §3/§4/§6 与 00 号 RV 台账里当前可动手的项排成"先做哪个" | 想知道"**下一个先做哪个**"时(本文只给裁定,排序在那边) | +| `docs/internal/27-execution-plan.md` | **执行计划(优先级象限)**:把本文 §3/§4/§6 与 00 号 RV 台账里当前可动手的项排成"先做哪个" | 想知道"**下一个先做哪个**"时(本文只给裁定,排序在那边) | | [`31-rl-training-primitives.md`](31-rl-training-primitives.md) | **RL 与可组合训练基础设施(2026-10-23 架构冻结,当前主线)**:`NamedTensorSet`/输出 schema、experience/objective 组件、通用 `TrainingGroupSession` 与编排边界;issue #23 仅为能力下界 | 设计 RL、多输出模型、多模型 Session 或接入未知库消费者前 | -| `docs/todo/00-code-review-remediation.md` | **2026-10-11 代码审查整改立项台账**(RV-01…RV-14):外部审查发现逐条复核 + 立项(证据/方案/验收/批次) | 接手审查整改时(本文只登记"是否要做",执行细节在那边) | +| `docs/internal/00-code-review-remediation.md` | **2026-10-11 代码审查整改立项台账**(RV-01…RV-14):外部审查发现逐条复核 + 立项(证据/方案/验收/批次) | 接手审查整改时(本文只登记"是否要做",执行细节在那边) | | `docs/history/history.md`「13 号清单合并归档」节 | 13 号清单(原 13 号文档,**已删除**)的条目原文与历史执行记录 | 只在需要追溯条目来源时 | | `docs/history/history.md` | 全仓唯一历史归档:演进记录 / 已修复勘误 / 被否决方案 / 性能 A/B | 查"为什么当初这么改、旧数字是多少" | -| `docs/todo/17-unified-tensor-engine.md` | **已落地**的底层总纲(M1–M6 全部实施;仅 M7 未立项) | 改 Tensor/Engine/存储前 | +| `docs/internal/17-unified-tensor-engine.md` | **已落地**的底层总纲(M1–M6 全部实施;仅 M7 未立项) | 改 Tensor/Engine/存储前 | | `docs/history/history.md`「docs/development 15 · 16」归档节 | 17 的前置设计(15)与 P0 盘点(16),历史引用 | 只做证据追溯 | ### 1.1 立项三问 @@ -50,7 +51,7 @@ 当前执行排序见 [`27-execution-plan.md`](27-execution-plan.md),专项方案见 [`31-rl-training-primitives.md`](31-rl-training-primitives.md)、 [`26-f16-speedup-plan.md`](26-f16-speedup-plan.md)、[`04`](04-memory-optimization.md)、 -[`25-release-requirements.md`](25-release-requirements.md) 等。本文只保留三样东西: +[`../contributors/release-requirements.md`](../contributors/release-requirements.md) 等。本文只保留三样东西: **要不要做**(§5 裁定表 / §6 触发条件 / §7 非目标)、**做到什么算完成**(§4 各行的验收口径)、 **现状实测**(§2/§3)。新增内容时先判断它属于哪一类;计划类内容进 27 号,本文只加一行指针。 @@ -78,13 +79,13 @@ | 底座 | 状态 | 依据 | |---|---|---| -| 统一 Tensor / ComputeEngine 契约(M1–M6) | 全部实施 | `docs/todo/17-unified-tensor-engine.md` §5 | +| 统一 Tensor / ComputeEngine 契约(M1–M6) | 全部实施 | `docs/internal/17-unified-tensor-engine.md` §5 | | 访问不变量(Tensor 存储私有、一切经引擎) | 铁律 #11,编译期强制 | `AGENTS.md` §5 | | L2+ 计算路径禁用 `Matrix` | 铁律 #12,审计口径 `L2-VIOLATIONS: 0` | `AGENTS.md` §5;`bench/doc_inventory.ps1` 第 [4] 节 | -| AOT 闭合世界 + 单 fold 注意力 kernel | 现行;掩码 × 位置偏置两正交维度 | `docs/todo/02-operator-fusion.md` | +| AOT 闭合世界 + 单 fold 注意力 kernel | 现行;掩码 × 位置偏置两正交维度 | `docs/internal/02-operator-fusion.md` | | 位置编码多态统一(按注入点分所有权) | 现行;新增 `compute_position_encoding.hpp` | `docs/history/history.md`「Layer 层简化轮」条 | | BPE 保序并行 encode(任意并行度逐字节一致) | 现行 | `AGENTS.md` §12 | -| 声明式初始化 `InitSpec`(初值跨进程确定) | 现行 | `docs/todo/17-unified-tensor-engine.md` §4.4 | +| 声明式初始化 `InitSpec`(初值跨进程确定) | 现行 | `docs/internal/17-unified-tensor-engine.md` §4.4 | | CPU/Vulkan 双后端 + 多设备选择 | 现行 | `AGENTS.md` §2 | **含义**:本文的路线图不需要再排"底层重构"——底层已完成;缺口集中在工程门禁与上层生态。 @@ -97,7 +98,7 @@ | # | 现象 | 坐标 | 影响面 | |---|---|---|---| -| C1 | GPU `stable=f16` 训练 loss 回读冻结(权重照常更新) | `docs/todo/14-f16-stable-gpu-loss-frozen.md` | GPU f16 训练的 loss 曲线不可观测;无对应 ctest 用例 | +| C1 | GPU `stable=f16` 训练 loss 回读冻结(权重照常更新) | `docs/internal/14-f16-stable-gpu-loss-frozen.md` | GPU f16 训练的 loss 曲线不可观测;无对应 ctest 用例 | | C2 | `optimizer=f16` 无 loss scaling 即更新爆炸、`stable=f16` 约 200 步 NaN | `docs/development/05-mixed-precision.md` §12.5;`src/text_train.cpp` 解析处只赋值不校验;核对与立项见 [`24-f16-training-defects.md`](24-f16-training-defects.md) | 用户可组合出必崩配置,且无任何启动期提示 | | C3 | `NormType::BatchNorm` **静默回落**到 LayerNorm | `compute_layer_mlp.hpp:782`(`make_norm_layer`);`README.md:248` 声称支持;`gui.py:60` 把 `batchnorm` 列为可选项;`model_spec.hpp:43` 保留枚举 | 模型规格写 batchnorm、实际跑 layernorm,无告警、无日志。**✅ 已解决**:真正实现 `BatchNorm` 层(P0-3),`make_norm_layer` 真分支,见 `docs/history/history.md` | | C4 | checkpoint(`.bin`)不存 Adam m/v | `model_serialization.hpp`(版本常量现为 **v7**,见该文件注释);`compute_optimizer.hpp` 无 `save_state/load_state` | TDR 重启 / `--resume` 后动量归零,续训轨迹不连续。**2026-10-16 裁定:范围扩写为「训练状态段」(计数器 / 优化器状态 / 训练配方 / 数据集身份),见表下 P1-2 行** | @@ -120,7 +121,7 @@ | E5 | ~~`src/text_train.cpp` 1746 行、34 处 `std::exit`~~ **✅ 已解决(P1-1 模块化,2026-10-16)**:1830 → **396 行**(入口只留接线),训练循环 / 恢复 / 断点三块拆到 `include/neuralnet.cpp/cli/text_train_{config,loop,recovery,checkpoint}.hpp`,三模块一律返回 `Result` 不终止进程——`std::exit` 全部集中在 **CLI 参数解析层**(`cli/text_train_config.hpp`) | 原坐标(CLI 解析 + 训练循环 + TDR 恢复 + checkpoint 混杂) | 原影响面(任一改动牵动全文件)已解除;C4 的前置阻塞解除,P1-2 可直接开工 | | E6 | 单文件多职责:`compute_vk_backend.hpp` 5174 行 | 该文件(fence / staging / dispatch / 算子混装) | header-only 项目里增量编译是主要开发成本 | | E7 | `README.md` 与实际不符:死链 `docs/history/history.md`、mojibake、声称链式 `add()`、文档索引缺 13–17 | `README.md:21`、`:35`、`:63`、`:269`、索引表(`:23` 起) | 新用户第一入口即误导;`add(args...)` 是返回 `Result` 的模板方法,**无链式 API** | -| E8 | `bench/doc_align_audit.ps1` 的 [A] 只检查**反引号里的文件名**,markdown 链接目标不查 | 该脚本 [A] 段正则 | **✅ 已修(2026-10-15)**:[A] 扩展为同时校验 markdown 链接的**目标可达性**(相对路径按文档所在目录解析;行内代码段先剥离,避免把示例链接误当链接);实测当场抓到 `todo/25-release-requirements.md` 的 `../CONTRIBUTING.md` 死链并一并修掉。README 的 `07-zipt-algorithm.md` 旧死链已在 P0-2 迭代中修 | +| E8 | `bench/doc_align_audit.ps1` 的 [A] 只检查**反引号里的文件名**,markdown 链接目标不查 | 该脚本 [A] 段正则 | **✅ 已修(2026-10-15)**:[A] 扩展为同时校验 markdown 链接的**目标可达性**(相对路径按文档所在目录解析;行内代码段先剥离,避免把示例链接误当链接);实测当场抓到 `contributors/release-requirements.md` 的 `../CONTRIBUTING.md` 死链并一并修掉。README 的 `07-zipt-algorithm.md` 旧死链已在 P0-2 迭代中修 | | E9 | **归约融合 shader 不支持"归约后逐元素后处理"形态**(`reduce(...) * k + c` 类表达式):GPU 硬报错拒绝(契约,防静默错值),CPU 已支持 | `GpuEngine::eval_expr_reduce` 的拒绝分支(错误文案即本缺口);回归锁 `src/ce_fusion_test.cpp`「归约+后处理 (reduce*k+c)」用例(断言 GPU 必须硬报错);机制背景 `docs/history/history.md` 同名条目 | 该形态只能拆两步 dispatch(先 `compute_reduce` 再 `dsl::compute` 后处理),多一次 kernel 与中间张量。**支持路径(通用、非单算子)**:归约生成器在归约累加收尾(epilogue)后接逐元素链发射(操作对象是归约结果的广播值),随后放开 `eval_expr_reduce` 的末指令校验;CPU 的指令下标反向切片前置校验已是同语义,可直接对拍 | ### 3.3 生态与可用性 @@ -128,20 +129,20 @@ | # | 现象 | 坐标 | 影响面 | |---|---|---|---| | X1 | ~~推理无 top-k / top-p 采样截断 / 无多轮上下文~~ **✅ 两半全完成(P0-5:采样器 2026-10-15 / 多轮闭环 2026-10-16)**:**采样** = `SamplingConfig`(temperature / top-k / top-p / repeat_penalty / repeat_window / seed)+ `text_infer` 五个开关(`--top-k`/`--top-p`/`--repeat-penalty`/`--repeat-window`/`--seed`)+ GUI GPT 推理 Tab 同步暴露 + 门禁 `sampling_test`。**多轮** = `Tokenizer::chat_prompt`(对话标记模板 + 按整轮截断)+ `--interactive`(进程内累积)/ `--turn`+`--reply-out`(历史自带、一次一问)+ GUI 多轮面板(`ChatSession`)+ 门禁 `chat_prompt_test` / `bench/gui_cli_audit.py` [7] | 采样器在 `compute_layer_base.hpp`(CPU 侧 host 采样,**不进 AOT 闭合世界**);多轮 prompt 构建在 `domain_tokenizer_base.hpp`,CLI 在 `src/text_infer.cpp`,GUI 历史在 `cli_controllers.py`(`ChatSession`)+ `gui.py` | **闭合(2026-10-16)**:`--interactive` 此前每轮只拼当轮输入(**每轮从零起算**)、GUI 完全无历史;现两条路径都带完整历史,且"上下文不丢"落到可断言形式 = 第 N 轮 prompt 以第 N-1 轮为**逐 token 前缀**(见 §4.1 P0-5 行) | -| X2 | ~~无 Dataset / DataLoader 抽象,文本训练数据加载不成体系~~ **前半已解决(19 号设计阶段一~三)**:`nn::Dataset` + `.nndataset`/`.nnvocab` 统一格式 + `dataset_gen`/`dataset_convert`,text_train 只吃数据集;**P2b 又补上样本层**(`dataset_samples.hpp`:训练单位 = 样本/窗口,`step` 是派生量)+ 训练工厂 `TextTrainer`;**剩 DataLoader/流式** | ~~`src/text_train.cpp` 内联数据路径;`train_pkg.py` / `cli_controllers.py` 各自处理~~(已收编,见 `docs/todo/19-unified-dataset.md`) | **流式**大语料仍不可行(`TextSampleSet` 仍整段物化,P2-4 后半解决) | +| X2 | ~~无 Dataset / DataLoader 抽象,文本训练数据加载不成体系~~ **前半已解决(19 号设计阶段一~三)**:`nn::Dataset` + `.nndataset`/`.nnvocab` 统一格式 + `dataset_gen`/`dataset_convert`,text_train 只吃数据集;**P2b 又补上样本层**(`dataset_samples.hpp`:训练单位 = 样本/窗口,`step` 是派生量)+ 训练工厂 `TextTrainer`;**剩 DataLoader/流式** | ~~`src/text_train.cpp` 内联数据路径;`train_pkg.py` / `cli_controllers.py` 各自处理~~(已收编,见 `docs/internal/19-unified-dataset.md`) | **流式**大语料仍不可行(`TextSampleSet` 仍整段物化,P2-4 后半解决) | | X3 | 无 Python / C 绑定 | 仓库仅有 `gui.py` 这一 Python 入口(subprocess 调 CLI) | 生态集成只能走命令行 + 文件 | | X4 | `gui.py` 六个 Tab、7 处手写 `collect_args` | `gui.py`(`def collect_args` 实测 7 处) | 加 CLI 选项要手改多处,漏参风险(13 §4 的"五个 Tab / 1471-1500"坐标已过期) | | X5 | ~~GUI 画布拖动全量降采样重绘~~ **✅ 已修(2026-10-15,P2-6 绘制半边)**:原坐标已过期(`_on_draw_move` 当时不降采样);实测的拖动开销真因是**逐事件新建画布项**(一笔 2000 事件 = 2000 个 item)+ 逐事件 PIL 画线。现改为一笔一个 item(原地 `coords` 刷新)+ 空帧跳过 + 视觉刷新按帧节流(`_PAINT_MS = 16`)+ PIL 光栅化延迟到边界(`_downsample_buffer` 唯一刷新点) | `gui.py` 的 `StrokeTrack` / `_paint_live` / `_rasterize_pending`;门禁 `bench/gui_draw_logic_audit.py` + `bench/gui_draw_runtime_audit.py` | 实测(同机合成 2000 事件):16.6 ms vs 旧写法 37.9 ms(**2.3×**);画布项 **2058 → 59**(O(事件) → O(笔数)) | -| X6 | **无"写自定义层"使用文档**(**文档部分已修,2026-10-11**):层接入的七条契约(`init_impl` NVI / `checkpoint_mode_` 缓存 / `activation_cache` / 精度 profile 用法 …)现成文于 `docs/development/write-a-custom-layer.md`(含自包含、经数值梯度检查实测通过的层模板 + 可复制 gradcheck 片段 + GPU 清单);`NN_UNWRAP` 是 unwrap 也已在该文与 `docs/development/cpp-api-manual.md` §1.3 说明 | 指南:`docs/development/write-a-custom-layer.md`;背景实测报告(含逐条坐标)见 `docs/development/20-custom-layer-ergonomics.md`(v1.7.0,库外视角) | 使用者写出"能编译但静默失效"的层(精度硬编码、offload 失效、gradcheck 全无);库内 C7(Conv2D 硬编码 F32)即同一成因;剩余缺口 = R2(`Layer::init` 精度自检)仍为代码项 | +| X6 | **无"写自定义层"使用文档**(**文档部分已修,2026-10-11**):层接入的七条契约(`init_impl` NVI / `checkpoint_mode_` 缓存 / `activation_cache` / 精度 profile 用法 …)现成文于 `docs/development/03-write-a-custom-layer.md`(含自包含、经数值梯度检查实测通过的层模板 + 可复制 gradcheck 片段 + GPU 清单);`NN_UNWRAP` 是 unwrap 也已在该文与 `docs/development/02-cpp-api-manual.md` §1.3 说明 | 指南:`docs/development/03-write-a-custom-layer.md`;背景实测报告(含逐条坐标)见 `docs/development/09-custom-layer-ergonomics.md`(v1.7.0,库外视角) | 使用者写出"能编译但静默失效"的层(精度硬编码、offload 失效、gradcheck 全无);库内 C7(Conv2D 硬编码 F32)即同一成因;剩余缺口 = R2(`Layer::init` 精度自检)仍为代码项 | ### 3.4 模型能力 | # | 现象 | 坐标 | 影响面 | |---|---|---|---| | M1 | 优化器共 **5 个**:SGD / SGDWithMomentum / Adam / **AdamW** / Muon;其中**直接派生自 `Optimizer` 的是 4 个**(SGD/SGDWithMomentum/Adam/Muon),`AdamW` 派生自 `Adam` | `compute_optimizer.hpp:200`(SGD)、`:236`(SGDWithMomentum)、`:294`(Adam)、`:434`(`AdamW : public Adam`)、`:628`(Muon);工厂注册名 `:723`、创建分支 `:745` | 缺无 m/v 状态的低显存优化器,模型规模受优化器状态限制(P2-2) | -| M2 | LRLA 仅存在于文档对比表,未实现 | `docs/development/06-rapt-algorithm.md` §LRLA | 线性注意力家族停在本项目基线 RLA-2/RAPT | -| M3 | ~~IR-C 跨表达式图融合不采用~~ **已恢复并接入训练路径(P1+P2)**:`begin_expr/end_expr` + 图融合(P1 链 / P2 写穿多输出)+ Adam/AdamW 接线;S6 自动窗口仍未接线 | `docs/todo/03-ir-optimization.md`;`docs/history/history.md`「IR-C 定位修正与恢复立项」「IR-C P2 收官」 | S6 之外的"能融的必须写进单个 `dsl::compute`"已放宽(跨表达式经录制段融合);**P4 CE online-softmax fold 已落地(通用 FoldSpec 机制,5→3 kernel/step,见 `docs/history/history.md`「CE online-softmax 单趟 fold(P4)」)**;**P3 跨链批量派发已落地(`#b` 批量变体 + BDA 实例表 + 图内同签名分组 CAP 32)**:设备表读数口径 = 批量/非批量分列(用户裁定),`fused@optimizer` 归零、派发计入 `fused_b@optimizer` 行,**合计 1330 → 57 calls/20 步(2.85/step ≤ 6/step)**;批量 vs 逐个逐字节一致(含同组混形状)、字节锚逐位不变,见 `docs/history/history.md`「P3 跨链批量派发」 | -| M4 | M7 存储多态未立项 | `docs/todo/17-unified-tensor-engine.md` §5 M7 行 | 新增第三后端仍需改 `compute_tensor.hpp` | +| M2 | LRLA 仅存在于文档对比表,未实现 | `docs/development/08-rapt-algorithm.md` §LRLA | 线性注意力家族停在本项目基线 RLA-2/RAPT | +| M3 | ~~IR-C 跨表达式图融合不采用~~ **已恢复并接入训练路径(P1+P2)**:`begin_expr/end_expr` + 图融合(P1 链 / P2 写穿多输出)+ Adam/AdamW 接线;S6 自动窗口仍未接线 | `docs/internal/03-ir-optimization.md`;`docs/history/history.md`「IR-C 定位修正与恢复立项」「IR-C P2 收官」 | S6 之外的"能融的必须写进单个 `dsl::compute`"已放宽(跨表达式经录制段融合);**P4 CE online-softmax fold 已落地(通用 FoldSpec 机制,5→3 kernel/step,见 `docs/history/history.md`「CE online-softmax 单趟 fold(P4)」)**;**P3 跨链批量派发已落地(`#b` 批量变体 + BDA 实例表 + 图内同签名分组 CAP 32)**:设备表读数口径 = 批量/非批量分列(用户裁定),`fused@optimizer` 归零、派发计入 `fused_b@optimizer` 行,**合计 1330 → 57 calls/20 步(2.85/step ≤ 6/step)**;批量 vs 逐个逐字节一致(含同组混形状)、字节锚逐位不变,见 `docs/history/history.md`「P3 跨链批量派发」 | +| M4 | M7 存储多态未立项 | `docs/internal/17-unified-tensor-engine.md` §5 M7 行 | 新增第三后端仍需改 `compute_tensor.hpp` | | M5 | ZiPT / AttnZip 已整体移除,代码保留在 `legacy/zipt` 分支 | `docs/history/history.md`「ZiPT 移除」条 | 记忆压缩方向暂缺实现 | | M6 | ~~**三值(T1_58)模型无法续训**~~ **✅ 已解决(P1-7,2026-10-16)**:原现象 = `.nnmodel` 载荷是打包形态,BitLinear 载入后进 `packed_only_` 部署态,`backward()` 直接报错(「部署态只读」)⇒ 三值模型不能从推理模型做 SFT / QAT 续训。**现在**:载入意图 `WeightLoadIntent::Trainable` 按文件 τ 反量化成 f32 latent(量化器不动点)+ 播种量化缓存 ⇒ 首次 forward 与推理文件逐位一致、可反向、可更新;`.nnmodel` 的 role 门禁(P1-2 的"唯一拒绝")已删除 | `ternary_pack.hpp`(`latent_row_scale`/`dequant_row`);`model_serialization.hpp`(`param_blob_to_entry` 意图分流 + `load_model`);`compute_layer_bitlinear.hpp`(`TernaryLatent + aux(τ)` 播种分支);`cli/text_train_recovery.hpp` | 缺口已关闭(见 §4.2 P1-7 行);推理侧部署只读态不变(`Inference` 为默认意图) | @@ -183,7 +184,7 @@ P4 = 持续优化方向(底座已稳后继续加杠杆,2026-10-14 立项, | 项目 | 目标 | 验收口径 | 成本 | 依赖 | |---|---|---|---|---| | **P0-1 CI 真跑构建 + 测试** ✅ **已完成(2026-10-12)**(最高优先) | workflow 加 `-DNN_ENABLE_TESTS=ON`,并在 Linux 与 Windows 各跑一轮 `ctest`(失败时输出完整失败日志);顺带再跑一轮 `NN_BIND_DEBUG=1 ctest`(RV-06 绑定门禁)。**实施**:`.github/workflows/cmake-single-platform.yml` 两个 configure 步各加 `-DNN_ENABLE_TESTS=ON`,Build 之后加 4 个测试步(Linux/Windows × 普通/`NN_BIND_DEBUG=1`,`--output-on-failure`);打包步补 `dataset_gen`/`dataset_convert`(8 个应用入口齐全)。**前置修复**:`matmul_q_impl`(CPU/GPU)在递归 impl 产物/静态工厂产物上进公共 `cast` 前未 stamp → 三值用例(`t1_58_test`/`ternary_gemm_test`/`model_roles_test`)在 `NN_BIND_DEBUG=1` 下红;补 `adopt` 后本机 Release+CPU `NN_BIND_DEBUG=1 ctest` **40/40** | GitHub Actions 绿且日志出现全部用例;需 Vulkan 的用例按退出码 77 记 skip 而非失败 | 完成 | 无 | -| **P0-2 文档一致性回正** ✅ **已完成 2026-10-15** | ① ctest 计数统一(当时实测 **48**〔GPU 树〕/ **46**〔无 Vulkan 树〕;同日 P0-5 加 `sampling_test` 后为 **49** / **47**、P4-2b 再加 `scan_bitwise_test` 后为 **50** / **48**,口径与历史数字的处理见 §2 口径说明);② `CMakeLists.txt` 版本与 tag 对齐(v1.8.2);③ 补 `docs/release-notes/v1.5.1.md`(2026-10-15 依据 `git log v1.5.0..v1.5.1` 与 history 两条归档**补写**);④ `README.md` 死链/mojibake/链式 API 声明/索引(已在前一轮迭代修完)。**⑤ 门禁补强(原 E8)**:`bench/doc_align_audit.ps1` 的 [A] 扩展到 markdown 链接目标,并修掉它当场抓到的 `todo/25` → `../CONTRIBUTING.md` 死链 | `bench/doc_align_audit.ps1` 的 [A][B][D][E][F] 可行动项为 0(2026-10-15 复测:[A] 0 / [D] 0 / [E] 0 / [F] 0);文档中 ctest 计数统一写当前值(当时 48,现 49) | 小–中(纯文档 + 审计脚本一段) | P0-1(否则改动无法被自动验证) | +| **P0-2 文档一致性回正** ✅ **已完成 2026-10-15** | ① ctest 计数统一(当时实测 **48**〔GPU 树〕/ **46**〔无 Vulkan 树〕;同日 P0-5 加 `sampling_test` 后为 **49** / **47**、P4-2b 再加 `scan_bitwise_test` 后为 **50** / **48**,口径与历史数字的处理见 §2 口径说明);② `CMakeLists.txt` 版本与 tag 对齐(v1.8.2);③ 补 `docs/release-notes/v1.5.1.md`(2026-10-15 依据 `git log v1.5.0..v1.5.1` 与 history 两条归档**补写**);④ `README.md` 死链/mojibake/链式 API 声明/索引(已在前一轮迭代修完)。**⑤ 门禁补强(原 E8)**:`bench/doc_align_audit.ps1` 的 [A] 扩展到 markdown 链接目标,并修掉它当场抓到的 `internal/25` → `../CONTRIBUTING.md` 死链 | `bench/doc_align_audit.ps1` 的 [A][B][D][E][F] 可行动项为 0(2026-10-15 复测:[A] 0 / [D] 0 / [E] 0 / [F] 0);文档中 ctest 计数统一写当前值(当时 48,现 49) | 小–中(纯文档 + 审计脚本一段) | P0-1(否则改动无法被自动验证) | | **P0-3 BatchNorm 禁止静默回落** ✅ **已完成(真实现路线)** | **已实施**:`compute_layer_mlp.hpp` 新增 `BatchNorm` 层(训练/推理双态、running 统计 EMA + `extra_state` 序列化、`forward_recompute` 抑制 EMA),`make_norm_layer` 真分支;`scan_exprs` 模型 pass 补推理态 fwd+bwd 覆盖(GPU 闭合世界);新增断言测试 `batchnorm_test`(+`--gpu` 变体),ctest 21 → 23,scan 结构 84 → 91(库内口径;样例收集器 93) | 构造 batchnorm 规格给出真层(可观测、不再静默降级);ctest 含 `batchnorm_test`;详见 `docs/history/history.md`「BatchNorm 落地」条 | 已完成 | 无 | | **P0-4 CMake install/export + CMakePresets** ⚡ **嵌入路径已完成(用户裁定拆分)** | **已实施**:门面目标 `neuralnet::nn`(`add_subdirectory` + 一行 link + 一个 include 即用;C++26/线程/`NN_HAS_VULKAN`/SPIR-V 头/Vulkan/shader 顺序全经接口传递)、`NN_ENABLE_GPU=AUTO\|ON\|OFF`、`NN_BUILD_APPS` 嵌入默认 OFF、`nn_enable_gpu_fusion` 树外可用(`NN_LIB_SOURCE_DIR/BINARY_DIR` CACHE 跨作用域 + GPU 不可用时 stub 报错)、消费方编译选项(`-Wno-pass-failed`/`-fexperimental-library`/`/utf-8`)随门面传递;样例 `examples/downstream/`(CPU/GPU 双路径实测通过)+ 指南 `docs/usage/05-consume-as-library.md`。**剩余**:`install()`/`find_package(neuralnet.cpp)`(用户裁定本轮不做);`CMakePresets.json` ✅ 已于 2026-10-11 落地(`cmake --preset dev/portable/cpu/probes`,历史记录见 `docs/history/history.md` 的 presets 条) | 嵌入口径 ✅:干净构建目录里 `cmake -S examples/downstream` CPU 与 GPU(`NN_ENABLE_GPU=ON`)两路径均编译、链接、运行通过(GPU 路径含 scan 收集 91 条 = 库内口径),fusion 树外调用可用;install 口径待剩余部分 | 已完成(嵌入)/ 小–中(剩余) | P0-1(preset 需进 CI 才不腐化) | | **P0-5 推理采样 top-k / top-p + 多轮对话闭环** ✅ **两半全完成(采样 2026-10-15 / 多轮闭环 2026-10-16)** | **采样半边(已实施)**:`nn::SamplingConfig`(temperature / top_k / top_p / repeat_penalty / repeat_window / seed)落在 `compute_layer_base.hpp`,共用采样器按"重复惩罚 → 温度 → top-k → top-p → softmax → 采样/贪心"固定顺序;`GPTModel`/`RAPTModel::generate` 新增配置重载(旧 temperature 重载保留、语义 = 全默认);`text_infer` 暴露 `--top-k` / `--top-p` / `--repeat-penalty` / `--repeat-window` / `--seed`,GUI GPT 推理 Tab 同步;门禁 `sampling_test`。**多轮闭环半边(2026-10-16,P0-5 尾项)**:① prompt 构建唯一真源 = `Tokenizer::chat_prompt`(`domain_tokenizer_base.hpp`):对话标记模板(`BOS<|system|>…<|end_of_system|><|user|>…<|end_of_user|><|assistant|>`,末轮 user 补 `<|assistant|>`)+ 内容两种给法(`text` 走 encode / `tokens` **原样灌入**);超 `seq_len` 时从**最旧的一问一答整轮丢弃**(system 块与末轮恒保留、丢弃后仍以 user 起头),无标记词表退化为换行相接 + 截尾。② CLI:`--interactive` 从"每轮只拼当轮输入"改为**进程内累积历史**(助手轮用生成的原 token 回灌,超限打印丢弃轮数);新增 `--turn :`(可重复,历史自带、一次一问)与 `--reply-out `(回复落盘 → 调用方不解析日志)与 `--system `;形状不合法(role 写错 / 不交替 / 末条不是 user / 与 `--prompt`·`--interactive` 并用)**解析期报错**。③ GUI:「GPT 推理」页新增「对话记录」面板 + **「💬 发送(多轮)」** + **「🧹 清空对话」**(历史 = `cli_controllers.py` 的 `ChatSession`,**无状态协议**:每轮把整段历史随采样参数一起传回 CLI);字段表新增「系统提示(多轮对话)」(→ `--system`);`TabBase._run_args` 抽出共用运行路径。**门禁**:`chat_prompt_test`(模板结构 / ★前缀不变式 / tokens 回灌 / 整轮截断 / 纯文本回退 / 真实 `text_infer` 子进程端到端:prompt tokens 与库逐 token 一致 + `--reply-out` == 生成 token 解码 / 7 条 CLI 负例)+ `bench/gui_cli_audit.py` 第 **[7]** 节(Python 侧参数面:第 N 轮 args 以第 N-1 轮为前缀、回复闭环、清空归零、`_on_send` 真的传历史)。**实测(三组「编译器 × 标准库」,2026-10-16)**:本机 clang 24 + libstdc++(`build/cpu`,Release + CPU-only)**52/52**;`102` WSL clang 24 + **libc++**(`~/nn-verify/build`)**52/52**;`102` WSL g++ 15.2 + libstdc++(同目录 `build-gcc`)**52/52**——三棵树均零告警(`-Werror`)且都含新用例 `chat_prompt_test`。本机 GPU 树(`build-gpu`,Release + Vulkan)新用例已构建并运行通过、`ctest -N` 注册 **54** 条,但**全量 GPU ctest 未跑**(本项结论只依赖 CPU 树)。`gui_cli_audit` 退出码 0(七节) | 采样:同 prompt 在 top-k / top-p 下输出可复现(同 seed)✅。多轮:**连续 N 轮不丢上下文** ✅ —— 可验证形式 = 第 N 轮的 prompt 以第 N-1 轮为**逐 token 前缀**(`chat_prompt_test` [2] 库级 + [6] CLI 端到端;GUI 侧 `gui_cli_audit` [7] 在参数层同款断言);GUI 侧真机链路已实测(`ChatSession` → `GptInferController` → `text_infer`:第 2 轮 prompt = 第 1 轮 prompt + 第 1 轮生成 token + `<|end_of_assistant|>` + `<|user|>` + 新输入 + `<|end_of_user|>` + `<|assistant|>`);超 `seq_len` 时按一问一答丢弃并有可见提示 | 中 | 无。命名冲突:`--topk` 属 `mnist_infer`、`--top` 属 `tokenizer_infer`;新开关取 `--top-k`/`--top-p`,无冲突。多轮开关取 `--turn`/`--reply-out`/`--system`,亦无冲突 | @@ -201,7 +202,7 @@ P4 = 持续优化方向(底座已稳后继续加杠杆,2026-10-14 立项, | **P1-3 危险精度组合启动期告警** ✅ **已完成 2026-10-13** | **不单独定义**——需求、口径、验收一律引用 [`24-f16-training-defects.md`](24-f16-training-defects.md) §2.3 / §5 F1(口径:仅警告,不退出、不加确认开关)。**落地**:`include/neuralnet.cpp/cli/cli_precision_warning.hpp`(`nn::cli::dangerous_precision_warning`)+ `text_train`/`mnist_train` 调用点 + 门禁 `src/cli_precision_warning_test.cpp`(单测组合矩阵 + 子进程捕获 stderr 断言退出码不变) | 见 24 号台账 F1 验收口径 | 小 | 无 | | **P1-4 `gpt_test` flaky 定位** ✅ **已完成 2026-10-15** | **未复现(278 次直跑零失败,含 2 核超订)且同机逐字节确定** ⇒ 定性为"环境差异或进程级异常",非测试随机性。**未加 retry/skip**(输出确定 ⇒ 失败必对应环境或代码变化);改为加环境指纹行 + 复用 P0-1 的 `--output-on-failure` 日志留存。证据/统计口径/复现命令见 `docs/history/history.md` 的同名条目与本文 §3.1 C6 行 | 连续大样本直跑零失败 ✅;结论入 history ✅ | 小–中 | P0-1 ✅ | | **P1-5 CI 冒烟扩到 MSVC Debug + 权重变化断言** ✅ **已完成(2026-10-18)** | Debug 构建冒烟;训练 N 步后断言参数**确实变化**(防"loss 不动"类静默失败)。**落地**:① `.github/workflows/cmake-single-platform.yml` 新增 `msvc-debug` job(`windows-latest` + Visual Studio 18 2026 生成器 = **cl.exe**;`NN_ENABLE_GPU=OFF` 纯 CPU,避开 Vulkan/glslc 变量;`NN_ENABLE_TESTS=ON`,`cmake --build`(Debug 配置)后 `ctest -C Debug`(C11 除外));② `src/optimizer_test.cpp` 新增 [4] **训练冒烟**:小 MLP + Adam 跑 8 步,断言 loss 有限且下降、全参数 L1 位移 > 1e-3;同一 `detect_movement()` 的负例(同一快照自比)必须判为"无移动",证明断言不是恒真。该段纯 CPU f32,无 Vulkan 也**不会 77 跳过**;③ 本机 `build/cpu`(Release + CPU-only)与 `build/p1-5-debug`(Debug + CPU-only,全量构建共 98 个 ninja 步骤)均实测 `optimizer_test` ALL PASS,`loss ≈3.016 → 0.1555(8 步),参数 L1 位移 41824.5`;④ Debug 全量 ctest 触发既有的 **C11**(RAPT f16 NaN;用户已排查,怀疑设备/后端自身问题,Release 通过只是概率)⇒ CI 的 Debug 测试步暂以 `-E "^rapt_test_f16$"` 排除并在 C11 登记,其余用例全跑;⑤ **MSVC 102 实机验证(2026-10-18,`ethan@192.168.1.102`,全新目录 `nn-p1-5-msvc`)**:VS 2026 18.10.4 / **cl 19.51.36260.0** / CMake 4.3.3,Debug + CPU-only。首次构建 `text_train.cpp` 触发 **C1128**(补 `/bigobj`,目录级 + 接口选项);ctest 又触发 **9 个 0xC00000FD 栈溢出**(`t1_58`/`bitnet_struct`/`model_roles`/`batchnorm`/`model_spec_validation`/`text_train_modules`/`train_state` + 2 个 GPU 变体,MSVC 默认 1 MB 栈;补 `/STACK:8388608`)。修复后 CI 口径 ctest **51/51 通过 / 0 失败 / 180.00 s**(`rapt_test_f16` 按 C11 排除,20 条 GPU/依赖 app 用例 skip;该用例在 102 MSVC Debug 上单独跑 **3/3 通过**,排除是为避免概率性红);另跑**不排除的完整 ctest 52/52 通过 / 181.61 s**(`rapt_test_f16` 2.33 s 通过);`optimizer_test` MSVC 实测 `loss 2.773293 → 0.170448(8 步),参数 L1 位移 41965.2`;⑥ GitHub `windows-latest` 已切到 VS 2026 镜像,生成器同步为 `Visual Studio 18 2026` | CI 中 MSVC Debug 目标编译通过;权重变化断言可检出冻结(含负例);**C1128 已实测触发 ⇒ `/bigobj` 已加;栈溢出已实测 ⇒ `/STACK:8388608` 已加** | 中 | P0-1。复用 `f16_writeback_probe` 的"8 步 Adam 参数必须移动"思路,但改跑纯 CPU f32 以覆盖无 Vulkan 的 Debug job | -| **P1-6 自定义层使用文档 + 精度自检**(文档部分 **✅ 已完成 2026-10-11**;精度自检 R2 **✅ 已完成 2026-10-14**) | ① 文档:已落 `docs/development/write-a-custom-layer.md`(层骨架模板 + 可复制 gradcheck 片段 + 七条契约 + GPU checklist;示例层经数值梯度检查实测通过 `max|num−an| = 4.7e-06`、50 步 Adam 收敛)。② 代码(**已完成**):`Layer::init` NVI 在 `init_impl` 之后统一执行 `check_param_precision_()`——层声明的 `param` 槽是存储精度时,逐个校验 `parameters()` 的张量实际存储精度与之相同(`precision_bytes == 0` 的 T1_58 等非存储精度声明跳过)。**它当场抓到了 3 处真实静默降级**:Conv2D 的 w_/b_、RAPT 的 token_emb_、以及 `ReLULinearAttention` **从未把 profile 转发给它自持的 4 个 Linear**(RAPT 注意力投影权重在 `--f16` 下一直是 f32)——前两处在 P2-3 修掉,第三处由本自检在扫描期报错后发现并修复(现 47/47 全绿) | 文档:按模板能写出可训练的自定义层;自检:硬编码 F32 的层在 init 期被拒绝 | 小 | ✅ **已完成 2026-10-14** | +| **P1-6 自定义层使用文档 + 精度自检**(文档部分 **✅ 已完成 2026-10-11**;精度自检 R2 **✅ 已完成 2026-10-14**) | ① 文档:已落 `docs/development/03-write-a-custom-layer.md`(层骨架模板 + 可复制 gradcheck 片段 + 七条契约 + GPU checklist;示例层经数值梯度检查实测通过 `max|num−an| = 4.7e-06`、50 步 Adam 收敛)。② 代码(**已完成**):`Layer::init` NVI 在 `init_impl` 之后统一执行 `check_param_precision_()`——层声明的 `param` 槽是存储精度时,逐个校验 `parameters()` 的张量实际存储精度与之相同(`precision_bytes == 0` 的 T1_58 等非存储精度声明跳过)。**它当场抓到了 3 处真实静默降级**:Conv2D 的 w_/b_、RAPT 的 token_emb_、以及 `ReLULinearAttention` **从未把 profile 转发给它自持的 4 个 Linear**(RAPT 注意力投影权重在 `--f16` 下一直是 f32)——前两处在 P2-3 修掉,第三处由本自检在扫描期报错后发现并修复(现 47/47 全绿) | 文档:按模板能写出可训练的自定义层;自检:硬编码 F32 的层在 init 期被拒绝 | 小 | ✅ **已完成 2026-10-14** | | **P1-7 三值模型的续训入口(打包 → latent 反量化载入)** ✅ **已完成(2026-10-16)** | 让 `--resume `(role=Model,三值层为打包形态)能进入**可训练态**:载入意图 `WeightLoadIntent`(与文件角色正交)分两路——`Inference`(默认)= 部署只读态、`Trainable` = 序列化层按文件 τ 把打包权重**反量化**成 f32 latent(`ternary_pack.hpp` 的 `latent_row_scale`/`dequant_row`,宿主侧逐行解码)+ 层按文件 τ **播种**量化缓存,不再落到 `packed_only_`。**反量化取量化器的不动点 `L = trit·(τ·K/n)`**(n = 该行非零 trit 数):字面的 `trit·τ` 会让逐行 absmean 变成 `τ·n/K` ⇒ 续训一开始就是有效权重的尺度跳变(见「为什么不是 `trit·τ`」)。**层协议不变**:反量化后用 `TernaryLatent + aux(τ)` 交回 `import_param`,dense / `.nnckpt` 路径逐位不变 | 反量化载入后首次 forward 的 wq/τ 与文件内打包权重**逐位一致**(量化确定性:`model_roles_test` [6] 位级比对打包字 + τ);随后 backward 可跑、8 步 Adam 参数确实移动(同一用例 + `text_train_modules_test` 的三值 GPT 端到端);dense 文件两种意图参数逐位相同;逐行 `absmean(latent) == τ`(不动点,实测最差相对偏差 5.0e-08,`ternary_gemm_test` [8]) | 小–中 | ✅ **已完成 2026-10-16**;前置 P1-2 的 role 语义已落地。落点 = `ternary_pack.hpp`(反量化 helper)、`model_serialization.hpp`(`param_blob_to_entry` 的意图分流 + `load_model` 新实参)、`compute_layer_bitlinear.hpp`(播种缓存)、`cli/text_train_recovery.hpp`(删 `check_resume_target`、改传 `Trainable`)、`src/mnist_train.cpp`。验收证据见 `docs/history/history.md`「P1-7」条 | | **P1-8 生命周期 v3 + Session 层** ✅ **2026-10-20 落地(v1.10.0-rc0)**;✅ **P2b 已完成 2026-10-21(v1.10.0-rc0.1)**;✅ **30 号单步边界 2026-10-22 修订** | 删 `Tensor` 的 `EngineId` provenance 与 `stamp_`/`adopt`/`bound`/`NN_BIND_DEBUG`,改为"设备域从存储派生"的统一模型(CPU/host 域常量 + GPU backend 域;逐操作数对本引擎校验;`import` 是唯一跨域入口)。同时修审计确认的 D1–D9 生命周期缺口(D3 的 optimizer 非拥有引用通过 Session 层结构化解决)。**30 号修订**:Session 接收 micro-batch、内置梯度累积并按 global batch 有效单位归一化;数据集经 `TextSampleSet` 接入 `TextTrainer`,运行态 `TrainState` 归 Trainer | 见 [`28`](28-lifecycle-v3.md) §5/§6、[`29`](29-session-architecture.md) §9、[`30`](30-training-session-step.md):CPU/GPU ctest + ASan + 文档审计;新增 global/micro 等价与累积回归 | 中–大 | 30 号已落地;剩余平台矩阵按发布要求执行 | @@ -225,7 +226,7 @@ P4 = 持续优化方向(底座已稳后继续加杠杆,2026-10-14 立项, | **P2-1 `.bin` 整文件校验和 + 尾部完整性标记** ✅ **已完成(2026-10-16,随 P1-2 同批交付)** | 尾部加 `[sha256 32B][magic "NNEND"]`(边写边算,`core_sha256.hpp` 的增量 `sha256_update` 已就绪);`MODEL_VERSION` **7 → 8**(与 P1-2 同一次升版)。**已实施(2026-10-16)**:v8 尾部 `[sha256 32B]["NNEND" 5B]`(边写边算)+ `verify_model_integrity` 在 `load_model` / `load_train_state` 先行校验;门禁 `train_state_test` [5](完好 / 翻一字节 / 截断三态)与 §8.2 门禁 7 的 ④ | 截断/损坏文件明确报错;合法文件 round-trip SHA256 一致 | 小–中 | P1-2(同一版本段改动,合并做省一次升版) | | **P2-2 Adafactor 类无 m/v 优化器** | 新增不物化二阶矩的优化器,训练更大模型 | 同任务对比 Adam 的显存下降与收敛曲线;`create_optimizer` 可创建 | 中 | 无 | | **P2-3 RAPT / CNN f16 接线** | ✅ **已完成 2026-10-14**。① RAPT:**27 处** `dsl::compute*` 补精度实参 `p_.compute`(此前全部落默认 F32);两个残差分支从硬编码 `Precision::F32` 改为 `p_.compute`(与 GPTBlock/TransformerEncoderLayer 同口径);`token_emb_`/`grad_token_emb_` 改 `p_.param`;`rms_norm_forward_/backward_` 的输出张量从默认 F32 改 `p_.compute`(**否则 dst/src 精度错配 → `insert_rows` 断言**)。② Conv2D:`w_`/`b_`/`grad_w_`/`grad_b_` 改 `p_.param`,4 处 `dsl::compute*` 补 `p_.compute`。③ `CnnConfig` 增 `precision` 字段,`build_cnn_model(_from_spec)` 在 add 之前注入(新增可选 profile 形参)。**门禁**:`cnn_smoke_test`/`rapt_smoke_test` 增 `--f16`;ctest 新增 4 条 `cnn_test_f16(_gpu)` / `rapt_test_f16(_gpu)`(断言 loss 有限且下降、梯度无 NaN) | f16 下 CNN/RAPT 训练健康收敛;默认 profile 的 f32 逐位不变(param/compute 默认 F32) | 中 | ✅ **已完成**(ctest 47/47) | -| **P2-4 Dataset / DataLoader 抽象 + 流式文本**(**前半 Dataset 已落地** = 19 号设计阶段一~三;**P2b 补上样本概念/训练工厂** = `dataset_samples.hpp` + `text_trainer.hpp`;本条只剩**流式后半**:DataLoader/分块迭代 `for_each_chunk`,不再把语料整段读进内存) | 流式加载(Dataset 格式与统一只读类见 `docs/todo/19-unified-dataset.md`) | 大文件训练内存曲线平稳;`dataset_test` 逐位一致口径回归 | 中 | 无 | +| **P2-4 Dataset / DataLoader 抽象 + 流式文本**(**前半 Dataset 已落地** = 19 号设计阶段一~三;**P2b 补上样本概念/训练工厂** = `dataset_samples.hpp` + `text_trainer.hpp`;本条只剩**流式后半**:DataLoader/分块迭代 `for_each_chunk`,不再把语料整段读进内存) | 流式加载(Dataset 格式与统一只读类见 `docs/internal/19-unified-dataset.md`) | 大文件训练内存曲线平稳;`dataset_test` 逐位一致口径回归 | 中 | 无 | | **P2-5 Python / C 绑定** | 提供稳定 C ABI 或 pybind 绑定,供生态集成 | 绑定层跑通训练/推理最小示例;ABI 报错信息可读 | 中–大 | **条件触发**(§6) | | **P2-6 GUI 声明式字段表 + 绘制节流** ✅ **两侧均已完成(2026-10-15)** | **已实施(绘制半边)**:一笔一个画布项(`_paint_live` 原地 `coords`)+ 空帧跳过 + 视觉刷新按帧节流(`_PAINT_MS = 16`,数据侧不节流)+ PIL 光栅化延迟到 `_downsample_buffer`(读缓冲唯一入口)。**实测**:合成 2000 motion 事件 16.6 ms vs 旧写法 37.9 ms(2.3×),画布项 2058 → 59。**✅ 字段表半边已完成(2026-10-15)**:`Field` 声明式表 + 纯函数 `collect_fields` + `ParamsMixin`;6 个 Tab 全部迁移(`engine→--gpu` / `precision_preset→--f16/--t1_58` / `input_method→input` 这类后处理显式保留);**逐字段等价性验证**:同一个 fake self 驱动 HEAD 版旧 `collect_args` 与新表实现,22 个场景中 17 个逐字段一致、4 个是有意收紧(fixed 调度下不再发被隐藏的 min_lr/warmup)、1 个命令行层等价;审计新增 [5] 节(表 ↔ Controller 闭包),并当场抓到 `TabBase` 遗留 `collect_args` 桩覆盖 mixin(4 个页会一个参数都不发)等 2 个真 bug | 现有 Tab 参数零遗漏(`bench/gui_cli_audit.py` 退出码 0,五节 ✅);拖动开销下降 ✅ | 小–中 | P0-5(采样新开关已定型 ✅) | | **P2-7 超大 header 拆分** | backend 拆 fence / staging / dispatch / 算子为独立 TU;`compute_vk_backend.hpp` 瘦身 | 拆分前后 build 全绿 + ctest 全绿 + CPU/GPU 字节锚逐位一致 | 中–大 | **前置 = 先补编译/链接期冒烟**(P0-1 + P1-5),否则拆分无回归网 | @@ -269,9 +270,9 @@ ZiPT 恢复、LRLA、CUDA、分布式(7 项)。 | 项目 | 现状(实测锚) | 方向 | 验收口径 | 成本 | 关联 | |---|---|---|---|---|---| | **P4-1 性能利用率继续提升** | GPU 忙率 ~95.5%(40HX f16)/ ~95.9%(850M);`墙钟 − 设备 kernel ≈ 4.2%`(P2-9,f32/f16 同幅、与精度无关) | ① 把剩余 4.2% 归因到 host 录制 / driver 提交 / fence 等待三处;② 提高设备端并行(帧环深度、descriptor 复用、队列提交粒度);③ CPU 线程池利用率(小算子并行度与分块) | `NN_PROFILE=1` 同窗配对 A/B:墙钟下降 ≥3% 且 busy% 上升;字节锚逐位不变 | 中 | P2-9(**已否决**的搬 I/O 不重复);`core_profile.hpp` | -| **P4-2 算子性能继续提升** ✅ **C10 派生的 (a)+(b) 均已完成(2026-10-15)** | `layer_bench` 已提供 op 级配对 A/B(`--op` … + `--dk`/`--hash`)。**(a)** `rms_norm_forward_` 逐头 1/rms 收集改设备侧拼装:step 741.81 → 521.68 ms(−29.7%)。**(b)** `scan_prefix_outer` 专用路径(dk ≤ 64)改**行归属 + 4 路展开 + `dk ≤ 32` 窄共享变体**:单次 **7.4–7.9 → 1.64 ms(4.7×)**、`layer_bench --op scan_prefix` 配对 A/B **5.9×**(10.9 → 1.85 ms @ dk=32)、同会话 e2e RAPT **step 888.24 → 510.24 ms(−42.6%)**;数值**逐位不变**(位级哈希 + `rapt_test` stdout md5 + 新门禁 `scan_bitwise_test`)。**新瓶颈(下一手)**:host 侧 staging 等待 `copy_from` ≈66% 墙钟(与 GPU 忙时成正比 ⇒ 与 P2-9 的「host 等待总量不变」同机制)。`scan_suffix_outer` **刻意不改**(流量/争用受限,加占用率实测更慢)。 | 按 op 逐项调参(tile / occupancy / 网格粒度)与算法(三值 GEMV、扫描原语);**不含**扩 native16 覆盖(P2-10 已裁定不做) | `layer_bench --op --hash` 配对 A/B 提效、无系统性回退(噪声 ±6%);端到端不回归。**(b) 已达**:−42.6% 且逐位不变 | 中(shader 迭代可只重建 `layer_bench` ≈2 min:PCH + 1 TU;全量重建 ≈20 min 只在最后做一次) | P2-11/P2-13;`docs/todo/02`;C10 归因(2026-10-15);细节/消融/否决项见 `docs/history/history.md`「P4-2 (b)」条 | -| **P4-3 显存开销继续压低** | 04 号 L1(激活重计算)/L2(池归还)已实施;三值权重已压 param 侧(4 B → <2 B);峰值显存(850M f16)606 MiB | 立项 04 号 **L3**:① Adafactor 类无 m/v 优化器(= P2-2);② 注意力/softmax 子图进一步融合、消除 Q/K/V 激活集物化;③ 优化器状态低精度(`AdamWQuant` 已存在,4 B → 与三值同量级) | 同任务峰值显存下降,loss 曲线与基线一致(gradcheck 全绿) | 中–大 | `docs/todo/04`(L3 待立项);P2-2 | -| **P4-4 API 易用性 + Fold 表达式自动化扫描** | ✅ **① fold 自登记已完成 2026-10-15**:注意力 fold 组合改由**定义方**自登记(`compute_layer_attention.hpp` 的 `attn_fold_anchor::register_all()` 在静态初始化期经 `FoldAnchor` 登记「掩码清单 × {无偏置, 位置偏置} × {MHA, GQA}」,掩码清单 `NN_ATTN_MASK_KIND_LIST` 是 X 宏单一真源 → 枚举与登记表同源);`expr_fold.hpp` 末尾同款登记它的 3 个 v1 样例;`scan_exprs.cpp` 的 fold 显式登记块**整体删除**(消除"手写登记块漏项 = GPU 闭合世界硬报错"这类风险)。**实测**:结构集合逐条(key + 指令摘要)与改动前零差异(126 条);`-DNN_SCAN_NO_ANCHOR` 下这 13 条 fold 结构全部消失(126 → 91)⇒ 自登记是唯一来源;新回归 `expr_fold_test` §8 锁代表值契约。② 之一 `dsl::compute` 无形状重载 **✅ 已完成 2026-10-15** | 剩余 ②:GUI 声明式字段表(= P2-6)、CLI/GUI/文档一致性 | ① 验收已达成:新增掩码/组合**无需改 `scan_exprs`**(`NN_SCAN_DUMP_SOURCES=1` 逐条来源可观测);结构数不丢(逐条对比零差异);`bench/gui_cli_audit.py` 退出码 0(本机实测 0) | 小–中 | `docs/todo/02`(fold 登记机制);P2-6 | +| **P4-2 算子性能继续提升** ✅ **C10 派生的 (a)+(b) 均已完成(2026-10-15)** | `layer_bench` 已提供 op 级配对 A/B(`--op` … + `--dk`/`--hash`)。**(a)** `rms_norm_forward_` 逐头 1/rms 收集改设备侧拼装:step 741.81 → 521.68 ms(−29.7%)。**(b)** `scan_prefix_outer` 专用路径(dk ≤ 64)改**行归属 + 4 路展开 + `dk ≤ 32` 窄共享变体**:单次 **7.4–7.9 → 1.64 ms(4.7×)**、`layer_bench --op scan_prefix` 配对 A/B **5.9×**(10.9 → 1.85 ms @ dk=32)、同会话 e2e RAPT **step 888.24 → 510.24 ms(−42.6%)**;数值**逐位不变**(位级哈希 + `rapt_test` stdout md5 + 新门禁 `scan_bitwise_test`)。**新瓶颈(下一手)**:host 侧 staging 等待 `copy_from` ≈66% 墙钟(与 GPU 忙时成正比 ⇒ 与 P2-9 的「host 等待总量不变」同机制)。`scan_suffix_outer` **刻意不改**(流量/争用受限,加占用率实测更慢)。 | 按 op 逐项调参(tile / occupancy / 网格粒度)与算法(三值 GEMV、扫描原语);**不含**扩 native16 覆盖(P2-10 已裁定不做) | `layer_bench --op --hash` 配对 A/B 提效、无系统性回退(噪声 ±6%);端到端不回归。**(b) 已达**:−42.6% 且逐位不变 | 中(shader 迭代可只重建 `layer_bench` ≈2 min:PCH + 1 TU;全量重建 ≈20 min 只在最后做一次) | P2-11/P2-13;`docs/internal/02`;C10 归因(2026-10-15);细节/消融/否决项见 `docs/history/history.md`「P4-2 (b)」条 | +| **P4-3 显存开销继续压低** | 04 号 L1(激活重计算)/L2(池归还)已实施;三值权重已压 param 侧(4 B → <2 B);峰值显存(850M f16)606 MiB | 立项 04 号 **L3**:① Adafactor 类无 m/v 优化器(= P2-2);② 注意力/softmax 子图进一步融合、消除 Q/K/V 激活集物化;③ 优化器状态低精度(`AdamWQuant` 已存在,4 B → 与三值同量级) | 同任务峰值显存下降,loss 曲线与基线一致(gradcheck 全绿) | 中–大 | `docs/internal/04`(L3 待立项);P2-2 | +| **P4-4 API 易用性 + Fold 表达式自动化扫描** | ✅ **① fold 自登记已完成 2026-10-15**:注意力 fold 组合改由**定义方**自登记(`compute_layer_attention.hpp` 的 `attn_fold_anchor::register_all()` 在静态初始化期经 `FoldAnchor` 登记「掩码清单 × {无偏置, 位置偏置} × {MHA, GQA}」,掩码清单 `NN_ATTN_MASK_KIND_LIST` 是 X 宏单一真源 → 枚举与登记表同源);`expr_fold.hpp` 末尾同款登记它的 3 个 v1 样例;`scan_exprs.cpp` 的 fold 显式登记块**整体删除**(消除"手写登记块漏项 = GPU 闭合世界硬报错"这类风险)。**实测**:结构集合逐条(key + 指令摘要)与改动前零差异(126 条);`-DNN_SCAN_NO_ANCHOR` 下这 13 条 fold 结构全部消失(126 → 91)⇒ 自登记是唯一来源;新回归 `expr_fold_test` §8 锁代表值契约。② 之一 `dsl::compute` 无形状重载 **✅ 已完成 2026-10-15** | 剩余 ②:GUI 声明式字段表(= P2-6)、CLI/GUI/文档一致性 | ① 验收已达成:新增掩码/组合**无需改 `scan_exprs`**(`NN_SCAN_DUMP_SOURCES=1` 逐条来源可观测);结构数不丢(逐条对比零差异);`bench/gui_cli_audit.py` 退出码 0(本机实测 0) | 小–中 | `docs/internal/02`(fold 登记机制);P2-6 | ### 4.6 RL 训练原语(2026-10-23 立项,当前主线) @@ -298,7 +299,7 @@ f16(P2-14/P2-15)与训练性能(P4-1/P4-2/P4-3)仍按原裁定暂缓, ## 5. 13 号清单逐条裁定表 -条目编号沿用 13 号原文的章节号(13 号文档本身已于 2026-10-11 删除)。 +条目编号沿用 13 号原文的章节号(13 号文档已删除,原文在 `docs/history/history.md`)。 其原正文的归档位置:**已执行/已否决记录**在 `docs/history/history.md`「13 号清单合并归档」节; **仍未决的条目**由下表承接。本节逐条覆盖其**全部 16 条**未决项(含 17 §5 的 M7),一条不漏。 @@ -327,12 +328,12 @@ f16(P2-14/P2-15)与训练性能(P4-1/P4-2/P4-3)仍按原裁定暂缓, | 项 | 精确触发条件 | 立项时先读 | |---|---|---| -| ~~IR-C 跨表达式图融合~~ **已落地** | **不再是触发项**:`begin_expr/end_expr` 图融合(P1 链 / P2 写穿多输出)已接入 Adam/AdamW step,§3.4 M3 | `docs/todo/03-ir-optimization.md` §5.3、§7;`expr_graph.hpp` | -| S6 自动窗口(跨 kernel 自动融合) | 同 IR-C 的调用方判据;当前"能融的直接写成单个 `dsl::compute`"已覆盖生产路径 | `docs/todo/02-operator-fusion.md` | -| M7 存储多态 | **第三后端出现**(CPU/Vulkan 之外的引擎要落地) | `docs/todo/17-unified-tensor-engine.md` §4.2 + §5 M7 | -| IR-D 第二 emitter | 需要 glsl 之外的代码生成后端,且该后端**必须走 AOT 闭合世界**(表达式结构须被 `scan_exprs` 覆盖) | `docs/todo/03-ir-optimization.md` 阶段 D;`expr_emitter.hpp` | +| ~~IR-C 跨表达式图融合~~ **已落地** | **不再是触发项**:`begin_expr/end_expr` 图融合(P1 链 / P2 写穿多输出)已接入 Adam/AdamW step,§3.4 M3 | `docs/internal/03-ir-optimization.md` §5.3、§7;`expr_graph.hpp` | +| S6 自动窗口(跨 kernel 自动融合) | 同 IR-C 的调用方判据;当前"能融的直接写成单个 `dsl::compute`"已覆盖生产路径 | `docs/internal/02-operator-fusion.md` | +| M7 存储多态 | **第三后端出现**(CPU/Vulkan 之外的引擎要落地) | `docs/internal/17-unified-tensor-engine.md` §4.2 + §5 M7 | +| IR-D 第二 emitter | 需要 glsl 之外的代码生成后端,且该后端**必须走 AOT 闭合世界**(表达式结构须被 `scan_exprs` 覆盖) | `docs/internal/03-ir-optimization.md` 阶段 D;`expr_emitter.hpp` | | ZiPT 恢复 | ① 压缩向量保证**因果**(压缩器只能看当前位置之前);② 实现质量对齐 RAPT/GPT(`forward_recompute` 梯度检查点 + activation offload + CLI/序列化/测试齐备);③ 有同参对比数据 | `docs/history/history.md`「ZiPT 移除」条;`legacy/zipt` 分支 | -| LRLA | 先有与 RLA-2 / RAPT 的**同参对比数据**(质量、显存、吞吐),再决定是否实现 | `docs/development/06-rapt-algorithm.md` | +| LRLA | 先有与 RLA-2 / RAPT 的**同参对比数据**(质量、显存、吞吐),再决定是否实现 | `docs/development/08-rapt-algorithm.md` | | Adafactor 类优化器 | 已排 **P2-2**;条件 = 需要训练超出 Adam m/v 显存预算的模型 | 本文 §4.3;`compute_optimizer.hpp` | | CUDA 后端 | **P3**。当前明确不支持(见 §7);触发 = 目标平台出现真实需求 + 有维护者承诺长期维护 + 愿意补 IR-D 第二 emitter 的 AOT 全链 | `AGENTS.md` §2;本文 §7 | | 分布式训练 | **P3**。触发 = 单机单卡能力被真实任务触顶,且有明确的多机部署场景 | 本文 §7 | @@ -422,7 +423,7 @@ f16(P2-14/P2-15)与训练性能(P4-1/P4-2/P4-3)仍按原裁定暂缓, Debug CPU-only 修复后 **51/51 通过(180 s)**。 **已知排除**:`rapt_test_f16` 是既有 C11(RAPT f16 NaN,用户已排查,怀疑设备/后端 自身问题;Release 通过只是概率),CI 冒烟暂以 `-E "^rapt_test_f16$"` 排除;大版本发布 - 清单([`25`](25-release-requirements.md) §1)仍要求 Debug **完整 ctest 全绿**,C11 + 清单([`25`](../contributors/release-requirements.md) §1)仍要求 Debug **完整 ctest 全绿**,C11 修复后必须删掉该排除项。 ### 8.3 验收纪律 @@ -446,7 +447,7 @@ f16(P2-14/P2-15)与训练性能(P4-1/P4-2/P4-3)仍按原裁定暂缓, ### 8.5 大版本发布要求 **大版本**升级(`1.x.y → 1.(x+1).0`,次版本号 +1、修订号归零)在常规门禁之上还要走一遍 -[`25-release-requirements.md`](25-release-requirements.md) 的必做清单:① 端到端模型训练测试 +[`../contributors/release-requirements.md`](../contributors/release-requirements.md) 的必做清单:① 端到端模型训练测试 (这类测试**不进默认 ctest**,太费时);② 发布文档;③ 完整 ctest + **Debug** 构建; ④ 多编译器 × 标准库(≥4 组)全新构建 + ctest。小 / 修订号升级不强制。 diff --git a/docs/todo/19-unified-dataset.md b/docs/internal/19-unified-dataset.md similarity index 99% rename from docs/todo/19-unified-dataset.md rename to docs/internal/19-unified-dataset.md index 0429c91..df6caed 100644 --- a/docs/todo/19-unified-dataset.md +++ b/docs/internal/19-unified-dataset.md @@ -2,7 +2,7 @@ > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 -> **状态**:设计定稿;**阶段一~三已实施**—— +> **状态**:现行(设计定稿;**阶段一~三已实施**—— > 阶段一 = KVRecord v2 + `.nnvocab` + `tokenizer_train` 切换 + `dataset_convert vocab`; > 阶段二 = `.nndataset` + `dataset_gen` + `nn::Dataset` + `text_train` 切换 + 模型 v6 内嵌 > (`MODEL_VERSION 5→6`,v5 及以下仍读内嵌 JSON);阶段三 = GUI / 控制器 / `train_pkg` / @@ -14,7 +14,7 @@ > 数据集经 `nn::TextTrainer` 直接接入训练([`29`](29-session-architecture.md) §8)。 > `.nndataset` 文件格式与"不做预切窗"的裁决(§0 #3)**均未变**;流式仍属 P2-4 后半。 > -> **关联**:`docs/todo/18-roadmap.md` X2(无 Dataset 抽象)/ P2-4(Dataset/DataLoader + 流式)—— +> **关联**:`docs/internal/18-roadmap.md` X2(无 Dataset 抽象)/ P2-4(Dataset/DataLoader + 流式)—— > 本文是其前半(格式统一 + 统一类)的详细设计;DataLoader/流式仍留在 P2-4 后半。 > `.nnpkg` 打包链路**本轮不在范围**(用户裁定),但 §6 标注了它的参数冲突依赖。 @@ -429,4 +429,4 @@ tokcache + `mark_assistant_spans` 输出**逐位一致** ⇒ `text_train` 训练 - KVRecord v1:`include/neuralnet.cpp/model_keyvalue_record.hpp` - 模型格式与内嵌词表:`include/neuralnet.cpp/model_serialization.hpp`(`read_tokenizer:478`) - 词表工厂与 JSON 解析:`domain_tokenizer{,_base,_bpe,_charbpe}.hpp` -- roadmap 对应条目:`docs/todo/18-roadmap.md` X2 / P2-4 +- roadmap 对应条目:`docs/internal/18-roadmap.md` X2 / P2-4 diff --git a/docs/todo/21-quantized-weights.md b/docs/internal/21-quantized-weights.md similarity index 99% rename from docs/todo/21-quantized-weights.md rename to docs/internal/21-quantized-weights.md index 81f2f67..f81d823 100644 --- a/docs/todo/21-quantized-weights.md +++ b/docs/internal/21-quantized-weights.md @@ -2,7 +2,7 @@ > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 -> **状态**:**P1 已实施**(2026-10-09 起草;2026-10-10 裁定尺度 / 打包 / 命名; +> **状态**:现行(**P1 已实施**;起草与裁定日期见下)—— > 2026-10-10 落地 P1 全部 5 步并提交,见 §9 提交清单与 §7 实施清单末列)。 > 本文现在同时是**实现依据**与**实现说明**:§4 是设计,§4.9 是"实现与设计的差异", > §5 是分期与验收(P1 ✅),§7 是文件级实施清单,§8 是架构图。 @@ -12,7 +12,7 @@ > **关联**:`05-mixed-precision.md`(Precision 语义契约 §7.2)、 > `17-unified-tensor-engine.md` §5 M7(存储多态——本文给出它的第一个触发条件)、 > `18-roadmap.md` §1.1 立项三问 + §3.1 C2/C3("可选但静默失效"缺陷类)、 -> `20-custom-layer-ergonomics.md`(自定义层的四条接入契约)。 +> `09-custom-layer-ergonomics.md`(自定义层的四条接入契约)。 > **参考实现**:`~/codes/Lumina-Engine`(llama.cpp b10991 分支)的 `GGML_TYPE_TQ1_0`。 > 本文 §3 是该格式与内核的完整拆解;§4 记录**哪些照搬、哪些必须重选**。 > **前置证据**:`research/ternary_ste/REPORT.md`(CPU 端三值/二值 STE 训练实测;两者都能把 @@ -451,7 +451,7 @@ MLP 路径(`build_mnist_mlp_model`)确实是 `model.add(...)` 一条 照此引入 `make_linear_layer(...)`,把 4 处 `Linear` 成员换成 `unique_ptr`, 即可让 `ModelSpec` 的一个开关同时切换 GPT/RAPT 的线性层类型。 - **不建议 ①**:模板化会把"层类型是编译期决定"这件事扩散到 attention/feedforward/GPT/RAPT - 四个头与全部实例化点,收益只是省掉一次虚调用——与 `docs/development/20-custom-layer-ergonomics.md` + 四个头与全部实例化点,收益只是省掉一次虚调用——与 `docs/development/09-custom-layer-ergonomics.md` 里"层接入四条契约"的方向相反。 --- @@ -615,7 +615,7 @@ graph TB 1. **训练期**(P2 打包):打包只压缩 `wq_` 那一项(2 B → 行级 base-3 ≈ 1.7 bpw),总账 **10 → ~8.3 B/元素(−17%)**;想再往下必须动 latent/优化器(f16 master、8-bit Adam), - 与三值本身无关。**所以"训练更省显存"不是三值的卖点**——`docs/todo/22` 的 2B4T 目标里 + 与三值本身无关。**所以"训练更省显存"不是三值的卖点**——`docs/internal/22` 的 2B4T 目标里 显存收益来自 GQA(K/V 头收窄)+ tied embedding(省一份 head),不是 BitLinear。 2. **推理/部署期**(P2 之后 + 去掉 latent/grad/optimizer):1.7 bpw vs f16 的 16 bpw ≈ **9.4×**, 这才是 1.58-bit 的名义收益;本项目当前没有单独的推理权重格式(`load_model` 仍读 latent)。 @@ -849,7 +849,7 @@ ctest **36/36**。 > 本节原描述的 `"NNQT"` 独立 magic / 独立读写器 / `--export-deploy` / > `Layer::sub_layers()` / packed-only 载入,已在**库级违规设计清理** -> (`docs/todo/23-library-design-cleanup-and-model-file-roles.md`)中**落地 +> (`docs/internal/23-library-design-cleanup-and-model-file-roles.md`)中**落地 > 删除**。**base-3 载荷**与 **τ 逐位复现**这两条结论继续有效,只是换了容器。 > 裁决与迁移步骤见 23;下面只写**现状口径**。 diff --git a/docs/todo/22-bitnet-2b4t-architecture.md b/docs/internal/22-bitnet-2b4t-architecture.md similarity index 99% rename from docs/todo/22-bitnet-2b4t-architecture.md rename to docs/internal/22-bitnet-2b4t-architecture.md index afc49cd..66e28ce 100644 --- a/docs/todo/22-bitnet-2b4t-architecture.md +++ b/docs/internal/22-bitnet-2b4t-architecture.md @@ -2,7 +2,7 @@ > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 -> **状态**:**立项 + S1/S2/S3/S4 + P2 全部实施完成**(2026-10-10 立项,同日落地并提交)。 +> **状态**:现行(**S1/S2/S3/S4 + P2 全部实施完成**)。 > 已落地:SubLN、GQA、tied embedding(S1–S3)、**FFN 激活 ReLU²**(S4,官方 `hidden_act`)、 > **GQA 的 in-kernel 头映射**(P2,省掉 K/V 的头展开物化)。 > **构建与验收在 `ethan@192.168.1.102`**(Windows + LLVM clang 23 + 真实 GPU @@ -418,7 +418,7 @@ graph TB 3. **新建 `BitNetModel` 平行容器**:要重抄位置编码/掩码族/KV cache/梯度检查点/文档掩码/ offload/flush —— 双份维护,收益为零。→ §0 第 2 条。 4. **模板化 `AttentionBase` / `FeedForward`**:把"层类型是编译期决定"扩散到 - 4 个头与全部实例化点,与 `20-custom-layer-ergonomics.md` 的方向相反。→ `21` §4.8.3。 + 4 个头与全部实例化点,与 `09-custom-layer-ergonomics.md` 的方向相反。→ `21` §4.8.3。 5. **RAPT 挂 SubLN/GQA**:RAPT 的注意力是 ReLU 线性注意力(无 softmax),不是 BitNet 的形态。 → §0 第 11 条。 diff --git a/docs/todo/23-library-design-cleanup-and-model-file-roles.md b/docs/internal/23-library-design-cleanup-and-model-file-roles.md similarity index 99% rename from docs/todo/23-library-design-cleanup-and-model-file-roles.md rename to docs/internal/23-library-design-cleanup-and-model-file-roles.md index 8df56b6..5bd9d75 100644 --- a/docs/todo/23-library-design-cleanup-and-model-file-roles.md +++ b/docs/internal/23-library-design-cleanup-and-model-file-roles.md @@ -1,6 +1,7 @@ # 库级违规设计清理:模型文件角色(`.nnmodel` / `.nnckpt`)· 参数形态协议 · 引擎能力体系 > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history.md`](../history/history.md)。 +> **状态**:现行。 > **状态:已实施(2026-10-11)**。三轮裁决已汇总于 §0;本文件记录**全库审查取证**与**设计**, > 以及**落地进度**(§2.5 各步带 ✅ / ⏳ 标记)。**范围 = 整个库的违规设计清理**(不只三值路径;三值只是触发点)。 diff --git a/docs/todo/24-f16-training-defects.md b/docs/internal/24-f16-training-defects.md similarity index 96% rename from docs/todo/24-f16-training-defects.md rename to docs/internal/24-f16-training-defects.md index e649d65..46cdfff 100644 --- a/docs/todo/24-f16-training-defects.md +++ b/docs/internal/24-f16-training-defects.md @@ -2,6 +2,7 @@ > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md); > 历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 > 状态(2026-10-18 更新):**F1–F4 已完成;F5 的「可训练性」已完成**(optimizer state scaling, > 2026-10-14)。后续拆成两套计划:**F7 = 标准 `--f16`(Plan A,参考 PyTorch AMP)**; @@ -18,7 +19,7 @@ > 关联:`docs/development/05-mixed-precision.md` §12.4/§12.5/§12.11;`precision.hpp`(`profile_all_f16` > 数值注记);[`14-f16-stable-gpu-loss-frozen.md`](14-f16-stable-gpu-loss-frozen.md); > [`18-roadmap.md`](18-roadmap.md) §3.1 的 C1/C2 与 §4.2 的 P1-3; -> [`25-release-requirements.md`](25-release-requirements.md)(F2 的端到端全 f16 训练归口大版本发布清单)。 +> [`../contributors/release-requirements.md`](../contributors/release-requirements.md)(F2 的端到端全 f16 训练归口大版本发布清单)。 ## 0. 结论速览 @@ -48,7 +49,7 @@ | 根因②代码位置 `Adam::adam_update_` K2(v 用 `p_.optimizer`)与 K3(`sqrt(v)+eps`) | ✅ 证实 | `compute_optimizer.hpp` `adam_update_`(K2 L330–333、K3 L345–353) | | 根因②:`v ≈ g²` ~ 1e-10 低于 f16 次正规最小 6e-8 → 下溢 0;`eps=1e-8 → 0` | ✅ 证实(f16 最小正规数 2⁻¹⁴≈6.1e-5、次正规最小 2⁻²⁴≈5.96e-8;默认 `eps=1e-8`) | `precision.hpp` §5.2 数值事实;`compute_optimizer.hpp` `Adam` 默认 `eps=1e-8`(L396) | | 根因②实测「loss 7.9→3.6e4」 | ✅ 与既有实测一致(另一次配制实测 1.8e7,同为爆炸形态) | `precision.hpp` L539–541 注记;[`14`](14-f16-stable-gpu-loss-frozen.md) §2.1 case c | -| 根因③「四字段全 f16 → loss 恒定」 | ✅ 机制证实;**常数口径已订正**:原 `precision.hpp` 注记的「32.1」无 bench 背书、且已在 2026-10-13 随修复移除(该注记仍停留在 F5 前的「不可训练」口径,R0 待同步)。GPU [`14`](14-f16-stable-gpu-loss-frozen.md) 的 `4.0137` **另有根因**:= CE 的 (1,1) loss 归约按 `stable=f16` 落盘**饱和到 f16 上限**(`≈ 65504/num_valid`,见 §3.1)——与「更新被舍入吃光」的数值性冻结是两回事,报告把二者并陈需分开看 | `precision.hpp` `profile_f16()` 注;[`14`](14-f16-stable-gpu-loss-frozen.md) §2 与 §3.1 | +| 根因③「四字段全 f16 → loss 恒定」 | ✅ 机制证实;**常数口径已订正**:原 `precision.hpp` 注记的「32.1」无 bench 背书、且已随修复移除(该注记仍停留在 F5 前的「不可训练」口径,R0 待同步)。GPU [`14`](14-f16-stable-gpu-loss-frozen.md) 的 `4.0137` **另有根因**:= CE 的 (1,1) loss 归约按 `stable=f16` 落盘**饱和到 f16 上限**(`≈ 65504/num_valid`,见 §3.1)——与「更新被舍入吃光」的数值性冻结是两回事,报告把二者并陈需分开看 | `precision.hpp` `profile_f16()` 注;[`14`](14-f16-stable-gpu-loss-frozen.md) §2 与 §3.1 | | 报告「14 号报告 Open / GPU 特有」 | ✅ 证实 | [`14-f16-stable-gpu-loss-frozen.md`](14-f16-stable-gpu-loss-frozen.md)(状态 Open) | | 报告 §三.2「`debug_profile_matrix` 矩阵**没有**四槽全 f16 这一行」 | ✅ 证实(cases = f32 / param / compute / stable / opt / f16(CLI),无 all=f16) | `src/f16_precision_test.cpp` `debug_profile_matrix`(cases L639–646) | | 报告 §三.2「预期 `[dbg stable=f16]` 与 `[dbg opt=f16]` 出现非有限/爆炸」 | ⚠️ **部分更正**(本档已实测复现,见 §2.4):`opt=f16` ✅ 爆炸(`3.4772 → 3.50e6 → … → nan`);`stable=f16` 在该 CPU 小 GPT(vocab 32、20 步)下**健康**(`3.4785 → 3.1797`)。~200 步 NaN 需大词表 + 更多步,报告对小矩阵的预期与实测矛盾 | [`14`](14-f16-stable-gpu-loss-frozen.md) §2.3;§2.4 复现输出 | @@ -333,7 +334,7 @@ K1 `#0002#b` / K2 `#0002#b` / 复合 `#10004#b`,各 32+32+6 实例);优化 | 立项 | 事项 | 验收口径 | 依赖 | 优先级 | 状态 | |---|---|---|---|---|---| | **F1** 危险精度组合**启动期告警**(口径:仅警告,不拒绝) | 启动期对 `optimizer=f16` 与四字段全 f16 打印明确警告后**继续运行**;`--f16` 与合法组合静默不受影响。**不** fail-fast、**不**加确认开关(备注:`stable=f16` 单独出现是否单列待定,见 §2.3) | 危险组合在 stderr 打印含字段/风险/文档指引的警告,退出码与训练行为不变;新增 CLI 断言测试(捕获 stderr) | 无 | 对应 [`18-roadmap.md`](18-roadmap.md) **P1-3**(该处已改为引用本档、不再单独定义) | ✅ **已完成 2026-10-13**(`cli_precision_warning.hpp` + 门禁 `cli_precision_warning_test`) | -| **F2** 补 GPU + 全 f16 覆盖缺口 | profile 组合矩阵补 `{F16,F16,F16,F16}` 行(CPU、廉价);把 stable=f16 / 全 f16 形态搬到 GPU 分支做数值断言。**端到端全 f16 模型训练不进 ctest**(太费时,见下注),改挂到大版本发布清单 [`25`](25-release-requirements.md) 第 1 项「端到端模型训练测试」 | 单字段 / 全 f16 组合有**廉价**断言进默认门禁;端到端全 f16 轨迹在大版本发布时实跑通过 | F1(或与 F1 同批) | 高(关 [`14`](14-f16-stable-gpu-loss-frozen.md) §3 缺口) | ✅ **已完成(组合矩阵 + GPU 分支 + CE 溢出回归,2026-10-13)**;端到端全 f16 仍归发布清单 | +| **F2** 补 GPU + 全 f16 覆盖缺口 | profile 组合矩阵补 `{F16,F16,F16,F16}` 行(CPU、廉价);把 stable=f16 / 全 f16 形态搬到 GPU 分支做数值断言。**端到端全 f16 模型训练不进 ctest**(太费时,见下注),改挂到大版本发布清单 [`25`](../contributors/release-requirements.md) 第 1 项「端到端模型训练测试」 | 单字段 / 全 f16 组合有**廉价**断言进默认门禁;端到端全 f16 轨迹在大版本发布时实跑通过 | F1(或与 F1 同批) | 高(关 [`14`](14-f16-stable-gpu-loss-frozen.md) §3 缺口) | ✅ **已完成(组合矩阵 + GPU 分支 + CE 溢出回归,2026-10-13)**;端到端全 f16 仍归发布清单 | | **F3** 修 GPU `stable=f16` loss 冻结 | 最小复现 → 定位并修。**实际结论**:不是回读链(`cast`/槽位)问题,而是 **CE 的 (1,1) loss 归约按 `stable=f16` 落盘溢出**(见 §3.1 订正) | 冻结/`inf` 消失;GPU + stable=f16 loss 曲线可观测;回归用例 | 无 | 高(既有 Open 故障,[`14`](14-f16-stable-gpu-loss-frozen.md)) | ✅ **已完成 2026-10-13**(详见 §3.1) | | **F4** f16 提速兑现 | 归因「f16 比 f32 慢」的时间去向;方案见 [`26`](26-f16-speedup-plan.md)(**存储路径**带宽优先、**原生 f16 用足**;口径「任意设备」) | ① 存储路径在任意设备(40HX / 850M / CPU)上 `--f16` step ≤ f32 且峰值显存更低、**不依赖** `shaderFloat16`;② capable 设备额外:原生 f16 已启用(`NN_VULKAN_NO_16BIT_ALU` A/B 显示原生开更快) | F3 等 | 中 | ✅ **已完成 2026-10-14**。根因订正 = 「运行期精度分派 `#x` 的三元税」为主(非"固定开销掩盖"、非"logits 仍 f32")→ 用 **S1s/S1t 编译期特化** + **网格粒度变体(P2-13)** 修掉。**跨设备结果**(各 15 步 ×3 轮):**850M**(无 `shaderFloat16`)`--f16` **2005 vs f32 2038 ms(−1.6%)**、峰值显存 **606 vs 818 MiB(−26%)**;**40HX**(有原生 f16 ALU)`--f16` **1013 vs f32 1046 ms(−3.2%)**;**CPU** f16 不再慢于 f32(3.6→1.9 s,见 P2-8)。另外 **F5 全 f16 已可训练**(§4.6)。S0/S1/S2/S5 的评估见 [`26`](26-f16-speedup-plan.md)(0/1/2 为实测后不做、5 为资格不再扩张) | | **F5** 全 f16 可用性 | ✅ **可训练性完成 2026-10-14**(产品化转 F6)。落地形态与原方案不同:不用训练循环里的 loss scaling,而是**在优化器状态更新处缩放**(`Adam::optimizer_state_scale_`)——进入 m/v 的梯度放大 **S=4096**(2 的幂 → f16 下无损)、`(1-β1)·S` / `(1-β2)·S²` / `eps·S` 同步换算。**为什么有效**:Adam 的更新是尺度不变的 `lr·(S·m̂)/(√(S²·v̂)+S·eps) = lr·m̂/(√v̂+eps)` ⇒ **更新量数学不变**,但 m~g·S、v~g²·S² 都回到 f16 正常区(根因 = v ≈ (1-β2)·g² ~ 1e-10 在 f16 下**下溢为 0** 而 m 仍在次正规区 ⇒ `m/(√v+eps)` 退化、更新暴涨 → 第 1 步即 NaN)。比 loss scaling 更内聚:不改 CLI / 不改梯度与裁剪语义、无"是否反缩放"分支;rparam 恒 f32 传递 ⇒ 原方案里的"eps flush-to-0"不成问题(eps 的**相对**比例由 `eps·S` 保持)。**边界**:|g| ≳ 0.0625 时 v 会溢出 f16 ⇒ 实践配 `--max-norm` 裁剪;启动期精度告警(F1)保持有效 | 四字段全 f16 在 CPU/GPU 上健康收敛 | F1/F2/F3 | 中 | ✅ **可训练性已完成**(见 §4.6);但 CE 标量仍是 F32 补丁、native16 未全覆盖 ⇒ **不等于真 f16**;🟡 **全流程真 f16 产品化 = F6** | @@ -351,7 +352,7 @@ K1 `#0002#b` / K2 `#0002#b` / 复合 `#10004#b`,各 32+32+6 实例);优化 > > **训练为何不进 ctest**:ctest 要能在 CI runner 上分钟级跑完,而模型端到端训练(含全 f16 形态) > 太费时——故默认门禁只放**廉价**断言,端到端训练归口大版本发布清单 -> [`25-release-requirements.md`](25-release-requirements.md)(F2 因此只把组合矩阵 / 数值断言放进 ctest)。 +> [`../contributors/release-requirements.md`](../contributors/release-requirements.md)(F2 因此只把组合矩阵 / 数值断言放进 ctest)。 ## 6. 证据索引 diff --git a/docs/todo/26-f16-speedup-plan.md b/docs/internal/26-f16-speedup-plan.md similarity index 99% rename from docs/todo/26-f16-speedup-plan.md rename to docs/internal/26-f16-speedup-plan.md index 8aeae5d..004fb29 100644 --- a/docs/todo/26-f16-speedup-plan.md +++ b/docs/internal/26-f16-speedup-plan.md @@ -2,6 +2,7 @@ > **读者**:项目开发者(本仓内部工作文档)。本册定位见 [`README.md`](README.md); > 历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 > 状态(2026-10-18):**F4 提速已收口;后续拆成 Plan A(标准 `--f16`,参考 PyTorch AMP)与 > Plan B(全流程真 f16)两条活跃路线**——S1s/S1t(编译期特化)+ diff --git a/docs/todo/27-execution-plan.md b/docs/internal/27-execution-plan.md similarity index 99% rename from docs/todo/27-execution-plan.md rename to docs/internal/27-execution-plan.md index 8e9902e..daf8299 100644 --- a/docs/todo/27-execution-plan.md +++ b/docs/internal/27-execution-plan.md @@ -2,6 +2,7 @@ > **读者**:项目开发者(本仓内部工作文档)。本分册定位见 [`README.md`](README.md); > 历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 > **本文与 [`18-roadmap.md`](18-roadmap.md) 的分工(唯一规则)**:18 号裁定"**要不要做 / 做到什么算完成**" > (做 / 条件触发 / 不做 + 验收口径 + 现状实测),本文只排"**先做哪个**"(象限 + 第一步动作 + 串行约束)。 diff --git a/docs/todo/28-lifecycle-v3.md b/docs/internal/28-lifecycle-v3.md similarity index 95% rename from docs/todo/28-lifecycle-v3.md rename to docs/internal/28-lifecycle-v3.md index 1653da7..eabba12 100644 --- a/docs/todo/28-lifecycle-v3.md +++ b/docs/internal/28-lifecycle-v3.md @@ -1,12 +1,12 @@ # 28 — 生命周期 v3:设备域模型与所有权收敛 > **读者**:项目开发者(本仓内部工作文档)。分册定位见 [`README.md`](README.md)。 -> **状态**:✅ **已实施(2026-10-20,分支 `dev/lifetime_refresh`,发布 `v1.10.0-rc0`)**。 +> **状态**:现行(**已实施,随 `v1.10.0` 发布**)。 > P0(安全修复)/ P1(v3 core)/ P3(backend 弱缓存)已完成并全绿;Session 层 P2a/P2b 见 > [`29`](29-session-architecture.md)(**P2b 已于 2026-10-21 落地,v1.10.0-rc0.1**);P4 文档收尾随本分支。决策记录见 §3;Session 层(原第 3 项)拆到 > [`29-session-architecture.md`](29-session-architecture.md)。 -> **替代关系**:本文取代 [`../development/08-object-lifetimes.md`](../development/08-object-lifetimes.md) -> 与 [`../development/09-engine-ownership.md`](../development/09-engine-ownership.md) 里"Tensor 保存 +> **替代关系**:本文取代 [`../development/07-engine-ownership.md`](../development/07-engine-ownership.md) +> 与 [`../development/07-engine-ownership.md`](../development/07-engine-ownership.md) 里"Tensor 保存 > EngineId provenance"的部分;实施完成后 08/09 按本文重写(见 §5 P4)。 > 执行排序见 [`27-execution-plan.md`](27-execution-plan.md);裁定台账见 [`18-roadmap.md`](18-roadmap.md) §4.2 P1-8。 @@ -26,9 +26,9 @@ |---|---|---|---| | D1 | **绑定检查没有比较 `this`**:`bind_check_` 只让操作数互相比较(首个 bound 作基准),从不验证操作数属于当前引擎 ⇒ 单操作数入口可让外来 GPU 张量进入任意引擎;`GpuEngine::import_impl` 对 `src.is_gpu()` 直接返回别名,跨 backend 传张量是 UB | 高 | `compute_engine.hpp` 的 `bind_check_one_`;`compute_gpu_engine.hpp` 的 `import_impl`;全仓无 mixed-engine 拒绝测试 | | D2 | **provenance 传播机器是持续维护税**:core_engine_id.hpp 83 行;`stamp_` 35 处;`adopt` 18 处;`bind_check_` 42 处;`NN_BIND_DEBUG` 3 处 + CI 第二轮 ctest。新增回退路径必须记得 stamp(历史上 RV-06、v1.9 f16 回退 cast 两次补漏) | 高 | 计数见 `bench/doc_inventory.ps1` 之外的 grep 口径;`docs/history/history.md` 对应条目 | -| D3 | **Optimizer 的 owner 契约是假的**:`params_/grads_` 是非拥有 `TensorRef` 指向 Model/Layer 成员 Tensor;Model 先析构 ⇒ `step()` UAF;两份文档却写"优化器晚于 Model 存活也安全" | 高 | `compute_optimizer.hpp`;`09-engine-ownership.md`、`08-object-lifetimes.md`;`layer_lifetime_test` 未覆盖 | +| D3 | **Optimizer 的 owner 契约是假的**:`params_/grads_` 是非拥有 `TensorRef` 指向 Model/Layer 成员 Tensor;Model 先析构 ⇒ `step()` UAF;两份文档却写"优化器晚于 Model 存活也安全" | 高 | `compute_optimizer.hpp`;`07-engine-ownership.md`、`07-engine-ownership.md`;`layer_lifetime_test` 未覆盖 | | D4 | **activation offload 状态机缺口**:`export_activations` 在 `offloaded_` 为真时静默 `return {}`,只有 import 清标志 ⇒ 两次 forward 之间可能静默用上一步 slab;slab 以 f32 记账,f16/t1_58 + offload 无配置期拒绝、无测试 | 中高 | `compute_layer_base.hpp` 的 `ActivationOffloader`;`cli/text_train_config.hpp` 未校验组合 | -| D5 | **GPU 后端生命周期不具确定性**:`GpuBackend::shared()` 的函数局部 static 强引用使 Vulkan 资源活到进程退出;`instance()` 叠加第二层 static,16 个调用点 | 中 | `backend/compute_vk_backend.hpp`;`09-engine-ownership.md` 声称 RAII 即时回收 | +| D5 | **GPU 后端生命周期不具确定性**:`GpuBackend::shared()` 的函数局部 static 强引用使 Vulkan 资源活到进程退出;`instance()` 叠加第二层 static,16 个调用点 | 中 | `backend/compute_vk_backend.hpp`;`07-engine-ownership.md` 声称 RAII 即时回收 | | D6 | **录制段生命周期**:`ExprSegment` 持裸 `ComputeEngine&`(作用域内丢引擎句柄 ⇒ 析构 UAF);跨线程 `end_expr` 静默 no-op | 中 | `compute_engine.hpp` 的 `ExprSegment`;`compute_gpu_engine.hpp` 的 `end_expr` | | D7 | **API 易用性**:~130 处 `create()` 后立刻退化成 `Engine&`(`raw_engine.get()` 别名 idiom);工厂/`create_optimizer` 只收 `ComputeEngine&`;`create_optimizer` 返回 `unique_ptr`/`nullptr` 与全库 `Result` 不一致 | 中 | 全仓用法审计 | | D8 | **文档双源/过期 + 门禁补丁税**:08/09 互相矛盾且重复;`usage/03` 自相矛盾;`cpp-api-manual` 示例返回 `unique_ptr` 但工厂返回 `Result`;`NN_BIND_DEBUG` 第二轮 CI 是 stamp 机制的补丁税 | 中 | 对应文件 | @@ -168,5 +168,5 @@ - 执行排序:[`27-execution-plan.md`](27-execution-plan.md) - 裁定台账:[`18-roadmap.md`](18-roadmap.md) §4.2 P1-8 - 现行底层契约:[`17-unified-tensor-engine.md`](17-unified-tensor-engine.md) -- 现行生命周期文档(将被本文取代):[`../development/08-object-lifetimes.md`](../development/08-object-lifetimes.md)、 - [`../development/09-engine-ownership.md`](../development/09-engine-ownership.md) +- 现行生命周期文档(将被本文取代):[`../development/07-engine-ownership.md`](../development/07-engine-ownership.md)、 + [`../development/07-engine-ownership.md`](../development/07-engine-ownership.md) diff --git a/docs/todo/29-session-architecture.md b/docs/internal/29-session-architecture.md similarity index 99% rename from docs/todo/29-session-architecture.md rename to docs/internal/29-session-architecture.md index dd3b6e9..77a4635 100644 --- a/docs/todo/29-session-architecture.md +++ b/docs/internal/29-session-architecture.md @@ -1,7 +1,7 @@ # 29 — Session 层:TrainingSession / TrainingGroupSession / InferenceSession > **读者**:项目开发者(本仓内部工作文档)。分册定位见 [`README.md`](README.md)。 -> **状态**:✅ **P2a 已实施(2026-10-20,`training_session.hpp` + `training_session_test`)**; +> **状态**:现行(**P2a/P2b 已实施,随 `v1.10.0` 发布**); > ✅ **P2b 已实施(2026-10-21,v1.10.0-rc0.1)**:`TrainingSession` 持有 `TrainState`; > 数据集经 `TextSampleSet`(样本 = 窗口)**直接接入训练工厂 `TextTrainer`**,CLI 退出训练循环 > 实现(见 §8)。`InferenceSession` 仍为设计占位;`TrainingGroupSession` 的通用架构已冻结、 diff --git a/docs/todo/30-training-session-step.md b/docs/internal/30-training-session-step.md similarity index 99% rename from docs/todo/30-training-session-step.md rename to docs/internal/30-training-session-step.md index 76b1626..d278047 100644 --- a/docs/todo/30-training-session-step.md +++ b/docs/internal/30-training-session-step.md @@ -1,7 +1,7 @@ # 30 — TrainingSession 单步协议与梯度累积 > **读者**:项目开发者。 -> **状态**:✅ 已实施(2026-10-22)。 +> **状态**:现行(已实施,随 `v1.11.0` 发布)。 > **关系**:本文修订 [`29-session-architecture.md`](29-session-architecture.md) 中 > “Session 只提供 zero_grad/clip/step 低层原语、Loss 全留训练工厂”的旧边界。 > `Model` 所有权、Optimizer 非拥有引用的生命周期修复不变。 diff --git a/docs/todo/31-rl-training-primitives.md b/docs/internal/31-rl-training-primitives.md similarity index 99% rename from docs/todo/31-rl-training-primitives.md rename to docs/internal/31-rl-training-primitives.md index 73dd0f1..8d881aa 100644 --- a/docs/todo/31-rl-training-primitives.md +++ b/docs/internal/31-rl-training-primitives.md @@ -1,7 +1,7 @@ # 31 — RL 训练原语与可组合训练基础设施 > **读者**:项目开发者(本仓内部设计文档)。 -> **状态**:✅ **已实施(2026-10-23,分支 `dev/rl_training`)**。 +> **状态**:现行(**已实施,随 `v1.12.0` 发布**)。 > **需求来源**:[GitHub issue #23](https://github.com/EthanPeng-2048/neuralnet.cpp/issues/23)。 > **用户裁定(2026-10-23)**:当前主线切到 RL;f16 与训练性能项继续后移,不作为 RL 的前置。 > **2026-10-23 库化修正**:issue #23 是能力**下界**,不是范围上界。公共 API 不得以 diff --git a/docs/todo/32-trainer-skeleton-and-openspec.md b/docs/internal/32-trainer-skeleton-and-openspec.md similarity index 99% rename from docs/todo/32-trainer-skeleton-and-openspec.md rename to docs/internal/32-trainer-skeleton-and-openspec.md index 38e61ba..3d3de3a 100644 --- a/docs/todo/32-trainer-skeleton-and-openspec.md +++ b/docs/internal/32-trainer-skeleton-and-openspec.md @@ -1,7 +1,7 @@ # 32 — 领域无关训练骨架(RunDriver)与开放模型规格(ModelSpecBase) > **读者**:项目开发者。 -> **状态**:📐 RFC(待实施)。 +> **状态**:现行(RFC 已实施:RunDriver / TrainState / BatchSource / ModelSpecBase 均已落地)。 > **关系**:本文修订 [`30-training-session-step.md`](30-training-session-step.md) 的层次边界, > 在「单步 Session(`30`)」与「文本 Run Driver(`TextTrainer`)」之间补上缺失的 > **领域无关骨架**层,并把封闭枚举 `ModelType` 的规格扩展为开放多态。 diff --git a/docs/todo/README.md b/docs/internal/README.md similarity index 82% rename from docs/todo/README.md rename to docs/internal/README.md index d0f5c0b..33072dd 100644 --- a/docs/todo/README.md +++ b/docs/internal/README.md @@ -1,20 +1,24 @@ -# todo/ —— 项目开发者内部工作区 +# internal/ —— 项目开发者内部工作区 > **本分册写给项目开发者**(改这个库的人),不是给调用者的。 -> 调用者要看的开发文档在 [`../development/`](../development/);历史归档在 [`../history/history.md`](../history/history.md)。 +> 调用者要看的开发文档在 [`../development/`](../development/);历史归档在 [`../history/history.md`](../history/history.md); +> 贡献者/作者的**规范与治理**(C++ 规范、踩坑警示录、文档规范、发布规则)在 [`../contributors/`](../contributors/README.md)。 +> **读者**:项目开发者(改这个库的人)。本分册定位见 [`README.md`](README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 ## 这里的文档怎么组织 -- **一件事一篇**:设计稿(含未实施部分)、路线图与裁定、现状盘点、编码规范、踩坑记录、 - 未修故障、审查/评审整改立项。 +- **一件事一篇**:设计稿(含未实施部分)、路线图与裁定、现状盘点、未修故障、审查/评审整改立项。 + **长期规范不放这里**——编码规范 / 踩坑 / 发布规则属"长期真源",在 [`../contributors/`](../contributors/README.md)。 - **裁定与计划分家(2026-10-15 起)**:**裁定台账**(要不要做 / 条件触发 / 不做 + 验收口径)住 [`18-roadmap.md`](18-roadmap.md);**执行计划**(先做哪个 / 第一步动作 / 并行与工时)一律**单独成文**, 18 号只留指针(当前执行排序 = [`27-execution-plan.md`](27-execution-plan.md),专项方案 = `31` / `26` / `04` / `25` / `28` / `29`)。 新增内容先判断属于哪一类:能二值化成"做/不做"的进 18,只描述顺序与动作的进 27。 - **允许带进度状态**(✅ 已实施 / ⏳ 待做 / ❌ 已否决),但**不写历史叙事**—— 演进过程、被否决方案的理由、旧数字一律进 `../history/history.md`。 -- 编号沿用历史编号(**新增接当前最大号**,不重排旧号),**编号缺号是正常的**(`05` `06` `20` 等留在 - `development/`;`13` 已删除;`15` `16` 已并入 `history/history.md`)。 +- **编号 = 稳定台账 ID**(文档规范见 [`../contributors/documentation-standard.md`](../contributors/documentation-standard.md) §1): + **新增接当前最大号,永不重排**,缺号是历史正常痕迹(`05`–`11`、`13`、`15`、`16`、`20`、`25`、`33` + 要么留在 `development/`、要么已删除/搬去 `contributors/`/并入 `history/`)。 ## 分类与索引 @@ -25,6 +29,7 @@ | [`00-code-review-remediation.md`](00-code-review-remediation.md) | **2026-10-11 代码审查整改立项台账**:审查发现的问题逐条立项(现象/证据/根因/方案/验收/优先级) | | [`18-roadmap.md`](18-roadmap.md) | **"某件事该不该做"的唯一入口**:未来 6–12 个月方向 + 未完成项**裁定**台账(做 / 条件触发 / 不做)+ 验收口径 + 现状实测;**§4.5 P4 = 持续优化方向**(性能利用率 / 算子性能 / 显存开销 + API 易用性与 Fold 自动化扫描)。**不含执行计划**(见下一行) | | [`27-execution-plan.md`](27-execution-plan.md) | **执行计划(优先级象限)**:把 18 号 §3/§4/§6 与 00 号 RV 台账里当前可动手的项排成"先做哪个"(重要×简单四象限 + 第一步动作 + 串行依赖)——**想知道"下一个先做哪个"读它** | +| [`32-trainer-skeleton-and-openspec.md`](32-trainer-skeleton-and-openspec.md) | **领域无关训练骨架(RunDriver)与开放模型规格(ModelSpecBase)RFC**(已实施):TrainState/BatchSource/RunDriver 分层 + ModelSpecBase 多态规格(issue #39/#26) | | [`31-rl-training-primitives.md`](31-rl-training-primitives.md) | **RL 与可组合训练基础设施(2026-10-23 ✅ 已实施)**:具名输出/schema(RL-0)→ experience/transforms/objectives(RL-1)→ `TrainingGroupSession` 与可替换编排(RL-2);实现/门禁清单见 §11,使用指南见 `usage/06-reinforcement-learning.md` | | [`26-f16-speedup-plan.md`](26-f16-speedup-plan.md) | **f16 提速 + 两套 f16 计划**:F4 存储路径提速已收口;§8 分 A/B 两条路线——**A = 标准 `--f16`(参考 PyTorch AMP,补动态 loss scaling/master weights)**;**B = 全流程真 f16(B-Mem 无 f32 持久态;capable 设备的 B-Arith 零转换)**。**§8.B.7 汇总 SR / GradientStabilizer / ECO / Unit Scaling / Peri-LN / attention δ 修复的外部证据与 R2.5 落地顺序**。A 是推荐默认,B 是实验/性能目标 | | [`04-memory-optimization.md`](04-memory-optimization.md) | 显存优化计划:L1 激活重计算(已实施)/ L2 内存池归还(已实施)/ L3 远期 | @@ -45,22 +50,19 @@ | [`30-training-session-step.md`](30-training-session-step.md) | **TrainingSession 单步协议(已实施)**:Session 接收 micro-batch、内置梯度累积、按 global batch 有效单位归一化并完成一次 optimizer update;`batch_size` 是理论 batch;Loss mask 固化在 Sample;epoch/lr 曲线/评估/运行态 `TrainState` 归 `TextTrainer`。改训练入口前读 | | [`31-rl-training-primitives.md`](31-rl-training-primitives.md) | **RL 与通用训练基础设施(✅ 已实施)**:具名多输出、schema 化 experience、可组合 policy objectives、通用多模型 Session 与可替换编排;落点/门禁见 §11 | -### 现状盘点 / 规范 / 教训 / 故障 +### 现状盘点 / 故障台账 | 文档 | 何时读 | |------|--------| | [`12-compute-engine-inventory.md`](12-compute-engine-inventory.md) | 引擎接口现状盘点(复现:`bench/doc_inventory.ps1`):virtual 方法数、Layer 直调分类、两套 CPU 求值机制、ctest 计数 | -| [`10-development-standards.md`](10-development-standards.md) | C++ 编码规范全文(内存管理 / 模块隔离 / 高性能 / 错误处理 / 注释) | -| [`08-pitfalls-and-lessons.md`](08-pitfalls-and-lessons.md) | **踩坑警示录,改代码前读**:分级 bug 与跨领域根因模式 | | [`14-f16-stable-gpu-loss-frozen.md`](14-f16-stable-gpu-loss-frozen.md) | **已修故障报告(根因已订正)**:GPU `--precision-stable f16` 训练 loss 打印冻结——真因 = CE 的 `(1,1)` 归约输出按 f16 落盘溢出(不是回读链) | | [`24-f16-training-defects.md`](24-f16-training-defects.md) | **f16 训练缺陷台账**:全 f16 NaN / loss 冻结 / `--f16` 降速——含报告核对与立项 F1–F7(F5 = 可训练性已完成;**F6 = 真 f16(Plan B)**;**F7 = 标准 `--f16`(Plan A)**) | -| [`25-release-requirements.md`](25-release-requirements.md) | **大版本发布要求**(`1.x.y → 1.(x+1).0`):端到端模型训练测试 / 发布文档 / 完整 ctest + Debug 构建 / 多编译器 × 标准库矩阵 | -| [`33-version-branch-and-release-policy.md`](33-version-branch-and-release-policy.md) | **版本号·分支·发布治理(三条红线)**:`v1..<漏洞修复>` 规则、**发布版本号必须由人提出(agent 不得擅自发布)**、`dev` 不写版本号、发布只在 `main`。定版本号 / 发版 / 改分支策略前读 | ## 相关(相邻分册 / 总档) | 想去哪 | 文档 | |--------|------| +| 贡献者/作者规范(C++ 规范 / 踩坑 / 文档规范 / 发布规则) | [`../contributors/README.md`](../contributors/README.md) | | 全仓历史归档(演进 / 勘误 / 否决 / A-B) | [`../history/history.md`](../history/history.md) | | 总索引与分册定位 | [`../README.md`](../README.md) | | 性能对比基准 | [`../benchmarks/`](../benchmarks/) | diff --git a/docs/introduction/01-architecture.md b/docs/introduction/01-architecture.md index 20b1448..90e0e0a 100644 --- a/docs/introduction/01-architecture.md +++ b/docs/introduction/01-architecture.md @@ -1,5 +1,7 @@ # neuralnet.cpp 架构设计 +> **读者**:想了解本库架构/性能/算法的读者(调用者视角的总览)。总索引见 [`../README.md`](../README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 从零实现的 C++26 神经网络库,支持 CPU/GPU 双后端、多层 Transformer、GPT 语言模型训练与推理。 --- @@ -275,7 +277,7 @@ class Tensor { > 引擎共 **52 个 virtual 方法**(复现 `bench/doc_inventory.ps1`);逐元素/广播/条件选择不设 eager 原语,一律经表达式 DSL >(`dsl::compute` / `compute_into` / `compute_reduce`)执行。接口全量清单见 -> `../todo/12-compute-engine-inventory.md`。 +> `../internal/12-compute-engine-inventory.md`。 **表达式统一入口:** diff --git a/docs/introduction/02-performance.md b/docs/introduction/02-performance.md index ff3417c..0b94667 100644 --- a/docs/introduction/02-performance.md +++ b/docs/introduction/02-performance.md @@ -1,5 +1,7 @@ # 性能优化手段 +> **读者**:想了解本库架构/性能/算法的读者(调用者视角的总览)。总索引见 [`../README.md`](../README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 本文档详细梳理 neuralnet.cpp 项目中的所有性能优化策略,涵盖 CPU 多线程、缓存优化、GPU 加速、内存管理、算法级优化等层面。 --- diff --git a/docs/introduction/03-algorithm-reference.md b/docs/introduction/03-algorithm-reference.md index 0b5668e..74b7714 100644 --- a/docs/introduction/03-algorithm-reference.md +++ b/docs/introduction/03-algorithm-reference.md @@ -1,5 +1,7 @@ # 算法参考:Layer / Loss / Optimizer +> **读者**:想了解本库架构/性能/算法的读者(调用者视角的总览)。总索引见 [`../README.md`](../README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 本文档详细解析 neuralnet.cpp 中每个计算组件的数学原理、实现细节和引擎原语分解。 --- diff --git a/docs/introduction/04-innovative-designs.md b/docs/introduction/04-innovative-designs.md index 471a625..38c70b3 100644 --- a/docs/introduction/04-innovative-designs.md +++ b/docs/introduction/04-innovative-designs.md @@ -1,5 +1,7 @@ # neuralnet.cpp 创新设计总览 +> **读者**:想了解本库架构/性能/算法的读者(调用者视角的总览)。总索引见 [`../README.md`](../README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 本文档汇总本项目中所有具有**原创性或系统性思考**的设计。它不是架构/性能/融合等专项文档的重复,而是从"为什么这么做、创新点在哪、带来什么收益"的角度,把这些设计串成一张全景图。 关联文档:`01-architecture` · `02-performance` · `03-algorithm-reference`(介绍类);专项设计见 `docs/` 下的融合、优化、IR 等文档。 diff --git a/docs/release-notes/README.md b/docs/release-notes/README.md index 1a8f3f4..c26a3af 100644 --- a/docs/release-notes/README.md +++ b/docs/release-notes/README.md @@ -1,6 +1,8 @@ # Release Notes 与版本号规范 > 本目录按版本一册:`v<主>..<漏洞修复>.md`。预发布候选用 `v1.10.0-rc0.1.md` 形式。 +> **读者**:查版本变更与版本号规则的调用者。本分册定位见 [`README.md`](README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 ## 1. 版本号定义 @@ -19,18 +21,25 @@ 3. **已发布版本不重打**:tag 一旦发布即冻结;发布后发现的问题以勘误块追加在该版本 release note 顶部,并指向修复版本(例:见 `v1.10.0.md` 勘误)。 4. **子仓库**(`extern/base` 等 5 个 submodule)遵循同一 `v1..<漏洞修复>` 规范,各自独立编号;基线 `v1.0.0` 已锁定于与主仓库 v1.13.0 同期的快照。 5. 每册 release note 的头部固定给出:发布范围(上一 tag → 本 tag)、主题、兼容性评级、验收基线。 -6. **发布治理**:版本号的定档与发布必须由**人**明确提出,**agent 不得擅自决定版本号或执行发布**(`git tag` / `gh release` 等);`dev` 与功能分支不写版本号,定档与发布只发生在 `main`。正文见 [`../todo/33-version-branch-and-release-policy.md`](../todo/33-version-branch-and-release-policy.md)。 +6. **发布治理**:版本号的定档与发布必须由**人**明确提出,**agent 不得擅自决定版本号或执行发布**(`git tag` / `gh release` 等);`dev` 与功能分支不写版本号,定档与发布只发生在 `main`。正文见 [`../contributors/release-policy.md`](../contributors/release-policy.md)。 ## 2. 目录索引 | 版本 | 主题 | |---|---| -| [v1.13.0](v1.13.0.md) | (见该册) | -| [v1.12.0](v1.12.0.md) | (见该册) | +| [v1.13.0](v1.13.0.md) | 子仓拆分(core / threadpool / kvrecord / dataset / tokenizer → `extern/` submodule) | +| [v1.12.0](v1.12.0.md) | RL 与可组合训练基础设施(具名多输出 / experience / objectives / `TrainingGroupSession`) | | [v1.11.0](v1.11.0.md) | batch/step 计数语义统一 + 梯度累积归一化修复 | | [v1.10.0](v1.10.0.md) | 对象生命周期 v3 + `TrainingSession` + `TextTrainer` | +| [v1.10.0-rc0.1](v1.10.0-rc0.1.md) | 预发布候选:Session 层 P2b(`TrainState` 归属) | +| [v1.10.0-rc0](v1.10.0-rc0.md) | 预发布候选:生命周期 v3 core | | [v1.9.0](v1.9.0.md) | (见该册) | -| [v1.8.x](v1.8.2.md) | (见该册) | -| [v1.7.x](v1.7.1.md) | (见该册) | -| [v1.6.x](v1.6.1.md) | (见该册) | -| [v1.5.x](v1.5.1.md) | (见该册) | +| [v1.8.2](v1.8.2.md) | 漏洞修复 | +| [v1.8.1](v1.8.1.md) | 漏洞修复(补写) | +| [v1.8.0](v1.8.0.md) | (见该册;2026-10-18 补写) | +| [v1.7.1](v1.7.1.md) | 漏洞修复(补写) | +| [v1.7.0](v1.7.0.md) | (见该册) | +| [v1.6.1](v1.6.1.md) | 漏洞修复(补写) | +| [v1.6.0](v1.6.0.md) | (见该册) | +| [v1.5.1](v1.5.1.md) | 漏洞修复(补写) | +| [v1.5.0](v1.5.0.md) | (见该册) | diff --git a/docs/release-notes/v1.10.0-rc0.1.md b/docs/release-notes/v1.10.0-rc0.1.md index a885ccb..60df168 100644 --- a/docs/release-notes/v1.10.0-rc0.1.md +++ b/docs/release-notes/v1.10.0-rc0.1.md @@ -8,7 +8,7 @@ > 训练循环不再由 CLI 实现(`cli/text_train_loop.hpp` 只留 hooks)。文件格式 v8 与版本号**不变**。 > **定位**:`rc0` 后续预发布候选,只覆盖 P2b 训练工厂/样本层;完整四编译器矩阵与 Linux+850M 权威口径 > **未在本次重跑**(沿用 v1.9.0 记录与 rc0 的 clang 口径)。正式版仍需按 -> [`docs/todo/25-release-requirements.md`](../todo/25-release-requirements.md) §1–§3 全量重跑。 +> [`docs/contributors/release-requirements.md`](../contributors/release-requirements.md) §1–§3 全量重跑。 ## 0. 亮点速览(TL;DR) @@ -146,7 +146,7 @@ auto report = NN_UNWRAP(trainer.fit()); // 返回 TextTrainReport 1. **流式 DataLoader 仍未做**(P2-4 后半):`TextSampleSet` 仍把子集整段物化到 `TextCorpus` (token_flow/doc_ids/loss_mask),超大语料的内存曲线问题与 rc0 相同。 -2. **`InferenceSession` / `RLTrainingSession` 仍为占位**(docs/todo/29 §6/§7)。 +2. **`InferenceSession` / `RLTrainingSession` 仍为占位**(docs/internal/29 §6/§7)。 3. **`create_optimizer` 自由工厂签名未收口**(D7:`unique_ptr`/`nullptr`),留待下个破坏性窗口; `Session` 已覆盖训练路径,CLI 不再使用自由工厂。 4. **`TextTrainer` 目前只服务文本/GPT 任务**(内置 sparse-CE);MNIST/自定义任务的通用 Step diff --git a/docs/release-notes/v1.10.0-rc0.md b/docs/release-notes/v1.10.0-rc0.md index 8923a5c..f427837 100644 --- a/docs/release-notes/v1.10.0-rc0.md +++ b/docs/release-notes/v1.10.0-rc0.md @@ -77,7 +77,7 @@ NN_UNWRAP(session.step()); // optimizer.step() + step_coun 1. `model_` 声明在 `opt_` 之前 ⇒ **optimizer 先于 Model 析构**(`TensorRef` 永悬空); 2. Session 不可拷贝、可移动(Layer 对象在堆上,移动后 `TensorRef` 仍有效); 3. `Model` 保持纯值对象——推理可直接用 `Model`,不需要 Session; -4. **Loss / 数据集 / epoch / CLI / 日志不归 Session**(防 god object,见 docs/todo/29 §4)。 +4. **Loss / 数据集 / epoch / CLI / 日志不归 Session**(防 god object,见 docs/internal/29 §4)。 自由工厂 `create_optimizer(name, engine, params, grads, ...)` **保留**:调用方必须保证 "optimizer 在其参数所有者存活期内销毁";需要结构保证时用 `TrainingSession`。 @@ -105,7 +105,7 @@ static std::shared_ptr create(); // 独立实例(测试/多设 | D5 `GpuBackend` 生命周期 | ✅ 修复 | `shared()` weak 缓存;`instance()` 删除;回归测试锁"全部释放 → 重建" | | D6 录制段生命周期 | ✅ 修复 | `ExprSegment` 持 `shared_ptr`;GPU `end_expr` 无录制 = 明确错误 | | D7 API 易用性 | ◐ 部分 | `TrainingSession` 收敛训练侧样板;`create_optimizer` 返回 `unique_ptr/nullptr` 的签名**未改**(外部 ABI 稳定,留待下个破坏性窗口) | -| D8 文档双源 | ✅ 本轮处理 | 08/09 假承诺与 `shared()` RAII 口径已纠正;生命周期单源文档重写见 docs/todo/28 §5 P4(本 rc 已完成主要矛盾修正) | +| D8 文档双源 | ✅ 本轮处理 | 08/09 假承诺与 `shared()` RAII 口径已纠正;生命周期单源文档重写见 docs/internal/28 §5 P4(本 rc 已完成主要矛盾修正) | | D9 洁癖项 | ◐ 未做 | `Layer::BindingState` 三态、`nn::TensorRef` 重名按计划随 P2b/后续窗口处理 | ## 5. 迁移表(v1.9.0 → v1.10.0-rc0) diff --git a/docs/release-notes/v1.10.0.md b/docs/release-notes/v1.10.0.md index 71c7641..2aea767 100644 --- a/docs/release-notes/v1.10.0.md +++ b/docs/release-notes/v1.10.0.md @@ -166,7 +166,7 @@ NN_UNWRAP(session.step()); // optimizer.step() + step_coun 1. `model_` 声明在 `opt_` 之前 ⇒ **optimizer 先于 Model 析构**(`TensorRef` 永不悬空); 2. Session 不可拷贝、可移动(Layer 对象在堆上,移动后 `TensorRef` 仍有效); 3. `Model` 保持纯值对象——推理可直接用 `Model`,不需要 Session; -4. **Loss / 数据集 / epoch / CLI / 日志不归 Session**(防 god object,见 [`../todo/29-session-architecture.md`](../todo/29-session-architecture.md) §4); +4. **Loss / 数据集 / epoch / CLI / 日志不归 Session**(防 god object,见 [`../internal/29-session-architecture.md`](../internal/29-session-architecture.md) §4); 5. `Session` 反查引擎走 `session.engine()`(= `model().engine()`),不持裸引擎引用。 ### 3.3 自由工厂保留 @@ -270,8 +270,8 @@ auto report = NN_UNWRAP(trainer.fit()); // 返回 TextTrainReport - CLI `TrainConfig : nn::TextTrainConfig`,只多入口字段(数据集/保存/恢复/模型结构/GPU/flush/checkpoint/offload); - `lr_scheduler.hpp` 上收库层(`nn::LrScheduleConfig` / `nn::StepLrScheduleConfig` / `nn::compute_epoch_lr` / `nn::compute_step_lr`);`cli/cli_lr_scheduler.hpp` 变转发头(`nn::cli::*` 旧名保留); -- 文档:`docs/development/09-engine-ownership.md` 重写为生命周期 v3 唯一真源、 - `08-object-lifetimes.md` 降为转发;`cpp-api-manual` / `usage/02` / `usage/03` / `AGENTS.md` 训练范式与迁移示例同步。 +- 文档:`docs/development/07-engine-ownership.md` 重写为生命周期 v3 唯一真源、 + `07-engine-ownership.md` 降为转发;`cpp-api-manual` / `usage/02` / `usage/03` / `AGENTS.md` 训练范式与迁移示例同步。 ## 6. 破坏性变更与迁移 @@ -321,7 +321,7 @@ auto report = NN_UNWRAP(trainer.fit()); // 返回 TextTrainReport > 口径:`NN_ENABLE_NATIVE=OFF` 可移植基线;GPU = **NVIDIA CMP 40HX / Vulkan 1.4.351 / 驱动 616.92**; > 最终源码 = `a9c6c6f` + §2.5 的 3 项发布审查修复。构建目录均为全新构建(`build/review/*`)。 -> 逐项命令、日志与报告索引见 [`../todo/25-release-requirements.md`](../todo/25-release-requirements.md) §7。 +> 逐项命令、日志与报告索引见 [`../contributors/release-requirements.md`](../contributors/release-requirements.md) §7。 | # | 验收项 | 结果 | |---|---|---| @@ -367,8 +367,8 @@ auto report = NN_UNWRAP(trainer.fit()); // 返回 TextTrainReport 1. **P2-4 流式 DataLoader 仍未做**:`TextSampleSet` 仍把子集整段物化到 `TextCorpus` (`token_flow / doc_ids / loss_mask`),超大语料的内存曲线问题与 rc0/rc0.1 相同; - 流式分块迭代(`for_each_chunk`)留后续([`../todo/18-roadmap.md`](../todo/18-roadmap.md) P2-4 / [`../todo/19-unified-dataset.md`](../todo/19-unified-dataset.md))。 -2. **`InferenceSession` / `RLTrainingSession` 仍为占位**([`../todo/29-session-architecture.md`](../todo/29-session-architecture.md) §6/§7), + 流式分块迭代(`for_each_chunk`)留后续([`../internal/18-roadmap.md`](../internal/18-roadmap.md) P2-4 / [`../internal/19-unified-dataset.md`](../internal/19-unified-dataset.md))。 +2. **`InferenceSession` / `RLTrainingSession` 仍为占位**([`../internal/29-session-architecture.md`](../internal/29-session-architecture.md) §6/§7), 未实现;触发条件 = 真实调用方出现(推理服务化 / RL 训练入口)。 3. **`create_optimizer` 自由工厂签名未收口**(D7):仍返回 `unique_ptr` / `nullptr`, 失败不是 `Result`;改名/改返回类型属破坏性变更,留待下一个破坏性窗口。 @@ -385,7 +385,7 @@ auto report = NN_UNWRAP(trainer.fit()); // 返回 TextTrainReport 7. **矩阵口径(2026-10-21 正式版实跑)**:Release+GPU / Debug+GPU(Windows clang 23.1 + MSVC STL)、 MSVC cl 19.51 Debug CPU-only、WSL clang 24 + libc++、WSL g++ 15.2 + libstdc++ 均**全新构建 + 完整 ctest**; GPU = **NVIDIA CMP 40HX / Vulkan 1.4.351 / 驱动 616.92**。真实数据集端到端训练与断点续训 - 使用最终源码二进制实跑。详见 §7 与 [`../todo/25-release-requirements.md`](../todo/25-release-requirements.md) §7。 + 使用最终源码二进制实跑。详见 §7 与 [`../contributors/release-requirements.md`](../contributors/release-requirements.md) §7。 `layer_bench` 配对 A/B **未做系统性回归对比**(本版无 kernel 数值路径改动);最终源码上做了单次 功能冒烟:GPU `matmul` 4.365 ms / 491.9 GFLOPS(hash `cbf7d4478bd536ab`)、`matmul_q` 0.796 ms / 2697.2 GFLOPS(hash `c5860cfcfcb371f9`),CPU 512³ 小规模两组哈希齐全(计时受并发负载影响,仅作参考)。 @@ -409,4 +409,4 @@ auto report = NN_UNWRAP(trainer.fit()); // 返回 TextTrainReport 只有间接覆盖(`cli_precision_warning_test` 在 MSVC Debug 下 skip,本机 CPU-only 无 offload 场景)。 后续可把 `precision_offload_combo_error()`(纯函数、不依赖 GPU)单测加进 `text_train_modules_test`。 -完整台账见 [`../todo/18-roadmap.md`](../todo/18-roadmap.md) 与 [`../todo/00-code-review-remediation.md`](../todo/00-code-review-remediation.md)。 +完整台账见 [`../internal/18-roadmap.md`](../internal/18-roadmap.md) 与 [`../internal/00-code-review-remediation.md`](../internal/00-code-review-remediation.md)。 diff --git a/docs/release-notes/v1.11.0.md b/docs/release-notes/v1.11.0.md index cf944bd..ec1768c 100644 --- a/docs/release-notes/v1.11.0.md +++ b/docs/release-notes/v1.11.0.md @@ -1,7 +1,7 @@ # neuralnet.cpp v1.11.0 Release Notes > **发布范围**:`v1.10.0`(tag `v1.10.0`,2026-10-21)→ `v1.11.0`(tag `v1.11.0`)。 -> **主题**:**TrainingSession 单步协议(`train_step`)与 global/micro batch 语义**(docs/todo/30)—— +> **主题**:**TrainingSession 单步协议(`train_step`)与 global/micro batch 语义**(docs/internal/30)—— > 梯度累积上收 Session、按 global batch 有效单位归一化、运行态 `TrainState` 归 `TextTrainer`。 > **兼容性**:**有破坏性变更**(API 与 CLI 行为)——`TrainingSession::train_state()` / `set_train_state()` > 删除(运行态移至 `TextTrainer`);`--batch-size` / `TextTrainConfig.batch_size` 从 **micro-batch** 改为 @@ -18,7 +18,7 @@ v1.10.0 的 `TrainingSession` 只提供 `zero_grad()` / `clip_grads()` / `step()` 低层原语,同时持有含 epoch、lr 曲线、batch/accum 与数据集身份的完整 `TrainState`;训练管线(zero_grad → forward/loss/ backward → clip → step)由 `TextTrainer` 与 `mnist_train` 各自手写,梯度累积的归一化也在循环侧。 -本版把“**一次参数更新**”收进 Session,形成稳定边界(docs/todo/30): +本版把“**一次参数更新**”收进 Session,形成稳定边界(docs/internal/30): - `TrainingSession` 是模型+优化器的训练生命周期容器,也是**一次 update 的执行器**; - 接收已装配的 **micro-batch**,经任务 Step 回调完成 forward/loss/backward,内部维护梯度累积, @@ -123,7 +123,7 @@ current_lr / optimizer_step / 累积 microsteps / pending loss)。 ## 6. 验收基线 -> 口径见 [`../todo/25-release-requirements.md`](../todo/25-release-requirements.md) §8(v1.11.0 发布实跑记录)。 +> 口径见 [`../contributors/release-requirements.md`](../contributors/release-requirements.md) §8(v1.11.0 发布实跑记录)。 | # | 验收项 | 结果 | |---|---|---| @@ -138,13 +138,13 @@ current_lr / optimizer_step / 累积 microsteps / pending loss)。 > 说明:`scan_bitwise_test` 在 Windows 按既有平台口径 skip(逐位锚以 Linux + 850M 为权威); > WSL 的 18 个 skip 全部是 GPU 依赖用例(CPU-only 树预期)。四组「编译器 × 标准库」矩阵的其余组合 -> (clang+libc++ / MSVC cl)沿用 `docs/todo/25-release-requirements.md` §8 的发布口径执行。 +> (clang+libc++ / MSVC cl)沿用 `docs/contributors/release-requirements.md` §8 的发布口径执行。 ## 7. 提交索引 | 主题 | 提交 | |---|---| -| TrainingSession 单步协议 + global/micro batch 语义 + 状态拆分(docs/todo/30 落地) | `bc37df3` | +| TrainingSession 单步协议 + global/micro batch 语义 + 状态拆分(docs/internal/30 落地) | `bc37df3` | > 正式版另含 1 个发布提交(`release: v1.11.0`,版本对齐 + 发布文档,即 tag `v1.11.0` 所指),不在此表。 diff --git a/docs/release-notes/v1.12.0.md b/docs/release-notes/v1.12.0.md index f59d813..e35f48b 100644 --- a/docs/release-notes/v1.12.0.md +++ b/docs/release-notes/v1.12.0.md @@ -20,7 +20,7 @@ v1.12.0 把此前散落在调用方的 policy-gradient 公共语义收进库层 - 首版分布为 categorical,其他分布经 `PolicyDistribution` 扩展; - 不新增引擎原语或 shader;RL 数值路径全部由现有 Tensor/Engine/DSL 组合。 -设计背景与能力下界见 [`../todo/31-rl-training-primitives.md`](../todo/31-rl-training-primitives.md), +设计背景与能力下界见 [`../internal/31-rl-training-primitives.md`](../internal/31-rl-training-primitives.md), 调用指南见 [`../usage/06-reinforcement-learning.md`](../usage/06-reinforcement-learning.md)。 ## 2. 新增能力 @@ -101,7 +101,7 @@ v1.12.0 把此前散落在调用方的 policy-gradient 公共语义收进库层 > 口径:`NN_ENABLE_NATIVE=OFF` 可移植基线;GPU = **NVIDIA CMP 40HX / Vulkan SDK > 1.4.350 / 驱动 616.92**。全部构建目录均为全新构建。逐项记录见 -> [`../todo/25-release-requirements.md`](../todo/25-release-requirements.md) §9。 +> [`../contributors/release-requirements.md`](../contributors/release-requirements.md) §9。 | # | 配置 | 构建 | 完整测试 | |---|---|---|---| diff --git a/docs/release-notes/v1.5.0.md b/docs/release-notes/v1.5.0.md index 12bf247..ca003ee 100644 --- a/docs/release-notes/v1.5.0.md +++ b/docs/release-notes/v1.5.0.md @@ -27,7 +27,7 @@ ## 1. 底层架构统一:Tensor / ComputeEngine / MemoryPool(M1–M6) -设计总纲见 [`docs/todo/17-unified-tensor-engine.md`](../todo/17-unified-tensor-engine.md), +设计总纲见 [`docs/internal/17-unified-tensor-engine.md`](../internal/17-unified-tensor-engine.md), 前序方案见 [`15-computeengine-refresh.md`](../history/history.md) 与 P0 盘点 [`16-computeengine-p0-inventory.md`](../history/history.md)。 @@ -95,7 +95,7 @@ - `ComputeEngine::pool_stats()` **不再有"CPU 返回空串"的空档**:无池引擎返回 `direct{ blocks=… live_bytes=… peak_bytes=… total_blocks=… total_bytes=… }`;GPU 照旧 `persist{…} transient{…}`。 - `release_idle_pool_blocks()` 对 CPU 是**语义成立的 no-op**(已写入头注释与 - [`04-memory-optimization.md`](../todo/04-memory-optimization.md))。 + [`04-memory-optimization.md`](../internal/04-memory-optimization.md))。 - 训练日志现在**一套代码读两个引擎**。 ### 1.8 M6:段 A / 段 B / 段 C 三段全落地 @@ -329,7 +329,7 @@ auto y = layer.forward_recompute(saved); - **GPU `stable=f16` 训练 loss 打印冻结(未修)**:`text_train --precision-stable f16` 时 step 恒 4.0137、 跨 epoch/跨进程逐位相同;**权重照常更新**(冻结仅在 loss 回读链);CPU 同配置健康; ctest 20/20 全绿但**无 GPU + stable=f16 用例**。 - 触发矩阵与证据见 [`14-f16-stable-gpu-loss-frozen.md`](../todo/14-f16-stable-gpu-loss-frozen.md)。 + 触发矩阵与证据见 [`14-f16-stable-gpu-loss-frozen.md`](../internal/14-f16-stable-gpu-loss-frozen.md)。 **推荐路径 `--f16`(stable/optimizer=f32)实测健康。** - **数值性限制**:四字段全 f16 不可训练——`optimizer=f16` 单独即令 Adam 更新爆炸, `stable=f16` 链约 200 步 NaN(见 [`05-mixed-precision.md`](../development/05-mixed-precision.md) §12.5)。 diff --git a/docs/release-notes/v1.5.1.md b/docs/release-notes/v1.5.1.md index 8c9493e..8bbc905 100644 --- a/docs/release-notes/v1.5.1.md +++ b/docs/release-notes/v1.5.1.md @@ -8,7 +8,7 @@ > 若干 GUI 默认值改为与 CLI 一致。库级 API(Layer / Tensor / ComputeEngine)无变更。 > > ⚠ **本文件为 2026-10-15 补写**(P0-2 的"缺 v1.5.1 release note"项,记于 -> [`../todo/18-roadmap.md`](../todo/18-roadmap.md) §3.2 E3):依据 = `git log/show v1.5.0..v1.5.1` +> [`../internal/18-roadmap.md`](../internal/18-roadmap.md) §3.2 E3):依据 = `git log/show v1.5.0..v1.5.1` > 的提交信息与 [`../history/history.md`](../history/history.md) 的两条归档 > (「ZiPT(AttnZip)移除」「GUI / CLI 参数一致性清理」),未引入任何新测量。 diff --git a/docs/release-notes/v1.6.0.md b/docs/release-notes/v1.6.0.md index 0698821..3e2c5d7 100644 --- a/docs/release-notes/v1.6.0.md +++ b/docs/release-notes/v1.6.0.md @@ -64,7 +64,7 @@ - 逐元素 `exp(|x|·α)/(√|y|+α)`:CPU f32 `0.6712035`(差 0)/ GPU f32(V0)`0.6712036`(差 5.96e-08)/ GPU **f16(V1 运行期分派)** `0.6708984`(差 3.05e-04,f16 舍入内)。 - 归一化形态 `rsqrt(col_reduce_sum(x)·inv + ε)`(`raxis=1`、`viewkinds=[0,8]`,与库内 LayerNorm/RMSNorm 同形):GPU f16 `1.2246094`。 - 含 rparams ⇒ native16 谓词不通过 ⇒ f16 命中必然是 `key#x`;注册表漏条目即硬报错,“跑通”本身即断言。 -- **残余不确定性**:25 条结构只有执行 Layer/模型才拿得到(锚点符号实例 `Expr{}` 与运行期实例折叠结果不同);实测两种形态不在其中但无法先验排除。若下游遇到闭合世界报错,预案是给 `nn_enable_gpu_fusion` 加 `COLLECT ` 钩子(触发条件见 [`18-roadmap.md`](../todo/18-roadmap.md))。 +- **残余不确定性**:25 条结构只有执行 Layer/模型才拿得到(锚点符号实例 `Expr{}` 与运行期实例折叠结果不同);实测两种形态不在其中但无法先验排除。若下游遇到闭合世界报错,预案是给 `nn_enable_gpu_fusion` 加 `COLLECT ` 钩子(触发条件见 [`18-roadmap.md`](../internal/18-roadmap.md))。 --- @@ -123,7 +123,7 @@ ### 7.3 新增(加性) -- CMake `nn_enable_gpu_fusion( MAIN )`(注意:函数在本仓 `CMakeLists.txt` 内、仓库无 `install()`/export,真正树外工程复用需先做 install/export,见 [`18-roadmap.md`](../todo/18-roadmap.md) E2)。样例 `examples/fusion_custom_layer*`。 +- CMake `nn_enable_gpu_fusion( MAIN )`(注意:函数在本仓 `CMakeLists.txt` 内、仓库无 `install()`/export,真正树外工程复用需先做 install/export,见 [`18-roadmap.md`](../internal/18-roadmap.md) E2)。样例 `examples/fusion_custom_layer*`。 - 新契约测试、`fusion_custom_layer_example` ctest、`NN_SCAN_DUMP_SOURCES` 来源诊断、闭合世界报错带 `key=`。 ### 7.4 无破坏 @@ -135,7 +135,7 @@ ## 8. 已知问题(本次未修) -- **GPU `stable=f16` 训练 loss 打印冻结(未修)**:`text_train --precision-stable f16` 时 step 恒 4.0137、跨 epoch/跨进程逐位相同;**权重照常更新**(冻结仅在 loss 回读链);CPU 同配置健康;ctest 21/21 全绿但**无 GPU + stable=f16 用例**。触发矩阵与证据见 [`14-f16-stable-gpu-loss-frozen.md`](../todo/14-f16-stable-gpu-loss-frozen.md)。**推荐路径 `--f16`(stable/optimizer=f32)实测健康。** +- **GPU `stable=f16` 训练 loss 打印冻结(未修)**:`text_train --precision-stable f16` 时 step 恒 4.0137、跨 epoch/跨进程逐位相同;**权重照常更新**(冻结仅在 loss 回读链);CPU 同配置健康;ctest 21/21 全绿但**无 GPU + stable=f16 用例**。触发矩阵与证据见 [`14-f16-stable-gpu-loss-frozen.md`](../internal/14-f16-stable-gpu-loss-frozen.md)。**推荐路径 `--f16`(stable/optimizer=f32)实测健康。** - **数值性限制**:四字段全 f16 不可训练——`optimizer=f16` 单独即令 Adam 更新爆炸,`stable=f16` 链约 200 步 NaN(见 [`05-mixed-precision.md`](../development/05-mixed-precision.md) §12.5)。 - **`text_train` 跨进程不可复现**:数据洗牌 RNG 仍为 `mt19937_64{random_device{}()}`(属运行期随机性,不迁 InitSpec);当前无数据洗牌种子 CLI 参数。 - **库外残余不确定性**(§4):25 条 dry-run-only 结构无法先验覆盖,预案 `COLLECT ` 钩子。 diff --git a/docs/release-notes/v1.7.0.md b/docs/release-notes/v1.7.0.md index e1b5087..9639a10 100644 --- a/docs/release-notes/v1.7.0.md +++ b/docs/release-notes/v1.7.0.md @@ -2,7 +2,7 @@ > **发布范围**:`v1.6.1`(384c58b,2026-10-04)→ `v1.7.0`;内容提交截至 `f7b6bf7`(2026-10-06),其后仅含本发布文档与版本同步提交。 > **提交量**:6 content commits,114 files changed,+6090 / −3150(含测试、文档与 Python 侧同步)。 -> **主题**:**统一数据集**——`.nndataset` / `.nnvocab` / **KVRecord v2** 格式统一 + 只读类 **`nn::Dataset`** + 生成/转换工具 **`dataset_gen` / `dataset_convert`**,`text_train` 只吃数据集、模型格式 **v6** 内嵌词表 kvrec;同批交付**错误处理宏族**(`NN_TRY`/`NN_UNWRAP`/`NN_EXIT`/`NN_FAIL`);ctest **24 → 27**。设计与逐条裁决见 [`19-unified-dataset.md`](../todo/19-unified-dataset.md)。 +> **主题**:**统一数据集**——`.nndataset` / `.nnvocab` / **KVRecord v2** 格式统一 + 只读类 **`nn::Dataset`** + 生成/转换工具 **`dataset_gen` / `dataset_convert`**,`text_train` 只吃数据集、模型格式 **v6** 内嵌词表 kvrec;同批交付**错误处理宏族**(`NN_TRY`/`NN_UNWRAP`/`NN_EXIT`/`NN_FAIL`);ctest **24 → 27**。设计与逐条裁决见 [`19-unified-dataset.md`](../internal/19-unified-dataset.md)。 > **兼容性**:**有破坏性变更**(CLI 参数、词表文件格式、`.tokcache` 移除,见 §6 迁移指南);**模型文件 v1–v5 零破坏**(v5 及以下仍读其内嵌 JSON 词表);引擎 / Layer / Tensor 接口无变更(`ComputeEngine` virtual 仍 49)。另含 `load_tokenizer_from_file` 签名变更(API 级,见 §6.3)。 ## 0. 亮点速览(TL;DR) @@ -132,11 +132,11 @@ ## 8. 已知问题(本次未修) -- **GPU `stable=f16` 训练 loss 打印冻结(未修)**:`text_train --precision-stable f16` 时 step 恒 4.0137、跨 epoch/跨进程逐位相同;**权重照常更新**(冻结仅在 loss 回读链);CPU 同配置健康;ctest 27/27 全绿但**无 GPU + stable=f16 用例**。触发矩阵与证据见 [`14-f16-stable-gpu-loss-frozen.md`](../todo/14-f16-stable-gpu-loss-frozen.md)。**推荐路径 `--f16`(stable/optimizer=f32)实测健康。** +- **GPU `stable=f16` 训练 loss 打印冻结(未修)**:`text_train --precision-stable f16` 时 step 恒 4.0137、跨 epoch/跨进程逐位相同;**权重照常更新**(冻结仅在 loss 回读链);CPU 同配置健康;ctest 27/27 全绿但**无 GPU + stable=f16 用例**。触发矩阵与证据见 [`14-f16-stable-gpu-loss-frozen.md`](../internal/14-f16-stable-gpu-loss-frozen.md)。**推荐路径 `--f16`(stable/optimizer=f32)实测健康。** - **数值性限制**:四字段全 f16 不可训练——`optimizer=f16` 单独即令 Adam 更新爆炸、`stable=f16` 链约 200 步 NaN(见 [`05-mixed-precision.md`](../development/05-mixed-precision.md) §12.5)。 - **`text_train` 跨进程不可复现**(沿袭 v1.6.0;本轮基线取证再次实测确认):同配置连续运行 loss 轨迹与保存模型哈希两两不同,根因未定位(数据洗牌 RNG `mt19937_64{random_device{}()}` 是已知随机源之一)。数据等价判据因此落在 `dataset_test` 的逐位对拍与确定性探针锚上,详见 [`history/history.md`](../history/history.md)「统一数据集」条。 - **`.nndataset`/`.nnvocab` 的 v2 地址为文件绝对偏移**:嵌套 kvrec 字节**不可整体搬迁**到别的文件(换基址复制会被连续性校验抓住并报错);需要搬迁时按字段表重建 addr(留作扩展)。 -- **`dataset_convert csv` / tabular 形态未实现**(阶段四预留,调用即明确报错);DataLoader / 流式加载未做(`load_text` 一次性物化大语料会占内存,见 [`18-roadmap.md`](../todo/18-roadmap.md) P2-4 后半)。 +- **`dataset_convert csv` / tabular 形态未实现**(阶段四预留,调用即明确报错);DataLoader / 流式加载未做(`load_text` 一次性物化大语料会占内存,见 [`18-roadmap.md`](../internal/18-roadmap.md) P2-4 后半)。 - **库外残余不确定性**(v1.6.0 遗留):25 条 dry-run-only 融合结构无法先验覆盖,预案 `COLLECT ` 钩子。 - **Windows 上 LeakSanitizer 不可用**;**GPU dev1(MESA/D3D12 转译)不可用**(设备级问题)。 diff --git a/docs/release-notes/v1.8.0.md b/docs/release-notes/v1.8.0.md index e89da06..681912c 100644 --- a/docs/release-notes/v1.8.0.md +++ b/docs/release-notes/v1.8.0.md @@ -30,7 +30,7 @@ - **打包原语**:布局 = 2 bit/权重 + 4 权重/字节 + 码值 = 三值 + 2(与 microsoft/BitNet 上游权重打包脚本一致);容器是 f32 张量当原始字,编解码唯一来源 `ternary_pack.hpp`。 - **CPU**:`matmul_q_impl` 行块解码(RB=64)+ 稠密微内核;禁止逐元素直算回退。 - **GPU**:`matmul_q.comp` 分块(BM=BN=64,x↔输出列 N / y↔输出行 M);`N ≤ 8 且 transA=0` 走 `matmul_q_gemv.comp`(subgroup=4 行,subgroup 内沿打包字分片)。 -- **实测**:850M / 40HX 的配对 A/B 与端到端口径见 [`../todo/21-quantized-weights.md`](../todo/21-quantized-weights.md) §4.12–§4.14;`layer_bench --op matmul,matmul_q,matmul_q_bw --f16` 可复现。 +- **实测**:850M / 40HX 的配对 A/B 与端到端口径见 [`../internal/21-quantized-weights.md`](../internal/21-quantized-weights.md) §4.12–§4.14;`layer_bench --op matmul,matmul_q,matmul_q_bw --f16` 可复现。 ## 3. 模型文件 v7 与角色语义 diff --git a/docs/release-notes/v1.8.1.md b/docs/release-notes/v1.8.1.md index 3e0973e..1927738 100644 --- a/docs/release-notes/v1.8.1.md +++ b/docs/release-notes/v1.8.1.md @@ -2,7 +2,7 @@ > **发布范围**:`v1.8.0`(`afcb3d0`,2026-10-11)→ `v1.8.1`。 > **主题**:**代码审查整改(RV-06 … RV-13)** + **CI 真跑测试与绑定不变量门禁** + **工程化(预设构建 / 格式与贡献指南 / 文档归档)** + **编译提速(ccache × PCH)**。 -> **兼容性**:**无破坏性 API 变更**——引擎接口与 virtual 计数不变、`get_*_spirv()` 名称与签名不变、`create_tensor` 签名保留(新增 `try_create_tensor`)、Layer/Loss/Optimizer/Model 公共入口无删除。逐条裁决与验收证据见 [`../todo/00-code-review-remediation.md`](../todo/00-code-review-remediation.md)。 +> **兼容性**:**无破坏性 API 变更**——引擎接口与 virtual 计数不变、`get_*_spirv()` 名称与签名不变、`create_tensor` 签名保留(新增 `try_create_tensor`)、Layer/Loss/Optimizer/Model 公共入口无删除。逐条裁决与验收证据见 [`../internal/00-code-review-remediation.md`](../internal/00-code-review-remediation.md)。 ## 0. 亮点速览(TL;DR) @@ -111,4 +111,4 @@ - **RV-12**:Loss 直构 IR 底层 spec 的第二条耦合通道(**先设计后动手**)。 - **RV-14**:VK Descriptor Set 回收专项审计(只审计,需 GPU)。 -完整台账(每条的现象/根因/方案/验收)见 [`../todo/00-code-review-remediation.md`](../todo/00-code-review-remediation.md)。 +完整台账(每条的现象/根因/方案/验收)见 [`../internal/00-code-review-remediation.md`](../internal/00-code-review-remediation.md)。 diff --git a/docs/release-notes/v1.8.2.md b/docs/release-notes/v1.8.2.md index 2cf7b6d..1de6c0d 100644 --- a/docs/release-notes/v1.8.2.md +++ b/docs/release-notes/v1.8.2.md @@ -2,7 +2,7 @@ > **发布范围**:`v1.8.1`(`830091f`,2026-10-12)→ `v1.8.2`。 > **主题**:**f16 训练缺陷修复(F1–F5,含"四字段全 f16 可训练")** + **f16 提速(编译期精度特化 / 批量派发 / 网格粒度变体 / F16C / f16 GEMM)** + **RAPT / CNN 的 f16 接线** + **`Layer::init` 参数精度自检**。 -> **兼容性**:**无破坏性 API 变更**——引擎接口与 virtual 计数(52)不变、`get_*_spirv()` 名称/签名不变、`create_tensor` 签名保留;仅新增可选字段/函数与一处 **init 期 fail-fast 收紧**(见 §4 与 §6)。逐条核验见 [`../todo/24-f16-training-defects.md`](../todo/24-f16-training-defects.md)(缺陷台账)与 [`../todo/26-f16-speedup-plan.md`](../todo/26-f16-speedup-plan.md)(提速方案)。 +> **兼容性**:**无破坏性 API 变更**——引擎接口与 virtual 计数(52)不变、`get_*_spirv()` 名称/签名不变、`create_tensor` 签名保留;仅新增可选字段/函数与一处 **init 期 fail-fast 收紧**(见 §4 与 §6)。逐条核验见 [`../internal/24-f16-training-defects.md`](../internal/24-f16-training-defects.md)(缺陷台账)与 [`../internal/26-f16-speedup-plan.md`](../internal/26-f16-speedup-plan.md)(提速方案)。 ## 0. 亮点速览(TL;DR) @@ -19,14 +19,14 @@ --- -## 1. f16 训练缺陷修复([`24`](../todo/24-f16-training-defects.md) F1–F5) +## 1. f16 训练缺陷修复([`24`](../internal/24-f16-training-defects.md) F1–F5) - **F3 修 GPU `stable=f16` loss 冻结**:真因**不是** loss 回读链,而是 CE 的 `(1,1)` loss 归约**输出按 `p_.stable` 落盘溢出**(`compute_loss.hpp` 的稠密与稀疏 `fused_forward_sparse_` 两条链)。修法 = 该 `(1,1)` 归约输出**恒 `Precision::F32`**。实测(850M):`seq256/b32` 由 `inf` → `9.0056 → 8.6922`;`stable=f16` 120 步无 NaN。回归用例见 `f16_precision_test` / `ce_fusion_test`。 - **F5 全 f16 可训练**:不用训练循环 loss scaling,而是在**优化器状态更新处缩放**(`Adam::optimizer_state_scale_`)——进入 `m/v` 的梯度放大 `S=4096`(2 的幂 → f16 下无损),`(1-β1)·S` / `(1-β2)·S²` / `eps·S` 同步换算。**为什么有效**:Adam 更新是尺度不变的 `lr·(S·m̂)/(√(S²·v̂)+S·eps) = lr·m̂/(√v̂+eps)` ⇒ 更新量数学不变,但 `m~g·S`、`v~g²·S²` 都回到 f16 正常区。边界:`|g| ≳ 0.0625` 时 `v` 会溢出 f16 ⇒ 实践配 `--max-norm` 裁剪。 - **F1 危险精度组合启动期告警**:新增 `include/neuralnet.cpp/cli/cli_precision_warning.hpp`(`nn::cli::dangerous_precision_warning`),`text_train` / `mnist_train` 在解析后、进训练循环前打印一次到 stderr;触发 = `optimizer=f16`(覆盖四字段全 f16)。**仅警告**:不退出、不加确认开关、退出码与训练行为不变。门禁 `src/cli_precision_warning_test.cpp`(单测组合矩阵 + 子进程捕获 stderr)。 -- **F2 覆盖缺口**:profile 组合矩阵补 `{F16,F16,F16,F16}` 行;`stable=f16` / 全 f16 形态进 GPU 分支做数值断言;CE 溢出回归。端到端全 f16 训练仍归**大版本发布清单**([`25`](../todo/25-release-requirements.md) 第 1 项,不进默认 ctest)。 +- **F2 覆盖缺口**:profile 组合矩阵补 `{F16,F16,F16,F16}` 行;`stable=f16` / 全 f16 形态进 GPU 分支做数值断言;CE 溢出回归。端到端全 f16 训练仍归**大版本发布清单**([`25`](../contributors/release-requirements.md) 第 1 项,不进默认 ctest)。 -## 2. f16 提速([`26`](../todo/26-f16-speedup-plan.md);台账 24 · F4) +## 2. f16 提速([`26`](../internal/26-f16-speedup-plan.md);台账 24 · F4) 验收锚 = **任意设备**(含无 `shaderFloat16` 的 850M)`--f16` step ≤ f32 且峰值显存更低。落地四件(另有一件 S3): @@ -35,7 +35,7 @@ - **P2-12 优化器 f16 批量派发**(`#b`):对每个 extras 为空的静态签名变体各发一份批量变体;残差根因 = **scan 与运行期不同源**(已修)。实测(40HX):`[ir-c][degrade]` **70 → 0 / 步**、优化器派发 **138.7 → 8.55 calls/步(−94%)**、host 阶段 **9.94 → 6.51 ms/步**;端到端墙钟在 GPU-bound(忙率 95.5%)下不可测。 - **P2-8 / S4 CPU F16C 转换**:`detail::float_to_half_bits` / `half_bits_to_float` 增 `__F16C__` 快路径(`_cvtss_sh`/`_cvtsh_ss`,imm8 = `_MM_FROUND_TO_NEAREST_INT` → 与 MXCSR 无关、恒 RNE);**常量求值**与 `NN_ENABLE_NATIVE=OFF` 可移植构建仍走软件位操作。`precision_test` 增「软/硬逐位一致」段(23 条 f32→f16 + 15 条 f16→f32)。 - **S3 f16 GEMM**(storage-only、f32 累加):`-DNN_SHADER_F16=1` 编第二份 SPIR-V;小 N(`N ≤ 8` 且 `transA=0`)走 `matmul_q_gemv.comp`。 -- **已评估-不做**(均附实测/上界证据,见 [`26`](../todo/26-f16-speedup-plan.md) §4):**S0**(step 内固定开销——前提被实测推翻)、**S1**(主导张量全 f16——实测净亏)、**S2**(f16x2 打包)、**S5 / P2-10**(native16 资格不再扩大——收益有界)。 +- **已评估-不做**(均附实测/上界证据,见 [`26`](../internal/26-f16-speedup-plan.md) §4):**S0**(step 内固定开销——前提被实测推翻)、**S1**(主导张量全 f16——实测净亏)、**S2**(f16x2 打包)、**S5 / P2-10**(native16 资格不再扩大——收益有界)。 ## 3. RAPT / CNN 的 f16 接线(roadmap P2-3) @@ -50,13 +50,13 @@ 它防的是一类**静默降级**:层把权重/梯度硬编码 F32(或忘用 `p_.param`)→ `--f16` 下该层参数仍是 f32,训练照跑、数值不错,但"f16 省字节"在其上完全落空。**当场抓到 3 处**:Conv2D 的 `w_/b_`、RAPT 的 `token_emb_`、`ReLULinearAttention` **从未把 profile 转发给它自持的 4 个 `Linear`**(RAPT 注意力投影权重在 `--f16` 下一直是 f32)——前两处在 P2-3 修掉,第三处由本自检报错后发现并修复。 -> **迁移提示(写自定义层的人)**:若你的层声明了 `PrecisionProfile.param` 为某种**存储精度**(f16/f32),但把参数张量硬编码成另一种,`init` 现在会**报错**(此前静默通过)。修法 = 参数创建时用 `p_.param`。指南见 [`../development/write-a-custom-layer.md`](../development/write-a-custom-layer.md)。 +> **迁移提示(写自定义层的人)**:若你的层声明了 `PrecisionProfile.param` 为某种**存储精度**(f16/f32),但把参数张量硬编码成另一种,`init` 现在会**报错**(此前静默通过)。修法 = 参数创建时用 `p_.param`。指南见 [`../development/03-write-a-custom-layer.md`](../development/03-write-a-custom-layer.md)。 ## 5. 工程化与文档 - **ctest 47 条**(34 个测试目标 + 13 个变体/附加):新增 `cli_precision_warning_test` 与 §3 的 4 条 f16 变体;`rapt_test` 补 GPU 可用性预检(CPU-only 构建下 f16_gpu 用例按退出码 77 = SKIP,不假红)。 - **文档审计回正**:`bench/doc_align_audit.ps1` 的 `[A][B][C][D][E][F]` **可行动项归零**——修若干处文档↔代码不一致(把 BitNet 的打包脚本改为带路径的外部引用、把文档里被当作 CLI flag 的 f32 档写回"默认、无 flag"、把 GQA 示意图中被误判成 CLI 参数的长箭头改掉),并给审计脚本补两处**合法白名单**(`ternary_deploy.hpp`/`ternary_deploy_test` 等已删文件/测试的历史提及;cmake/ctest 自带选项)。 -- **现状画像刷新**([`18-roadmap.md`](../todo/18-roadmap.md) §2 / §8.1、[`12`](../todo/12-compute-engine-inventory.md)):`include/` 74 hpp / 41247 行、`src/` 75 cpp / 26614 行、`shaders/` 22 comp、`docs/` 43 md;`compute_vk_backend.hpp` 经 v1.8.1 拆分后 **1055 行**;引擎 **52 virtual / Layer 直调 27 / 宿主桥 41**。 +- **现状画像刷新**([`18-roadmap.md`](../internal/18-roadmap.md) §2 / §8.1、[`12`](../internal/12-compute-engine-inventory.md)):`include/` 74 hpp / 41247 行、`src/` 75 cpp / 26614 行、`shaders/` 22 comp、`docs/` 43 md;`compute_vk_backend.hpp` 经 v1.8.1 拆分后 **1055 行**;引擎 **52 virtual / Layer 直调 27 / 宿主桥 41**。 ## 6. 兼容性说明 @@ -73,7 +73,7 @@ | 本机 `ctest`(Release + Vulkan 设备可用) | **47/47 通过**(0 skip) | | `bench/doc_align_audit.ps1` | `[A][B][D][E][F]` **可行动 0** | | `bench/doc_inventory.ps1` | `virtual methods 52/52`、`L2-VIOLATIONS: 0`、宿主桥 41(仅披露)、`HANDWRITTEN-RESIDUE: 0`、exit 0 | -| 跨设备 `--f16` ≤ f32([`26`](../todo/26-f16-speedup-plan.md) §5) | 850M **−1.6%**、40HX **−3.2%**、CPU 不再慢于 f32 | +| 跨设备 `--f16` ≤ f32([`26`](../internal/26-f16-speedup-plan.md) §5) | 850M **−1.6%**、40HX **−3.2%**、CPU 不再慢于 f32 | ## 8. 提交索引 @@ -100,4 +100,4 @@ - **P0-5**:推理 top-k / top-p 采样 + 多轮对话闭环。 - **P1-1 / P1-2 / P1-5**:`text_train` 模块化、checkpoint 优化器状态(Adam m/v 入 `.nnckpt`)、CI 冒烟扩 MSVC Debug + 权重变化断言。 -完整台账见 [`../todo/18-roadmap.md`](../todo/18-roadmap.md)。 +完整台账见 [`../internal/18-roadmap.md`](../internal/18-roadmap.md)。 diff --git a/docs/release-notes/v1.9.0.md b/docs/release-notes/v1.9.0.md index fa9286d..e16d1d1 100644 --- a/docs/release-notes/v1.9.0.md +++ b/docs/release-notes/v1.9.0.md @@ -70,7 +70,7 @@ v1.9.0 可读 **v5 / v6 / v7 / v8**,写出一律为 **v8**。v1.8.x 及更旧 - `GpuBuffer` 不再在析构时回查可能已死亡的全局单例; - `layer_lifetime_test` 覆盖 Tensor 晚于引擎析构、Layer / Model / Optimizer 保活、跨引擎拒绝,以及 `NN_GPU_LIFETIME_FULL=1` 下的完整 GPU 释放路径。 -`GpuBackend::instance()` 保留为兼容入口,但新代码应使用 `shared()`;生命周期契约见 [`../development/08-object-lifetimes.md`](../development/08-object-lifetimes.md) 与 [`../development/09-engine-ownership.md`](../development/09-engine-ownership.md)。 +`GpuBackend::instance()` 保留为兼容入口,但新代码应使用 `shared()`;生命周期契约见 [`../development/07-engine-ownership.md`](../development/07-engine-ownership.md) 与 [`../development/07-engine-ownership.md`](../development/07-engine-ownership.md)。 ## 3. 推理采样与多轮对话 @@ -88,7 +88,7 @@ v1.9.0 可读 **v5 / v6 / v7 / v8**,写出一律为 **v8**。v1.8.x 及更旧 - GPU 存储从代数层下沉到 `backend/compute_gpu_storage.hpp`,切断 L1 对 Vulkan 后端的反向依赖。 - 原语 pipeline 收敛为单一目录与布局表;融合 kernel 的 9 张并行元数据表合并为 `FusedKernel`。 - descriptor set 的错误分支统一经 `release_desc_set_now()`,batch 模式不再双重释放。 -- backend 拆分后的结构、所有权和扩展步骤见 [`../development/07-vulkan-backend-map.md`](../development/07-vulkan-backend-map.md)。 +- backend 拆分后的结构、所有权和扩展步骤见 [`../development/06-vulkan-backend-map.md`](../development/06-vulkan-backend-map.md)。 ### 4.2 RAPT 与扫描原语 @@ -137,7 +137,7 @@ v1.9.0 可读 **v5 / v6 / v7 / v8**,写出一律为 **v8**。v1.8.x 及更旧 | `--f16` | **8.7734 → 7.5770** | 健康下降,无 NaN | | `--t1_58` | **8.8839 → 8.0488** | 健康下降,无 NaN | -复现命令与更多口径见 [`../todo/25-release-requirements.md`](../todo/25-release-requirements.md) §4。 +复现命令与更多口径见 [`../contributors/release-requirements.md`](../contributors/release-requirements.md) §4。 ## 8. 提交索引 @@ -164,4 +164,4 @@ v1.9.0 可读 **v5 / v6 / v7 / v8**,写出一律为 **v8**。v1.8.x 及更旧 - **RV-12**:Loss 直接构造 IR spec 与 `FoldAnchor` 的时间耦合,仍按“先设计、后动手”跟踪。 - **实验 / 后续性能项**:真 f16 长跑矩阵、RAPT GQA in-kernel、FFN `ReLU²` 官方对拍与 HF 权重转换器。 -完整台账见 [`../todo/18-roadmap.md`](../todo/18-roadmap.md) 与 [`../todo/00-code-review-remediation.md`](../todo/00-code-review-remediation.md)。 +完整台账见 [`../internal/18-roadmap.md`](../internal/18-roadmap.md) 与 [`../internal/00-code-review-remediation.md`](../internal/00-code-review-remediation.md)。 diff --git a/docs/usage/01-quickstart-model.md b/docs/usage/01-quickstart-model.md index f62886e..bafa137 100644 --- a/docs/usage/01-quickstart-model.md +++ b/docs/usage/01-quickstart-model.md @@ -1,5 +1,7 @@ # 快速上手:构建自己的模型 +> **读者**:要用本库跑训练/推理的调用者。总索引见 [`../README.md`](../README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 **本教程教你如何使用 `ComputeEngine` + `Layer` + `Model` 三件套从零构建神经网络模型。** --- @@ -42,7 +44,7 @@ auto result = model.forward(input); // engine 在 Model 内部自动传递 > 两者取其一即可(都带 `#pragma once`,混用无副作用)。转发头是**整洁性**入口, > **不省编译时间** —— 各头的依赖闭包本就相互牵连,真正省 parse 是另一个专项 -> (`docs/todo/18-roadmap.md`)。模型工厂(`build_gpt_model` 等)与分词器 +> (`docs/internal/18-roadmap.md`)。模型工厂(`build_gpt_model` 等)与分词器 > 仍在 `domain_*.hpp`,名字已足够清楚,不另起转发头。 --- @@ -130,7 +132,7 @@ NN_UNWRAP(model.add(128, 4, 512, 1024)); // GPT 块 `Tensor` 是所有数据的统一容器: ```cpp -// M1(docs/todo/17 §4.1)起:创建/读写张量一律经 Engine—— +// M1(docs/internal/17 §4.1)起:创建/读写张量一律经 Engine—— // Tensor 的静态工厂与存储访问器已私有化,绕过引擎 = 编译错误。 // 通过 Engine 创建(统一入口:自动分配、出生绑定到引擎) @@ -138,7 +140,7 @@ nn::Tensor t1 = engine.create_tensor(784, 32); // 纯分配 nn::Tensor t3 = engine.create_tensor(784, 32); (void)engine.zero(t3); // 清零(分配后手动) -// M2(docs/todo/17 §4.4):声明式初始化——层算分布参数,引擎填数; +// M2(docs/internal/17 §4.4):声明式初始化——层算分布参数,引擎填数; // 分布类 seed 必填(同 seed 不同张量由引擎混流,不撞流) nn::Tensor t_w = engine.create_tensor(32, 10, nn::Precision::F32, nn::InitSpec::uniform(-0.1f, 0.1f, nn::kInitSeed)); diff --git a/docs/usage/02-quickstart-train-infer.md b/docs/usage/02-quickstart-train-infer.md index 902ef26..6031563 100644 --- a/docs/usage/02-quickstart-train-infer.md +++ b/docs/usage/02-quickstart-train-infer.md @@ -1,5 +1,7 @@ # 快速上手:训练与推理 +> **读者**:要用本库跑训练/推理的调用者。总索引见 [`../README.md`](../README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 **本教程教你如何使用 neuralnet.cpp 训练和推理 MNIST 手写数字识别与 GPT 文本生成模型。** --- @@ -83,7 +85,7 @@ GPT 训练需要一份文本语料(如 `datasets/llm_corpus.txt`,用 `script ### 准备数据集(dataset_gen) 训练数据统一为 `.nndataset` 文件:token 流、词表、loss 掩码、test 子集都在**生成期** -定好并嵌入数据集(设计见 `docs/todo/19-unified-dataset.md`): +定好并嵌入数据集(设计见 `docs/internal/19-unified-dataset.md`): ```bash # 先训词表(tokenizer_train),再打包数据集(dataset_gen) @@ -405,7 +407,7 @@ int main() { > (`TextSampleSet::steps_per_epoch(global_batch_size)`)——`steps_per_epoch` **不是** CLI 旗标, > 也不再由调用方手算。已切好样本集时用高性能入口 > `TextTrainer::create(session, train_set, test_set, recipe)`;样本集 / -> batch 装配接口见 [`../development/cpp-api-manual.md`](../development/cpp-api-manual.md) §13.3。 +> batch 装配接口见 [`../development/02-cpp-api-manual.md`](../development/02-cpp-api-manual.md) §13.3。 ### GPT 推理(自回归生成) diff --git a/docs/usage/03-compute-engine-usage.md b/docs/usage/03-compute-engine-usage.md index 157ea6c..b8e8333 100644 --- a/docs/usage/03-compute-engine-usage.md +++ b/docs/usage/03-compute-engine-usage.md @@ -7,6 +7,8 @@ > **不覆盖**:引擎内部实现(`*_impl`、shader、内存池算法)、Layer/Loss/Optimizer 的算法语义、IR/代码生成管线细节。这些见 §23"相关文档"。 > > **版本锚**:以 `include/neuralnet.cpp/compute_engine.hpp`(2021 行)、`expr_dsl.hpp`(1655 行)、`compute_tensor.hpp`、`precision.hpp`、`core_config.hpp`、`core_errors.hpp` 的当前实现为准。任何与本手册不符的代码行为以源码为准,并请同步修订本手册。 +> **读者**:要用本库跑训练/推理的调用者。总索引见 [`../README.md`](../README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 --- @@ -116,7 +118,7 @@ nn::CpuEngine& engine = *engine_owner; > **但优化器与模型之间仍需顺序**:`Optimizer` 的 `params_/grads_` 是 Model > 内 Tensor 的非拥有引用,**必须早于 Model 销毁**(Model 先析构 → `step()` > UAF)。由 `nn::TrainingSession` 统一拥有两者可结构性避免 -> ([`todo/29`](../todo/29-session-architecture.md))。 +> ([`internal/29`](../internal/29-session-architecture.md))。 **统一工厂**(CLI 入口用的写法,可直接复用): @@ -261,7 +263,7 @@ struct nn::PrecisionProfile { // / profile_master_weights() / profile_all_f16() ``` -> **三值 `T1_58` 与 f16/f32 正交(docs/todo/21-quantized-weights.md)**:f16 是"换更窄的 +> **三值 `T1_58` 与 f16/f32 正交(docs/internal/21-quantized-weights.md)**:f16 是"换更窄的 > 容器"(舍入,全算子统一 P);`T1_58` 是"换一种权重表示"(按逐行 absmean 尺度把权重投影到 > `{-1,0,+1}`,需要额外尺度 γ)。因此它**不进提升序**(`precision_rank()` 对它无定义, > `max_precision` 直接 fail-fast),在 P1 里也只作为 `PrecisionProfile.param` 的一句**声明** @@ -1236,7 +1238,7 @@ auto back = engine.rearrange_3d(*ctx, heads * d_k, batch, seq, true); // inver > **接口约定泄漏提示**:状态块偏移(`0 / BHdk / 2*BHdk / 4*BHdk`)是引擎契约的一部分,Layer 必须按上表手工切块——`compute_layer_rapt.hpp:535-785` 的复杂度很大一部分来自这里。 -算法细节见 `docs/development/06-rapt-algorithm.md`。 +算法细节见 `docs/development/08-rapt-algorithm.md`。 --- @@ -1702,13 +1704,13 @@ if (nn::dsl::env_flag("NN_PREC_TRACE")) | 文档 | 何时读 | |---|---| -| `docs/development/01-compute-engine-development.md` | 想**扩展引擎**(加新原语)而不是使用它 | -| `docs/todo/12-compute-engine-inventory.md` | 引擎 52 个 virtual 方法的盘点与 Layer 直调分类(复现:`bench/doc_inventory.ps1`) | +| `docs/development/04-compute-engine-development.md` | 想**扩展引擎**(加新原语)而不是使用它 | +| `docs/internal/12-compute-engine-inventory.md` | 引擎 52 个 virtual 方法的盘点与 Layer 直调分类(复现:`bench/doc_inventory.ps1`) | | `docs/development/05-mixed-precision.md` | 多精度类型系统、f16 语义锚与实测结论(§12 已知限制) | -| `docs/todo/02-operator-fusion.md` + `03-ir-optimization.md` | 表达式融合与 IR 细节 | -| `docs/todo/17-unified-tensor-engine.md` | 统一张量/引擎总纲:访问不变量(铁律 #11)、Matrix 降级(铁律 #12)、InitSpec、批量读写、内存契约 | -| `docs/development/06-rapt-algorithm.md` | 扫描原语的算法背景 | -| `docs/todo/08-pitfalls-and-lessons.md` | 踩坑警示录(改代码前读) | +| `docs/internal/02-operator-fusion.md` + `03-ir-optimization.md` | 表达式融合与 IR 细节 | +| `docs/internal/17-unified-tensor-engine.md` | 统一张量/引擎总纲:访问不变量(铁律 #11)、Matrix 降级(铁律 #12)、InitSpec、批量读写、内存契约 | +| `docs/development/08-rapt-algorithm.md` | 扫描原语的算法背景 | +| `docs/contributors/pitfalls.md` | 踩坑警示录(改代码前读) | | `docs/introduction/01-architecture.md` | 完整分层架构与数据流 | | `docs/usage/01-quickstart-model.md` | 用现成 Layer 搭模型的教程 | | `docs/usage/02-quickstart-train-infer.md` | 训练/推理 CLI + C++ API + GUI | diff --git a/docs/usage/04-train-package.md b/docs/usage/04-train-package.md index 3e961ec..fa216ee 100644 --- a/docs/usage/04-train-package.md +++ b/docs/usage/04-train-package.md @@ -1,5 +1,7 @@ # 训练包:跨设备复现训练 +> **读者**:要用本库跑训练/推理的调用者。总索引见 [`../README.md`](../README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 **用一个文件记录超参与训练集,用一条命令在任意设备上按超参训练, 方便在多台设备上做训练/测试/对比。** @@ -64,7 +66,7 @@ python train_pkg.py new --task mnist -o runs/mnist.json MNIST 的 `data.train` 是**数据集目录**(如 `datasets/mnist_data`), GPT 的 `data.train` 是**`.nndataset` 数据集文件**(token/词表/loss 掩码/test 子集 -都在生成期定好,见 `docs/todo/19-unified-dataset.md`;`.nnpkg` 只搬这一个文件)。 +都在生成期定好,见 `docs/internal/19-unified-dataset.md`;`.nnpkg` 只搬这一个文件)。 ## 工作流 diff --git a/docs/usage/05-consume-as-library.md b/docs/usage/05-consume-as-library.md index 5403ed1..73f4600 100644 --- a/docs/usage/05-consume-as-library.md +++ b/docs/usage/05-consume-as-library.md @@ -2,6 +2,8 @@ > 面向**把 neuralnet.cpp 放进自己工程**的使用者。目标形态:CMake 两行 + 源码一个 include。 > 本仓自身的构建/测试见 `AGENTS.md` §2;本文只讲消费侧。 +> **读者**:要用本库跑训练/推理的调用者。总索引见 [`../README.md`](../README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 ## 1. 快速开始 @@ -117,7 +119,7 @@ nn_enable_gpu_fusion(my_app MAIN ${CMAKE_CURRENT_SOURCE_DIR}/my_app_main.cpp) `cxx_std_26`;MSVC cl 不识别 `cxx_std_26`,降级传 `cxx_std_23`——其映射即 `/std:c++latest`,C++26 预览全开)。MSVC 下消费方源码也须为 UTF-8(`/utf-8` 已传)。 - **install / `find_package` 尚不支持**:当前只支持源码嵌入(add_subdirectory / - FetchContent)。`install()`/export 见 `docs/todo/18-roadmap.md` P0-4 的剩余部分 + FetchContent)。`install()`/export 见 `docs/internal/18-roadmap.md` P0-4 的剩余部分 (`CMakePresets.json` 已于 2026-10-11 落地,但它是**本仓开发**用的构建口径, 消费方不需要它——你只要 `add_subdirectory` + 链 `neuralnet::nn`)。 - **只支持 CPU / Vulkan 双后端**(无 CUDA)。 diff --git a/docs/usage/06-reinforcement-learning.md b/docs/usage/06-reinforcement-learning.md index 5400948..bd13a89 100644 --- a/docs/usage/06-reinforcement-learning.md +++ b/docs/usage/06-reinforcement-learning.md @@ -2,7 +2,7 @@ > **读者**:需要在 neuralnet.cpp 之上实现 policy gradient、PPO、GRPO, > 或把模型/rollout/buffer 拆成可替换组件的库使用者。 -> **状态**:✅ 已实施(2026-10-23,分支 `dev/rl_training`)。 +> **状态**:现行(已实施,随 `v1.12.0` 发布)。 本库提供的是**RL 基础设施**,不是内置环境或游戏框架。它包含: diff --git a/docs/usage/07-thread-safety.md b/docs/usage/07-thread-safety.md index 19a4f30..e490769 100644 --- a/docs/usage/07-thread-safety.md +++ b/docs/usage/07-thread-safety.md @@ -3,6 +3,8 @@ > **一句话结论**:本库**不提供任何跨线程并发调用保证**——服务化/多线程下游请用 > 「**每 worker 一线程一引擎**」模型,或对共享引擎做**外部串行化**。 > 本文给出每个对象的明确口径与依据,让下游不必靠猜(issue #38)。 +> **读者**:要用本库跑训练/推理的调用者。总索引见 [`../README.md`](../README.md);历史归档在 [`../history/history.md`](../history/history.md)。 +> **状态**:现行。 ## 1. 总契约 diff --git a/gui.py b/gui.py index fee49e9..89c5e0d 100644 --- a/gui.py +++ b/gui.py @@ -108,7 +108,7 @@ def optimizer_options(exe_name: str = "mnist_train") -> List[str]: # 混合精度选项(compute/stable/optimizer 三槽:只接受数值精度) PRECISION_OPTIONS = ["f32", "f16"] # param 槽额外接受三值权重(1.58-bit,BitLinear): -# t1_58 = 权重三值化 + STE(docs/todo/21-quantized-weights.md)。 +# t1_58 = 权重三值化 + STE(docs/internal/21-quantized-weights.md)。 # 已接线:文本侧 GPT(--model gpt:4 投影 + fc1/fc2 + 未 tie 的 LM head)、 # 图像侧 --arch mlp。未接线(选它=明确报错,非静默失效):--model rapt 前置拒绝, # --arch transformer/cnn 在层能力校验处报错。 @@ -300,7 +300,7 @@ def _v(key, note=""): return Field(key, note, "virtual") # ── P1-2:断点续训(`.nnckpt`)的禁列(与 CLI 同一口径)────────────────── # 指向带训练状态段的断点时,形状 / 配方 / 计数器一律由断点决定;显式给出即报错 -# (docs/todo/18 §4.2 P1-2、docs/todo/23 §2.1.1)。**唯一真源** = +# (docs/internal/18 §4.2 P1-2、docs/internal/23 §2.1.1)。**唯一真源** = # `include/neuralnet.cpp/cli/text_train_config.hpp` 的 `kForbiddenResumeFlags` # (本集合存的是 kwargs 键;→ CLI 旗标的映射由各字段的 arg/name 决定, # 门禁 `bench/gui_cli_audit.py` [6] 节按该映射核对两边一致)。 diff --git a/include/neuralnet.cpp/algebra_matrix.hpp b/include/neuralnet.cpp/algebra_matrix.hpp index ab44d96..2594b2b 100644 --- a/include/neuralnet.cpp/algebra_matrix.hpp +++ b/include/neuralnet.cpp/algebra_matrix.hpp @@ -33,7 +33,7 @@ namespace nn { - // ── 宿主直配账本(M5,docs/todo/17 §4.5 D5)────────────────────── + // ── 宿主直配账本(M5,docs/internal/17 §4.5 D5)────────────────────── // CPU 侧没有内存池:`MatrixT` 的存储走 `std::make_unique_for_overwrite` // 直配。为了让 `ComputeEngine::pool_stats()` 在**所有**引擎上语义完整 // (17 §2 目标 4"内存契约统一"),这里把每一次宿主分配/释放记账: @@ -88,7 +88,7 @@ namespace nn // - L2+ 计算层使用 Result 进行运行时错误处理(用户输入校验) // - 原因:Matrix 是底层原语,一次 size_t 比较不影响 Release 性能; // 上层需要向用户报告错误,故使用 Result - // - 参见 docs/todo/10-development-standards.md "分层职责单一" 章节 + // - 参见 docs/contributors/cpp-standards.md "分层职责单一" 章节 // ═══════════════════════════════════════════════════════════════════════ // ── MatrixT

— 类型化矩阵存储(docs/development/05-mixed-precision.md D2:存储精度是 P)── // element = elem

(f16 / f32);F32 实例即按 float 连续存储的普通矩阵。 diff --git a/include/neuralnet.cpp/batch_source.hpp b/include/neuralnet.cpp/batch_source.hpp index 82f0619..a7ec478 100644 --- a/include/neuralnet.cpp/batch_source.hpp +++ b/include/neuralnet.cpp/batch_source.hpp @@ -16,7 +16,7 @@ // 只用**指针形式** `std::any_cast(&payload)` 读取(返回 nullptr,不抛异常; // -fno-exceptions 下安全)。骨架不解释载荷内容,只透传给域自己的 StepFn。 // -// 与 TrainingSession(docs/todo/30)的分工:本头只管"取样顺序 + 装配", +// 与 TrainingSession(docs/internal/30)的分工:本头只管"取样顺序 + 装配", // 不碰梯度 / 归一化 / 裁剪 —— 后者仍是 Session 的职责。 // ───────────────────────────────────────────────────────────────────────── @@ -72,7 +72,7 @@ class BatchSource // ── 预置适配器:样本表 + 每 epoch shuffle + 按下标装配(文本/视觉复用)──── // -// 语义与 TextTrainer::fit 的取样顺序一致(docs/todo/30 可观测行为锚): +// 语义与 TextTrainer::fit 的取样顺序一致(docs/internal/30 可观测行为锚): // · 步网格 = ceil(sample_count / batch_size); // · 每 epoch 重排样本顺序(epoch 作种子 ⇒ 同 seed 跨续训可复现); // · 末批不满(samples < batch_size); diff --git a/include/neuralnet.cpp/cli/cli_precision_warning.hpp b/include/neuralnet.cpp/cli/cli_precision_warning.hpp index 75a043c..679f7e2 100644 --- a/include/neuralnet.cpp/cli/cli_precision_warning.hpp +++ b/include/neuralnet.cpp/cli/cli_precision_warning.hpp @@ -1,6 +1,6 @@ // ── cli_precision_warning.hpp — 危险精度组合启动期告警(仅警告,不拒绝)───── // -// 口径见 docs/todo/24-f16-training-defects.md §2.3 / §5 F1: +// 口径见 docs/internal/24-f16-training-defects.md §2.3 / §5 F1: // · 触发集合 = `optimizer = F16`(四字段全 f16 必含 optimizer=F16,故被覆盖); // · `stable = F16` **单独**出现不触发(小模型健康,大词表才 ~200 步 NaN, // 是否单列见 24 §5 F1 备注)——但若与触发字段同时出现,会在同一条警告里 @@ -38,7 +38,7 @@ namespace nn::cli std::string w; w += "[精度警告] 检测到危险精度组合(仅提醒,不阻断训练,详见 " - "docs/todo/24-f16-training-defects.md §2):\n"; + "docs/internal/24-f16-training-defects.md §2):\n"; w += std::string(" · optimizer=") + nn::precision_name(p.optimizer) + ":Adam 二阶矩 v≈g²~1e-10 在 f16 下溢为 0 → 更新量 -lr·m̂/(√v̂+eps) " "爆炸 → loss 发散/NaN。\n"; diff --git a/include/neuralnet.cpp/cli/text_train_checkpoint.hpp b/include/neuralnet.cpp/cli/text_train_checkpoint.hpp index db5c354..30f8db5 100644 --- a/include/neuralnet.cpp/cli/text_train_checkpoint.hpp +++ b/include/neuralnet.cpp/cli/text_train_checkpoint.hpp @@ -1,6 +1,6 @@ // ── text_train_checkpoint.hpp — text_train 的两类模型产出(.nnckpt / .nnmodel)─ // -// P1-1 拆出的 checkpoint 模块(docs/todo/18-roadmap.md §4.2)。职责: +// P1-1 拆出的 checkpoint 模块(docs/internal/18-roadmap.md §4.2)。职责: // * **断点路径派生**:`--save` 的 .nnmodel 路径 → 同名 .nnckpt; // * **断点保存的记账语义**:一次写失败**不终止训练**(磁盘抖动不该毁掉整轮), // 但收尾必须让进程非零退出——否则"断点没落盘"会被脚本/CI/训练包当成"这轮 @@ -28,7 +28,7 @@ namespace nn::cli { -// ── 训练断点路径派生(docs/todo/23 §2.1 文件角色)──────────────────────── +// ── 训练断点路径派生(docs/internal/23 §2.1 文件角色)──────────────────────── // `--save` 的路径换扩展名为 .nnckpt(`gpt_model.nnmodel` → `gpt_model.nnckpt`); // 非 .nnmodel 路径一律追加 .nnckpt。 [[nodiscard]] inline std::string text_train_ckpt_path(const std::string& save_path) @@ -48,7 +48,7 @@ class TextTrainCheckpointLog public: // 保存一次训练断点(Checkpoint 角色:含训练参数,三值层写 f32 latent)。 // P1-2 起同时写**训练状态段**(`TrainState` + 优化器状态张量):断点是 - // "训练的可续点",续训时以状态段为唯一权威(docs/todo/23 §2.1.1)。 + // "训练的可续点",续训时以状态段为唯一权威(docs/internal/23 §2.1.1)。 // 失败不终止——打印一行(带"第 N 次")并计数;成功静默(与旧行为逐字一致)。 void save(const std::string& path, nn::Model& model, const nn::ModelSpec& spec, const std::string& tokenizer_bytes, const nn::TrainState& state, diff --git a/include/neuralnet.cpp/cli/text_train_config.hpp b/include/neuralnet.cpp/cli/text_train_config.hpp index 8ea113c..7030b45 100644 --- a/include/neuralnet.cpp/cli/text_train_config.hpp +++ b/include/neuralnet.cpp/cli/text_train_config.hpp @@ -3,7 +3,7 @@ // 本头是 text_train 唯一允许**直接终止进程**的地方(`std::exit`):参数错误属于 // 用户输入错误,用退出码表达最直接(与 mnist_train 的 parse_args 同口径)。 // 训练循环 / 恢复 / 断点保存三个模块一律返回 `Result`,不终止进程——见 -// docs/todo/18-roadmap.md §4.2 P1-1 的"std::exit 只在 CLI 参数解析层出现"。 +// docs/internal/18-roadmap.md §4.2 P1-1 的"std::exit 只在 CLI 参数解析层出现"。 // // 内容: // * `TrainConfig`(train_loop / recovery / checkpoint 三模块的输入) @@ -86,7 +86,7 @@ void print_text_train_usage(const char *prog) // RV-04:名单文本由 nn::optimizer_table()(唯一真源)生成,不再手抄 help.opt("--optimizer ", "优化器: " + nn::optimizer_names("/") + - " (默认: adam)\nadamwquant: 量化状态的 AdamW(状态 4 B/权重 vs 8 B;见 docs/todo/21 §4.13)"); + " (默认: adam)\nadamwquant: 量化状态的 AdamW(状态 4 B/权重 vs 8 B;见 docs/internal/21 §4.13)"); help.opt("--weight-decay ", "AdamW 权重衰减系数 (默认: 0.01)"); help.opt("--beta1 ", "Adam/AdamW 一阶动量衰减 β1 (默认: 0.9,sgd/muon 忽略)"); help.opt("--beta2 ", "Adam/AdamW 二阶动量衰减 β2 (默认: 0.999,sgd/muon 忽略)\nLLM 预训练惯例常取 0.95 (GPT-3/LLaMA 配方)"); @@ -126,12 +126,12 @@ void print_text_train_usage(const char *prog) help.section("混合精度 (docs/development/05-mixed-precision.md)"); help.opt("--f16", "快捷方式: f16 存储 (param/compute=F16,stable/optimizer=F32)"); - help.opt("--t1_58", "快捷方式: 精度预设 t1_58 = f16 存储 + 三值权重\n(param=T1_58,compute=F16,stable/optimizer=F32;等价于 --f16 再把 param 换成 t1_58)。\n范围与前置拒绝同 --precision-param t1_58(docs/todo/21-quantized-weights.md §4.10)"); + help.opt("--t1_58", "快捷方式: 精度预设 t1_58 = f16 存储 + 三值权重\n(param=T1_58,compute=F16,stable/optimizer=F32;等价于 --f16 再把 param 换成 t1_58)。\n范围与前置拒绝同 --precision-param t1_58(docs/internal/21-quantized-weights.md §4.10)"); help.opt("--precision-param ", "权重/参数精度 (默认: f32);t1_58 = 三值权重(1.58-bit)——\n" "GPT 已支持(注意力 4 投影 + fc1/fc2 + 未 tie 的 LM head 全部换成\n" "BitLinear;P1.5 落地);--model rapt 选它会被前置拒绝\n" - "(docs/todo/21-quantized-weights.md §4.8.3)"); + "(docs/internal/21-quantized-weights.md §4.8.3)"); help.opt("--precision-compute ", "常规算子计算精度 (matmul/逐元素/gather,默认: f32)"); help.opt("--precision-stable ", "数值敏感算子精度 (softmax/LayerNorm/loss,默认: f32)"); help.opt("--precision-optimizer ", "优化器状态精度 (Adam m/v,默认: f32)"); @@ -170,12 +170,12 @@ struct TrainConfig : nn::TextTrainConfig // ── 本进程**显式给出**的 A/B 类旗标(P1-2;按旗标名登记,不含值)────── // 断点续训(role=Checkpoint 且带训练状态段)时,这些旗标一律禁止输入 - // (docs/todo/23 §2.1.1),续训路径据此报错;`role=Model`(SFT warm start) + // (docs/internal/23 §2.1.1),续训路径据此报错;`role=Model`(SFT warm start) // 时它们才是合法的配方来源。 std::vector explicit_train_flags; }; -// ── 断点续训禁列(P1-2,docs/todo/18 §4.2 / docs/todo/23 §2.1.1)────────── +// ── 断点续训禁列(P1-2,docs/internal/18 §4.2 / docs/internal/23 §2.1.1)────────── // A 类(计数器/状态)+ B 类(形状/配方):断点是**训练的可续点**,这些值由 // 断点自带的状态段提供,续训时再显式给 = 把轨迹掰弯(lr 曲线形状、step 网格、 // 精度路径都会跟着变),故一律报错。 diff --git a/include/neuralnet.cpp/cli/text_train_loop.hpp b/include/neuralnet.cpp/cli/text_train_loop.hpp index da2a73d..62fd5d6 100644 --- a/include/neuralnet.cpp/cli/text_train_loop.hpp +++ b/include/neuralnet.cpp/cli/text_train_loop.hpp @@ -238,7 +238,7 @@ inline void log_text_train_gradient_stats(nn::ComputeEngine& engine, for (auto& grad_ref : grads) { const auto& grad = grad_ref.get(); - // M1(docs/todo/17 §4.1):张量读取一律经引擎下载到宿主 + // M1(docs/internal/17 §4.1):张量读取一律经引擎下载到宿主 // (GPU 直接下载;CPU 同样走 to_matrix,f16 存储也安全) nn::Matrix mat; { diff --git a/include/neuralnet.cpp/cli/text_train_recovery.hpp b/include/neuralnet.cpp/cli/text_train_recovery.hpp index 422d189..13abce1 100644 --- a/include/neuralnet.cpp/cli/text_train_recovery.hpp +++ b/include/neuralnet.cpp/cli/text_train_recovery.hpp @@ -1,10 +1,10 @@ // ── text_train_recovery.hpp — `--resume` 恢复路径(TDR 重启 / 分段续训)─────── // -// P1-1 拆出的 recovery 模块(docs/todo/18-roadmap.md §4.2): +// P1-1 拆出的 recovery 模块(docs/internal/18-roadmap.md §4.2): // ① **断点状态采纳**(P1-2 第三刀 B):`--resume` 指向带训练状态段的断点时, // 形状/配方/起点一律由状态段决定,显式给出 A/B 类旗标即报错;数据集身份 // 不一致硬报错(无逃生阀);优化器状态(含 `t`)随之恢复。 -// 角色语义(v8,docs/todo/23 §2.1.1):`.nnckpt` = 断点续训、 +// 角色语义(v8,docs/internal/23 §2.1.1):`.nnckpt` = 断点续训、 // `.nnmodel` = warm start(SFT,CLI 全权)。**P1-7 起没有需要拒绝的组合**: // 三值 `.nnmodel` 的打包载荷在载入时按文件 τ 反量化成 f32 latent // (`WeightLoadIntent::Trainable`)⇒ 同样可续训。v5/v6/v7 老文件放行(零破坏)。 @@ -42,7 +42,7 @@ namespace nn::cli { -// ── 角色语义(v8;2026-10-16 裁定,docs/todo/23 §2.1.1)────────────────── +// ── 角色语义(v8;2026-10-16 裁定,docs/internal/23 §2.1.1)────────────────── // · Checkpoint(`.nnckpt`)⇒ **断点续训**:状态段是唯一权威(A/B 类参数禁列)。 // · Model(`.nnmodel`)⇒ **warm start**(CLI 全权):SFT / 换数据集续训的入口, // 优化器冷启动、step/lr 从 0 起算。三值模型同样走这里 —— 打包载荷在载入时 @@ -171,7 +171,7 @@ struct ResumeStateAdoption } else { - // docs/todo/30:旧状态的 batch_size 是 micro-batch;还原成等效 global。 + // docs/internal/30:旧状态的 batch_size 是 micro-batch;还原成等效 global。 // 旧断点若落在累积中间,pending gradients 不在文件里,只能从最近的 // 已完成 update 边界继续。 if (s.recipe.accum_steps == 0) @@ -217,7 +217,7 @@ struct ResumeStateAdoption return result; } -// ── 数据集身份门禁(硬错、无逃生阀;docs/todo/23 §2.1.1)──────────────── +// ── 数据集身份门禁(硬错、无逃生阀;docs/internal/23 §2.1.1)──────────────── // 数据集一变 ⇒ 窗口数变 ⇒ steps_per_epoch 变 ⇒ step 级调度的 total_steps、 // `global_step` 的语义、epoch 边界**同时**改变 ⇒ "同一断点 + 不同数据集" // 不存在正确的续训语义。合法出口 = 从 `.nnmodel` 开新一轮。 diff --git a/include/neuralnet.cpp/compute_engine.hpp b/include/neuralnet.cpp/compute_engine.hpp index 45cbf94..a900503 100644 --- a/include/neuralnet.cpp/compute_engine.hpp +++ b/include/neuralnet.cpp/compute_engine.hpp @@ -115,7 +115,7 @@ enum class ReduceOp : uint32_t return expr_prec_sig_make(bits, P == Precision::F16); } -// ── InitSpec — 声明式张量初始化(M2,docs/todo/17 §4.4)────────────── +// ── InitSpec — 声明式张量初始化(M2,docs/internal/17 §4.4)────────────── // 分工(铁律 #3):**层算分布参数**(limit / mean / stddev 这类层语义留在 // Layer),**引擎负责填数**(只管把 shape×precision×分布的数填出来)。 // 初始化策略(host 生成后上传 vs 设备端原生生成)由引擎自选,调用方不可见 @@ -237,7 +237,7 @@ struct EngineInfo class ComputeEngine : public std::enable_shared_from_this { public: - // ── 生命周期与设备域(docs/todo/28-lifecycle-v3.md)────────────────── + // ── 生命周期与设备域(docs/internal/28-lifecycle-v3.md)────────────────── // 引擎必须由 shared_ptr 管理(CpuEngine::create / GpuEngine::create)。 // 会解引用引擎的 Layer / Model / Optimizer / ExprGraph / ExprSegment 保存 // keepalive();Tensor 不保存引擎身份——设备域从**存储**派生。 @@ -397,7 +397,7 @@ class ComputeEngine : public std::enable_shared_from_this // ── 张量工厂(统一接口,§6.4, §6.5)──────────────────────────────── // P 由调用方显式指定(§8.5):无隐式推导,无 Auto - // 公共非虚入口在尾部统一做设备域检查(v3,docs/todo/28 §4.3), + // 公共非虚入口在尾部统一做设备域检查(v3,docs/internal/28 §4.3), // 引擎只实现 create_tensor_impl / from_matrix_impl(protected)——避免 // 每个 override 各自漏 stamp。to_matrix 输出 Matrix(宿主),不参与 stamp。 // RV-02(工厂错误协议收敛):错误**结构化**上抛,不再"空张量 + stderr"。 @@ -507,7 +507,7 @@ class ComputeEngine : public std::enable_shared_from_this } // ══════════════════════════════════════════════════════════════════════ - // I/O 分组(M3,docs/todo/17 §4.3 D3/D9 + §3 D11): + // I/O 分组(M3,docs/internal/17 §4.3 D3/D9 + §3 D11): // from_matrix / to_matrix / import / read / write / get_index / set_index // 宿主数据进出张量只准经本组动词;D9:from_matrix/to_matrix 保留原名 // (Matrix = 宿主 I/O 载体),批量 read/write 为**本体**,索引级 @@ -572,7 +572,7 @@ class ComputeEngine : public std::enable_shared_from_this // // 问题:Layer 的"参数派生物"(BitLinear 的 τ/wq)只在**参数变过**时才需要 // 重算,而 forward 每步都会被调用(梯度累积 N 次、自回归生成每 token 一次 - // ——见 docs/todo/21 §4.11)。判断"变没变"必须有一个便宜且**不漏 + // ——见 docs/internal/21 §4.11)。判断"变没变"必须有一个便宜且**不漏 // 报**的信号。 // // 机制:Tensor 的存储对象(MatrixT / GpuBuffer)持有一个单调计数 @@ -749,7 +749,7 @@ class ComputeEngine : public std::enable_shared_from_this return write(t, std::span(buf)); } - // ── reshape(M1,docs/todo/17 §3 D10:修改类操作一律引擎方法)── + // ── reshape(M1,docs/internal/17 §3 D10:修改类操作一律引擎方法)── // 语义同原 Tensor::reshape:GPU 共享底层 buffer(零拷贝视图)、CPU 按 // precision_ 复制数据到新形状;设备域随存储派生(v3),空槽保持无效 // 的输入形状由引擎校验。元素数不匹配返回错误(原 NN_ASSERT 升级)。 @@ -1180,7 +1180,7 @@ class ComputeEngine : public std::enable_shared_from_this // // BitLinear 的"有效权重"是 τ∘W(W 三值、τ 逐行 absmean)。打包后权重容器 // 只占 **0.25 B/权重**(f16 稠密缓冲 2 B/权重),代价是必须由专用内核解码 - // —— docs/todo/21 §4.6 的"T1_58 张量只进量化 GEMM"在这里落地为 + // —— docs/internal/21 §4.6 的"T1_58 张量只进量化 GEMM"在这里落地为 // "打包容器只进 matmul_q"(布局见 ternary_pack.hpp)。 // // trit_pack(w (R,K) f32, τ (R,1) f32) → 容器 (R, ceil(K/16)) f32 @@ -1817,7 +1817,7 @@ class ComputeEngine : public std::enable_shared_from_this } } - // ── 设备域检查(生命周期 v3,docs/todo/28-lifecycle-v3.md §4.3)────── + // ── 设备域检查(生命周期 v3,docs/internal/28-lifecycle-v3.md §4.3)────── // 每个 public NVI 入口逐个操作数比较 `Tensor::device_domain_()` 与本引擎 // 域:空/无效张量(域 = 0)豁免(交由各入口既有的无效/形状检查拒绝); // 其余必须**等于本引擎域**。跨域入口只有 `import`(CPU→GPU 上载)与 diff --git a/include/neuralnet.cpp/compute_layer_attention.hpp b/include/neuralnet.cpp/compute_layer_attention.hpp index 511b87d..81bb36c 100644 --- a/include/neuralnet.cpp/compute_layer_attention.hpp +++ b/include/neuralnet.cpp/compute_layer_attention.hpp @@ -226,7 +226,7 @@ enum class AttnMaskKind // 掩码(`NN_ATTN_MASK_KIND_LIST`)× {无偏置, 位置偏置} × {MHA, GQA} // 其中"无掩码 + 位置偏置"不是本仓会构造的组合(无层路径),故实际为 5×2 = 10 // 条结构。形状/运行期参数(seq/dk/bh 与 kv_ratio 的具体值)**不进 key** → 一 -// 组代表值即覆盖所有形状(docs/todo/22 §3.2 P2;GQA 的 HeadGroup 视图种类进 +// 组代表值即覆盖所有形状(docs/internal/22 §3.2 P2;GQA 的 HeadGroup 视图种类进 // key,比本身不进 → MHA/GQA 各一条)。 // 可用 `-DNN_SCAN_NO_ANCHOR` 关掉(与 FusedAnchor 同一 A/B 开关:只影响登记 // 集合、不改语义)。 @@ -489,7 +489,7 @@ class AttentionBase : public Layer protected: std::size_t d_model_; std::size_t num_heads_; - // ── GQA(分组查询注意力,docs/todo/22 §3.2)───────────────────── + // ── GQA(分组查询注意力,docs/internal/22 §3.2)───────────────────── // n_head_kv_ == num_heads_ 时退化为 MHA(既有路径逐位不变)。 // 头映射 = 块映射:query head h 用 KV head `h / (num_heads_/n_head_kv_)` //(llama.cpp FA 内核 `ik2 = iq2 / rk2` 与 HF `repeat_kv` 的 reshape 一致)。 @@ -527,7 +527,7 @@ class AttentionBase : public Layer // ── 分数掩码策略(构造期/配置期定型;热路径只调用,不判断变体)── std::unique_ptr mask_; - // ── SubLN(BitNet b1.58 的"子层归一化",docs/todo/22 §3.1)────── + // ── SubLN(BitNet b1.58 的"子层归一化",docs/internal/22 §3.1)────── // **子层内部**的额外归一化:挂在 attention 输出(宽 d_model)与输出投影 // w_o_ 之间。默认 nullptr = 关(既有路径逐位不变)。类型跟随模型的 // norm_type(2B4T = RMSNorm)——与 GPTBlock 的 norm1_/norm2_ 同一工厂。 diff --git a/include/neuralnet.cpp/compute_layer_base.hpp b/include/neuralnet.cpp/compute_layer_base.hpp index 8ab02b1..f28be00 100644 --- a/include/neuralnet.cpp/compute_layer_base.hpp +++ b/include/neuralnet.cpp/compute_layer_base.hpp @@ -163,7 +163,7 @@ struct TernaryProfileSplit std::string("层 ") + layer_name + ":收到 param=t1_58,但该层不是" "三值模式(weight_quant=None)—— 三值权重只对 BitLinear 有意义;" "请以 weight_quant=t1_58 构造该层,或把 param 改回 f16/f32" - "(docs/todo/21-quantized-weights.md §4.8.3)"); + "(docs/internal/21-quantized-weights.md §4.8.3)"); } TernaryProfileSplit out{profile, profile}; if (out.self.param == Precision::T1_58) out.self.param = Precision::F32; @@ -191,7 +191,7 @@ struct TernaryProfileSplit } // ══════════════════════════════════════════════════════════════════════════ -// 参数形态协议(v7 文件角色;docs/todo/23 §2.2) +// 参数形态协议(v7 文件角色;docs/internal/23 §2.2) // // 一句话:**kind 是参数级的**。序列化层按 `Model::parameters()` 的顺序逐条读写 // `[kind][precision][rows][cols][aux][payload]`,由**拥有该参数的那个层** @@ -290,7 +290,7 @@ class Layer // 层在 `init(engine)` 时绑定(公共 init 是 NVI 包装,绑定后转 init_impl), // forward/backward/zero_grad/forward_recompute 不再收 engine 形参。 // - // **生命周期契约(09-engine-ownership.md)**:engine_ 是强引用。层存活 + // **生命周期契约(07-engine-ownership.md)**:engine_ 是强引用。层存活 // 期间引擎不会析构;init 时从 ComputeEngine& 的 weak_from_this() 提升。 std::shared_ptr engine_; BindingState binding_state_ = BindingState::unbound; @@ -349,7 +349,7 @@ class Layer NN_UNWRAP(false, std::string("set_precision_profile: 层已 init,精度 profile 之后不可变(层=") + layer_name() + ")—— 请在 init(engine) 之前注入" - "(docs/todo/21-quantized-weights.md §4.3.2(b))"); + "(docs/internal/21-quantized-weights.md §4.3.2(b))"); } p_ = profile; for (Layer* c : param_children()) @@ -369,7 +369,7 @@ class Layer [[nodiscard]] virtual Result backward(const Tensor& grad_output) = 0; - // ── 具名多输出协议(docs/todo/31 RL-0)───────────────────────────── + // ── 具名多输出协议(docs/internal/31 RL-0)───────────────────────────── // 默认层是单端口 "output";复合层(OutputBundleLayer)覆盖下列入口。 // 不接受 schema 的重载只供单层直接使用;序列中的最后一层由 Model 把 // ModelSpec 中登记的 schema 显式传入。 @@ -731,7 +731,7 @@ class Layer + layer_name() + " 的 " + t.shape_str() + " 实际 " + precision_name(t.precision()) + ",但 param=" + precision_name(p_.param) - + "(硬编码 F32 会让 --f16 在该层静默失效;见 docs/todo/18 P1-6 R2)"); + + "(硬编码 F32 会让 --f16 在该层静默失效;见 docs/internal/18 P1-6 R2)"); } return {}; } @@ -760,7 +760,7 @@ class Layer NN_FAIL(std::string("精度能力校验失败: 层 ") + layer_name() + " 不支持 " + slot + "=" + precision_name(got) + "(该槽允许: " + allowed.to_string() - + ")—— 见 docs/todo/21-quantized-weights.md §4.2"); + + ")—— 见 docs/internal/21-quantized-weights.md §4.2"); } public: diff --git a/include/neuralnet.cpp/compute_layer_bitlinear.hpp b/include/neuralnet.cpp/compute_layer_bitlinear.hpp index 86b469d..78d2c7b 100644 --- a/include/neuralnet.cpp/compute_layer_bitlinear.hpp +++ b/include/neuralnet.cpp/compute_layer_bitlinear.hpp @@ -2,7 +2,7 @@ // ── compute_layer_bitlinear.hpp — 三值(1.58-bit)线性层 BitLinear ────────── // -// 设计:docs/todo/21-quantized-weights.md §4.4(P1 形态)。 +// 设计:docs/internal/21-quantized-weights.md §4.4(P1 形态)。 // 前置证据:research/ternary_ste/REPORT.md(同一套 DSL 组合的 STE 训练 PoC)、 // research/ternary_scale/REPORT.md(尺度 = 逐行 absmean 的实测依据)。 // @@ -550,7 +550,7 @@ class BitLinear final : public Layer // 必须单独出向量(这条限制与 RParam 无关)。 // 2) wq ← select(|W|>0.5τ 的正负两侧) —— compute_into 原地写 f16 缓冲。 // 合计每步每层 2 次 dispatch(原 3 次)、2 趟权重读(4+4 B/元素)+ 1 趟 - // f16 写(2 B/元素);见 docs/todo/21 §4.11 的字节账。 + // f16 写(2 B/元素);见 docs/internal/21 §4.11 的字节账。 [[nodiscard]] Result quantize_weights_() { ComputeEngine& engine = engine_ref(); diff --git a/include/neuralnet.cpp/compute_layer_feedforward.hpp b/include/neuralnet.cpp/compute_layer_feedforward.hpp index f9e35a0..5556614 100644 --- a/include/neuralnet.cpp/compute_layer_feedforward.hpp +++ b/include/neuralnet.cpp/compute_layer_feedforward.hpp @@ -33,7 +33,7 @@ class FeedForward final : public Layer bool use_swiglu_ = false; bool use_relu2_ = false; - // ── SubLN(BitNet b1.58 的"子层归一化",docs/todo/22 §3.1)────── + // ── SubLN(BitNet b1.58 的"子层归一化",docs/internal/22 §3.1)────── // **子层内部**的额外归一化:挂在中间激活(宽 d_ff)与输出投影 fc2 之间。 // 默认 nullptr = 关(既有路径逐位不变)。类型跟随模型的 norm_type // (2B4T = RMSNorm)——经 make_norm_layer 构造,与 GPTBlock 的 norm1_/norm2_ diff --git a/include/neuralnet.cpp/compute_layer_gpt.hpp b/include/neuralnet.cpp/compute_layer_gpt.hpp index baa9a12..6ade6f8 100644 --- a/include/neuralnet.cpp/compute_layer_gpt.hpp +++ b/include/neuralnet.cpp/compute_layer_gpt.hpp @@ -283,7 +283,7 @@ class GPTModel final : public Layer // `effective_weight_quant`) WeightQuant weight_quant_ = WeightQuant::None; - // ── tied embedding(docs/todo/22 §3.3)──────────────────────── + // ── tied embedding(docs/internal/22 §3.3)──────────────────────── // true:head 复用 token_emb_(logits = W_embᵀ·x),lm_head_ 不建参数、 // 不进 parameters();head 侧 dW 累加进 grad_token_emb_(与嵌入侧 // 的 scatter_add_rows 同一张缓冲,优化器每步只清一次)。 diff --git a/include/neuralnet.cpp/compute_layer_rapt.hpp b/include/neuralnet.cpp/compute_layer_rapt.hpp index 336e1d0..67a18fc 100644 --- a/include/neuralnet.cpp/compute_layer_rapt.hpp +++ b/include/neuralnet.cpp/compute_layer_rapt.hpp @@ -23,7 +23,7 @@ namespace nn { // ══════════════════════════════════════════════════════════════════════════ -// ReLULinearAttention — RLA-2:极简硬截断线性注意力(docs/development/06-rapt-algorithm.md) +// ReLULinearAttention — RLA-2:极简硬截断线性注意力(docs/development/08-rapt-algorithm.md) // // 算法(RLA-2,修正版;causal / bidirectional 均支持): // q' = ReLU(RoPE(q)), k' = ReLU(RoPE(k)), v = W_v·x(V 不做 ReLU) @@ -32,7 +32,7 @@ namespace nn // out_t = num_t / den_t // 其中 S_t = { i<=t }(causal)或 { 全部 }(bidirectional)。 // -// 与原版 RLA 的关键差异(06-rapt-algorithm.md §3 家族演进): +// 与原版 RLA 的关键差异(08-rapt-algorithm.md §3 家族演进): // * 分母:Sum 归一化(加权平均)替代 L2 归一化(余弦约束) // → 输出量级恒定(不随 √L 增长),梯度流更平稳。 // * 无 A 状态(Σ k'k'^T):分母仅依赖 z = Σk',无需二次型。 @@ -423,7 +423,7 @@ class ReLULinearAttention final : public Layer } // RLA-2:RMSNorm on Q and K(per-head, dk blocks) - // 稳定数值分布,减少神经元死亡,保持 ReLU 硬截断纯粹性(06-rapt-algorithm.md §3)。 + // 稳定数值分布,减少神经元死亡,保持 ReLU 硬截断纯粹性(08-rapt-algorithm.md §3)。 // checkpoint 模式:不驻留任何 backward 缓存,交由 forward_recompute 重建。 { const std::size_t BHrms = batch * num_heads_; diff --git a/include/neuralnet.cpp/compute_loss.hpp b/include/neuralnet.cpp/compute_loss.hpp index 8f32438..d686cb4 100644 --- a/include/neuralnet.cpp/compute_loss.hpp +++ b/include/neuralnet.cpp/compute_loss.hpp @@ -247,7 +247,7 @@ class CrossEntropyLoss final : public Loss // 列归约融合为单次 dispatch(GPU 上 1 个融合 kernel) // 末步 (1,B)→(1,1) 的**输出恒 F32**(不用 p_.stable):该标量是 // 跨 batch×seq 的求和(≈ -log(vocab)·batch),大 batch 下可超 f16 - // 上限 65504 → 按 stable=f16 落盘会溢出为 ±inf(docs/todo/24 §2.1 + // 上限 65504 → 按 stable=f16 落盘会溢出为 ±inf(docs/internal/24 §2.1 // 「loss 归约输出按 P 落盘」的真实后果;14 号台账的「4.0137 冻结」 // 即该溢出的另一种硬件表现)。归约内部本就恒 f32 累加,输出改 F32 // 即得正确值,且调用方随后本就 cast 到 F32 回读。 @@ -412,7 +412,7 @@ class CrossEntropyLoss final : public Loss // 输出精度**恒 F32**(不用 p_.stable):该 (1,1) 标量是跨 // batch×seq 的 log_prob 求和(≈ -log(vocab)·token 数),大 batch·seq // (如 16384 token)下远超 f16 上限 65504 → 按 stable=f16 落盘会 - // 溢出为 ±inf(docs/todo/24 §2.1;14 号台账的「4.0137 冻结」= 该 + // 溢出为 ±inf(docs/internal/24 §2.1;14 号台账的「4.0137 冻结」= 该 // 溢出在部分硬件上饱和为 f16 max 的表现)。归约内部恒 f32 累加, // 输出改 F32 即得正确值;调用方本就 cast 到 F32 回读。 Tensor total_t; diff --git a/include/neuralnet.cpp/compute_optimizer.hpp b/include/neuralnet.cpp/compute_optimizer.hpp index 3647754..dba1289 100644 --- a/include/neuralnet.cpp/compute_optimizer.hpp +++ b/include/neuralnet.cpp/compute_optimizer.hpp @@ -205,7 +205,7 @@ class Optimizer return {}; } - // ══ 断点状态导出/载入(P1-2,docs/todo/18 §4.2 / docs/todo/23 §2.1.1)══ + // ══ 断点状态导出/载入(P1-2,docs/internal/18 §4.2 / docs/internal/23 §2.1.1)══ // 契约(改这四个函数前先读): // · 张量**顺序**是格式契约:一旦随版本发布就不得改变(要改 = 升 // `TRAIN_STATE_VERSION` 并在载入侧分支)。当前顺序: @@ -383,7 +383,7 @@ class Adam : public Optimizer // 1.7e5] —— m 稳在 f16 正常区,v 的下缘远离次正规区(这正是要修的); // · 上缘 1.7e5 > 65504 ⇒ **|g| ≳ 0.0625 时 v 会溢出**。该边界与 // `--precision-optimizer f16` 的危险性同源,已由启动期精度告警提示 - // (docs/todo/24 §2);实践上配 `--max-norm` 梯度裁剪即可约束 |g|。 + // (docs/internal/24 §2);实践上配 `--max-norm` 梯度裁剪即可约束 |g|。 // · S 取 2 的幂 → 与 g 的相乘在 f16 下**无损**(指数平移),不引入额外舍入。 [[nodiscard]] Scalar optimizer_state_scale_() const noexcept { @@ -447,7 +447,7 @@ class Adam : public Optimizer // 但当 param 槽不是"存储精度"时必须以张量自身为准 —— 例如 BitLinear 的 // T1_58(latent 恒 f32):照搬 p_.param 会拿非存储精度去建张量 // (CPU 走 f32 兜底、GPU 在 check_precision_supported 处硬报错 = - // 两端行为不一致)。见 docs/todo/21-quantized-weights.md §4.3.2。 + // 两端行为不一致)。见 docs/internal/21-quantized-weights.md §4.3.2。 const Precision upd_prec = (precision_bytes(p_.param) != 0) ? p_.param : params_[i].get().precision(); diff --git a/include/neuralnet.cpp/compute_tensor.hpp b/include/neuralnet.cpp/compute_tensor.hpp index f0f9725..21d4166 100644 --- a/include/neuralnet.cpp/compute_tensor.hpp +++ b/include/neuralnet.cpp/compute_tensor.hpp @@ -12,7 +12,7 @@ // - 使用 shared_ptr 内部持有存储,拷贝廉价(零拷贝传递) // - 设备域(v3):不保存任何身份字段;`device_domain_()` 从**存储**派生 // (CPU → kHostDomain;GPU → GpuBuffer 的 backend 标识;空 → 0)。 -// 详见 docs/todo/28-lifecycle-v3.md +// 详见 docs/internal/28-lifecycle-v3.md // ───────────────────────────────────────────────────────────────────────── #include @@ -34,14 +34,14 @@ namespace nn { // ComputeEngine 前置声明:Tensor 不保存引擎指针/身份,设备域从存储派生 -//(docs/todo/28-lifecycle-v3.md §4)。 +//(docs/internal/28-lifecycle-v3.md §4)。 class ComputeEngine; class CpuEngine; class GpuEngine; namespace detail { -// 引擎域内通道(M1,docs/todo/17 §4.1 豁免之一): +// 引擎域内通道(M1,docs/internal/17 §4.1 豁免之一): // Tensor 存储访问器与静态直构工厂私有化后,DSL 求值器(expr_dsl.hpp 的 // eval_cpu / 扫描占位 / 求值叶子)经此创建与访问 Tensor 存储。 // 库外(测试/tools/CLI)禁止使用——绕过引擎的编译期强制靠下方访问器私有化。 @@ -78,7 +78,7 @@ class Tensor // 纯元数据(不涉及存储访问,铁律 #11 不适用);非录制张量恒为 0。 std::uint64_t virtual_tag_ = 0; - // ── M1 访问收口(docs/todo/17 §4.1):存储与创建只对引擎域内开放 ── + // ── M1 访问收口(docs/internal/17 §4.1):存储与创建只对引擎域内开放 ── // 公共面只剩形状/精度/设备查询、valid()、shape_str()。 // 绕过引擎摸存储 = 编译错误(库内豁免:引擎 friend + detail::TensorAccess)。 friend class ComputeEngine; @@ -292,7 +292,7 @@ class Tensor // 语义:"本张量的存储内容**可能已经变了**"的单调计数(存储对象持有: // MatrixT::write_epoch_ / GpuBuffer::write_epoch_,故 Tensor 拷贝/别名 // 共享同一计数)。用途:派生缓冲(如 BitLinear 的三值权重)判断"输入 - // 是否变过",从而**只在必要时**重算 —— 见 docs/todo/21 §4.11。 + // 是否变过",从而**只在必要时**重算 —— 见 docs/internal/21 §4.11。 // // 契约:只有 **ComputeEngine 的写入口**会推进它(`touch_write_epoch_` // 私有,friend 限定);库外无法直写存储(M1,铁律 #11),因此"版本没变 @@ -416,7 +416,7 @@ class Tensor } // ── reshape(GPU 共享底层 buffer;CPU 复制数据)────────────────────── - // M1(docs/todo/17 §3 D10):移入引擎——公共入口是 + // M1(docs/internal/17 §3 D10):移入引擎——公共入口是 // ComputeEngine::reshape(bind_check 后调用),本实现只对引擎域内可见。 // 后端无关入口:上层无需直接访问 gpu_tensor() / cpu_matrix() 即可调整形状。 // GPU:共享底层 buffer,仅改形状元数据(零拷贝);CPU:Matrix 无"零拷贝 @@ -531,7 +531,7 @@ inline void Tensor::touch_write_epoch_() noexcept #endif } -// ── 引擎域内访问通道(M1,docs/todo/17 §4.1 豁免之一)────────────── +// ── 引擎域内访问通道(M1,docs/internal/17 §4.1 豁免之一)────────────── // Tensor 的存储访问器/静态直构工厂已私有化;DSL 求值器(expr_dsl.hpp)在 // friend 关系下经本结构创建与读写存储。库外(测试/tools/CLI)不得使用—— // 绕过引擎摸张量的正道是 engine.from_matrix / to_matrix / create_tensor。 diff --git a/include/neuralnet.cpp/core_domain.hpp b/include/neuralnet.cpp/core_domain.hpp index deae0be..8e4cd52 100644 --- a/include/neuralnet.cpp/core_domain.hpp +++ b/include/neuralnet.cpp/core_domain.hpp @@ -1,6 +1,6 @@ #pragma once -// ── core_domain.hpp — 设备域(对象生命周期 v3,docs/todo/28-lifecycle-v3.md)── +// ── core_domain.hpp — 设备域(对象生命周期 v3,docs/internal/28-lifecycle-v3.md)── // // 域从**存储**派生,不保存身份: // · CPU 存储 → `kHostDomain`(进程级常量;所有 CPU 引擎共享宿主内存, diff --git a/include/neuralnet.cpp/core_observer_ptr.hpp b/include/neuralnet.cpp/core_observer_ptr.hpp index 7bfbf0c..8cde4d7 100644 --- a/include/neuralnet.cpp/core_observer_ptr.hpp +++ b/include/neuralnet.cpp/core_observer_ptr.hpp @@ -16,7 +16,7 @@ // // ⚠ 引擎生命周期不要用 observer_ptr:Tensor 不保存引擎身份(设备域从存储派生);Layer / Model / // Optimizer / ExprGraph 持有 shared_ptr。详见 -// docs/development/09-engine-ownership.md。 +// docs/development/07-engine-ownership.md。 // ───────────────────────────────────────────────────────────────────────── #pragma once diff --git a/include/neuralnet.cpp/dataset_samples.hpp b/include/neuralnet.cpp/dataset_samples.hpp index 8811bf8..17eb61e 100644 --- a/include/neuralnet.cpp/dataset_samples.hpp +++ b/include/neuralnet.cpp/dataset_samples.hpp @@ -1,6 +1,6 @@ // ── dataset_samples.hpp — 训练样本视图:Dataset → 样本(窗口)→ batch ─────── // -// P2b 的"样本概念"(docs/todo/29 §8、docs/todo/19 §0 裁决 #2/#3): +// P2b 的"样本概念"(docs/internal/29 §8、docs/internal/19 §0 裁决 #2/#3): // · **存储单位 = doc**(`.nndataset` 里的一行文本); // · **训练单位 = sample**(一个 seq_len 的滑动窗口,可能跨 doc 边界); // · **step = ceil(sample_count / batch_size)** —— 派生量,不是数据集概念。 diff --git a/include/neuralnet.cpp/domain_mnist.hpp b/include/neuralnet.cpp/domain_mnist.hpp index a858962..032b253 100644 --- a/include/neuralnet.cpp/domain_mnist.hpp +++ b/include/neuralnet.cpp/domain_mnist.hpp @@ -94,7 +94,7 @@ inline const std::vector MNIST_LAYER_DIMS = { // 结构:Linear → Norm → GeLU × (N-1) + Linear(最后一层) // norm_type 决定归一化层:LayerNorm / RMSNorm / BatchNorm。 // -// **三值(T1_58)路径**(docs/todo/21-quantized-weights.md §4.8): +// **三值(T1_58)路径**(docs/internal/21-quantized-weights.md §4.8): // `precision.param == T1_58` 时线性层换成 `BitLinear`(三值权重 + STE), // 其余层(norm / 激活)行为不变。两种 profile 分工: // · BitLinear —— 拿**完整** precision(它的 param 槽只接受 T1_58); @@ -243,7 +243,7 @@ inline const std::vector MNIST_LAYER_DIMS = { if (!spec.is_mlp()) NN_FAIL("weight_quant=t1_58 该构建入口只支持 MLP 架构:GPT 走 " "build_gpt_model_from_spec,RAPT 与 MNIST Transformer(ViT 风格)" - "的三值接线尚未落地(见 docs/todo/21-quantized-weights.md §4.8.3)"); + "的三值接线尚未落地(见 docs/internal/21-quantized-weights.md §4.8.3)"); precision.param = Precision::T1_58; } diff --git a/include/neuralnet.cpp/engine.hpp b/include/neuralnet.cpp/engine.hpp index a6d940d..24e55c3 100644 --- a/include/neuralnet.cpp/engine.hpp +++ b/include/neuralnet.cpp/engine.hpp @@ -8,7 +8,7 @@ // // ⚠ 这是**整洁性**入口,**不省 parse**:各头的依赖闭包本就相互牵连(如 // `compute_tensor.hpp` 无条件引用 Vulkan 后端头),真正省时间要按依赖 -// 重切(另案,见 docs/todo/18-roadmap.md P0-4 / 编译提速)。 +// 重切(另案,见 docs/internal/18-roadmap.md P0-4 / 编译提速)。 // // 提供:`ComputeEngine`(原语接口)、`CpuEngine`,以及 GPU 构建下的 `GpuEngine`。 // 用法: diff --git a/include/neuralnet.cpp/expr_dsl.hpp b/include/neuralnet.cpp/expr_dsl.hpp index bfb8a9c..6a301b4 100644 --- a/include/neuralnet.cpp/expr_dsl.hpp +++ b/include/neuralnet.cpp/expr_dsl.hpp @@ -67,7 +67,7 @@ inline bool env_flag(const char* name) namespace nn::dsl { -// M1(docs/todo/17 §4.1):Tensor 存储访问已私有化,DSL 求值器经 +// M1(docs/internal/17 §4.1):Tensor 存储访问已私有化,DSL 求值器经 // 引擎域内通道 detail::TensorAccess 创建/读写张量(friend 关系,库外禁用)。 using TensorAccess = ::nn::detail::TensorAccess; @@ -564,7 +564,7 @@ struct MatmulRef bool transA = false; bool transB = false; std::uint32_t batch = 1; // 批量数(形状参数,不进 key) - // GQA 头分组比(docs/todo/22 §3.2 P2):>1 时该操作数只存 + // GQA 头分组比(docs/internal/22 §3.2 P2):>1 时该操作数只存 // batch/ratio 份行块(多个 query 头共享一个 KV 头)。1 = 恒等。 std::uint32_t a_kv_ratio = 1; std::uint32_t b_kv_ratio = 1; @@ -956,7 +956,7 @@ inline constexpr bool has_reduction_v> { return MatmulRef{std::move(a), std::move(b), transA, transB, batch}; } // GQA 变体:a_kv_ratio / b_kv_ratio > 1 时该操作数只存 batch/ratio 份行块 -// (多个连续 query 头共享一个 KV 头;块映射见 docs/todo/22 §3.2)。 +// (多个连续 query 头共享一个 KV 头;块映射见 docs/internal/22 §3.2)。 [[nodiscard]] inline MatmulRef matmul_kv(Tensor a, Tensor b, bool transA, bool transB, std::uint32_t batch, @@ -1100,7 +1100,7 @@ template // 输出网格形状推导(供 dsl::compute / compute_reduce 的**无形状重载**) // // 背景:`dsl::compute(engine, expr, rows, cols[, P])` 必带输出形状——调用方 -// 反复手写 `x.rows(), x.cols()`(docs/todo/18-roadmap.md P4-4 记为 API 摩擦点)。 +// 反复手写 `x.rows(), x.cols()`(docs/internal/18-roadmap.md P4-4 记为 API 摩擦点)。 // `dsl::compute(engine, expr[, P])` 用**唯一口径**从表达式推导该形状: // // 输出网格 = 各"网格贡献者"的**广播合并**(逐维:相等,或其一为 1)。 diff --git a/include/neuralnet.cpp/expr_emitter.hpp b/include/neuralnet.cpp/expr_emitter.hpp index 1e60964..e2f1c2d 100644 --- a/include/neuralnet.cpp/expr_emitter.hpp +++ b/include/neuralnet.cpp/expr_emitter.hpp @@ -3,7 +3,7 @@ // ═══════════════════════════════════════════════════════════════════════════ // expr_emitter.hpp — 后端 emitter 抽象(IR-D) // -// 对应文档 `docs/todo/03-ir-optimization.md` IR-D:把后端代码生成从 GLSL 专用 +// 对应文档 `docs/internal/03-ir-optimization.md` IR-D:把后端代码生成从 GLSL 专用 // 抽象为 emitter 接口,实现"一份 canonical IR → 多后端代码": // // IR (canonical ExprSpec) → GlslEmitter(当前唯一注册后端) diff --git a/include/neuralnet.cpp/expr_glsl_gen.hpp b/include/neuralnet.cpp/expr_glsl_gen.hpp index 25415dc..e095f98 100644 --- a/include/neuralnet.cpp/expr_glsl_gen.hpp +++ b/include/neuralnet.cpp/expr_glsl_gen.hpp @@ -277,7 +277,7 @@ inline void glsl_view_read(std::ostringstream& os, return vp; } -// ── GQA:操作数"行块号"表达式(docs/todo/22 §3.2 P2)────────────── +// ── GQA:操作数"行块号"表达式(docs/internal/22 §3.2 P2)────────────── // 该操作数的视图是 HeadGroup 时,行块号 = base / 头分组比(比走运行期 vp 槽, // param 不进 key → 任意 n_rep 共用一份 shader); // 其余视图原样返回 base → 生成代码与既有逐字节相同(MHA 路径零变化)。 @@ -1186,7 +1186,7 @@ inline void glsl_emit_matmul_tail_fn(std::ostringstream& L, const ExprSpec& spec // PC 形态:{count, cols, rows, vector_out, fold_k} + vp… + consts… + rparams… // cols = 输入列数 K(glsl_view_read 索引用);fold_k = K(块循环上界)。 // 与后端 run_fused_gpu 的 fold 形态组包必须逐字段一致(PC 固定头坑, -// 见 docs/todo/08-pitfalls-and-lessons.md §4.10)。 +// 见 docs/contributors/pitfalls.md §4.10)。 // 寄存器物化:状态/标量类 = float r{n};元素类 = float e{n}[BLOCK](块内每 // kb 一值);块归约 dst = float red{n}(行标量,经 Reduce 操作数广播)。 // 状态初值一律 bit_cast → uintBitsToFloat 字面量(±inf/任意 float 零精度损失, @@ -1544,7 +1544,7 @@ inline std::string generate_glsl_fold(const std::string& name, const ExprSpec& s // count, cols(=键长), rows, vector_out(=输出列数,运行时), fold_k, // [mm_k, mm_batch], vp.., c.., rp.. // ——创建侧 push range / 写入侧 pc_base / 本声明必须三处同改(不同步 = -// PC 错位静默错值;坑记录见 docs/todo/08-pitfalls-and-lessons.md §4.10)。 +// PC 错位静默错值;坑记录见 docs/contributors/pitfalls.md §4.10)。 inline std::string generate_glsl_fold_v2(const std::string& name, const ExprSpec& spec, ExprPrecSig sig = 0) { diff --git a/include/neuralnet.cpp/expr_graph.hpp b/include/neuralnet.cpp/expr_graph.hpp index 515d08f..61e1087 100644 --- a/include/neuralnet.cpp/expr_graph.hpp +++ b/include/neuralnet.cpp/expr_graph.hpp @@ -10,7 +10,7 @@ // 2. Tensor 占位标记经公共元数据访问器(virtual_tag/ // set_virtual_tag),存储访问收口在引擎域内。 // -// 对应文档 `docs/todo/03-ir-optimization.md` IR-C:把扁平 ExprSpec 演进为图 IR +// 对应文档 `docs/internal/03-ir-optimization.md` IR-C:把扁平 ExprSpec 演进为图 IR // (DAG),为 begin_expr/end_expr 提供多表达式融合分析。 // // 图结构: diff --git a/include/neuralnet.cpp/expr_opt.hpp b/include/neuralnet.cpp/expr_opt.hpp index c2d9577..1888ac4 100644 --- a/include/neuralnet.cpp/expr_opt.hpp +++ b/include/neuralnet.cpp/expr_opt.hpp @@ -3,7 +3,7 @@ // ═══════════════════════════════════════════════════════════════════════════ // expr_opt.hpp — ExprSpec 规范化与优化 pass(IR-A + IR-B) // -// 对应文档 `docs/todo/03-ir-optimization.md`: +// 对应文档 `docs/internal/03-ir-optimization.md`: // - IR-A:canonicalize_expr_spec(DCE / 常量折叠 / 代数化简 / 稳定重编号) // - IR-B:CSE(公共子表达式消除)+ 寄存器分配(liveness 线性扫描) // @@ -12,7 +12,7 @@ // expr_spec_key(spec) ≡ expr_spec_key(canonicalize_expr_spec(spec)) // (scan 构建期与 runtime 运行期都必须先 canonicalize 再算 key,两端一致。) // -// 关键不变量(架构红线,详见 `docs/todo/03-ir-optimization.md`): +// 关键不变量(架构红线,详见 `docs/internal/03-ir-optimization.md`): // 1. **不改变 views/inputs**(顺序、内容)——只优化 instrs/consts/num_regs。 // 运行时 dispatch 的输入绑定顺序不变(融合 shader binding 布局不变), // gpu_inputs 按原 inputs 传递即可。 @@ -213,7 +213,7 @@ namespace nn if (e == ins.dst) { is_output = true; break; } // 只重映射实际使用的操作数(未使用的 b/c 是默认哨兵 {0,0}, - // 不得当 Reg(0) 重编号——见 docs/todo/03-ir-optimization.md 关键坑 ②) + // 不得当 Reg(0) 重编号——见 docs/internal/03-ir-optimization.md 关键坑 ②) const std::size_t nops = expr_instr_num_operands(op); const ExprOperand a = remap_op(ins.a); const ExprOperand b = (nops >= 2) ? remap_op(ins.b) : ins.b; diff --git a/include/neuralnet.cpp/expr_spec.hpp b/include/neuralnet.cpp/expr_spec.hpp index 77c51d3..33dc242 100644 --- a/include/neuralnet.cpp/expr_spec.hpp +++ b/include/neuralnet.cpp/expr_spec.hpp @@ -194,7 +194,7 @@ enum class ExprViewKind : uint8_t // RowAccess 同属"逐元素索引/局部读取"类,走 elementwise 生成路径。 GroupedReduceSum = 13, GroupedReduceMax = 14, - // ── GQA 头分组(docs/todo/22 §3.2 的 P2 in-kernel 版)────────── + // ── GQA 头分组(docs/internal/22 §3.2 的 P2 in-kernel 版)────────── // 读取语义**同 Linear**(恒等索引);区别只在 `param`:它是该操作数的 // **头分组比**(n_rep > 1 时表示"只存 1/n_rep 份行块、多个连续 query 头 // 共享一个 KV 头",块映射同 llama.cpp FA 的 ik2=iq2/rk2 与 HF repeat_kv)。 @@ -541,7 +541,7 @@ inline constexpr std::size_t EXPR_MAX_EXTRA_OUT = 4; n += expr_view_runtime_param_slots(static_cast(v.kind)); return n; } -// ── GQA:该输入的"头分组比"(docs/todo/22 §3.2 P2)──────────────── +// ── GQA:该输入的"头分组比"(docs/internal/22 §3.2 P2)──────────────── // HeadGroup 视图的 param 即该操作数的头分组比 n_rep(1 = 恒等/非 GQA)。 // GPU 生成器与 CPU 参考都从这里取——单一真源,避免两侧口径漂移。 [[nodiscard]] inline std::uint32_t gqa_ratio_of(const ExprSpec& s, diff --git a/include/neuralnet.cpp/model_container.hpp b/include/neuralnet.cpp/model_container.hpp index c3f8fed..f3f6cee 100644 --- a/include/neuralnet.cpp/model_container.hpp +++ b/include/neuralnet.cpp/model_container.hpp @@ -118,7 +118,7 @@ class Model // 添加已构造的层并**显式**注入给定 profile(跳过 default_precision_)。 // 用于"同一模型内按层类型分派精度"的场景:三值 MLP 里 BitLinear 要 // param=T1_58,而非权重层/归一化层的 param 槽不适用(仍走模型默认)。 - // 见 docs/todo/21-quantized-weights.md §4.8。 + // 见 docs/internal/21-quantized-weights.md §4.8。 Result add_layer(std::unique_ptr layer, const PrecisionProfile& profile) { layer->set_precision_profile(profile); @@ -158,7 +158,7 @@ class Model } [[nodiscard]] const std::optional& spec() const noexcept { return spec_; } - // ── 具名多输出(docs/todo/31 RL-0)──────────────────────────────── + // ── 具名多输出(docs/internal/31 RL-0)──────────────────────────────── void set_output_schema(TensorSchema schema) { output_schema_ = std::move(schema); diff --git a/include/neuralnet.cpp/model_serialization.hpp b/include/neuralnet.cpp/model_serialization.hpp index 0fd69a2..160e636 100644 --- a/include/neuralnet.cpp/model_serialization.hpp +++ b/include/neuralnet.cpp/model_serialization.hpp @@ -62,19 +62,19 @@ namespace nn // // precision 字节: 0 = f32, 1 = f64(用于校验保存时与加载时的 Scalar 类型一致) // -// 角色语义(v8 起冻结,docs/todo/23 §2.1.1):checkpoint = model 的**超集** —— +// 角色语义(v8 起冻结,docs/internal/23 §2.1.1):checkpoint = model 的**超集** —— // 同一容器 + role 字节,训练状态段 role-gated(Model 写 0 长度)。`.nnckpt` // 仍需能被推理入口直接读(裁决第 3 条的"测试推理"用途),故不做独立格式。 // ═══════════════════════════════════════════════════════════════════════════ inline constexpr uint32_t MODEL_MAGIC = 0x4E4E4E4E; // "NNNN" -// v7(docs/todo/23):**文件角色**(role 字节:Model=推理 / Checkpoint=训练) +// v7(docs/internal/23):**文件角色**(role 字节:Model=推理 / Checkpoint=训练) // + **参数级 kind**([kind][precision][rows][cols][aux_len][payload_len][aux][payload])。 // · 角色决定"写哪些参数":`.nnmodel` 写推理所需全部参数(三值层写打包形态); // `.nnckpt` 写模型 + 训练参数(三值层写 f32 latent)。 // · v5/v6 的扁平矩阵序列仍**可读**(role 缺失按 Model 处理);**写一律 v7**。 // v6: 内嵌词表改为 .nnvocab kvrec(v5 及以下仍读其内嵌 JSON,见上)。 -// v8(docs/todo/18 §4.2 P1-2 + §4.3 P2-1 合批): +// v8(docs/internal/18 §4.2 P1-2 + §4.3 P2-1 合批): // · **训练状态段**(role 门控;spec 之后):`TrainState` 的 kvrec(计数器 / // 训练配方含精度 profile 与 lr 曲线形状 / 数据集身份)+ 优化器状态张量条目。 // Model 角色写 0 长度;老文件(v7 及以下)缺段 ⇒ 冷启动语义(零破坏)。 @@ -988,7 +988,7 @@ struct ParamBlob // ── 训练状态段(v8;role 门控)────────────────────────────────────────── // 仅 Checkpoint 角色可携带;Model 角色必须为空(推理文件不带训练状态, -// docs/todo/23 §2.1.1)。`optimizer_blobs` 的顺序由优化器定义 +// docs/internal/23 §2.1.1)。`optimizer_blobs` 的顺序由优化器定义 // (`Optimizer::save_state` 的产出顺序即载入时的期望顺序)。 struct CheckpointState { @@ -1005,7 +1005,7 @@ struct CheckpointState { if (ckpt.state != nullptr && role != ModelRole::Checkpoint) NN_FAIL("训练状态段只能写入 Checkpoint 角色(.nnckpt):推理模型(.nnmodel)" - "不得携带训练状态(docs/todo/23 §2.1.1)"); + "不得携带训练状态(docs/internal/23 §2.1.1)"); if (ckpt.state == nullptr && !ckpt.optimizer_blobs.empty()) NN_FAIL("优化器状态张量必须与训练状态一同写入(CheckpointState::state 为空)"); @@ -1130,7 +1130,7 @@ struct CheckpointState // ── 只读训练状态段(v8):计数器 / 训练配方 / 数据集身份(不读权重)────── // 供续训路径在建模型**之前**取精度 profile 与计数器、供 CLI/GUI 显示断点状态。 // 没有该段(role=Model,或 v7 及以下 / 未接线的断点)→ 明确报错,调用方据此 -// 回落"冷启动语义"(docs/todo/18 §4.2 P1-2)。 +// 回落"冷启动语义"(docs/internal/18 §4.2 P1-2)。 [[nodiscard]] inline Result> peek_train_state( const std::string &filename) { diff --git a/include/neuralnet.cpp/model_spec.hpp b/include/neuralnet.cpp/model_spec.hpp index e76bd61..38f3e73 100644 --- a/include/neuralnet.cpp/model_spec.hpp +++ b/include/neuralnet.cpp/model_spec.hpp @@ -97,7 +97,7 @@ enum class NormPlace : uint32_t } } -// ── 权重三值量化(docs/todo/21-quantized-weights.md §4.7)────────── +// ── 权重三值量化(docs/internal/21-quantized-weights.md §4.7)────────── // 描述"这个模型的线性层是不是 BitLinear(三值权重 1.58-bit + STE)"。 // None = 普通 Linear(f32/f16 权重) // T1_58 = BitLinear(param=T1_58;latent 仍 f32,量化缓冲是派生物、不落盘) @@ -333,7 +333,7 @@ class RaptSpec : public ModelSpecBase // ═══════════════════════════════════════════════════════════════════════ struct ModelSpec { - // ── 域无关公共字段(通用多输出规范,docs/todo/31 RL-0)────────────── + // ── 域无关公共字段(通用多输出规范,docs/internal/31 RL-0)────────────── std::optional output_schema; // nullopt = 旧单输出模型 std::vector output_packing; // 空 = 不生成兼容打包表示 diff --git a/include/neuralnet.cpp/rl_experience.hpp b/include/neuralnet.cpp/rl_experience.hpp index 77e830a..e8d9e3a 100644 --- a/include/neuralnet.cpp/rl_experience.hpp +++ b/include/neuralnet.cpp/rl_experience.hpp @@ -1,6 +1,6 @@ #pragma once -// ── rl_experience.hpp — 可扩展经验记录与 advantage 变换(docs/todo/31 RL-1a) +// ── rl_experience.hpp — 可扩展经验记录与 advantage 变换(docs/internal/31 RL-1a) // // 形状约定:转移字段使用 `(seq, batch)`,row = 时间、col = 独立轨迹。 // `T = seq * batch` 仍可由调用方按 batch-major 展平;经验 schema 不把数据 diff --git a/include/neuralnet.cpp/rl_pipeline.hpp b/include/neuralnet.cpp/rl_pipeline.hpp index 5050a2d..fa5491e 100644 --- a/include/neuralnet.cpp/rl_pipeline.hpp +++ b/include/neuralnet.cpp/rl_pipeline.hpp @@ -1,6 +1,6 @@ #pragma once -// ── rl_pipeline.hpp — 可替换 RL 编排组件(docs/todo/31 RL-2b)───────────── +// ── rl_pipeline.hpp — 可替换 RL 编排组件(docs/internal/31 RL-2b)───────────── // // 固定顺序:rollout source → experience buffer → batch sampler → task update。 // 环境、自对局、规则、算法细节与 replay policy 均留给消费者。pipeline 只 diff --git a/include/neuralnet.cpp/rl_policy.hpp b/include/neuralnet.cpp/rl_policy.hpp index ca31d23..e1cffbd 100644 --- a/include/neuralnet.cpp/rl_policy.hpp +++ b/include/neuralnet.cpp/rl_policy.hpp @@ -2,7 +2,7 @@ // ── rl_policy.hpp — categorical policy distribution 与 objective 组件 ────── // -// docs/todo/31 RL-1b: +// docs/internal/31 RL-1b: // · logits: (actions, T),action/advantage/log-prob/mask: (1,T) 或同形; // · policy objective 的上下文入口强类型接收 PolicyBatchView; // · 继续适配现有 Loss:forward(pred,target) 在没有 RL 上下文时明确报错; diff --git a/include/neuralnet.cpp/run_driver.hpp b/include/neuralnet.cpp/run_driver.hpp index ebbaf10..60a3736 100644 --- a/include/neuralnet.cpp/run_driver.hpp +++ b/include/neuralnet.cpp/run_driver.hpp @@ -2,7 +2,7 @@ // ── run_driver.hpp — 领域无关训练骨架(RFC 32 §5;issue #39)───────────── // -// 补上 `TrainingSession`(单步,docs/todo/30)与 `TextTrainer`(文本域驱动) +// 补上 `TrainingSession`(单步,docs/internal/30)与 `TextTrainer`(文本域驱动) // 之间的**空洞层**:epoch/step 循环、lr 调度接线、断点节奏、报告聚合。 // // 分层(不变 vs 可变): diff --git a/include/neuralnet.cpp/tensor_schema.hpp b/include/neuralnet.cpp/tensor_schema.hpp index 36fd7e4..ca313c0 100644 --- a/include/neuralnet.cpp/tensor_schema.hpp +++ b/include/neuralnet.cpp/tensor_schema.hpp @@ -1,6 +1,6 @@ #pragma once -// ── tensor_schema.hpp — 有序张量字段 schema(docs/todo/31 §3)────────────── +// ── tensor_schema.hpp — 有序张量字段 schema(docs/internal/31 §3)────────────── // // 公共语义: // · 字段按稳定顺序保存;名称只允许在 setup/deserialize 期解析; diff --git a/include/neuralnet.cpp/ternary_pack.hpp b/include/neuralnet.cpp/ternary_pack.hpp index 517bccb..e6e7ba7 100644 --- a/include/neuralnet.cpp/ternary_pack.hpp +++ b/include/neuralnet.cpp/ternary_pack.hpp @@ -13,10 +13,10 @@ // 与 BitNet 的**唯一差别**:不采用其 CUDA 侧的 32-bit interleave 置换 // (`interleave_weight_int8`,那是为 coalesced 访问做的重排,解码等价), // 本项目按自然顺序存放 —— 位宽、码值映射、每字节权重数一致,故"编解码" -// 可以逐位对拍(docs/todo/21 §5 的 P2 验收第 4 条)。 +// 可以逐位对拍(docs/internal/21 §5 的 P2 验收第 4 条)。 // // 为什么容器是 f32 张量而不是新的存储类型:张量存储多态(M7)是独立立项 -// (docs/todo/17 §5);打包缓冲只在引擎原语内部被当作**原始字**读写 +// (docs/internal/17 §5);打包缓冲只在引擎原语内部被当作**原始字**读写 // (`std::bit_cast`),从不参与浮点运算 —— 契约由本头 + 原语共同保证。 // // 为什么不用 base-3(1.59 bpw,docs 21 §0 的 D2 裁决):本步对齐的是官方 GPU diff --git a/include/neuralnet.cpp/text_train_config.hpp b/include/neuralnet.cpp/text_train_config.hpp index 19b1fb7..1f4f8eb 100644 --- a/include/neuralnet.cpp/text_train_config.hpp +++ b/include/neuralnet.cpp/text_train_config.hpp @@ -27,7 +27,7 @@ namespace nn // 本结构的同名字段只是"喂给循环/断点状态"的副本,必须与 Session 完全一致 // (`TextTrainer::create` 逐项校验并报错)。起步用 `nn::make_text_train_config(session)`。 // -// **Batch 语义(docs/todo/30)**:`batch_size` 是一次 optimizer update 覆盖的 +// **Batch 语义(docs/internal/30)**:`batch_size` 是一次 optimizer update 覆盖的 // 理论 global batch;每次 forward/backward 的 micro batch = // `batch_size / accum_steps`。`steps_per_epoch` 与计数器均以 update step 为单位。 // diff --git a/include/neuralnet.cpp/text_trainer.hpp b/include/neuralnet.cpp/text_trainer.hpp index 18fcacc..b2c7b85 100644 --- a/include/neuralnet.cpp/text_trainer.hpp +++ b/include/neuralnet.cpp/text_trainer.hpp @@ -1,6 +1,6 @@ // ── text_trainer.hpp — 文本训练 Run Driver:数据集 → global batch → Session ─ // -// P2b(docs/todo/29 §8)的"训练工厂":把原先散在 `text_train.cpp` / `cli/ +// P2b(docs/internal/29 §8)的"训练工厂":把原先散在 `text_train.cpp` / `cli/ // text_train_loop.hpp` 里的**数据装配 + epoch×step 循环 + 断点状态**收进库层, // 调用方只需要: // @@ -10,7 +10,7 @@ // nn::TextTrainConfig{})); // auto report = NN_UNWRAP(trainer.fit()); // -// 分工(docs/todo/30): +// 分工(docs/internal/30): // · `TrainingSession` 拥有 Model + Optimizer,执行 micro-step 并内置梯度累积; // · Step 回调承载文本 sparse-CE,Session 不认识 token/loss mask; // · `TextSampleSet` 拥有样本与最终 loss_mask,负责 batch 装配; diff --git a/include/neuralnet.cpp/train_state.hpp b/include/neuralnet.cpp/train_state.hpp index 2fce3d5..aac9152 100644 --- a/include/neuralnet.cpp/train_state.hpp +++ b/include/neuralnet.cpp/train_state.hpp @@ -24,8 +24,8 @@ // 文件 sha256 + tokens/docs/**样本数**;旧 rc0 断点键 `dataset_windows` // 兼容读 / steps_per_epoch / loss_scope)。 // -// 为什么这些必须随断点走(而不是续训时由 CLI 再给一遍):docs/todo/18 §4.2 -// P1-2、docs/todo/23 §2.1.1 —— ①精度 profile 今天完全不进文件,f16 断点忘带 +// 为什么这些必须随断点走(而不是续训时由 CLI 再给一遍):docs/internal/18 §4.2 +// P1-2、docs/internal/23 §2.1.1 —— ①精度 profile 今天完全不进文件,f16 断点忘带 // `--f16` 会被静默重建成 f32;②数据集 / `--epochs` / `--batch-size` 三者都能 // 改变 lr 曲线形状(`total_epochs`、`total_steps`、`global_step` 都从这里派生); // ③只存 m/v 而丢 `t` 会让偏置修正在重启后从 0 重算。 @@ -86,7 +86,7 @@ struct TrainRecipe std::uint64_t total_steps = 0; // **曲线形状**(step 级调度的 total_steps) std::uint64_t warmup_epochs = 0; std::uint64_t warmup_steps = 0; - // docs/todo/30:新状态写 global batch;旧状态缺语义键时 batch 仍按 + // docs/internal/30:新状态写 global batch;旧状态缺语义键时 batch 仍按 // micro-batch 解释。步号在新语义下均指 optimizer update。 std::uint64_t batch_size = 0; std::uint64_t micro_batch_size = 0; @@ -110,7 +110,7 @@ struct DatasetIdentity std::string loss_scope; // all / assistant(生成期定好,随数据集) }; -// ── 数据集身份校验(文本域续训门禁;docs/todo/18 §4.2 P1-2)────────────── +// ── 数据集身份校验(文本域续训门禁;docs/internal/18 §4.2 P1-2)────────────── // 一致判据 = **sha256 相同且网格三元组相同**。数据集一变,样本数/网格变 ⇒ // steps_per_epoch 变 ⇒ step 级调度的 total_steps、global_step 的语义、 // epoch 边界**同时**改变 ⇒ "同一断点 + 不同数据集"不存在正确的续训语义。 diff --git a/include/neuralnet.cpp/training_session.hpp b/include/neuralnet.cpp/training_session.hpp index 9f9771e..dd9f916 100644 --- a/include/neuralnet.cpp/training_session.hpp +++ b/include/neuralnet.cpp/training_session.hpp @@ -1,6 +1,6 @@ #pragma once -// ── training_session.hpp — TrainingSession:单次参数更新会话(docs/todo/30)── +// ── training_session.hpp — TrainingSession:单次参数更新会话(docs/internal/30)── // // 定位: // · 拥有 Model + Optimizer,结构性保证 optimizer 先于参数所有者析构; diff --git a/research/README.md b/research/README.md index a5f70d1..e174372 100644 --- a/research/README.md +++ b/research/README.md @@ -72,7 +72,7 @@ [`poc_binary_ste.cpp`](ternary_ste/poc_binary_ste.cpp)(`dsl::compute` + `select` + `rparam` + `matmul`)。 * **重跑**:报告 §1「复现」(一条 `clang++` 命令;两个程序毫秒级跑完 3000 步)。 * **边界**:**只证明算法路径可行,不证明性能**——全部是 CPU、f32 存储、单层玩具问题。它是 - [`../docs/todo/21-quantized-weights.md`](../docs/todo/21-quantized-weights.md) 的**前置证据**, + [`../docs/internal/21-quantized-weights.md`](../docs/internal/21-quantized-weights.md) 的**前置证据**, 不等于三值整机能力(打包内核 / 精度枚举 / 能力声明是另一条线)。 ### 2.4 [`ternary_scale/`](ternary_scale/REPORT.md) — 三值量化的「尺度规则 × 粒度」(D1 裁定依据) @@ -111,8 +111,8 @@ 结论 + 数字 + 样本量,然后才是过程。 2. 单列一节 **「本实测不能说明什么」**——边界比结论更常被人误用。 3. 给出**从零复现**的入口命令(含构建口径、设备、数据集来源);原始日志与权重不要进仓。 -4. 结论若影响代码/设计决策,在 [`../docs/todo/`](../docs/todo/) 的相应设计稿里引用本报告 - (例:`ternary_scale` → `docs/todo/21-quantized-weights.md` 的 D1 裁定)。 +4. 结论若影响代码/设计决策,在 [`../docs/internal/`](../docs/internal/) 的相应设计稿里引用本报告 + (例:`ternary_scale` → `docs/internal/21-quantized-weights.md` 的 D1 裁定)。 5. 在本文件 §2 加一条索引(结论 / 证据 / 重跑 / 边界 四段式)。 尚未执行的研究可以先用 `TODO` 状态入库,但必须明确:它不提供效果结论,不可被代码/设计稿 diff --git a/research/f16_weight_decay/REPORT.md b/research/f16_weight_decay/REPORT.md index 7b9274a..96ab810 100644 --- a/research/f16_weight_decay/REPORT.md +++ b/research/f16_weight_decay/REPORT.md @@ -115,7 +115,7 @@ SPIR-V/Vulkan 并未把 float→float16 的舍入钉死为 round-to-nearest-even (而不是 N·ULP),或直接与 CPU 结果逐位对拍。 4. **文档勘误**:`docs/development/05-mixed-precision.md` §12.5 “profile_f16 与 f32 轨迹一致” 的结论只在 wd=0/短跑下成立; - AGENTS/已交付能力里的 f16 描述与 `docs/todo/14` 需要补这条已知问题。 + AGENTS/已交付能力里的 f16 描述与 `docs/internal/14` 需要补这条已知问题。 ## 7. 材料与复现 @@ -238,6 +238,6 @@ CPU/GPU 全部通过。 - f16 **次正规/溢出**边界:`nn_f16_rne` 已按 f16 网格处理次正规区;`-0.0` 经 次正规分支可能归一为 `+0.0`(数值等价,不影响训练)。 - 未做:§6 建议 2(对 f16 参数跳过 decoupled decay)与建议 4 之外的**文档勘误** - (`docs/development/05` §12.5、`AGENTS.md` 已知问题、`docs/todo/14`) + (`docs/development/05` §12.5、`AGENTS.md` 已知问题、`docs/internal/14`) 仍待补——根修已使原缺陷消失,但"f16 存储下 `lr·wd < 0.5 ULP` 时 decay 为恒等" 这一语义值得写进精度文档。 diff --git a/research/rla/README.md b/research/rla/README.md index 5e79fd5..09226cb 100644 --- a/research/rla/README.md +++ b/research/rla/README.md @@ -38,7 +38,7 @@ 3. [`compute_engine.hpp`](../../include/neuralnet.cpp/compute_engine.hpp):扫描原语语义。 4. [`src/rapt_gradcheck.cpp`](../../src/rapt_gradcheck.cpp) 与 [`src/rapt_smoke_test.cpp`](../../src/rapt_smoke_test.cpp):正确性和接线证据。 -5. [`docs/development/06-rapt-algorithm.md`](../../docs/development/06-rapt-algorithm.md): +5. [`docs/development/08-rapt-algorithm.md`](../../docs/development/08-rapt-algorithm.md): 面向使用者的概览。历史设计叙述若与源码冲突,以源码和 `01` 为准。 ## 4. 当前不回答的问题 diff --git a/research/ternary_scale/REPORT.md b/research/ternary_scale/REPORT.md index 5190153..510fc41 100644 --- a/research/ternary_scale/REPORT.md +++ b/research/ternary_scale/REPORT.md @@ -153,7 +153,7 @@ absmax 87.97 / 65.60 / 72.95 / 68.57 / 64.05。 4. **llama.cpp 的 `TQ1_0` 选 absmax 有其语境**:它是"事后量化别人训好的 f32 权重", 此时没有任何训练去适应量化误差,逐块 absmax 至少能保证**相对**误差有界;而我们做 QAT / 从头训, 权重会适应量化,此时唯一该关心的是"三值码位的信息容量",absmean 完胜。 -5. **落地含义(对应 `docs/todo/21-quantized-weights.md`)**: +5. **落地含义(对应 `docs/internal/21-quantized-weights.md`)**: `TQ1_0` 的**编码与解码照抄**(base-3 5-per-byte + 定点 `(s·3^n·3)>>8`), 但**块内尺度换成 absmean**;又因为 llama.cpp 的 256 块要求行宽整除 256(我们 d_model=64/128、 MNIST 784/10 都不满足),块粒度取**行**(per-row):既满足 absmean、又没有整除约束、 diff --git a/research/ternary_scale/probe_scale.cpp b/research/ternary_scale/probe_scale.cpp index 981bdb1..278f98b 100644 --- a/research/ternary_scale/probe_scale.cpp +++ b/research/ternary_scale/probe_scale.cpp @@ -1,6 +1,6 @@ // ── probe_scale.cpp — 三值量化「尺度规则 × 粒度」对真实权重的影响 ────────────── // 配套报告:research/ternary_scale/REPORT.md -// 设计文档:docs/todo/21-quantized-weights.md(这条对应待定项 D1) +// 设计文档:docs/internal/21-quantized-weights.md(这条对应待定项 D1) // // 问题:三值化 w -> q*tau(q ∈ {-1,0,+1})里,tau 取 // · 统计量:absmean(BitNet b1.58)还是 absmax(llama.cpp TQ1_0) diff --git a/research/ternary_ste/REPORT.md b/research/ternary_ste/REPORT.md index 51b46f2..8c68675 100644 --- a/research/ternary_ste/REPORT.md +++ b/research/ternary_ste/REPORT.md @@ -9,7 +9,7 @@ > | 三值(含 0) | `select(w>0.5γ, +1, select(w<-0.5γ, -1, 0))` | 14.207462 → **0.000000** | **1370 / 1370 = 100%** | > | 二值 | `select(w>0, +1, -1)` | 20.949087 → **0.000000** | **2048 / 2048 = 100%** | > -> 本文是 `docs/todo/21-quantized-weights.md` 的**前置证据**:它证明 P1 的算法路径 +> 本文是 `docs/internal/21-quantized-weights.md` 的**前置证据**:它证明 P1 的算法路径 > (Layer 级量化 + STE backward)没有障碍,剩下的是架构与工程(精度枚举、能力声明、打包内核)。 > **它不证明性能**——本文全部是 CPU、f32 存储、单层玩具问题。 @@ -84,7 +84,7 @@ STE 用恒等映射 `dWq/dW ≈ 1` 替代,于是 `dW_latent = γ · dY · Xᵀ --- -## 3. 实现要点(与 `docs/todo/21-quantized-weights.md` 的对应) +## 3. 实现要点(与 `docs/internal/21-quantized-weights.md` 的对应) 1. **量化只用现有 DSL**:`ExprOp` 里已有 `Gt` / `Lt` / `Select` / `Abs`,`rparam` 承载"值不进 key"的 运行期标量(γ、阈值、lr)。所以本探针**没有新增引擎原语、没有新增 dtype**。 diff --git a/research/ternary_ste/poc_binary_ste.cpp b/research/ternary_ste/poc_binary_ste.cpp index acd8fcb..7f1e436 100644 --- a/research/ternary_ste/poc_binary_ste.cpp +++ b/research/ternary_ste/poc_binary_ste.cpp @@ -1,5 +1,5 @@ // ── poc_binary_ste.cpp — 纯 1-bit(二值)权重的 STE 训练最小探针 ────────────── -// 配套报告:research/ternary_ste/REPORT.md;设计文档:docs/todo/21-quantized-weights.md +// 配套报告:research/ternary_ste/REPORT.md;设计文档:docs/internal/21-quantized-weights.md // // 与 poc_ternary_ste.cpp 的唯一区别:量化器是 sign(W)(值域 {-1,+1},没有 0), // 教师也是二值 {-0.5,+0.5}。用于回答"纯 1-bit 是否同样可行"。 diff --git a/research/ternary_ste/poc_ternary_ste.cpp b/research/ternary_ste/poc_ternary_ste.cpp index b195990..0ba11e4 100644 --- a/research/ternary_ste/poc_ternary_ste.cpp +++ b/research/ternary_ste/poc_ternary_ste.cpp @@ -1,5 +1,5 @@ // ── poc_ternary_ste.cpp — 三值(1.58-bit)权重的 STE 训练最小探针 ───────────── -// 配套报告:research/ternary_ste/REPORT.md;设计文档:docs/todo/21-quantized-weights.md +// 配套报告:research/ternary_ste/REPORT.md;设计文档:docs/internal/21-quantized-weights.md // // 目的:用**现有公开 API**(无库改动)证明"Layer 级三值量化 + STE backward"在本引擎上可行。 // 任务:学一个教师三元线性映射 y = W_t · x(W_t ∈ {-0.5, 0, +0.5}),训练后逐项比对教师模式。 diff --git a/scripts/doc_audit.py b/scripts/doc_audit.py new file mode 100644 index 0000000..5cbe9c6 --- /dev/null +++ b/scripts/doc_audit.py @@ -0,0 +1,487 @@ +#!/usr/bin/env python3 +"""doc_audit.py — 文档↔代码对齐审计 + 文档规范检查(只读,跨平台) + +规范正文:docs/contributors/documentation-standard.md §5。 +移植并扩展 bench/doc_align_audit.ps1 的 A–D/F 类检查;新增 E 类(头部模板/状态词/ +索引登记)与 G 类(代码示例清单)。ps1 保留至 Windows 侧迁移完成,口径以规范为准。 + +用法: + python scripts/doc_audit.py # 全量检查;有 FAIL 时 exit 1 + python scripts/doc_audit.py --report # 另生成 build/doc_audit/code_examples_report.md +""" +import argparse +import os +import re +import sys + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# ── 白名单(每项带来历注释,新增须说明)────────────────────────────────── + +# [A] 历史文件:已被有意删除,历史文档提及属正常(勿报警) +HISTORICAL_FILES = [ + 'compute_cuda_engine.hpp', 'compute_cuda_backend.hpp', 'cuda_kernels.h', 'cuda_kernels.cu', + 'expr_graph.hpp', 'cpu_emitter.hpp', 'algebra_expr.hpp', 'algebra_compute.hpp', + 'perf_smoke.cpp', 'mnist_common.hpp', 'train_bytebpe.py', + 'expr_fuse_test.cpp', 'expr_spec_test.cpp', 'matmul_fusion_test.cpp', + 'offload_primitive_test.cpp', 'offload_test.cpp', 'broadcast.comp', + 'compute_precision_engine.hpp', # P-1 随 PrecisionEngine 下沉删除 + 'compute_layer_zipt.hpp', 'domain_zipt.hpp', # ZiPT 移除(分支 legacy/zipt) + 'ternary_deploy.hpp', # NNQT 独立部署格式,随库级清理(internal/23)删除 + '08-object-lifetimes.md', # 2026-11 文档重构删除的转发页(真源 = 07-engine-ownership.md) +] + +# [B] 已删除符号(命中行若带"不存在/已删除"等否定语境则跳过) +DEAD_SYMBOLS = [ + 'axpy_inplace', 'broadcast_row_inplace', 'broadcast_col_inplace', 'elementwise_unary', + 'elementwise_binary_scalar', 'elementwise_select_scalar_cond', 'offload_store', 'offload_load', + 'multiply_transposed_add_to', 'compute::apply', 'algebra_expr', 'algebra_compute', + 'set_offload_enabled', 'UnaryOp', 'CompareOp', +] +NEGATION_PAT = re.compile(r'不存在|已删除|已移除|没有|无此|已归档|归档于|历史') + +# [D] 外部工具参数白名单(非本仓 CLI:ctest/cmake/glslc/torch 脚本等) +EXTERNAL_FLAGS = { + '--test-dir', '--parallel', '--target-env', '--dtype', '--adam-eps', '--device', + '--task', '--compress', '--list', '--image', '--list-backends', '--summary', '--include', + '--preset', '--workflow', '--list-presets', '--output-on-failure', + # git 自带选项(文档命令用):git clang-format --diff / clone --recurse-submodules / tag --tags + '--diff', '--recurse-submodules', '--tags', +} +# [D] 已在文档中明确标注"已移除"的历史参数 +REMOVED_FLAGS = { + '--cuda', '--tdr-retry', '--max-tdr-retries', '--memory-tokens', '--window', + '--osc-guard', '--osc-window', '--osc-threshold', + '--no-cache', '--test-file', '--loss-scope', '--export-deploy', +} +# [D] 文档已标注"计划中、尚未实现"的参数(实现后移出本表) +PLANNED_FLAGS = {'--stochastic-rounding', '--unit-scaling'} + +# [F] 历史/已并入测试名(当时目标名,勿再报警) +HISTORICAL_TESTS = { + 'expr_fuse_test', 'expr_graph_test', 'expr_spec_test', 'matmul_fusion_test', + 'offload_primitive_test', 'zipt_test', 'zipt_gradcheck', 'zipt_smoke_test', + 'zipt_consistency_test', 'zipt_doc_test', 'ternary_deploy_test', +} + +# [E] 头部模板豁免(文档规范 §2.2):历史归档 / 随 tag 冻结 / 采集时快照 +HEADER_EXEMPT = [ + re.compile(r'^research/'), # research/ 有自己的四段式口径(research/README.md) + re.compile(r'^docs/history/history\.md$'), + re.compile(r'^docs/release-notes/v[\d.]+(-rc[\d.]+)?\.md$'), + re.compile(r'^docs/benchmarks/.+\.md$'), +] +# [E] 状态词表(封闭集合) +VALID_STATUS = {'现行', '冻结', 'TODO', '转发页', '已归档'} + + +def rel(p): + return os.path.relpath(p, ROOT).replace(os.sep, '/') + + +def walk(exts, skip_dirs={'build', '.git', 'extern', 'node_modules', '.venv', '__pycache__'}): + for root, dirs, files in os.walk(ROOT): + dirs[:] = [d for d in dirs if d not in skip_dirs and not d.startswith('.')] + for fn in files: + if os.path.splitext(fn)[1] in exts: + yield os.path.join(root, fn) + + +HISTORY_MD = None # 在 main 里赋值 + + +def load_docs(): + """审计对象:AGENTS.md / README.md / CONTRIBUTING.md + docs/**.md + research/**.md""" + docs = [os.path.join(ROOT, x) for x in ('AGENTS.md', 'README.md', 'CONTRIBUTING.md')] + for p in walk({'.md'}): + r = rel(p) + if r.startswith(('docs/', 'research/')): + docs.append(p) + return sorted(docs) + + +def strip_inline_code(line): + return re.sub(r'`[^`]*`', '', line) + + +def read_lines(p): + with open(p, encoding='utf-8') as f: + return f.read().split('\n') + + +def load_code_text(): + parts = [] + for p in walk({'.hpp', '.cpp'}, skip_dirs={'build', '.git', 'node_modules', '.venv', '__pycache__'}): + if rel(p).startswith(('include/', 'src/', 'tools/', 'extern/')): + with open(p, encoding='utf-8', errors='replace') as f: + parts.append(f.read()) + for p in walk({'.py'}): + with open(p, encoding='utf-8', errors='replace') as f: + parts.append(f.read()) + with open(os.path.join(ROOT, 'CMakeLists.txt'), encoding='utf-8') as f: + parts.append(f.read()) + return '\n'.join(parts) + + +# ═══ [A] 文档引用的文件/链接目标存在 ═════════════════════════════════════ + +def check_A(docs): + miss, hist, link_miss, link_checked = 0, 0, 0, 0 + print('=== [A] 文档引用但仓库中不存在的文件 / 链接目标 ===') + # 全仓真实文件名索引(递归,含 extern/ 子仓头文件,与 ps1 口径一致) + real_names = set() + for p in walk({'.hpp', '.cpp', '.comp', '.py'}, + skip_dirs={'build', '.git', 'node_modules', '.venv', '__pycache__'}): + real_names.add(os.path.basename(p)) + for fn in os.listdir(ROOT): + if os.path.isfile(os.path.join(ROOT, fn)): + real_names.add(fn) + # 构建生成物(AOT 融合管线产物,ps1 扫 build/generated;未构建机器上不存在,勿报) + GENERATED_FILES = {'fused_registry.hpp'} + # 目录/仓库名被反引号包裹(非文件引用)与外部项目文件引用 + NON_FILE_NAMES = {'neuralnet.cpp', 'go_train_cli.cpp'} + for d in docs: + if d == HISTORY_MD: + continue # 历史归档按设计记录已删符号/已删文件(ps1 同口径,整体豁免 A) + hits = [] + lines = read_lines(d) + for i, line in enumerate(lines): + for m in re.finditer(r'`([A-Za-z0-9_]+\.(hpp|cpp|comp|py|md))`', line): + name = m.group(1) + if name.endswith('.md'): + continue # md 引用走链接检查(裸文件名跨目录歧义大) + if name not in real_names: + if name in GENERATED_FILES or name in NON_FILE_NAMES: + continue + if name in HISTORICAL_FILES: + hist += 1 + else: + hits.append(f'{i+1}: `{name}`') + # markdown 链接目标(剥行内代码防误报;外部/锚点跳过) + text = strip_inline_code(line) + for m in re.finditer(r'\]\(([^)\s]+)\)', text): + t = m.group(1) + if re.match(r'^(https?:|mailto:|codex:|#)', t): + continue + target = t.split('#')[0] + if not target: + continue + link_checked += 1 + full = os.path.normpath(os.path.join(os.path.dirname(d), target)) + if not os.path.exists(full): + link_miss += 1 + hits.append(f'{i+1}: {t}') + if hits: + miss += len(hits) + shown = hits[:12] + print(f' -- {rel(d)}({len(hits)} 处,示前 12)') + for h in shown: + print(f' {h}') + print(f' [A] 可行动 {miss} 处(检查了 {link_checked} 个链接目标);历史白名单跳过 {hist} 处\n') + return miss + + +# ═══ [B] 已删除符号的文档残留 ═══════════════════════════════════════════ + +def check_B(docs): + print('=== [B] 已删除符号的文档残留 ===') + total = 0 + cache = {} + for sym in DEAD_SYMBOLS: + remains, neg = [], 0 + for d in docs: + if d == HISTORY_MD: + continue + if d not in cache: + cache[d] = read_lines(d) + lines = cache[d] + for i, line in enumerate(lines): + if sym not in line: + continue + win = ' '.join(lines[i:i + 3]) + if NEGATION_PAT.search(win): + neg += 1 + else: + remains.append(f'{rel(d)}:{i+1}: {line.strip()[:78]}') + if remains: + total += len(remains) + print(f' -- {sym}: {len(remains)} 处') + for r in remains[:6]: + print(f' {r}') + if neg: + print(f' (另有 {neg} 处为「该符号不存在/已删除」陈述,跳过)') + print(f' [B] 合计 {total} 处残留\n') + return total + + +# ═══ [C] 数字型断言披露(WARN)═══════════════════════════════════════════ + +def check_C(docs): + print('=== [C] 数字型断言(需人工与实测核对,WARN)===') + n = 0 + pat = re.compile(r'\d+ 个 virtual|\d+ 个目标|ctest \d+|\d+/\d+ *(绿|全绿|通过|测试)|目标(\d+ 个)') + for d in docs: + if d == HISTORY_MD: + continue + for i, line in enumerate(read_lines(d)): + if pat.search(line): + n += 1 + if n <= 15: + print(f' {rel(d)}:{i+1}: {line.strip()[:88]}') + print(f' [C] 共 {n} 处披露\n') + return 0 # WARN 不阻塞 + + +# ═══ [D] CLI 参数存在性 ══════════════════════════════════════════════════ + +def check_D(docs, code_text): + print('=== [D] 文档引用但代码中不存在的 CLI 参数 ===') + flags = {} + for d in docs: + if d == HISTORY_MD: + continue + for i, line in enumerate(read_lines(d)): + for m in re.finditer(r'(? 20: + print(f' …(仅示前 20)') + print(f' [H] 合计 {total} 处(改写为当前事实或移入 history/history.md)\n') + return total + + +def check_G(docs, report_path): + print('=== [G] 代码示例清单 ===') + snippets = extract_snippets(docs) + # 违规判定:C++ 块声明了 api 角色 → 必须写成 "example api";未声明 → 默认 snippet(允许) + bad = 0 + report = ['# 代码示例复核报告(自动生成,勿手改)', '', + f'共 {len(snippets)} 个代码块。**机器只核对符号存在性;逻辑正确性由人工复核**——', + '改了 API/CLI 后跑 `python scripts/doc_audit.py --report` 并通读本文件。', ''] + by_file = {} + for f, ln, lang, role, body in snippets: + by_file.setdefault(f, []).append((ln, lang, role, body)) + for f in sorted(by_file): + report.append(f'## {f}') + report.append('') + for ln, lang, role, body in by_file[f]: + report.append(f'### {f}:{ln} 语言={lang} 角色={role}') + # 抽取片段中的符号供人工对照 + api_refs = sorted(set(re.findall(r'\bnn::[A-Za-z_][A-Za-z0-9_]*', body))) + cli_refs = sorted(set(re.findall(r'(? -o // 旧 JSON 词表 → .nnvocab(kvrec v2)。旧 JSON 词表不再被 // tokenizer/text_* 直读,迁移后所有入口只吃 .nnvocab。 @@ -132,7 +132,7 @@ int convert_vocab(const Config &cfg) int convert_csv(const Config &) { std::cerr << "dataset_convert csv 尚未实现(tabular 形态为阶段四预留," - "见 docs/todo/19-unified-dataset.md §4.4)\n"; + "见 docs/internal/19-unified-dataset.md §4.4)\n"; return 1; } diff --git a/src/dataset_gen.cpp b/src/dataset_gen.cpp index 7ea3176..d70f93f 100644 --- a/src/dataset_gen.cpp +++ b/src/dataset_gen.cpp @@ -1,6 +1,6 @@ // ── 文本数据集生成器(dataset_gen)──────────────────────────────────────── // -// 文本 + 词表 → .nndataset(docs/todo/19-unified-dataset.md §6.1): +// 文本 + 词表 → .nndataset(docs/internal/19-unified-dataset.md §6.1): // 读文本 → trim/过滤 → 并行 tokenize(保序)→ 掩码(--loss-scope assistant) // → 打包写 .nndataset(词表/来源/生成参数作配套层层嵌套 kvrec)。 // diff --git a/src/dataset_samples_test.cpp b/src/dataset_samples_test.cpp index 86ce992..e141561 100644 --- a/src/dataset_samples_test.cpp +++ b/src/dataset_samples_test.cpp @@ -1,6 +1,6 @@ // ── dataset_samples_test — 训练样本概念(TextSampleSet / TextSample / batch)── // -// P2b 验收(docs/todo/29 §8):数据集只存 doc;**训练单位 = 样本(窗口)**; +// P2b 验收(docs/internal/29 §8):数据集只存 doc;**训练单位 = 样本(窗口)**; // update step = ceil(样本数 / global_batch_size) 是派生量。本测试锁住: // [1] 切窗:偏移序列、样本数、steps_per_epoch(派生) // [2] sample(i) 的视图(tokens/doc_ids/loss_mask/valid_len) diff --git a/src/dsl_shape_infer_test.cpp b/src/dsl_shape_infer_test.cpp index fa3d64c..348e130 100644 --- a/src/dsl_shape_infer_test.cpp +++ b/src/dsl_shape_infer_test.cpp @@ -1,7 +1,7 @@ // ─────────────────────────────────────────────────────────────────────────── // dsl_shape_infer_test.cpp — dsl::compute / compute_reduce 的**无形状重载** // -// 背景:docs/todo/18-roadmap.md P4-4 把"`dsl::compute` 无 2 参重载"记为 API +// 背景:docs/internal/18-roadmap.md P4-4 把"`dsl::compute` 无 2 参重载"记为 API // 摩擦点(调用方反复手写 `x.rows(), x.cols()`)。本测试锁定新重载的口径: // // [1] 推导形状 == 显式形状(一族表达式:一元/二元/广播/select/matmul 段 diff --git a/src/expr_fused_key_test.cpp b/src/expr_fused_key_test.cpp index 1e58fd0..d170819 100644 --- a/src/expr_fused_key_test.cpp +++ b/src/expr_fused_key_test.cpp @@ -1,5 +1,5 @@ // ── expr_fused_key_test — "结构 = 表达式类型" 不变量(AOT 自登记的前提)──────── -// 背景(docs/todo/02 §自登记锚点):`FusedAnchor` 在构建期按表达式 +// 背景(docs/internal/02 §自登记锚点):`FusedAnchor` 在构建期按表达式 // **类型**默认构造一个"符号实例"折叠出结构并登记;运行时同一调用点折叠出的 key // 必须与它一致,否则闭合世界 miss。成立条件 = **key 只描述结构**: // ① 常量池**值**不进 key(只喂个数;值经 push constant `c` 传给 shader) diff --git a/src/expr_graph_test.cpp b/src/expr_graph_test.cpp index befbed3..c40bad3 100644 --- a/src/expr_graph_test.cpp +++ b/src/expr_graph_test.cpp @@ -2,7 +2,7 @@ // expr_graph_test.cpp — 图 IR + 融合分析(IR-C)单元验证(纯 CPU、无 GPU) // // Tensor/Matrix 访问走引擎 API:create_tensor/write/to_matrix——铁律 #11。 -// 验证内容(对应 docs/todo/03-ir-optimization.md 的验证策略): +// 验证内容(对应 docs/internal/03-ir-optimization.md 的验证策略): // 1. 链融合正确性:A→B 融合成单 kernel 后求值 == 逐节点求值 // 2. 多节点链融合(3 节点) // 3. 融合边界:非链(无消费者 / 多消费者 / 非 Linear 引用)不融合 diff --git a/src/expr_matmul_test.cpp b/src/expr_matmul_test.cpp index ded1dfa..0ea8279 100644 --- a/src/expr_matmul_test.cpp +++ b/src/expr_matmul_test.cpp @@ -1,7 +1,7 @@ // ─────────────────────────────────────────────────────────────────────────── -// expr_matmul_test.cpp — 算子融合二期(docs/todo/02):matmul 参与 IR 融合 +// expr_matmul_test.cpp — 算子融合二期(docs/internal/02):matmul 参与 IR 融合 // -// 对应 docs/todo/02-operator-fusion.md(IR 地基 + CPU 正确性两步): +// 对应 docs/internal/02-operator-fusion.md(IR 地基 + CPU 正确性两步): // 1. ExprSpec 增加 MatmulSpec(前置 matmul 段)+ ExprOperandKind::Matmul: // C = op(A,B) 作为逐元素链的"虚拟寄存器 0",链内按 (r,c) 读取。 // 2. CpuEngine::eval_expr 支持 matmul 段(matmul 预计算 + 逐元素链), diff --git a/src/expr_opt_test.cpp b/src/expr_opt_test.cpp index 2147a93..8295cd3 100644 --- a/src/expr_opt_test.cpp +++ b/src/expr_opt_test.cpp @@ -1,7 +1,7 @@ // ─────────────────────────────────────────────────────────────────────────── // expr_opt_test.cpp — IR 优化 pass(IR-A + IR-B)单元验证(纯 CPU、无 GPU) // -// 验证内容(对应 docs/todo/03-ir-optimization.md 的验证策略): +// 验证内容(对应 docs/internal/03-ir-optimization.md 的验证策略): // 1. canonicalize 各 pass 正确性:DCE / 常量折叠 / 代数化简 / CSE / 寄存器分配 // 2. 确定性:同一 spec 多次 canonicalize 结果完全相同(含 key) // 3. 语义等价:canonical 前后 CPU 求值结果一致(含归约表达式) diff --git a/src/expr_reduce_test.cpp b/src/expr_reduce_test.cpp index 8d3b4ce..2c8330e 100644 --- a/src/expr_reduce_test.cpp +++ b/src/expr_reduce_test.cpp @@ -1,7 +1,7 @@ // ─────────────────────────────────────────────────────────────────────────── // expr_reduce_test.cpp — ExprSpec 归约语义(归约视图 + 归约指令)CPU 验证 // -// 对应 docs/todo/02-operator-fusion.md 阶段一: +// 对应 docs/internal/02-operator-fusion.md 阶段一: // 1. 归约视图:对输入 Tensor 直接归约出 (rows,1)/(1,cols) 标量向量,参与 // 算术时自动按行/按列广播(ExprViewKind::RowReduceSum/Max、ColReduceSum/Max)。 // 2. 归约指令:对表达式结果归约(ExprOp::RowSum/RowMax/ColSum/ColMax), diff --git a/src/f16_precision_test.cpp b/src/f16_precision_test.cpp index cbff4af..b7ab62e 100644 --- a/src/f16_precision_test.cpp +++ b/src/f16_precision_test.cpp @@ -632,7 +632,7 @@ void test_f16_model_e2e(nn::ComputeEngine& raw, nn::ComputeEngine& eng) // ── 8. profile 组合矩阵:默认门禁廉价断言 + NN_F16_DEBUG 逐阶段诊断 ─────── // 逐字段拆开跑同一个小 GPT(初值/数据/步数全固定 → 确定性)。cases 含此前缺失的 -// 「全 f16」= {F16,F16,F16,F16}(docs/todo/24 §2.4 覆盖缺口 / §5 F2): +// 「全 f16」= {F16,F16,F16,F16}(docs/internal/24 §2.4 覆盖缺口 / §5 F2): // · 健康组合(f32 / param / compute / stable / --f16):loss 全程有限且末步不高于首步; // · 危险组合(opt=f16 / 全 f16,24 §2 已定位机制):只断言"能跑完"——数值形态由 // 机制说明 + 下方轨迹打印披露,**不作健康断言**(否则 F5 修好它们时本测试反红)。 @@ -679,7 +679,7 @@ void run_profile_matrix(nn::ComputeEngine& eng, bool verbose) g_label = saved; } -// ── 9. CE loss 标量归约在 stable=f16 下不得溢出(docs/todo/24 §2 / 14 号台账)── +// ── 9. CE loss 标量归约在 stable=f16 下不得溢出(docs/internal/24 §2 / 14 号台账)── // ── 10. 四字段全 f16(含 optimizer=f16)可训练(F5)──────────────────────── // 关键修复(2026-10-14):Adam 的二阶矩 v ≈ (1-β2)·g² 在 f16 下**下溢为 0** // (g~1e-5 ⇒ v~1e-10),而一阶矩 m ~1e-8 仍在次正规区 ⇒ `m/(√v+eps)` 退化、 diff --git a/src/layer_lifetime_test.cpp b/src/layer_lifetime_test.cpp index 6e052fe..bbddf0d 100644 --- a/src/layer_lifetime_test.cpp +++ b/src/layer_lifetime_test.cpp @@ -1,6 +1,6 @@ // ── layer_lifetime_test — 生命周期 v3:设备域模型与强所有权 ──────────────── // -// v3 契约(docs/todo/28-lifecycle-v3.md §4): +// v3 契约(docs/internal/28-lifecycle-v3.md §4): // [1] 域从存储派生:CPU 张量 → kHostDomain;空/无效 = 0(唯一豁免); // Tensor 不再保存任何引擎身份字段 // [2] 引擎不可栈上构造(必须由 create() 的 shared_ptr 管理) diff --git a/src/lifetime_contract_test.cpp b/src/lifetime_contract_test.cpp index 935dbcc..282409f 100644 --- a/src/lifetime_contract_test.cpp +++ b/src/lifetime_contract_test.cpp @@ -1,6 +1,6 @@ // ── lifetime_contract_test — P0 生命周期契约(CPU 可跑的负例)─────────────── // -// 覆盖 docs/todo/28-lifecycle-v3.md §5 P0 的三处安全修复(不破坏 API): +// 覆盖 docs/internal/28-lifecycle-v3.md §5 P0 的三处安全修复(不破坏 API): // [1] ExprSegment 持 shared_ptr:录制段内丢掉外部最后一个 // 引擎句柄,end() 仍然安全(原实现持裸引用 = 析构 UAF) // [2] ActivationOffloader 状态机:未 import 的导出不能被下一次 export 静默 diff --git a/src/mnist_train.cpp b/src/mnist_train.cpp index 3fc527c..6b67be2 100644 --- a/src/mnist_train.cpp +++ b/src/mnist_train.cpp @@ -44,7 +44,7 @@ using nn::Scalar; // ── 精度解析辅助 ───────────────────────────────────────────────────────── // allow_t1_58:三值(T1_58)**只适用于 param 槽**("该层权重是三值"), // compute/stable/optimizer 出现它一律在参数解析处拒绝,而不是拖到 init 期才报 -// 能力校验错误(docs/todo/21-quantized-weights.md §4.1)。 +// 能力校验错误(docs/internal/21-quantized-weights.md §4.1)。 nn::Precision parse_precision(const std::string& name, const char* flag, bool allow_t1_58 = false) { @@ -82,7 +82,7 @@ void print_usage(const char *prog) // RV-04:名单文本由 nn::optimizer_table()(唯一真源)生成,不再手抄 help.opt("--optimizer ", "优化器: " + nn::optimizer_names("/") + - " (默认: adam)\nadamwquant: 量化状态的 AdamW(状态 4 B/权重 vs 8 B;见 docs/todo/21 §4.13)"); + " (默认: adam)\nadamwquant: 量化状态的 AdamW(状态 4 B/权重 vs 8 B;见 docs/internal/21 §4.13)"); help.opt("--weight-decay ", "AdamW 权重衰减系数 (默认: 0.01)"); help.opt("--max-samples ", "限制训练样本数 (默认: 全部,用于快速测试)"); help.opt("--shuffle-steps ", "每 epoch 打乱 batch 顺序 (默认: true)"); @@ -122,7 +122,7 @@ void print_usage(const char *prog) help.opt("--precision-param ", "权重/参数精度 (默认: f32);t1_58 = 三值权重 BitLinear(1.58-bit);" "本入口仅 MLP 架构支持(transformer/CNN 由层能力校验报错)," - "GPT 见 text_train;docs/todo/21-quantized-weights.md"); + "GPT 见 text_train;docs/internal/21-quantized-weights.md"); help.opt("--precision-compute ", "常规算子计算精度 (默认: f32)"); help.opt("--precision-stable ", "数值敏感算子精度 (默认: f32)"); help.opt("--precision-optimizer ", "优化器状态精度 (默认: f32)"); @@ -538,7 +538,7 @@ int main(int argc, char *argv[]) { TrainConfig cfg = parse_args(argc, argv); - // ── 危险精度组合启动期告警(仅警告,不拒绝;docs/todo/24 §2.3 F1)──── + // ── 危险精度组合启动期告警(仅警告,不拒绝;docs/internal/24 §2.3 F1)──── // optimizer=f16(含四字段全 f16)只打印一次到 stderr:不改变退出码、不阻断 // 训练、不静默降级;`--f16` 与合法组合返回空串(静默)。 if (const std::string warn = nn::cli::dangerous_precision_warning(cfg.precision); @@ -551,7 +551,7 @@ int main(int argc, char *argv[]) // ── 如果 --resume,从文件读取规格覆盖 CLI 参数 ────────── if (cfg.load_existing) { - // 角色校验(v7,docs/todo/23 §2.1):推理模型文件不含训练参数 → + // 角色校验(v7,docs/internal/23 §2.1):推理模型文件不含训练参数 → // 明确拒绝;v5/v6 老 .bin 无 role 字段 → 按训练文件处理(零破坏)。 { uint32_t resume_version = 0; @@ -714,7 +714,7 @@ int main(int argc, char *argv[]) { std::cout << "[精度] 三值权重已启用(T1_58 / BitLinear:量化 forward + STE backward," "latent 恒 f32)\n" - " [范围] P1 支持 MLP 路径;docs/todo/21-quantized-weights.md\n"; + " [范围] P1 支持 MLP 路径;docs/internal/21-quantized-weights.md\n"; } if (cfg.precision.param == nn::Precision::F16 || cfg.precision.compute == nn::Precision::F16 || @@ -757,7 +757,7 @@ int main(int argc, char *argv[]) // 不在这里再注入:`build_mnist_model_from_spec` 已在 add 之前用 // `Model::set_default_precision_profile` 注入(权重按精度创建),这里的 // 二次调用对 MLP 是冗余的;而按 D3(b),profile 在 init 后**不可变** - //(再注入即 fail-fast)。见 docs/todo/21-quantized-weights.md §4.3.2。 + //(再注入即 fail-fast)。见 docs/internal/21-quantized-weights.md §4.3.2。 { const auto& pp = cfg.precision; if (pp.param != nn::Precision::F32 || pp.compute != nn::Precision::F32 || @@ -790,7 +790,7 @@ int main(int argc, char *argv[]) } } - // ── 训练生命周期容器(P2b,docs/todo/29)───────────────── + // ── 训练生命周期容器(P2b,docs/internal/29)───────────────── // Session 同时拥有 Model + Optimizer(成员声明顺序保证 optimizer 先析构), // 结构性消除"优化器必须早于参数所有者销毁"的调用约定。model 在此前已完成 // resume 载入(--resume 需要 model 存在),故顺序 = build → resume → create。 diff --git a/src/model_roles_test.cpp b/src/model_roles_test.cpp index 83416ee..874594d 100644 --- a/src/model_roles_test.cpp +++ b/src/model_roles_test.cpp @@ -1,5 +1,5 @@ // ── model_roles_test — 模型文件角色(v7:.nnmodel / .nnckpt)+ 参数形态协议 ── -// 设计依据:docs/todo/23-library-design-cleanup-and-model-file-roles.md §2.1/§2.2 +// 设计依据:docs/internal/23-library-design-cleanup-and-model-file-roles.md §2.1/§2.2 // // 覆盖(取代原 ternary_deploy_test 的部署格式面 —— NNQT 独立格式已删除): // [1] Model 角色(推理):三值层的权重以**打包形态**落盘(盘上 base-3); diff --git a/src/optimizer_state_test.cpp b/src/optimizer_state_test.cpp index fa09508..462518f 100644 --- a/src/optimizer_state_test.cpp +++ b/src/optimizer_state_test.cpp @@ -1,6 +1,6 @@ // ── optimizer_state_test — 优化器断点状态导出/载入(P1-2)──────────────────── // -// 验收(docs/todo/18-roadmap.md §4.2 P1-2): +// 验收(docs/internal/18-roadmap.md §4.2 P1-2): // "TDR 模拟重启后动量非零且 loss 轨迹连续"。本测试把它机械化: // ① 状态存在性(每个优化器要么有状态、要么被显式登记为无状态); // ② 重启后状态非零; diff --git a/src/rl_experience_test.cpp b/src/rl_experience_test.cpp index bb8ea45..f6c80e8 100644 --- a/src/rl_experience_test.cpp +++ b/src/rl_experience_test.cpp @@ -1,6 +1,6 @@ // ── rl_experience_test — experience schema 与 advantage transforms ───────── // -// docs/todo/31 RL-1a: +// docs/internal/31 RL-1a: // [1] 标准/自定义字段、必需字段、PolicyBatchView; // [2] GAE 手算值、done 截断、bootstrap、mask; // [3] MonteCarloReturn; diff --git a/src/t1_58_test.cpp b/src/t1_58_test.cpp index 28c3daa..68afa9a 100644 --- a/src/t1_58_test.cpp +++ b/src/t1_58_test.cpp @@ -1,5 +1,5 @@ // ── t1_58_test — 三值(T1_58)精度与 BitLinear ────────────────────────────── -// 设计依据:docs/todo/21-quantized-weights.md(P1 验收 §5/§7) +// 设计依据:docs/internal/21-quantized-weights.md(P1 验收 §5/§7) // // 覆盖: // [1] PrecisionSet / PrecisionSupport 语义(默认集合 = {f16,f32} × 四槽) diff --git a/src/tensor_precision_test.cpp b/src/tensor_precision_test.cpp index 2a546ec..e5ea6c9 100644 --- a/src/tensor_precision_test.cpp +++ b/src/tensor_precision_test.cpp @@ -1,5 +1,5 @@ // ── tensor_precision_test.cpp — D3:Tensor 精度属性 + 引擎 I/O 往返 ────────── -// M1 访问收口(docs/todo/17 §4.1)后,Tensor 存储访问器与静态直构 +// M1 访问收口(docs/internal/17 §4.1)后,Tensor 存储访问器与静态直构 // 工厂已私有:本测试全部经 ComputeEngine 创建/读写(upload/download/create_tensor/ // reshape),验收口径同步修订(原 docs/development/05 §13 中依赖 cpu_matrix/ // cpu_shared 直读的条目改为"经引擎往返"等价验证): diff --git a/src/tensor_schema_test.cpp b/src/tensor_schema_test.cpp index 44157f3..cdb29bb 100644 --- a/src/tensor_schema_test.cpp +++ b/src/tensor_schema_test.cpp @@ -1,6 +1,6 @@ // ── tensor_schema_test — 通用输出/experience 的公共契约 ──────────────────── // -// docs/todo/31 §6 公共基础 + RL-0 的 schema 前置: +// docs/internal/31 §6 公共基础 + RL-0 的 schema 前置: // [1] 有序字段、名称解析、稳定指纹; // [2] 重复/空字段名、跨 schema handle、越界 handle; // [3] 必需/可选字段、未知/重名字段; diff --git a/src/ternary_gemm_test.cpp b/src/ternary_gemm_test.cpp index 45aed38..d90b338 100644 --- a/src/ternary_gemm_test.cpp +++ b/src/ternary_gemm_test.cpp @@ -1,5 +1,5 @@ // ── ternary_gemm_test — 三值打包权重与量化 GEMM(P2 / F3)──────────────────── -// 设计依据:docs/todo/21-quantized-weights.md §5 的 P2 验收 +// 设计依据:docs/internal/21-quantized-weights.md §5 的 P2 验收 // · 打包往返逐位(编码/解码) // · 数值与 P1 的 f16 稠密缓冲路径一致(同 latent 权重下三值逐位) // · 位宽账:0.25 B/权重(f16 稠密 = 2 B/权重) diff --git a/src/test_common.hpp b/src/test_common.hpp index 87a5802..478fdb0 100644 --- a/src/test_common.hpp +++ b/src/test_common.hpp @@ -46,7 +46,7 @@ } \ } while (0) -// ── M1 访问收口(docs/todo/17 §4.1):库外一律经引擎上传/下载 ─────── +// ── M1 访问收口(docs/internal/17 §4.1):库外一律经引擎上传/下载 ─────── // Tensor 存储与静态直构工厂收归引擎私有后,测试的填数/对拍路径为: // 填数:宿主 Matrix 上写好 → upload(eng, m) 生成引擎张量 // 对拍:download(eng, t) 取回宿主 Matrix(P=F32:f16 精确升位,不丢值) diff --git a/src/text_train.cpp b/src/text_train.cpp index f44160e..cb0d05f 100644 --- a/src/text_train.cpp +++ b/src/text_train.cpp @@ -1,6 +1,6 @@ // ── GPT 文本生成训练程序(引擎化架构) ────────────────────────────────────── // -// 输入:.nndataset 数据集(docs/todo/19-unified-dataset.md)—— +// 输入:.nndataset 数据集(docs/internal/19-unified-dataset.md)—— // tokenize、loss 掩码、词表都在生成期(dataset_gen)定好并嵌入数据集。 // // 数据流(P2b:数据集 → **样本** → 训练工厂): @@ -141,7 +141,7 @@ namespace // ── 数据集身份(P1-2 断点门禁的"内容"侧)──────────────────────────── // 路径是**位置**(机器相关、CLI 优先),sha256 + 网格是**身份**(断点权威)。 // 身份不同 ⇒ 样本网格、step 号语义、lr 曲线形状全变 ⇒ 续训路径硬报错 - // (出口 = 从 .nnmodel 开新一轮,docs/todo/23 §2.1.1)。 + // (出口 = 从 .nnmodel 开新一轮,docs/internal/23 §2.1.1)。 nn::DatasetIdentity dataset_identity; dataset_identity.path = cfg.text_path; NN_TRY_MSG(sha_r, "计算数据集身份失败", nn::sha256_file_hex(cfg.text_path)); @@ -154,7 +154,7 @@ namespace dataset_identity.steps_per_epoch = train_samples.steps_per_epoch(cfg.batch_size); - // ── 数据集身份门禁(硬错、无逃生阀;docs/todo/23 §2.1.1)──────────── + // ── 数据集身份门禁(硬错、无逃生阀;docs/internal/23 §2.1.1)──────────── // 数据集变 ⇒ 样本数变 ⇒ steps_per_epoch 变 ⇒ step 级调度的 total_steps、 // global_step 语义、epoch 边界同时改变 ⇒ "同一断点 + 不同数据集"没有正确 // 的续训语义。合法出口 = 从 .nnmodel 开新一轮(下面的 warm start 分支)。 @@ -246,7 +246,7 @@ namespace if (cfg.precision.param == nn::Precision::T1_58) NN_FAIL("RAPT 尚不支持三值权重(--precision-param t1_58):RLA 注意力的" " 4 个 Linear 还没接 make_linear_layer,\n" - "见 docs/todo/21-quantized-weights.md §4.8.3。\n" + "见 docs/internal/21-quantized-weights.md §4.8.3。\n" " · 三值 GPT:改用 --model gpt\n" " · 三值 MLP:mnist_train --arch mlp --precision-param t1_58"); model_build = nn::build_rapt_model(*engine, nn::RAPTConfig{ @@ -277,7 +277,7 @@ namespace std::cout << "[精度] 三值权重已启用(T1_58 / BitLinear:量化 forward + " "STE backward,latent 恒 f32)\n" " [范围] GPT(注意力 4 投影 + FFN fc1/fc2 + 未 tie 的 LM head);" - "RAPT/Transformer 见 docs/todo/21-quantized-weights.md §4.8.3\n"; + "RAPT/Transformer 见 docs/internal/21-quantized-weights.md §4.8.3\n"; if (pp.param != nn::Precision::F32 || pp.compute != nn::Precision::F32 || pp.stable != nn::Precision::F32 || pp.optimizer != nn::Precision::F32) { @@ -352,7 +352,7 @@ namespace // 非致命失败(读不到规格、载参失败)打印提示后继续从头训练(旧行为)。 if (cfg.load_existing) { - // 不加语境前缀:角色门禁的报错文案是用户可见契约(docs/todo/23 §2.1), + // 不加语境前缀:角色门禁的报错文案是用户可见契约(docs/internal/23 §2.1), // 原样透出;返回的 TextTrainResume(spec_restored / weights_loaded) // 只有测试消费,主流程按进度打印即可。 NN_TRY_CHECK(nn::cli::resume_text_train(*engine, cfg, model, spec, std::cout, std::cerr)); @@ -434,7 +434,7 @@ int main(int argc, char *argv[]) { nn::cli::TrainConfig cfg = nn::cli::parse_text_train_args(argc, argv); - // ── 危险精度组合启动期告警(仅警告,不拒绝;docs/todo/24 §2.3 F1)──── + // ── 危险精度组合启动期告警(仅警告,不拒绝;docs/internal/24 §2.3 F1)──── // optimizer=f16(含四字段全 f16)只打印一次到 stderr:不改变退出码、不阻断 // 训练、不静默降级;`--f16` 与合法组合返回空串(静默)。 if (const std::string warn = nn::cli::dangerous_precision_warning(cfg.precision); diff --git a/src/text_train_modules_test.cpp b/src/text_train_modules_test.cpp index 4a7bbde..8f4ae5c 100644 --- a/src/text_train_modules_test.cpp +++ b/src/text_train_modules_test.cpp @@ -1,6 +1,6 @@ // ── text_train_modules_test — P1-1 拆出的模块(recovery / checkpoint)回归 ── // -// 验收(docs/todo/18-roadmap.md §4.2 P1-1):"新增恢复路径单测"。 +// 验收(docs/internal/18-roadmap.md §4.2 P1-1):"新增恢复路径单测"。 // 覆盖: // [1] 断点路径派生:`--save` 的 .nnmodel → 同名 .nnckpt;非 .nnmodel 追加。 // [2] 恢复路径的角色语义:Checkpoint = 断点续训、Model = warm start(都放行); @@ -138,7 +138,7 @@ void test_role_gate_and_roundtrip(const std::filesystem::path& dir) log.save(ckpt_file, original, spec, kTokenizerBytes, ckpt_state, no_blobs, std::cerr); CHECK(log.failures() == 0, "断点写到可写路径不应记账失败"); - // 角色语义(v8,2026-10-16 裁定;docs/todo/23 §2.1.1): + // 角色语义(v8,2026-10-16 裁定;docs/internal/23 §2.1.1): // Model(.nnmodel)= warm start(SFT)⇒ **放行**(三值同样放行,见下面的 // P1-7 反量化块);Checkpoint / 老文件 / 不存在 ⇒ 放行。 // **P1-7 已删除**"三值 .nnmodel 必须被拒"那条门禁(`check_resume_target` @@ -205,7 +205,7 @@ void test_role_gate_and_roundtrip(const std::filesystem::path& dir) ar3.error().message.find("禁止") != std::string::npos, "报错文案应列出被禁旗标与规则"); - // docs/todo/30:旧断点缺 batch 语义键 ⇒ micro-batch 解释, + // docs/internal/30:旧断点缺 batch 语义键 ⇒ micro-batch 解释, // 恢复时换成等效 global,并把 micro step 计数折成 update step。 nn::TextTrainState legacy_state; legacy_state.counters.epoch = 1; diff --git a/src/text_trainer_test.cpp b/src/text_trainer_test.cpp index f25b58c..f294cf5 100644 --- a/src/text_trainer_test.cpp +++ b/src/text_trainer_test.cpp @@ -1,6 +1,6 @@ // ── text_trainer_test — 训练工厂(TextTrainer)端到端回归 ─────────────────── // -// P2b 验收(docs/todo/29 §8):数据集**直接接入**训练工厂;样本概念归一; +// P2b 验收(docs/internal/29 §8):数据集**直接接入**训练工厂;样本概念归一; // 训练状态由工厂装配、Session 持有。本测试锁住: // [1] create(dataset):内部建样本集 / 载词表 / 数据身份(num_samples、steps) // [2] fit():步数 = ceil(样本数/batch)、参数移动、epoch 汇总 + 测试评估输出 diff --git a/src/train_state_test.cpp b/src/train_state_test.cpp index 03ea149..80b6ed1 100644 --- a/src/train_state_test.cpp +++ b/src/train_state_test.cpp @@ -1,6 +1,6 @@ // ── train_state_test — v8 训练状态段 + 尾部校验和(P1-2 / P2-1)回归 ───────── // -// 验收(docs/todo/18-roadmap.md §4.2 P1-2 + §4.3 P2-1、§8.2 门禁 7): +// 验收(docs/internal/18-roadmap.md §4.2 P1-2 + §4.3 P2-1、§8.2 门禁 7): // 老文件缺段 = 冷启动语义;save→load→save 逐字节一致;截断/损坏文件明确报错。 // // 覆盖: diff --git a/src/training_session_test.cpp b/src/training_session_test.cpp index 4984e64..09742f3 100644 --- a/src/training_session_test.cpp +++ b/src/training_session_test.cpp @@ -1,6 +1,6 @@ // ── training_session_test — TrainingSession 生命周期与训练原语 ────────────── // -// docs/todo/29-session-architecture.md §8 P2a 验收: +// docs/internal/29-session-architecture.md §8 P2a 验收: // [1] 创建 → 8 步 step 参数确实移动(优化器与参数连通) // [2] Session 移动后 step 正常(TensorRef 指向堆上 Layer 成员,地址稳定) // [3] 作用域结束析构顺序正确(optimizer 先于 Model;ASan 下验证) @@ -127,7 +127,7 @@ run_mse_step(nn::TrainingSession& session, const nn::Tensor& x, void test_accumulation_and_session_state() { - // docs/todo/30:Session 内部累积;未到边界不更新,移动后状态仍有效。 + // docs/internal/30:Session 内部累积;未到边界不更新,移动后状态仍有效。 auto engine = nn::CpuEngine::create(); nn::Model model(*engine); CHECK(model.add(4, 3), "state: add"); diff --git a/src/write_epoch_test.cpp b/src/write_epoch_test.cpp index 071a17e..9411b73 100644 --- a/src/write_epoch_test.cpp +++ b/src/write_epoch_test.cpp @@ -1,5 +1,5 @@ // ── write_epoch_test — 写版本(write epoch)契约 + BitLinear 量化缓存 ────── -// 设计依据:docs/todo/21-quantized-weights.md §4.11(F1/F4/F6 落地) +// 设计依据:docs/internal/21-quantized-weights.md §4.11(F1/F4/F6 落地) // // 覆盖: // [1] 逐写入口:每一个"经引擎媒介写入张量存储"的公共入口都推进写版本 diff --git a/tools/scan_exprs.cpp b/tools/scan_exprs.cpp index 3dbc04c..9419bb7 100644 --- a/tools/scan_exprs.cpp +++ b/tools/scan_exprs.cpp @@ -119,7 +119,7 @@ int main(int argc, char* argv[]) [[maybe_unused]] const auto dry_run = [&](nn::ComputeEngine& engine, const nn::PrecisionProfile& prof) { scan_prof = prof; - // M1(docs/todo/17 §4.1):库外不再直构 Tensor——scan 输入经 + // M1(docs/internal/17 §4.1):库外不再直构 Tensor——scan 输入经 // 引擎创建(出生绑定与本段 dry-run 使用的 engine 一致)。 const auto scan_tensor = [&](std::size_t rows, std::size_t cols) { @@ -207,7 +207,7 @@ int main(int argc, char* argv[]) } } - // ── 算子融合二期(docs/todo/02-operator-fusion.md):matmul 参与 IR 融合 ── + // ── 算子融合二期(docs/internal/02-operator-fusion.md):matmul 参与 IR 融合 ── // 结构 = Layer 内 dsl::matmul(A,B)+bias+relu 折叠后的派生物: // 前置 matmul 段(MatmulSpec)+ 尾逐元素链(Add + Max)。 // 这里直接构造折叠后的结构并登记(与 dsl::compute 登记 spec 是同一机制), @@ -242,7 +242,7 @@ int main(int argc, char* argv[]) } } - // ── 算子融合二期(docs/todo/02-operator-fusion.md S5):matmul+归约组合(注意力结构) + // ── 算子融合二期(docs/internal/02-operator-fusion.md S5):matmul+归约组合(注意力结构) // bmm_reduce / bmm_denom 的 IR 等价物:matmul 段被归约指令消费, // 不物化 (M,N) 得分矩阵(kernel 内联点积重算)。结构不依赖形状。 // Q (M,K),K 存储 (N,K)(transB=1):QK^T = matmul(Q, K, transB) @@ -343,7 +343,7 @@ int main(int argc, char* argv[]) attn_ad.set_doc_ids(doc_ids); run_csa(attn_ad); } - // GQA(docs/todo/22 §3.2 的 P2):K/V_t 走 **HeadGroup 视图** + // GQA(docs/internal/22 §3.2 的 P2):K/V_t 走 **HeadGroup 视图** // (头分组比是运行期 vp 参数、**不进 key** → 登记一次覆盖任意 n_rep, // 但"视图种类"本身是结构 → 必须是独立一条,否则 GPU 闭合世界对 // GQA 的 fold 直接硬报错)。heads=2 / n_head_kv=1 → ratio 2。 @@ -820,7 +820,7 @@ int main(int argc, char* argv[]) // 出现 → **只由这一条用例产出**;漏掉就是 GPU 闭合世界硬报错 // (AGENTS §7:dry-run/模型 pass 是结构的主要来源)。 // 结构不依赖精度(prof 只决定占位张量精度)→ 与其它用例同处一跑。 - // 见 docs/todo/21-quantized-weights.md §7 第 4 项。 + // 见 docs/internal/21-quantized-weights.md §7 第 4 项。 { nn::PrecisionProfile t1 = prof; t1.param = nn::Precision::T1_58; From 62affb8be831e00609dca036aee169008d705d55 Mon Sep 17 00:00:00 2001 From: EthanPeng-2048 Date: Fri, 30 Oct 2026 23:25:30 +0800 Subject: [PATCH 4/4] =?UTF-8?q?chore:=20=E7=A7=BB=E9=99=A4=20bench/doc=5Fa?= =?UTF-8?q?lign=5Faudit.ps1=20=E4=B8=8E=20.template/=20=E5=9B=BE=E6=A0=87?= =?UTF-8?q?=E5=8E=9F=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 文档审计唯一实现 = scripts/doc_audit.py(ps1 的 A–D/F 类已移植并扩展 E/G/H 三类;当前口径引用同步为 doc_audit.py,历史台账/实跑记录保持原样) - ps1 加入 doc_audit.py 的历史白名单(历史文档提及不再报警) - .template/ 的图标 zip 交付原件移除(README 实际引用的解压版在 assets/, 已随上一提交入库) --- bench/doc_align_audit.ps1 | 261 -------------------- docs/contributors/documentation-standard.md | 3 +- docs/internal/18-roadmap.md | 6 +- docs/internal/19-unified-dataset.md | 2 +- docs/internal/27-execution-plan.md | 2 +- scripts/doc_audit.py | 8 +- 6 files changed, 11 insertions(+), 271 deletions(-) delete mode 100644 bench/doc_align_audit.ps1 diff --git a/bench/doc_align_audit.ps1 b/bench/doc_align_audit.ps1 deleted file mode 100644 index 10ac7ea..0000000 --- a/bench/doc_align_audit.ps1 +++ /dev/null @@ -1,261 +0,0 @@ -# doc_align_audit.ps1 — 文档↔代码对齐审计(只读) -# 检查三类不一致: -# [A] 文档引用的文件是否存在:① 反引号里的 *.hpp/*.cpp/*.comp/*.py 文件名; -# ② markdown 链接目标 `](路径)`(相对路径按文档所在目录解析;外部 URL / 锚点 -# `#…` / `codex:` 跳过)——② 是本轮(2026-10-15,E8)补强项 -# [B] 文档中是否仍引用已删除的符号 -# [C] 数字型断言(virtual 数 / ctest 目标数 / N/N 绿)是否与实测一致 -param( - [string]$Root = (Split-Path -Parent $PSScriptRoot), - [int]$MaxPerFile = 12 -) - -$ErrorActionPreference = 'Stop' -Set-Location $Root - -# ── 实测事实 ──────────────────────────────────────────────────────────── -$fact = [ordered]@{} -$fact['virtual_in_engine'] = (Select-String -Path 'include\neuralnet.cpp\compute_engine.hpp' -Pattern '\bvirtual\b').Count -$fact['ctest_targets'] = (Select-String -Path 'CMakeLists.txt' -Pattern 'list\(APPEND NN_TEST_TARGETS').Count -$fact['headers'] = (Get-ChildItem -Recurse include -Filter *.hpp).Count -$fact['shaders'] = (Get-ChildItem shaders -Filter *.comp).Count -Write-Host '=== 实测事实 ===' -foreach ($k in $fact.Keys) { Write-Host (" {0,-18} {1}" -f $k, $fact[$k]) } -Write-Host '' - -# 全仓真实文件名索引(include/src/shaders/tools + build 生成物 + 各目录 python) -$realFiles = @{} -Get-ChildItem -Recurse -Include *.hpp,*.cpp,*.comp,*.py -File -Path include,src,shaders,tools,bench,scripts,compare_with_torch -ErrorAction SilentlyContinue | - ForEach-Object { $realFiles[$_.Name] = $true } -Get-ChildItem -Recurse -Include *.hpp -File -Path build\generated -ErrorAction SilentlyContinue | - ForEach-Object { $realFiles[$_.Name] = $true } -Get-ChildItem -File -Filter *.py | ForEach-Object { $realFiles[$_.Name] = $true } - -# 历史白名单:这些文件**已被有意删除**,历史文档中提及属正常(勿再报警) -$historicalFiles = @('compute_cuda_engine.hpp','compute_cuda_backend.hpp','cuda_kernels.h','cuda_kernels.cu', - 'expr_graph.hpp','cpu_emitter.hpp','algebra_expr.hpp','algebra_compute.hpp', - 'perf_smoke.cpp','mnist_common.hpp','train_bytebpe.py', - 'expr_fuse_test.cpp','expr_graph_test.cpp','expr_spec_test.cpp','matmul_fusion_test.cpp', - 'offload_primitive_test.cpp','offload_test.cpp','broadcast.comp', - 'compute_precision_engine.hpp', # P-1 随 PrecisionEngine 下沉删除 - 'compute_layer_zipt.hpp','domain_zipt.hpp', # ZiPT 移除(分支 legacy/zipt) - 'ternary_deploy.hpp') # NNQT 独立部署格式,随库级清理(docs/internal/23)删除 - -# ── [A] 文档引用的文件是否存在 ────────────────────────────────────────── -Write-Host '=== [A] 文档引用但仓库中不存在的文件 ===' -# docs/history/history.md 是全仓唯一的历史归档,按设计记录已删符号/已删文件 → 整体豁免 -$docs = @('AGENTS.md','README.md') + - (Get-ChildItem -Recurse docs -Filter *.md | - Where-Object { $_.Name -ne 'history.md' } | - ForEach-Object { $_.FullName }) -$missCount = 0 -$histCount = 0 -foreach ($d in $docs) { - $lines = Get-Content $d - $hits = @() - for ($i = 0; $i -lt $lines.Count; $i++) { - foreach ($m in [regex]::Matches($lines[$i], '`([A-Za-z0-9_]+\.(hpp|cpp|comp|py))`')) { - $name = $m.Groups[1].Value - if (-not $realFiles.ContainsKey($name)) { - if ($historicalFiles -contains $name) { $histCount++; continue } - $rel = if ($d -match '^[A-Z]:') { Resolve-Path -Relative $d } else { $d } - $hits += (" {0}:{1} {2}" -f $rel, ($i + 1), $name) - } - } - } - if ($hits.Count -gt 0) { - $missCount += $hits.Count - Write-Host (" -- {0}({1} 处,示前 {2})" -f $d, $hits.Count, [Math]::Min($MaxPerFile, $hits.Count)) - $hits | Select-Object -First $MaxPerFile | ForEach-Object { Write-Host $_ } - } -} -# [A]② markdown 链接目标:相对路径按**文档所在目录**解析(跨目录引用写 `../…`)。 -# 豁免:外部 URL / `mailto:` / 纯锚点 `#…` / `codex:` 深链。检查数写入台账(链接目标数 -# 会随文档增长,只作披露;**可行动 = 找不到**)。 -$linkMiss = 0 -$linkChecked = 0 -foreach ($d in $docs) { - $dir = Split-Path -Parent $d - if (-not $dir) { $dir = '.' } - $lines = Get-Content $d - $hits = @() - for ($i = 0; $i -lt $lines.Count; $i++) { - # 先剥掉行内代码段(`…`):文档里常把 `](路径)` 作为**示例**写在反引号内, - # 不是真链接 —— 不剥会误报(实测 18-roadmap 的 E8 行即此类)。 - $text = $lines[$i] -replace '`[^`]*`', '' - foreach ($m in [regex]::Matches($text, '\]\(([^)\s]+)\)')) { - $t = $m.Groups[1].Value - if ($t -match '^(https?:|mailto:|codex:|#)') { continue } - $p = ($t -split '#')[0] - if (-not $p) { continue } - $linkChecked++ - if (-not (Test-Path -LiteralPath (Join-Path $dir $p))) { - $hits += (" {0}:{1} {2}" -f $d, ($i + 1), $t) - } - } - } - if ($hits.Count -gt 0) { - $linkMiss += $hits.Count - Write-Host (" -- {0}({1} 处,示前 {2})" -f $d, $hits.Count, [Math]::Min($MaxPerFile, $hits.Count)) - $hits | Select-Object -First $MaxPerFile | ForEach-Object { Write-Host $_ } - } -} -Write-Host (" [A] 可行动 {0} 处 = 反引号文件名 {1} 处 + markdown 链接目标 {2} 处(检查了 {3} 个链接目标);历史白名单跳过 {4} 处(已删文件的历史提及)" -f ($missCount + $linkMiss), $missCount, $linkMiss, $linkChecked, $histCount) -Write-Host '' - -# ── [B] 已删除符号的文档残留 ──────────────────────────────────────────── -Write-Host '=== [B] 已删除符号的文档残留 ===' -$dead = @('axpy_inplace','broadcast_row_inplace','broadcast_col_inplace','elementwise_unary', - 'elementwise_binary_scalar','elementwise_select_scalar_cond','offload_store','offload_load', - 'multiply_transposed_add_to','compute::apply','algebra_expr','algebra_compute', - 'set_offload_enabled','UnaryOp','CompareOp') -$docLines = @{} # 惰性缓存:按文件读一次,供跨行否定窗口判断复用 -foreach ($s in $dead) { - # 命中行(及其后 2 行,覆盖跨行的"……均不存在"陈述)若是在说明该符号不存在/ - # 已删除/已归档,属当前事实而非残留 - $all = @(Select-String -Path @($docs) -Pattern $s -SimpleMatch -ErrorAction SilentlyContinue) - $negPat = '不存在|已删除|已移除|没有|无此|已归档|归档于|历史' - $negCount = 0 - $remain = @() - foreach ($m in $all) { - if (-not $docLines.ContainsKey($m.Path)) { $docLines[$m.Path] = @(Get-Content $m.Path) } - $lines = $docLines[$m.Path] - $win = @($m.Line) - foreach ($k in 1, 2) { - $idx = $m.LineNumber - 1 + $k - if ($idx -lt $lines.Count) { $win += $lines[$idx] } - } - if (($win -join ' ') -match $negPat) { $negCount++ } else { $remain += $m } - } - if ($remain.Count -gt 0) { - Write-Host (" -- {0}: {1} 处" -f $s, $remain.Count) - $remain | Select-Object -First $MaxPerFile | ForEach-Object { - Write-Host (" {0}:{1}: {2}" -f (Split-Path $_.Path -Leaf), $_.LineNumber, $_.Line.Trim().Substring(0,[Math]::Min(78,$_.Line.Trim().Length))) - } - } - if ($negCount -gt 0) { Write-Host (" (另有 {0} 处为「该符号不存在/已删除」的当前事实陈述,跳过)" -f $negCount) } -} -Write-Host '' - -# ── [C] 数字型断言 ────────────────────────────────────────────────────── -Write-Host '=== [C] 数字型断言(需与实测核对)===' -Select-String -Path @($docs) -Pattern '\d+ 个 virtual|\d+ 个目标|ctest \d+|\d+/\d+ *(绿|全绿|通过|测试)|目标(\d+ 个)' -ErrorAction SilentlyContinue | - ForEach-Object { " {0}:{1}: {2}" -f (Split-Path $_.Path -Leaf), $_.LineNumber, $_.Line.Trim().Substring(0,[Math]::Min(88,$_.Line.Trim().Length)) } -Write-Host '' - -# ── 代码侧符号索引(include + src + tools + python + CMake)────────────── -$codeText = ((Get-ChildItem -Recurse -Include *.hpp,*.cpp -File -Path include,src,tools | - ForEach-Object { Get-Content $_.FullName -Raw }) -join "`n") -$pyText = ((Get-ChildItem -Recurse -Include *.py -File -Path . | - Where-Object { $_.FullName -notmatch '\\build\\|\\.venv\\|node_modules' } | - ForEach-Object { Get-Content $_.FullName -Raw }) -join "`n") -$codeText = $codeText + "`n" + $pyText -$cmText = Get-Content CMakeLists.txt -Raw - -# 外部工具参数白名单(非本项目 CLI:ctest/cmake/glslc/torch 脚本等) -$externalFlags = @('--test-dir','--parallel','--target-env','--dtype','--adam-eps','--device', - '--task','--compress','--list','--image','--list-backends', - '--summary', # vulkaninfo(16 §复现命令) - '--include', # grep(16 §复现命令) - # cmake / ctest / cpack 自带选项(文档复现命令用,非本仓 CLI) - '--preset','--workflow','--list-presets','--output-on-failure') -# 已在文档中明确标注"已移除"的历史参数 -# --memory-tokens / --window : ZiPT(AttnZip) 专用,随 ZiPT 移除 -# --osc-guard/-window/-threshold : mnist_train 的幽灵选项(帮助声明、解析不存在),已清除 -# --vocab/--test-file/--loss-scope/--no-cache(text_train 上): 随统一数据集 -# (19 号设计阶段二)已移除——词表/掩码/test 子集随 .nndataset -# (--vocab 仍存在于 text_infer/tokenizer_infer,此处只登记 text_train 语境的提及) -$removedFlags = @('--cuda','--tdr-retry','--max-tdr-retries', - '--memory-tokens','--window', - '--osc-guard','--osc-window','--osc-threshold', - '--no-cache','--test-file','--loss-scope', - # --export-deploy : NNQT 独立部署格式的导出口,随库级清理 - # (docs/internal/23,2026-10-11)删除 → 文件角色 - # .nnmodel/.nnckpt 取代 - '--export-deploy') -# 已在 26 §8.B.7 明确标注“计划中、默认关闭、尚未实现”的参数。它们不得出现在 -# 当前 --help / 解析分支里;实现后应移出本表(届时代码侧会自然命中)。 -$plannedFlags = @('--stochastic-rounding','--unit-scaling') - -# ── [D] 文档里的 CLI 参数是否存在 ──────────────────────────────────────── -Write-Host '=== [D] 文档引用但代码中不存在的 CLI 参数(--flag)===' -$flags = @{} -foreach ($d in $docs) { - $lines = Get-Content $d - for ($i = 0; $i -lt $lines.Count; $i++) { - foreach ($m in [regex]::Matches($lines[$i], '(? **2026-10-16:GUI 多轮对话闭环(P0-5 尾项)已完成**——按 §8 约定从本表删除。 > 落地形态 = `Tokenizer::chat_prompt`(唯一 prompt 构建)+ `--turn`/`--reply-out`/`--system` diff --git a/scripts/doc_audit.py b/scripts/doc_audit.py index 5cbe9c6..52c86a8 100644 --- a/scripts/doc_audit.py +++ b/scripts/doc_audit.py @@ -1,9 +1,10 @@ #!/usr/bin/env python3 """doc_audit.py — 文档↔代码对齐审计 + 文档规范检查(只读,跨平台) -规范正文:docs/contributors/documentation-standard.md §5。 -移植并扩展 bench/doc_align_audit.ps1 的 A–D/F 类检查;新增 E 类(头部模板/状态词/ -索引登记)与 G 类(代码示例清单)。ps1 保留至 Windows 侧迁移完成,口径以规范为准。 +规范正文:docs/contributors/documentation-standard.md §5——本文档审计的**唯一实现**。 +八类检查:A 文件/链接、B 已删符号残留、C 数字断言披露、D CLI 参数、E 头部模板/状态词/ +索引登记、F nn:: 符号与测试名、G 代码示例清单(--report 生成人工复核报告)、 +H 历史性记载禁令。 用法: python scripts/doc_audit.py # 全量检查;有 FAIL 时 exit 1 @@ -29,6 +30,7 @@ 'compute_layer_zipt.hpp', 'domain_zipt.hpp', # ZiPT 移除(分支 legacy/zipt) 'ternary_deploy.hpp', # NNQT 独立部署格式,随库级清理(internal/23)删除 '08-object-lifetimes.md', # 2026-11 文档重构删除的转发页(真源 = 07-engine-ownership.md) + 'doc_align_audit.ps1', # 文档审计由 scripts/doc_audit.py 承担(口径见文档规范 §5) ] # [B] 已删除符号(命中行若带"不存在/已删除"等否定语境则跳过)