TensorPlay AI
打开导航
博客

四大核心库的解耦之道

这篇文章从一次前向计算出发,解释 P10、TPX、Stax 与 NN 为什么分开,以及这种边界如何帮助学习、研究和硬件实验。

先回答:四个库分别解决什么问题?

P10 负责“把数算出来”,TPX 负责“记住怎样求梯度”,Stax 负责“把一串计算变成可以优化的图”,NN 负责“用模块和优化器组织模型”。四者不是四个彼此重复的入口,而是四种不同的变化速度。

如果所有能力都塞进一个 Tensor 类型,最容易使用的 API 会同时携带存储、设备、梯度、图捕获和网络层状态。读者很难知道一次加法究竟在哪一层发生,维护者也很难替换其中一个实现。

P10:计算基石

P10 专注张量计算,不包含自动微分策略。Tensor 作为轻量句柄,TensorImpl 保存形状、步长、数据类型、设备和存储等运行时信息;CPU、CUDA 或其他后端可以通过不同实现提供具体内核。

这个边界让纯数值程序可以直接使用 P10,也让新增硬件时不必先理解整个自动微分系统。验证 P10 时,可以从 TensorImpl、Dispatcher、内存布局和 kernel 调用一路向下跟踪。

  • 负责 Tensor、TensorImpl、存储、形状、步长和设备信息。
  • 通过 Dispatcher 将算子请求交给匹配设备与数据类型的内核。
  • 不把 GradFn 或反向传播调度强行放入每一次纯计算。

TPX:微分扩展层

TPX 组合 P10 张量并附加 requires_grad、grad 和 grad_fn 等微分状态。它监听由 P10 执行的数值操作,记录输入、输出与梯度规则,再把这些记录组织成动态图。

这意味着自动微分是可选的观察层,而不是所有计算都必须承担的内置成本。关闭追踪时,前向路径可以保持接近纯 P10;打开追踪时,TPX 才建立后向所需的 DAG。

Stax:性能引擎

Stax 的输入不是一份神秘的模型表示,而是可观察的 P10 操作序列。它可以捕获这条路径,分析算子之间的依赖,并实验算子融合、内存复用、静态图和 JIT 等优化。

把图优化单独放在 Stax 中有一个实际好处:性能实验不会改变 P10 的基础语义。对照优化前后的图、内核和输出,就可以判断优化是等价变换还是引入了新的行为。

NN:组织模型,而不是隐藏计算

NN 在 P10 与 TPX 之上提供 Linear、Conv、Adam、SGD 等模块、损失函数和优化器。它降低了构建网络的门槛,但不改变底层计算的可读路径:模块最终仍然展开为张量操作、自动微分节点和后端内核。

因此,NN 适合快速搭建模型,P10 与 TPX 适合继续向下追踪。当一个高层模块出现问题时,可以沿着同一条链路回到具体的算子和存储,而不是只能在黑盒 API 之外猜测。

性能与工程结论:只写仓库能够证明的

不能只因为架构更容易阅读,就推导出 TensorPlay 在所有模型、设备和数据类型上都更快。仓库已经提供了可复现的比较入口,但性能结论必须来自同一硬件、同一输入、同一 warmup 与重复次数下的实际运行结果。

当前最具体的证据入口是 benchmark/gemm_perf.py:它比较 CPU 与 CUDA 上不同矩阵形状和数据类型的 GEMM,输出 Torch 与 TensorPlay 的毫秒数、TFLOP/s 和比值。更完整的 benchmark/benchmark_resnet_classification.py 则固定权重、数据顺序和训练配置,检查 logits、Top-1 预测、p50/p95 延迟、吞吐以及编译路径。

所以官网把 TensorPlay 的确定性优势写成“边界清楚、路径可验证”,把性能写成“可测量、待逐配置报告”。这比先写一个没有结果文件支撑的“更快”更可信。

  • 性能证据:报告实际毫秒数、吞吐与 TensorPlay / Torch 比值,不用笼统形容词。
  • 正确性证据:同一组权重下比较 logits 误差、预测一致性和标签一致性。
  • 架构证据:从 TensorImpl、Dispatcher、GradFn 到 kernel 的源码与测试可以继续追踪。

当前仓库基线:一个可核对的 CPU 读数

为避免只描述方法,我们在 2026-08-25 的 WSL checkout 中直接运行 benchmark/gemm_perf.py cpu:AMD Ryzen 7 8845HS、16 个逻辑 CPU、Torch 2.13.0+cpu、TensorPlay 1.0.0rc0,脚本默认 warmup 5 次、计时 20 次。

两个已完成的 FP32 GEMM 读数是:2048³,Torch 52.096 ms、TensorPlay 44.261 ms,脚本的 Torch/TP 时间比为 1.18x;512³,Torch 0.993 ms、TensorPlay 0.926 ms,比值为 1.07x。它说明这两个 CPU 配置下存在可测差异,但不代表 CUDA、FP64、训练吞吐或所有模型都同样优越。

当前环境没有可用 CUDA,仓库的 ResNet 对比也因缺少 test/data 没有生成完整结果。因此这些数字应被视为可复核的 CPU 基线,而不是最终性能榜单;后续发布应随硬件、commit 和完整 JSON 一起记录。

一次前向传播如何穿过四层

以 Linear 层中的矩阵乘法为例,NN 组织参数与调用,TPX 判断是否记录梯度,P10 创建或复用张量并发起 matmul,Dispatcher 根据设备和数据类型选择 CPU 或 CUDA 内核,Stax 则可以在更高层捕获这段操作并进行图优化。

NN.Linear.forward(x)
  -> TPX records matmul when requires_grad is enabled
  -> P10 creates the tensor operation
  -> Dispatcher selects a kernel by device and dtype
  -> CPU/CUDA kernel executes
  -> TPX stores the backward rule

单向依赖带来的可替换性

NN 指向 TPX 与 P10,Stax 指向 P10;P10 不需要反向依赖 NN。各组件可以独立开发、编译、测试、升级和按需组合。新增硬件主要落在 P10,新增微分模式主要落在 TPX,新的图优化则集中在 Stax。

这种设计不是为了增加目录层级,而是为了让实验边界清楚。研究者可以替换一个 kernel,比较两个 Dispatcher 策略,或者实现一个新的 GradFn,而不必修改整个框架。

如何验证这套架构

  • 从同一个输入分别关闭和开启 requires_grad,比较前向数值与执行路径。
  • 在 CPU 与 CUDA 上运行同一算子,检查 DispatchKey、输出形状、数据类型和误差。
  • 记录一段操作后查看图节点、GradFn 和反向拓扑顺序。
  • 对启用 Stax 的版本与普通执行版本做输出、内存和耗时对照。
Ask DeepWiki