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
48 changes: 31 additions & 17 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,25 +90,20 @@ option(NN_ENABLE_TESTS "Build test/verification executables" OFF)
# 收集实际构建的目标,供 GPU/CUDA 统一启用(避免引用未定义目标)
set(NN_APP_TARGETS "")
set(NN_TEST_TARGETS "")
set(NN_BENCH_TARGETS "") # 性能基准(仅测试构建,手工运行,不注册 ctest)

# ── MNIST 目标 ──────────────────────────────────────────────────────────────
# ── MNIST 目标(标准构建核心应用) ───────────────────────────────────────
nn_add_executable(mnist_train src/mnist_train.cpp)
nn_add_executable(mnist_infer src/mnist_infer.cpp)
nn_add_executable(mnist_bench src/mnist_bench.cpp)
list(APPEND NN_APP_TARGETS mnist_train mnist_infer mnist_bench)
list(APPEND NN_APP_TARGETS mnist_train mnist_infer)

# ── 文本目标(GPT 训练/推理 + BPE 分词器训练/推理) ───────────────────
# ── 文本目标(GPT 训练/推理 + BPE 分词器训练/推理,标准构建核心应用) ──
nn_add_executable(text_train src/text_train.cpp)
nn_add_executable(text_infer src/text_infer.cpp)
nn_add_executable(tokenizer_train src/tokenizer_train.cpp)
nn_add_executable(tokenizer_infer src/tokenizer_infer.cpp)
list(APPEND NN_APP_TARGETS text_train text_infer tokenizer_train tokenizer_infer)

# ── 计算性能基准工具 ─────────────────────────────────────────────────────
nn_add_executable(compute_bench src/compute_bench.cpp)
nn_add_executable(bench_thresholds src/bench_thresholds.cpp)
list(APPEND NN_APP_TARGETS compute_bench bench_thresholds)

# ── 测试 / 验证目标(默认关闭,NN_ENABLE_TESTS=ON 时构建)─────────────
if(NN_ENABLE_TESTS)

Expand Down Expand Up @@ -176,6 +171,14 @@ if(NN_ENABLE_TESTS)
nn_add_executable(expr_opt_test src/expr_opt_test.cpp)
list(APPEND NN_TEST_TARGETS expr_opt_test)

# ── 图 IR + 融合分析测试(IR-C:expr_graph.hpp 纯函数,无 GPU) ─────
nn_add_executable(expr_graph_test src/expr_graph_test.cpp)
list(APPEND NN_TEST_TARGETS expr_graph_test)

# ── 图 IR 融合 GPU 端到端(IR-C:begin_expr/end_expr 融合执行) ─────
nn_add_executable(expr_fuse_test src/expr_fuse_test.cpp)
list(APPEND NN_TEST_TARGETS expr_fuse_test)

# ── ModelSpec 架构校验一致性测试(load_model 文件头 vs 模型规格比对) ────
nn_add_executable(model_spec_validation_test src/model_spec_validation_test.cpp)
list(APPEND NN_TEST_TARGETS model_spec_validation_test)
Expand All @@ -184,14 +187,6 @@ if(NN_ENABLE_TESTS)
nn_add_executable(softmax_gradcheck src/softmax_gradcheck.cpp)
list(APPEND NN_TEST_TARGETS softmax_gradcheck)

# ── 注意力反向逐级调试探针(对比暴力 Matrix 参考与引擎原语) ────────────
nn_add_executable(attn_debug src/attn_debug.cpp)
list(APPEND NN_TEST_TARGETS attn_debug)

# ── batched_matmul 原语探针(四种转置组合 vs 手工参考) ───────────────────
nn_add_executable(matmul_probe src/matmul_probe.cpp)
list(APPEND NN_TEST_TARGETS matmul_probe)

# ── M4 matmul 融合原语测试(bmm_reduce/bmm_denom/bmm_apply,CPU+GPU) ──
# ── M6 两趟式注意力反向原语测试(bmm_q_backward/bmm_kv_backward,CPU+GPU)
# ── M5 列式 softmax 融合原语测试(col_softmax_denom/col_softmax_sparse_forward)
Expand All @@ -202,6 +197,13 @@ if(NN_ENABLE_TESTS)
nn_add_executable(ce_fusion_test src/ce_fusion_test.cpp)
list(APPEND NN_TEST_TARGETS ce_fusion_test)

# ── 性能基准工具(仅测试构建;手工运行,不注册 ctest) ──
nn_add_executable(mnist_bench src/mnist_bench.cpp)
nn_add_executable(compute_bench src/compute_bench.cpp)
nn_add_executable(bench_thresholds src/bench_thresholds.cpp)
nn_add_executable(reduce_bench src/reduce_bench.cpp)
list(APPEND NN_BENCH_TARGETS mnist_bench compute_bench bench_thresholds reduce_bench)

