First answer: what does each library own?
P10 computes values, TPX records how values can produce gradients, Stax captures operations for graph experiments, and NN organizes models, losses, and optimizers. They are not four competing APIs; they represent four different kinds of change.
When storage, devices, gradients, graph capture, and network state all live in one Tensor abstraction, it becomes difficult to answer where an operation actually runs. TensorPlay keeps those questions visible by giving each concern a smaller boundary.
P10: compute foundation
P10 focuses on tensor computation and contains no autograd strategy. Tensor is a lightweight handle while TensorImpl carries shape, stride, dtype, device, and storage information. CPU, CUDA, and other backends can provide concrete kernels behind that interface.
This boundary lets a numerical program use P10 directly and lets a hardware experiment start from TensorImpl, Dispatcher, memory layout, and kernel execution instead of loading the whole training stack.
- Own Tensor, TensorImpl, storage, shape, stride, and device state.
- Route operator requests to kernels selected by device and dtype.
- Keep gradient recording out of computation that does not need it.
TPX: differentiation extension
TPX wraps P10 tensors and adds requires_grad, grad, and grad_fn state. It observes operations executed by P10, records inputs and outputs, and builds the dynamic graph needed for backward.
Autograd is therefore an optional observation layer rather than a requirement for every tensor operation. With tracing disabled, the forward path can stay close to pure P10; with tracing enabled, TPX adds the graph state needed for differentiation.
Stax: performance engine
Stax captures P10 operations as an explicit sequence that can be analyzed and transformed. It is the place to experiment with operator fusion, memory reuse, static graphs, and JIT-style acceleration without changing P10 semantics.
Keeping graph optimization separate makes comparisons possible: run the same operation graph before and after a transformation, then inspect outputs, kernels, memory behavior, and timing.
NN: organize models without hiding computation
NN provides Linear, Conv, Adam, SGD, loss functions, and modular network components over P10 and TPX. Familiar Python conventions are an entry point, not the endpoint: a high-level call can still be traced down to tensor operations, gradient nodes, and backend kernels.
That makes NN useful for building a model quickly while leaving P10 and TPX available for debugging and research. A problem in a high-level module can be followed back to an operator and its storage rather than diagnosed from outside a black box.
Performance and engineering conclusions: write only what the repo proves
A readable architecture does not prove that TensorPlay is faster for every model, device, and dtype. The repository does provide reproducible comparison entry points, but a performance claim must come from an actual run with the same hardware, inputs, warmup, and repeat count.
The most direct evidence is benchmark/gemm_perf.py. It compares CPU and CUDA GEMM cases across matrix shapes and dtypes, reporting milliseconds, TFLOP/s, and the ratio. The fuller benchmark/benchmark_resnet_classification.py fixes weights, data order, and training settings, then checks logits, Top-1 predictions, p50/p95 latency, throughput, and compile paths.
The website therefore describes TensorPlay’s certain strength as a traceable boundary and treats performance as measurable, configuration-specific evidence. That is more credible than claiming “faster” without a checked-in result artifact.
- Performance evidence: report measured milliseconds, throughput, and TensorPlay / Torch ratios.
- Correctness evidence: compare logit error, prediction identity, and label identity from the same weights.
- Architecture evidence: continue from TensorImpl, Dispatcher, GradFn, and kernels into source and tests.
Current checkout baseline: one auditable CPU reading
To make the performance discussion concrete, we ran benchmark/gemm_perf.py cpu from the WSL checkout on August 25, 2026: AMD Ryzen 7 8845HS, 16 logical CPUs, Torch 2.13.0+cpu, and TensorPlay 1.0.0rc0. The script used its default five warmup iterations and twenty timed iterations.
The two completed FP32 GEMM readings were: 2048³, Torch 52.096 ms versus TensorPlay 44.261 ms, a 1.18x Torch/TP elapsed-time ratio; and 512³, Torch 0.993 ms versus TensorPlay 0.926 ms, a 1.07x ratio. This shows a measurable difference for these two CPU configurations, not a universal advantage across CUDA, FP64, training throughput, or every model.
CUDA was unavailable in this environment, and the ResNet comparison did not produce a complete result because test/data is absent from the checkout. Treat these numbers as a reproducible CPU baseline rather than a final leaderboard; future releases should record hardware, commit, and the complete JSON result together.
One forward pass through four layers
For a matrix multiplication inside a Linear layer, NN organizes parameters and calls the layer, TPX decides whether to record the operation, P10 creates the tensor operation, Dispatcher selects a CPU or CUDA kernel, and Stax can later capture the operation for graph optimization.
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 ruleHow to verify the architecture
- Run the same input with requires_grad disabled and enabled, then compare values and execution state.
- Run an operator on CPU and CUDA and inspect its DispatchKey, shape, dtype, and error tolerance.
- Record a short operation sequence and inspect its graph nodes, GradFn objects, and backward order.
- Compare optimized and ordinary execution by output, memory behavior, and timing.
