Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
# 本文件是「目标风格」的机器可读定义,与 docs/todo/10-development-standards.md §8
# 「代码风格规范」一一对应。它是**增量**工具,不是整仓重排脚本:
# 本文件是代码风格的机器可读定义,与 docs/contributors/cpp-standards.md §8
# 「代码风格规范」一一对应。**全仓已于 2026-10-31 按本配置统一格式化**(提交 5854b98,
# 5 个子仓同步),因此现有代码即基线,新增/改动代码的增量格式化不应再产生大 diff:
#
# ✅ 推荐:对新文件、或你正在改的代码用 `git clang-format`(只格式化改动行)
# ⚠ 存量文件保留手工排版(对齐的中文注释块、按语义分组的续行),对**整个**文件
# 跑 clang-format 会产生大 diff —— 实测**即便用本文件**,全仓 150 个源文件整体
# 格式化仍会改约 **41%** 的行(`include/` 单独看约 44%);主因是续行折行策略与
# `if (c) stmt;` 单行/两行之争(两种写法仓内各约一半)。
# 整仓重排**不在本仓的维护范围**;提交时请勿顺手格式化未改动的大段代码。
# ✅ 只用 `git clang-format` 格式化**你这次改动**的行;
# ⚠ 不要在功能 PR 里顺手格式化无关文件(会让 review 与 git blame 失真)。
#
# 与仓内实际风格的取舍(实测依据,见 docs/history/history.md 的「代码风格」条):
# 与仓内风格的取舍(实测依据,见 docs/history/history.md 的「代码风格」条):
# · 大括号:函数/类型/控制语句一律另起一行(Allman)——仓内主流写法;
# · 顶层 namespace 内容不缩进(NamespaceIndentation: None)——仓内主流;
# 少数历史文件(algebra_matrix.hpp / core_threadpool.hpp / cli/*.hpp)带缩进,
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ dist/

# ==================== Editors ====================
.vscode/
.cache/
.idea/
*.swp
*.swo
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ cmake -B build -G Ninja -DNN_ENABLE_TESTS=ON && cmake --build build && ctest --t
| 加/改 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/contributors/cpp-standards.md` §8 |
| 代码风格(机器可读) | `.clang-format`(全仓已于 2026-10-31 按本配置统一格式化,现有代码即基线;改动时用 `git clang-format` 只格式化自己的改动行)+ `.editorconfig` + `.gitattributes`(全仓 **LF**);规则文本见 `docs/contributors/cpp-standards.md` §8 |

## 4. 分层架构(L0→L5,严格单向依赖,上层只依赖下层公有接口)

Expand Down
10 changes: 9 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ cmake_minimum_required(VERSION 3.30)

# VERSION 以 git tag 为准(本仓无 CONFIGURE_FILE 消费该字段,
# 它只是元数据——发版时同步到最新 tag,实际版本以 git tag / gh release 为准)
project(neuralnet.cpp VERSION 1.13.0 LANGUAGES CXX)
project(neuralnet.cpp VERSION 1.14.1 LANGUAGES CXX)

# ── IDE / clangd:导出 compile_commands.json(仅顶层工程时)───────────────
# include 路径(include/ + extern/*/include + build/generated)全部来自
Expand Down Expand Up @@ -120,6 +120,14 @@ if(MSVC)
add_link_options(/STACK:8388608)
else()
add_compile_options(-fno-exceptions -Wall -Wextra -Wpedantic -Werror)
# GCC 15.2 在 -O3 + PCH 下对 std::optional / std::unique_ptr 的**内联析构**
# 报 -Wmaybe-uninitialized 假阳性(诊断里的内存位置全是 <unknown>;实测
# src/layer_lifetime_test.cpp 的 `unique_ptr<nn::Model>` 析构路径,成员已由
# make_unique/默认初始化,无真实未初始化读取)。Clang 不产生该告警,因此
# 只对 GNU 关闭此子告警;-Wuninitialized 保持开启。
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Wno-maybe-uninitialized)
endif()
endif()

# Windows 上的 clang++(GNU-like 驱动)不是 CMake 的 MSVC 分支,但链接仍走
Expand Down
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,16 @@ NN_VULKAN_DEVICE=850M ./build/test/bitnet_struct_test --gpu # 显式选卡
(命名 / 缩进 4 空格 / include 顺序 / 注释语言),机器可读版本是同目录的 [`.clang-format`](.clang-format)。

```bash
# ✅ 推荐:只格式化**你这次改动**的行(历史文件是手工排版的,整文件格式化会产生大 diff)
# ✅ 推荐:只格式化**你这次改动**的行
git clang-format # 对暂存区相对 HEAD 的改动
git clang-format --diff # 只看会改什么

