tensorstudio 1.0.0rc2__tar.gz → 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.github/workflows/ci.yml +12 -0
  2. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.github/workflows/publish-testpypi.yml +1 -0
  3. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.github/workflows/publish.yml +7 -1
  4. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/CHANGELOG.md +25 -0
  5. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/CMakeLists.txt +3 -1
  6. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/PKG-INFO +33 -28
  7. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/README.md +32 -27
  8. tensorstudio-1.0.1/benchmark_all.py +48 -0
  9. tensorstudio-1.0.1/benchmarks/__init__.py +2 -0
  10. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/benchmark_report.py +87 -23
  11. tensorstudio-1.0.1/benchmarks/results.md +311 -0
  12. tensorstudio-1.0.1/benchmarks/results_matmul.md +45 -0
  13. tensorstudio-1.0.1/benchmarks/results_reductions.md +75 -0
  14. tensorstudio-1.0.1/benchmarks/results_tensor_ops.md +285 -0
  15. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Autograde/index.md +1 -1
  16. tensorstudio-1.0.1/docs/Benchmarks/index.md +65 -0
  17. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Hardware/cpu-backend.md +4 -4
  18. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Neural Networks/training.md +1 -1
  19. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Roadmap/index.md +2 -2
  20. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Usage/serialization.md +1 -1
  21. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Usage/tensors.md +1 -1
  22. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/api.md +30 -0
  23. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/autograd.md +1 -1
  24. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/data.md +2 -2
  25. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/development.md +10 -3
  26. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/index.md +6 -9
  27. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/publishing.md +24 -8
  28. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/quickstart.md +1 -1
  29. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/serialization.md +2 -2
  30. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/tensors.md +2 -2
  31. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/windows.md +1 -1
  32. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/version.hpp +1 -1
  33. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/mkdocs.yml +12 -0
  34. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/pyproject.toml +1 -1
  35. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/_version.py +1 -1
  36. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bind_tensor.cpp +14 -6
  37. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/ops.cpp +49 -6
  38. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/tensor.cpp +128 -6
  39. tensorstudio-1.0.1/test_all.py +102 -0
  40. tensorstudio-1.0.1/tests/test_benchmark_report.py +71 -0
  41. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_import.py +1 -1
  42. tensorstudio-1.0.0rc2/benchmarks/results.md +0 -214
  43. tensorstudio-1.0.0rc2/benchmarks/results_matmul.md +0 -38
  44. tensorstudio-1.0.0rc2/docs/Benchmarks/index.md +0 -53
  45. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.github/workflows/wheels.yml +0 -0
  46. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.gitignore +0 -0
  47. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.pre-commit-config.yaml +0 -0
  48. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/CONTRIBUTING.md +0 -0
  49. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/LICENSE +0 -0
  50. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/SECURITY.md +0 -0
  51. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_activations.py +0 -0
  52. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_autograd.py +0 -0
  53. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_elementwise.py +0 -0
  54. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_matmul.py +0 -0
  55. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_reductions.py +0 -0
  56. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_tensor_ops.py +0 -0
  57. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_training_loop.py +0 -0
  58. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Neural Networks/modules.md +0 -0
  59. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Usage/numpy-interop.md +0 -0
  60. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/linux.md +0 -0
  61. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/macos.md +0 -0
  62. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/nn.md +0 -0
  63. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/optim.md +0 -0
  64. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/examples/basic_tensor_ops.py +0 -0
  65. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/examples/linear_regression.py +0 -0
  66. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/examples/save_load_model.py +0 -0
  67. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/examples/tiny_mlp.py +0 -0
  68. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/autograd.hpp +0 -0
  69. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/device.hpp +0 -0
  70. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/dtype.hpp +0 -0
  71. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/errors.hpp +0 -0
  72. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/module.hpp +0 -0
  73. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/ops.hpp +0 -0
  74. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/optim.hpp +0 -0
  75. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/random.hpp +0 -0
  76. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/serialization.hpp +0 -0
  77. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/shape.hpp +0 -0
  78. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/storage.hpp +0 -0
  79. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/tensor.hpp +0 -0
  80. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/_C.pyi +0 -0
  81. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/__init__.py +0 -0
  82. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/autograd.py +0 -0
  83. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/data/__init__.py +0 -0
  84. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/data/dataloader.py +0 -0
  85. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/data/dataset.py +0 -0
  86. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/errors.py +0 -0
  87. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/grad_mode.py +0 -0
  88. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/nn/__init__.py +0 -0
  89. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/nn/functional.py +0 -0
  90. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/nn/losses.py +0 -0
  91. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/nn/modules.py +0 -0
  92. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/ops.py +0 -0
  93. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/__init__.py +0 -0
  94. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/adam.py +0 -0
  95. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/adamw.py +0 -0
  96. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/lr_scheduler.py +0 -0
  97. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/sgd.py +0 -0
  98. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/utils.py +0 -0
  99. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/py.typed +0 -0
  100. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/serialization.py +0 -0
  101. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/tensor.py +0 -0
  102. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/typing.py +0 -0
  103. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bind_autograd.cpp +0 -0
  104. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bind_nn.cpp +0 -0
  105. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bind_ops.cpp +0 -0
  106. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bind_optim.cpp +0 -0
  107. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bindings.cpp +0 -0
  108. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bindings.hpp +0 -0
  109. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/autograd.cpp +0 -0
  110. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/device.cpp +0 -0
  111. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/dtype.cpp +0 -0
  112. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/errors.cpp +0 -0
  113. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/module.cpp +0 -0
  114. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/optim.cpp +0 -0
  115. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/random.cpp +0 -0
  116. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/serialization.cpp +0 -0
  117. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/shape.cpp +0 -0
  118. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/storage.cpp +0 -0
  119. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_autograd.py +0 -0
  120. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_data.py +0 -0
  121. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_nn.py +0 -0
  122. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_numpy_interop.py +0 -0
  123. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_ops.py +0 -0
  124. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_optim.py +0 -0
  125. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_serialization.py +0 -0
  126. {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_tensor.py +0 -0
@@ -30,6 +30,10 @@ jobs:
30
30
  run: mypy --python-version ${{ matrix.python-version }} python/tensorstudio
31
31
  - name: Tests
32
32
  run: pytest -q
33
+ - name: Runner scripts
34
+ run: |
35
+ python test_all.py --help
36
+ python benchmark_all.py --help
33
37
  - name: Example
34
38
  run: python examples/basic_tensor_ops.py
35
39
 
@@ -59,6 +63,10 @@ jobs:
59
63
  run: mypy --python-version ${{ matrix.python-version }} python/tensorstudio
60
64
  - name: Tests
61
65
  run: pytest -q
66
+ - name: Runner scripts
67
+ run: |
68
+ python test_all.py --help
69
+ python benchmark_all.py --help
62
70
  - name: Example
63
71
  run: python examples/basic_tensor_ops.py
64
72
 
@@ -88,5 +96,9 @@ jobs:
88
96
  run: mypy --python-version ${{ matrix.python-version }} python/tensorstudio
89
97
  - name: Tests
90
98
  run: pytest -q
99
+ - name: Runner scripts
100
+ run: |
101
+ python test_all.py --help
102
+ python benchmark_all.py --help
91
103
  - name: Example
92
104
  run: python examples/basic_tensor_ops.py
@@ -106,3 +106,4 @@ jobs:
106
106
  uses: pypa/gh-action-pypi-publish@release/v1
107
107
  with:
108
108
  repository-url: https://test.pypi.org/legacy/
109
+ skip-existing: true
@@ -6,7 +6,7 @@ on:
6
6
  types: [published]
7
7
  push:
8
8
  tags:
9
- - "v1.0.0"
9
+ - "v*"
10
10
 
11
11
  permissions:
12
12
  contents: read
@@ -103,5 +103,11 @@ jobs:
103
103
  pattern: dist-*
104
104
  path: dist
105
105
  merge-multiple: true
106
+ - name: Verify artifacts
107
+ run: |
108
+ python -m pip install -U twine
109
+ python -m twine check dist/*
106
110
  - name: Publish to PyPI
107
111
  uses: pypa/gh-action-pypi-publish@release/v1
112
+ with:
113
+ skip-existing: true
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.1
4
+
5
+ - Added `test_all.py` for one-command local release checks covering lint,
6
+ typing, tests, examples, docs, build, and package metadata validation.
7
+ - Added `benchmark_all.py` for one-command full benchmark report generation.
8
+ - Added explicit benchmark win columns for NumPy, TensorFlow, PyTorch, and JAX,
9
+ plus fastest-library reporting for each benchmark case.
10
+ - Hardened release publishing triggers so future `v*` tags are eligible for
11
+ the publish workflow instead of only `v1.0.0`.
12
+ - Updated docs to describe benchmark interpretation, local release checks, and
13
+ site navigation for benchmark, hardware, roadmap, and usage pages.
14
+
15
+ ## 1.0.0
16
+
17
+ - Promoted the CPU-only stable API foundation from release candidate status.
18
+ - Added direct C++ buffer copies for NumPy import/export paths.
19
+ - Added faster typed tensor construction, flat-vector export, contiguous tensor
20
+ copy, and floating-point optimizer update paths.
21
+ - Added a `float32` contiguous matmul fast path that avoids double accumulation
22
+ and per-element dtype conversion for the common training dtype.
23
+ - Added typed contiguous reduction kernels for `sum` and `mean`.
24
+ - Expanded benchmark reports with framework version metadata and PyTorch
25
+ win/loss summaries.
26
+ - Updated documentation to describe honest `1.0.0` performance boundaries.
27
+
3
28
  ## 1.0.0rc2
4
29
 
5
30
  - Added `*_like` tensor creation helpers for zero, one, full, empty, uniform
@@ -1,7 +1,9 @@
1
1
  cmake_minimum_required(VERSION 3.18)
2
2
 
3
- project(tensorstudio VERSION 1.0.0 LANGUAGES CXX)
3
+ project(tensorstudio VERSION 1.0.1 LANGUAGES CXX)
4
4
 
5
+ find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)
6
+ set(PYBIND11_FINDPYTHON ON)
5
7
  find_package(pybind11 CONFIG REQUIRED)
6
8
 
7
9
  set(TENSORSTUDIO_CORE_SOURCES
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tensorstudio
3
- Version: 1.0.0rc2
3
+ Version: 1.0.1
4
4
  Summary: TensorStudio is a compact C++ tensor and autograd engine with a Python API for learning, experimentation, and lightweight ML workloads.
5
5
  Keywords: tensor,autograd,machine-learning,cpp,pybind11
6
6
  Author: TensorStudio contributors
@@ -65,14 +65,12 @@ Description-Content-Type: text/markdown
65
65
  TensorStudio is a compact C++ tensor and autograd engine with a Python API for
66
66
  learning, experimentation, and lightweight ML workloads.
67
67
 
68
- TensorStudio `1.0.0rc2` is a release candidate for a CPU-only stable API
69
- foundation. It is eager-only, intentionally small, and not a replacement for
70
- mature ML frameworks. The final `1.0.0` version should only be tagged after the
71
- Windows, Linux, and macOS release checklist passes.
68
+ TensorStudio `1.0.1` is a CPU-only stable API foundation. It is eager-only,
69
+ intentionally small, and not a replacement for mature ML frameworks.
72
70
 
73
71
  ## Install
74
72
 
75
- From PyPI, once release-candidate wheels are published:
73
+ From PyPI:
76
74
 
77
75
  ```bash
78
76
  python -m pip install tensorstudio
@@ -219,8 +217,8 @@ for features, targets in loader:
219
217
  print(features.shape, targets.shape)
220
218
  ```
221
219
 
222
- The v1 release candidate DataLoader is intentionally single-process so it works
223
- cleanly on Windows without multiprocessing setup.
220
+ The v1 DataLoader is intentionally single-process so it works cleanly on
221
+ Windows without multiprocessing setup.
224
222
 
225
223
  ## Performance
226
224
 
@@ -229,34 +227,38 @@ performance is still experimental. Benchmarks live in `benchmarks/` and can be
229
227
  run locally:
230
228
 
231
229
  ```bash
230
+ python benchmark_all.py
232
231
  python benchmarks/benchmark_report.py
233
232
  ```
234
233
 
235
- On one Windows CPython 3.10 run for `1.0.0rc2`, TensorStudio beat NumPy on 11
236
- small activation/reduction benchmark cases and lost on 78 NumPy-comparable
237
- cases. The strongest local wins were small `sigmoid`, `sum`, and `mean` cases;
238
- medium elementwise operations and matrix multiplication remain slower than
239
- NumPy. The C++ contiguous matmul fast path is much faster than the original
240
- naive storage-access loop, but it is not a BLAS replacement. See
241
- `benchmarks/results.md` for the full table, platform details, and exact timings.
234
+ `benchmark_all.py` writes `benchmarks/results.md` and includes explicit win
235
+ columns for NumPy, TensorFlow, PyTorch, and JAX when those libraries are
236
+ available locally.
237
+
238
+ On one Windows CPython 3.10 run for `1.0.1`, TensorStudio beat NumPy on 13
239
+ small activation/reduction benchmark cases and lost on 76 NumPy-comparable
240
+ cases. Against PyTorch CPU `2.12.1+cpu`, TensorStudio won 71 local cases and
241
+ lost 23. The strongest local wins were small eager operations where framework
242
+ dispatch overhead dominates; larger matrix multiplication, larger transcendental
243
+ activations, and larger autograd workloads remain faster in PyTorch and NumPy.
244
+ See `benchmarks/results.md` for the full table, platform details, and exact
245
+ timings.
242
246
 
243
247
  Snapshot from that local run:
244
248
 
245
- | operation | shape | TensorStudio median | NumPy median | speedup | result |
246
- |---|---:|---:|---:|---:|---|
247
- | `sigmoid` | `(1,)` | 0.0016 ms | 0.0036 ms | 2.2170x | win |
248
- | `mean` | `(1,)` | 0.0014 ms | 0.0081 ms | 5.8562x | win |
249
- | `mean` | `(8,)` | 0.0016 ms | 0.0079 ms | 5.0005x | win |
250
- | `add` | `(16384,)` | 0.0100 ms | 0.0037 ms | 0.3682x | loss |
251
- | `matmul` | `(256, 256)` | 4.1393 ms | 0.4222 ms | 0.1020x | loss |
249
+ | operation | shape | TensorStudio | NumPy | PyTorch CPU | TS vs NumPy | TS vs PyTorch |
250
+ |---|---:|---:|---:|---:|---:|---:|
251
+ | `sigmoid` | `(32,)` | 0.0018 ms | 0.0036 ms | 0.0575 ms | 2.0414x | 32.2110x |
252
+ | `mean` | `(32,)` | 0.0016 ms | 0.0069 ms | 0.0112 ms | 4.4051x | 7.1262x |
253
+ | `chain_relu` | `(128,)` | 0.0086 ms | 0.0039 ms | 0.0567 ms | 0.4488x | 6.5977x |
254
+ | `matmul` | `(256, 256)` | 2.4215 ms | 0.4027 ms | 0.0832 ms | 0.1663x | 0.0343x |
255
+ | `elementwise_backward` | `(1024,)` | 2.3527 ms | n/a | 0.1887 ms | n/a | 0.0802x |
252
256
 
253
- Speedup is `NumPy median / TensorStudio median`, so values above `1.0x` favor
254
- TensorStudio. The matmul result is from the optimized C++ contiguous path; a
255
- pre-optimization run was about 259 ms for the same `(256, 256)` case on this
256
- machine.
257
+ Speedup is `competitor median / TensorStudio median`, so values above `1.0x`
258
+ favor TensorStudio.
257
259
 
258
- Do not treat these results as universal. TensorStudio does not currently claim
259
- to be faster than NumPy, TensorFlow, PyTorch, or JAX overall.
260
+ Do not treat these results as universal. TensorStudio does not claim to be
261
+ faster than NumPy, TensorFlow, PyTorch, or JAX overall.
260
262
 
261
263
  ## Save And Load
262
264
 
@@ -276,6 +278,7 @@ unsafe because pickle can execute arbitrary code.
276
278
 
277
279
  ```bash
278
280
  python -m pip install -e ".[dev,docs]"
281
+ python test_all.py --skip-build
279
282
  ruff check .
280
283
  mypy python/tensorstudio
281
284
  pytest -q
@@ -288,6 +291,7 @@ scikit-build-core, and C++20.
288
291
 
289
292
  ## Release Checklist
290
293
 
294
+ - `python test_all.py` passes locally.
291
295
  - `ruff check .` passes.
292
296
  - `mypy python/tensorstudio` passes.
293
297
  - `pytest -q` passes on Windows, Linux, and macOS.
@@ -312,6 +316,7 @@ tokens or print secrets.
312
316
  - CPU backend only.
313
317
  - Eager execution only.
314
318
  - No CUDA or Metal backend yet.
319
+ - No BLAS-backed matrix multiplication yet.
315
320
  - No graph compiler or distributed runtime.
316
321
  - No convolution layers yet.
317
322
  - No sparse tensors or advanced indexing.
@@ -7,14 +7,12 @@
7
7
  TensorStudio is a compact C++ tensor and autograd engine with a Python API for
8
8
  learning, experimentation, and lightweight ML workloads.
9
9
 
10
- TensorStudio `1.0.0rc2` is a release candidate for a CPU-only stable API
11
- foundation. It is eager-only, intentionally small, and not a replacement for
12
- mature ML frameworks. The final `1.0.0` version should only be tagged after the
13
- Windows, Linux, and macOS release checklist passes.
10
+ TensorStudio `1.0.1` is a CPU-only stable API foundation. It is eager-only,
11
+ intentionally small, and not a replacement for mature ML frameworks.
14
12
 
15
13
  ## Install
16
14
 
17
- From PyPI, once release-candidate wheels are published:
15
+ From PyPI:
18
16
 
19
17
  ```bash
20
18
  python -m pip install tensorstudio
@@ -161,8 +159,8 @@ for features, targets in loader:
161
159
  print(features.shape, targets.shape)
162
160
  ```
163
161
 
164
- The v1 release candidate DataLoader is intentionally single-process so it works
165
- cleanly on Windows without multiprocessing setup.
162
+ The v1 DataLoader is intentionally single-process so it works cleanly on
163
+ Windows without multiprocessing setup.
166
164
 
167
165
  ## Performance
168
166
 
@@ -171,34 +169,38 @@ performance is still experimental. Benchmarks live in `benchmarks/` and can be
171
169
  run locally:
172
170
 
173
171
  ```bash
172
+ python benchmark_all.py
174
173
  python benchmarks/benchmark_report.py
175
174
  ```
176
175
 
177
- On one Windows CPython 3.10 run for `1.0.0rc2`, TensorStudio beat NumPy on 11
178
- small activation/reduction benchmark cases and lost on 78 NumPy-comparable
179
- cases. The strongest local wins were small `sigmoid`, `sum`, and `mean` cases;
180
- medium elementwise operations and matrix multiplication remain slower than
181
- NumPy. The C++ contiguous matmul fast path is much faster than the original
182
- naive storage-access loop, but it is not a BLAS replacement. See
183
- `benchmarks/results.md` for the full table, platform details, and exact timings.
176
+ `benchmark_all.py` writes `benchmarks/results.md` and includes explicit win
177
+ columns for NumPy, TensorFlow, PyTorch, and JAX when those libraries are
178
+ available locally.
179
+
180
+ On one Windows CPython 3.10 run for `1.0.1`, TensorStudio beat NumPy on 13
181
+ small activation/reduction benchmark cases and lost on 76 NumPy-comparable
182
+ cases. Against PyTorch CPU `2.12.1+cpu`, TensorStudio won 71 local cases and
183
+ lost 23. The strongest local wins were small eager operations where framework
184
+ dispatch overhead dominates; larger matrix multiplication, larger transcendental
185
+ activations, and larger autograd workloads remain faster in PyTorch and NumPy.
186
+ See `benchmarks/results.md` for the full table, platform details, and exact
187
+ timings.
184
188
 
185
189
  Snapshot from that local run:
186
190
 
187
- | operation | shape | TensorStudio median | NumPy median | speedup | result |
188
- |---|---:|---:|---:|---:|---|
189
- | `sigmoid` | `(1,)` | 0.0016 ms | 0.0036 ms | 2.2170x | win |
190
- | `mean` | `(1,)` | 0.0014 ms | 0.0081 ms | 5.8562x | win |
191
- | `mean` | `(8,)` | 0.0016 ms | 0.0079 ms | 5.0005x | win |
192
- | `add` | `(16384,)` | 0.0100 ms | 0.0037 ms | 0.3682x | loss |
193
- | `matmul` | `(256, 256)` | 4.1393 ms | 0.4222 ms | 0.1020x | loss |
191
+ | operation | shape | TensorStudio | NumPy | PyTorch CPU | TS vs NumPy | TS vs PyTorch |
192
+ |---|---:|---:|---:|---:|---:|---:|
193
+ | `sigmoid` | `(32,)` | 0.0018 ms | 0.0036 ms | 0.0575 ms | 2.0414x | 32.2110x |
194
+ | `mean` | `(32,)` | 0.0016 ms | 0.0069 ms | 0.0112 ms | 4.4051x | 7.1262x |
195
+ | `chain_relu` | `(128,)` | 0.0086 ms | 0.0039 ms | 0.0567 ms | 0.4488x | 6.5977x |
196
+ | `matmul` | `(256, 256)` | 2.4215 ms | 0.4027 ms | 0.0832 ms | 0.1663x | 0.0343x |
197
+ | `elementwise_backward` | `(1024,)` | 2.3527 ms | n/a | 0.1887 ms | n/a | 0.0802x |
194
198
 
195
- Speedup is `NumPy median / TensorStudio median`, so values above `1.0x` favor
196
- TensorStudio. The matmul result is from the optimized C++ contiguous path; a
197
- pre-optimization run was about 259 ms for the same `(256, 256)` case on this
198
- machine.
199
+ Speedup is `competitor median / TensorStudio median`, so values above `1.0x`
200
+ favor TensorStudio.
199
201
 
200
- Do not treat these results as universal. TensorStudio does not currently claim
201
- to be faster than NumPy, TensorFlow, PyTorch, or JAX overall.
202
+ Do not treat these results as universal. TensorStudio does not claim to be
203
+ faster than NumPy, TensorFlow, PyTorch, or JAX overall.
202
204
 
203
205
  ## Save And Load
204
206
 
@@ -218,6 +220,7 @@ unsafe because pickle can execute arbitrary code.
218
220
 
219
221
  ```bash
220
222
  python -m pip install -e ".[dev,docs]"
223
+ python test_all.py --skip-build
221
224
  ruff check .
222
225
  mypy python/tensorstudio
223
226
  pytest -q
@@ -230,6 +233,7 @@ scikit-build-core, and C++20.
230
233
 
231
234
  ## Release Checklist
232
235
 
236
+ - `python test_all.py` passes locally.
233
237
  - `ruff check .` passes.
234
238
  - `mypy python/tensorstudio` passes.
235
239
  - `pytest -q` passes on Windows, Linux, and macOS.
@@ -254,6 +258,7 @@ tokens or print secrets.
254
258
  - CPU backend only.
255
259
  - Eager execution only.
256
260
  - No CUDA or Metal backend yet.
261
+ - No BLAS-backed matrix multiplication yet.
257
262
  - No graph compiler or distributed runtime.
258
263
  - No convolution layers yet.
259
264
  - No sparse tensors or advanced indexing.
@@ -0,0 +1,48 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from benchmarks.benchmark_report import run_benchmarks
7
+
8
+ ALL_SECTIONS = {
9
+ "elementwise",
10
+ "matmul",
11
+ "reductions",
12
+ "activations",
13
+ "autograd",
14
+ "training_loop",
15
+ }
16
+
17
+
18
+ def main() -> None:
19
+ parser = argparse.ArgumentParser(description="Run every TensorStudio benchmark section.")
20
+ parser.add_argument(
21
+ "--section",
22
+ action="append",
23
+ choices=sorted(ALL_SECTIONS),
24
+ help="Run only the selected section. Repeat for multiple sections.",
25
+ )
26
+ parser.add_argument(
27
+ "--output",
28
+ type=Path,
29
+ default=Path("benchmarks") / "results.md",
30
+ help="Markdown report path. Defaults to benchmarks/results.md.",
31
+ )
32
+ parser.add_argument(
33
+ "--print",
34
+ action="store_true",
35
+ help="Print the full Markdown report after writing it.",
36
+ )
37
+ args = parser.parse_args()
38
+
39
+ selected_sections = set(args.section or ALL_SECTIONS)
40
+ report = run_benchmarks(selected_sections, args.output)
41
+ if args.print:
42
+ print(report)
43
+ else:
44
+ print(f"Wrote benchmark report to {args.output}")
45
+
46
+
47
+ if __name__ == "__main__":
48
+ main()
@@ -0,0 +1,2 @@
1
+ """Local TensorStudio benchmark helpers."""
2
+
@@ -62,6 +62,11 @@ def _optional_import(module_name: str) -> Any | None:
62
62
  return None
63
63
 
64
64
 
65
+ def _version_note(module: Any) -> str:
66
+ version = getattr(module, "__version__", "")
67
+ return str(version) if version else "available"
68
+
69
+
65
70
  def _shape_label(shape: tuple[int, ...]) -> str:
66
71
  return "(" + ", ".join(str(dim) for dim in shape) + ("," if len(shape) == 1 else "") + ")"
67
72
 
@@ -135,19 +140,41 @@ def _load_libraries() -> list[Library]:
135
140
  if tf is not None:
136
141
  with suppress(Exception):
137
142
  tf.config.set_visible_devices([], "GPU")
138
- libraries.append(Library("TensorFlow CPU eager", lambda array: tf.constant(array)))
143
+ libraries.append(
144
+ Library(
145
+ "TensorFlow CPU eager",
146
+ lambda array: tf.constant(array),
147
+ True,
148
+ _version_note(tf),
149
+ )
150
+ )
139
151
  else:
140
152
  libraries.append(Library("TensorFlow CPU eager", _numpy_factory, False, "not installed"))
141
153
 
142
154
  torch = _optional_import("torch")
143
155
  if torch is not None:
144
- libraries.append(Library("PyTorch CPU", lambda array: torch.from_numpy(array.copy())))
156
+ libraries.append(
157
+ Library(
158
+ "PyTorch CPU",
159
+ lambda array: torch.from_numpy(array.copy()),
160
+ True,
161
+ _version_note(torch),
162
+ )
163
+ )
145
164
  else:
146
165
  libraries.append(Library("PyTorch CPU", _numpy_factory, False, "not installed"))
147
166
 
148
167
  jnp = _optional_import("jax.numpy")
149
168
  if jnp is not None:
150
- libraries.append(Library("JAX CPU dispatch", lambda array: jnp.array(array)))
169
+ jax = _optional_import("jax")
170
+ libraries.append(
171
+ Library(
172
+ "JAX CPU dispatch",
173
+ lambda array: jnp.array(array),
174
+ True,
175
+ _version_note(jax or jnp),
176
+ )
177
+ )
151
178
  else:
152
179
  libraries.append(Library("JAX CPU dispatch", _numpy_factory, False, "not installed"))
153
180
 
@@ -512,12 +539,24 @@ def _format_float(value: float | None) -> str:
512
539
  return f"{value:.4f}"
513
540
 
514
541
 
542
+ def _format_win(value: float | None) -> str:
543
+ if value is None:
544
+ return "n/a"
545
+ return "yes" if value > 1.0 else "no"
546
+
547
+
515
548
  def _speedup(ts_ms: float | None, competitor_ms: float | None) -> float | None:
516
549
  if ts_ms is None or competitor_ms is None or ts_ms <= 0:
517
550
  return None
518
551
  return competitor_ms / ts_ms
519
552
 
520
553
 
554
+ def _fastest_library(medians: dict[str, float]) -> str:
555
+ if not medians:
556
+ return "n/a"
557
+ return min(medians.items(), key=lambda item: item[1])[0]
558
+
559
+
521
560
  def _run_cases(cases: Iterable[BenchmarkCase], libraries: list[Library]) -> dict[str, Stats]:
522
561
  results: dict[str, Stats] = {}
523
562
  for case in cases:
@@ -559,34 +598,49 @@ def _render_report(
559
598
  for library in libraries:
560
599
  if library.name in {"TensorStudio", "NumPy"}:
561
600
  continue
562
- status = "available" if library.available else f"unavailable ({library.note})"
601
+ status = (
602
+ f"available ({library.note})"
603
+ if library.available
604
+ else f"unavailable ({library.note})"
605
+ )
563
606
  lines.append(f"- {library.name}: {status}")
564
607
  lines.append("")
565
608
  lines.append("## Summary")
566
609
  lines.append("")
567
610
 
568
- wins = 0
569
- losses = 0
570
- for case in cases:
571
- ts_stats = results.get(_result_key(case, "TensorStudio"))
572
- np_stats = results.get(_result_key(case, "NumPy"))
573
- ratio = _speedup(
574
- ts_stats.median_ms if ts_stats else None,
575
- np_stats.median_ms if np_stats else None,
576
- )
577
- if ratio is None:
578
- continue
579
- if ratio > 1.0:
580
- wins += 1
581
- else:
582
- losses += 1
611
+ def win_loss_against(library_name: str) -> tuple[int, int]:
612
+ wins = 0
613
+ losses = 0
614
+ for benchmark_case in cases:
615
+ ts_stats = results.get(_result_key(benchmark_case, "TensorStudio"))
616
+ competitor_stats = results.get(_result_key(benchmark_case, library_name))
617
+ ratio = _speedup(
618
+ ts_stats.median_ms if ts_stats else None,
619
+ competitor_stats.median_ms if competitor_stats else None,
620
+ )
621
+ if ratio is None:
622
+ continue
623
+ if ratio > 1.0:
624
+ wins += 1
625
+ else:
626
+ losses += 1
627
+ return wins, losses
628
+
629
+ wins, losses = win_loss_against("NumPy")
583
630
  lines.append(f"- TensorStudio wins versus NumPy: `{wins}`")
584
631
  lines.append(f"- TensorStudio losses versus NumPy: `{losses}`")
632
+
633
+ for competitor in ["PyTorch CPU", "TensorFlow CPU eager", "JAX CPU dispatch"]:
634
+ competitor_wins, competitor_losses = win_loss_against(competitor)
635
+ if competitor_wins or competitor_losses:
636
+ lines.append(f"- TensorStudio wins versus {competitor}: `{competitor_wins}`")
637
+ lines.append(f"- TensorStudio losses versus {competitor}: `{competitor_losses}`")
585
638
  lines.append("")
639
+
586
640
  if wins == 0:
587
641
  lines.append(
588
642
  "TensorStudio did not beat NumPy on this machine for the available benchmark set. "
589
- "Performance remains a blocker for a final `1.0.0` performance claim."
643
+ "Performance remains a blocker for broad performance claims."
590
644
  )
591
645
  else:
592
646
  lines.append(
@@ -598,10 +652,13 @@ def _render_report(
598
652
  lines.append("")
599
653
  lines.append(
600
654
  "| category | operation | shape | library | median ms | mean ms | min ms | "
601
- "max ms | std ms | TS vs NumPy | TS vs TensorFlow | TS vs PyTorch | TS vs JAX | result |"
655
+ "max ms | std ms | TS vs NumPy | TS vs TensorFlow | TS vs PyTorch | TS vs JAX | "
656
+ "win vs NumPy | win vs TensorFlow | win vs PyTorch | win vs JAX | "
657
+ "fastest library | result |"
602
658
  )
603
659
  lines.append(
604
- "|---|---|---:|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---|"
660
+ "|---|---|---:|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|"
661
+ "---|---|---|---|---|---|"
605
662
  )
606
663
 
607
664
  for case in cases:
@@ -626,6 +683,7 @@ def _render_report(
626
683
  medians.get("JAX CPU dispatch"),
627
684
  ),
628
685
  }
686
+ fastest = _fastest_library(medians)
629
687
  for library in libraries:
630
688
  stats = results.get(_result_key(case, library.name))
631
689
  if stats is None:
@@ -650,13 +708,19 @@ def _render_report(
650
708
  f"{_format_float(speedups['NumPy'])} | "
651
709
  f"{_format_float(speedups['TensorFlow CPU eager'])} | "
652
710
  f"{_format_float(speedups['PyTorch CPU'])} | "
653
- f"{_format_float(speedups['JAX CPU dispatch'])} | {result} |"
711
+ f"{_format_float(speedups['JAX CPU dispatch'])} | "
712
+ f"{_format_win(speedups['NumPy'])} | "
713
+ f"{_format_win(speedups['TensorFlow CPU eager'])} | "
714
+ f"{_format_win(speedups['PyTorch CPU'])} | "
715
+ f"{_format_win(speedups['JAX CPU dispatch'])} | "
716
+ f"{fastest} | {result} |"
654
717
  )
655
718
  lines.append("")
656
719
  lines.append(
657
720
  "Speedup columns are `competitor median / TensorStudio median`; values above 1.0 mean"
658
721
  )
659
722
  lines.append("TensorStudio was faster for that specific case.")
723
+ lines.append("Win columns say whether that same speedup is above 1.0 for the competitor.")
660
724
  lines.append("")
661
725
  return "\n".join(lines)
662
726