endif()

# ── 测试目标统一处理:输出到 <默认可执行目录>/test,并注册到 ctest ──────────
Expand All @@ -220,6 +222,11 @@ if(NN_ENABLE_TESTS)
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test)
add_test(NAME ${TARGET} COMMAND ${TARGET})
endforeach()
# 基准工具输出到 test/,但不注册 ctest(手工运行)
foreach(TARGET ${NN_BENCH_TARGETS})
set_target_properties(${TARGET} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test)
endforeach()
endif()

# ── Vulkan GPU 加速(可选) ────────────────────────────────────────────────
Expand Down Expand Up @@ -307,6 +314,10 @@ if(Vulkan_FOUND)
target_link_libraries(scan_exprs PRIVATE nn_core Vulkan::Vulkan)
add_custom_command(
OUTPUT ${NN_EXPR_SCAN_BIN}
# scan_exprs 是原生可执行文件,直接写文件、不会自建目录。
# Ninja 会自动创建自定义命令的输出目录,但 Makefiles 生成器不会,
# 全新构建时 generated/ 尚未存在会写入失败(见 08-pitfalls)。
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/generated
COMMAND scan_exprs ${NN_EXPR_SCAN_BIN}
DEPENDS scan_exprs ${SCAN_SRC}
COMMENT "[GPU] Scanning Layer expressions (scan_exprs) → expr_specs.bin"
Expand All @@ -319,6 +330,8 @@ if(Vulkan_FOUND)
target_link_libraries(gen_fused PRIVATE nn_core)
add_custom_command(
OUTPUT ${NN_FUSED_REGISTRY_HPP}
# 同 scan_exprs:gen_fused 也是原生可执行文件,需先确保输出目录存在
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/generated
COMMAND gen_fused ${CMAKE_BINARY_DIR}/generated ${GLSLC} ${NN_EXPR_SCAN_BIN}
DEPENDS gen_fused ${FUSED_GEN_SRC} ${NN_EXPR_SCAN_BIN}
COMMENT "[GPU] Synthesizing fused shaders (gen_fused) → fused_registry.hpp"
Expand All @@ -339,6 +352,7 @@ if(Vulkan_FOUND)
set(NN_GPU_TARGETS ${NN_APP_TARGETS})
if(NN_ENABLE_TESTS)
list(APPEND NN_GPU_TARGETS ${NN_TEST_TARGETS})
list(APPEND NN_GPU_TARGETS ${NN_BENCH_TARGETS})
endif()

foreach(TARGET ${NN_GPU_TARGETS})
Expand Down
15 changes: 14 additions & 1 deletion cli_controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ class MnistTrainController(CLIController):
MNIST训练CLI控制器

封装mnist_train.exe,支持以下功能:
- 架构选择:MLP或Transformer
- 架构选择:MLP、Transformer 或 CNN
- 训练参数:轮数、学习率、批大小、优化器等
- 设备选择:CPU、GPU(Vulkan)、CUDA
- 模型管理:保存、恢复
Expand Down Expand Up @@ -470,6 +470,19 @@ def _format_args(self, **kwargs) -> List[str]:
if "eval_samples" in kwargs:
args.extend(["--eval-samples", self._format_arg_value(kwargs["eval_samples"])])

# CNN专用参数 (LeNet-5 风格)
if "cnn_channels" in kwargs:
args.extend(["--cnn-channels", self._format_arg_value(kwargs["cnn_channels"])])

if "cnn_kernels" in kwargs:
args.extend(["--cnn-kernels", self._format_arg_value(kwargs["cnn_kernels"])])

if "cnn_pool" in kwargs:
args.extend(["--cnn-pool", self._format_arg_value(kwargs["cnn_pool"])])

if "cnn_fc" in kwargs:
args.extend(["--cnn-fc", self._format_arg_value(kwargs["cnn_fc"])])

# 振荡检测
if "osc_guard" in kwargs:
args.extend(["--osc-guard", self._format_arg_value(kwargs["osc_guard"])])
Expand Down
17 changes: 16 additions & 1 deletion docs/11-ir-optimization.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# IR 优化(IR Optimization)—— 为融合算子引入中间表示

> 状态:**IR-A(canonicalize:DCE/常量折叠/代数化简/稳定重编号)+ IR-B(CSE + 寄存器分配 liveness)✅ 已实施(2026-08-23)**;IR-C(图 IR)/IR-D(emitter)待立项
> 状态:**IR-A(canonicalize:DCE/常量折叠/代数化简/稳定重编号)+ IR-B(CSE + 寄存器分配 liveness)✅ 已实施(2026-08-23)**;**IR-C(图 IR + begin_expr/end_expr 融合分析)✅ 已实施(基础版:逐元素链拼接,2026-08-24)**;**IR-D(后端 emitter 抽象)✅ 已实施(2026-08-24)**;IR-C 进阶(多输入 DAG 融合 / 跨 kernel 自动融合)待立项
> 关联文档:`09-operator-fusion.md`(算子融合)、`DEVELOPMENT_STANDARDS.md`(分层铁律)、`08-pitfalls-and-lessons.md`
> 目标:在**不推翻现有 AOT 闭合世界**的前提下,把 `ExprSpec` 从"直通轻量 IR"演进为带优化 pass 的规范 IR,分阶段提升开发便利与代码质量。

Expand Down Expand Up @@ -168,6 +168,21 @@ IR → GlslEmitter / CudaEmitter / CpuEmitter
> - 验证:新增 `src/expr_opt_test`(各 pass/确定性/幂等/语义等价/上限压力/归约区段互斥);`expr_dsl_test`/`expr_reduce_test`/`tensor_expr_test`/`fused_gpu_test`/`matmul_fusion_test`/`ce_fusion_test`/gradcheck 系列/gpt_checkpoint_test 全绿;MNIST + text_train(CPU/GPU、含 checkpoint-every)端到端训练正常。
> - 顺带修复预存在 bug:`text_train --save-interval 0` 触发 `(step+1) % 0` 整数除零崩溃(HEAD 亦复现,与 IR 无关)。

> **实施记录(2026-08-24,IR-C 基础版 + IR-D 已完成)**:
> - **IR-C(图 IR + 融合分析,`expr_graph.hpp`)**:
> - 图结构:`ExprGraphNode{ spec(canonical), rows/cols, vector_out, dep_of_input, input_tensors }` + `ExprGraph`;`add_node` 录制(依赖识别基于 Tensor 的 `virtual_tag`,占位 Tensor 标记前序节点输出)。
> - 融合分析 `fuse_expr_graph`:贪心按节点序,维护"当前 kernel";**逐元素链拼接**——B 以 Linear 视图消费 A 的输出且 A 无其他消费者、形状相同、均无归约 → 把 A 的指令内联进 B(A 输出寄存器作为 B 的操作数),中间结果不落显存、单 kernel dispatch。拼接后 canonicalize + validate;超限/非法 → 保守放弃融合(各自成 kernel)。归约节点/归约输出作为融合边界。
> - `Tensor` 增加 `virtual_tag`(0=非节点输出;reshape 保留)。
> - **引擎接入**:`GpuEngine::begin_expr/end_expr` 录制 → `end_expr` 融合执行(每 kernel 一次 AOT dispatch,输出写入末尾节点占位 buffer——`run_fused_gpu` 新增 `output_override` 参数复用占位);`CpuEngine` 在 `NN_EXPR_SCAN` 下 begin/end 录制并登记融合后的复合 spec(闭合世界两端一致);`dsl::compute/compute_reduce` 的 scan 分支在录制段内加入录制图。
> - 演示 Layer:`FusedChainLayer`(forward 用 begin_expr/end_expr 写三段链式表达式,GPU 融合成单 kernel,CPU 逐节点参考)。
> - **关键坑**:① 拼接时 B 的常量池必须追加在 A 之后(否则 Const 引用越界,canonicalize 产出垃圾索引);② 录制段内单个表达式**不单独登记**(被融合进复合 spec),闭合世界要求 scan dry-run 覆盖录制段内所有可能的融合组合(含 backward);③ 中间量不逃逸是融合语义约束(如 LayerNorm/RMSNorm 的 cache 中间结果不可包进 begin/end 段)。
> - 验证:新增 `src/expr_graph_test`(链融合/三节点链/独立分支/多消费者/归约边界/上限压力/确定性/依赖识别/输入顺序)+ `src/expr_fuse_test`(GPU 端到端:FusedChain forward 融合 err=0、手写录制融合 err=0、backward/未录制回归)。
> - **IR-D(emitter 抽象,`expr_emitter.hpp`)**:
> - `ExprEmitter` 纯接口(name/generate/generate_reduce)+ `emitter_registry`(按后端名选择工厂)。
> - `GlslEmitter`(glsl_gen.hpp 现有 generate_glsl/generate_glsl_reduce 封装)+ `CpuEmitter`(cpu_emitter.hpp,生成可编译 C++ 直线代码,验证"一份 IR 多后端";数值与 CPU 解释器一致)。
> - `gen_fused` 经 emitter 注册表选择后端(默认 glsl);`--list-backends` 展示可用后端(glsl/cpu)。
> - 验证:ctest 24/24 全绿(含新增 expr_graph_test / expr_fuse_test);`scan_exprs` 收集到 20 条融合表达式(含 FusedChain 融合复合 spec + backward);`fused_gpu_test` 等既有回归无回归。

**推荐**:先落地 IR-A + IR-B(约 1 周),解决真实痛点并铺好确定性地基;IR-C 视需求再投入。

---
Expand Down
Loading
Loading