# 单文件(新文件随意;旧文件请确认 diff 可接受)
# 单文件(新文件随意;旧文件整体跑通常已无 diff)
clang-format -i path/to/new_file.hpp
```

> `.clang-format` 是**目标风格**,不是整仓重排脚本:对现有文件整体跑它约 4 成行会变
> (仓内 `if (c) stmt;` 单行与两行两种写法都大量存在)。**请不要在功能 PR 里顺手格式化无关文件。**
> 全仓已于 2026-10-31 按 `.clang-format` **统一格式化**(提交 `5854b98`,子仓同步),
> 现有代码即基线;新增/改动代码用上面的增量方式保持一致即可。**请不要在功能 PR 里顺手格式化无关文件。**
> 缩进/行尾/编码这类字符级约定由 [`.editorconfig`](.editorconfig) 与 [`.gitattributes`](.gitattributes) 统一(**全仓 LF**)。

### 3.3 提交信息
Expand Down
9 changes: 8 additions & 1 deletion bench/gui_cli_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,15 @@ def exe_path(exe: str) -> Path:

历史上这里写死 `build/<exe>.exe`,在 Linux 上直接 FileNotFoundError ——
本门禁因此只能在 Windows 跑。按"先 .exe 后无后缀"的顺序探测。
`CMakePresets.json` 的构建把产物放在 `build/<preset>/` 下,故再遍历一层 preset 目录
(`--help` 文案与构建类型无关,取哪个 preset 都不影响本门禁的判定)。
"""
for cand in (ROOT / "build" / f"{exe}.exe", ROOT / "build" / exe):
names = (f"{exe}.exe", exe)
cands = [ROOT / "build" / n for n in names]
for sub in sorted((ROOT / "build").glob("*")):
if sub.is_dir():
cands += [sub / n for n in names]
for cand in cands:
if cand.exists():
return cand
return ROOT / "build" / f"{exe}.exe"
Expand Down
7 changes: 6 additions & 1 deletion cli_controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,12 @@ def _get_executable_path(self) -> str:
exe_path = build_dir / exe_name
if exe_path.exists():
return str(exe_path)


# preset 构建(CMakePresets.json)把产物放在 build/<preset>/ 下
for sub in sorted(build_dir.glob("*")):
if sub.is_dir() and (sub / exe_name).exists():
return str(sub / exe_name)

# 尝试在当前目录查找
current_dir = Path(__file__).parent
exe_path = current_dir / exe_name
Expand Down
19 changes: 13 additions & 6 deletions docs/contributors/cpp-standards.md
Original file line number Diff line number Diff line change
Expand Up @@ -684,20 +684,27 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)

### 8.2 格式规范

> 机器可读真源是仓库根的 [`.clang-format`](../../.clang-format)(全仓已于 2026-10-31
> 按该配置统一格式化,现有代码即基线);下面只列最常用的几条。

```cpp
// 缩进:4 个空格
if (condition) {
do_something();
// 缩进:4 个空格;行宽:100 列
// 大括号:Allman(函数 / 类型 / 控制语句一律另起一行)
void function()
{
// ...
}

// 大括号:K&R 风格
void function() {
// ...
if (condition)
{
do_something();
}

// 指针/引用:靠近类型名
int* ptr; // 推荐
const std::vector<int>& vec; // 推荐

// 注释不重排、行尾注释不对齐;include 顺序按 §8.3(工具不排序)
```

### 8.3 包含顺序
Expand Down
63 changes: 63 additions & 0 deletions docs/contributors/release-requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,3 +357,66 @@ f32 `.nnmodel` warm start 1 step:loss **7.6060**;文件 SHA-256
- 审查修复:PPO off-policy 负 advantage 梯度、GAE mask 值泄漏、policy batch 形状、
forward 失败后的具名反向状态、不可信 schema 解码上限、pipeline post-hook 状态提交;
全部加入对应 RL 用例。

---

## 10. 2026-10-31 `v1.14.0` 发布实跑记录

> 测试对象 = `main` 的发布定档提交。口径:GPU = **NVIDIA CMP 40HX / Vulkan SDK 1.4.350**;
> Windows 两树用本机 preset(`NN_ENABLE_NATIVE=ON`),WSL 两树 `NN_ENABLE_NATIVE=OFF` + `NN_ENABLE_GPU=OFF`;
> 构建一律 `-j32`(本机 32 核)。

### 10.1 完整 ctest(Release / Debug)

| 树 | 构建 | 完整 ctest |
|---|---|---|
| Windows clang 23.1 + MSVC STL / **Release** / Vulkan | 160/160 步 | **73 注册 → 72 pass + 1 skip + 0 fail**(84.3 s,`ctest -j16`);skip = `scan_bitwise_test` |
| Windows clang 23.1 + MSVC STL / **Debug** / Vulkan | 160/160 步 | **73 注册 → 73 pass + 0 skip + 0 fail**(434.6 s,顺序) |

> Debug 必须顺序执行:`-j16` 并行时 `f16_precision_test` 被 GPU 争用拖到 40 min+(单跑 50.6 s 通过);
> Release 并行无此现象。v1.13.0 记录的既有失败(`t1_58_test` / `write_epoch_test`)本版全部 Passed。

### 10.2 真实语料端到端训练(40HX)

TinyStories 前 20,000 条 → **20,000 docs / 4,241,421 tokens / 8,208 词 / 66,273 个 seq64 窗口**;
GPT `d_model=64 / heads=4 / layers=2 / d_ff=128 / seq_len=64`,`--batch-size 8 --accum-steps 2`,20 step:

| 配方 | loss(step 20) | 备注 |
|---|---|---|
| f32 | 8.7566 → **7.6110** | 1.2 s,无 NaN/冻结 |
| `--f16` | 8.7620 → **7.6741** | 0.4 s |
| `--t1_58` | 8.9024 → **8.1851** | 0.5 s |

- 断点续训:`--save-interval 5` 的 step20 `.nnckpt` → `--resume` 续 3 步,loss
**7.6525 → 7.5733 → 7.5231**;日志确认优化器 76 张量、`t=20` 恢复;
- warm start:f32 `.nnmodel` 续 1 步 loss 7.6361,SHA-256 `19A26875…` → `77968371…`(参数确实移动)。

### 10.3 四组「编译器 × 标准库」

| 配置 | 结果 |
|---|---|
| Windows clang 23.1 + **MSVC STL** / Release / Vulkan | 见 §10.1(72 pass + 1 skip) |
| Windows clang 23.1 + **MSVC STL** / Debug / Vulkan | 见 §10.1(73 pass) |
| WSL g++ 15.2 + **libstdc++** / Release / CPU-only | 140/140 步;**71 注册 → 59 pass + 12 skip + 0 fail**(11.5 s) |
| WSL clang 24.0 + **libc++** / Release / CPU-only | 140/140 步;**71 注册 → 59 pass + 12 skip + 0 fail**(10.3 s) |

> `cl.exe + MSVC STL` 一组本机无 MSVC 工具链(`cl.exe` 不在 PATH、VS 未安装),**未在本机复跑**,
> 沿用 CI 口径,记为已知覆盖缺口。WSL 的 12 个 GPU/offload 用例按 77 skip(无 Vulkan)。
>
> 本轮修掉的两个**纯 CPU 构建**真实缺陷(`dev` 提交 `a49311d`):
> ① 无 Vulkan 时 `gpu_batch_scope_test` 的 `make_conv_model` 触发 `-Wunused-function -Werror`;
> ② GCC 15.2 在 `-O3` + PCH 下对 `std::optional/std::unique_ptr` 内联析构报
> `-Wmaybe-uninitialized` 假阳性(诊断位置均为 `<unknown>`)→ 仅对 GNU 关闭该子告警。

### 10.4 门禁与独立发布审查

- `bench/doc_inventory.ps1`:**PASS**(`L2-VIOLATIONS: 0`、`HANDWRITTEN-RESIDUE: 0`、`TERMINATING-CALLS: 0`);
- `bench/audit_dangling.ps1`:exit 0;`bench/gui_cli_audit.py`:**PASS,可行动 0**
(修复了 preset 构建产物定位:`build/<preset>/`);
- 独立只读审查(`v1.13.0..dev`):**P0 无**;格式化提交按 token 流比对 182 个 C++ 文件 **0 语义差异**;
`8406b39` 的 `NN_TRY/NN_FAIL` 改写与宏展开逐字等价;
- **P1(2,记入 release note §5 已知限制)**:
① 二次续训的 Adam `t` 退化(`make_train_state` 用 `session_.step_count()` 写 `optimizer_step`);
② `TrainingSession::resume` 先覆盖权重后 `verify_resume`(错误路径半提交);
- **P2(4)**:步进驱动 `max_steps==0` 空跑成功返回、`save_checkpoint` 覆盖 `global_step` 的口径分歧、
`InferenceScope::error()` 可解引用空 optional、`5854b98` 夹带 `extern/base` 指针且提交说明与实际不符。
15 changes: 15 additions & 0 deletions docs/history/history.md
Original file line number Diff line number Diff line change
Expand Up @@ -2178,6 +2178,21 @@ GPU 后端 / GPU 引擎头文件「历史状态类注释」摘录。整改原则
- 验收:`.clang-format` 能被 clang-format 23 解析(`--style=file` 退出码 0);`.gitattributes`
落地后 `git status` 无重规范化噪声(工作树本来就全 LF)。

## 全仓 clang-format 基线化(2026-10-31)

- 类型:演进记录(**推翻**上文 2026-10-11「整仓 clang-format 重排被否决」的结论)
- 内容:`5854b98` 对全仓 187 个 `*.cpp` / `*.hpp` / `*.inc` 跑 `clang-format -i`(配置即
`.clang-format`,未改任何取值),净改动约 1.9 万行;随后 5 个子仓各自同配置格式化并打
tag(base `v1.0.2`、dataset `v1.0.1`、kvrecord `v1.1.1`、threadpool `v1.0.1`、
tokenizer `v1.0.1`),门面 `c94f315` bump 指针。
- 为什么推翻旧结论:旧结论的前提是「存量手工排版是风格基线,整仓重排会制造 41% 的行级
噪声」;维护者决定把噪声**一次性付清**,此后新改动不再需要与两种写法共存,`git clang-format`
的增量格式化也不再产生大 diff。
- 代价(已知,不再重复申诉):`git blame` 在该提交处断代,历史行归属需 `-w --follow` 或
`git blame <5854b98^> -- path` 回看;`src/` 测试与 4 个 `compute_vk_backend_*.inc` 同批被重排。
- 验收:Release 全量 ctest **73 注册 → 72 pass + 1 skip + 0 fail**(skip = `scan_bitwise_test`,
Windows 平台口径),证明格式化未改语义(宏续行、字符串拼接、4 个 `.inc` 表均编译通过)。

---

# AGENTS.md
Expand Down
1 change: 1 addition & 0 deletions docs/release-notes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

| 版本 | 主题 |
|---|---|
| [v1.14.0](v1.14.0.md) | 训练骨架(`TrainState`/`BatchSource`/`RunDriver`)+ 开放规格(`ModelSpecBase`)+ `Embedding`/`CrossAttention` + 宿主桥公开 API + 全仓格式化基线 |
| [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 计数语义统一 + 梯度累积归一化修复 |
Expand Down
Loading
Loading