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.
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.github/workflows/ci.yml +12 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.github/workflows/publish-testpypi.yml +1 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.github/workflows/publish.yml +7 -1
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/CHANGELOG.md +25 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/CMakeLists.txt +3 -1
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/PKG-INFO +33 -28
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/README.md +32 -27
- tensorstudio-1.0.1/benchmark_all.py +48 -0
- tensorstudio-1.0.1/benchmarks/__init__.py +2 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/benchmark_report.py +87 -23
- tensorstudio-1.0.1/benchmarks/results.md +311 -0
- tensorstudio-1.0.1/benchmarks/results_matmul.md +45 -0
- tensorstudio-1.0.1/benchmarks/results_reductions.md +75 -0
- tensorstudio-1.0.1/benchmarks/results_tensor_ops.md +285 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Autograde/index.md +1 -1
- tensorstudio-1.0.1/docs/Benchmarks/index.md +65 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Hardware/cpu-backend.md +4 -4
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Neural Networks/training.md +1 -1
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Roadmap/index.md +2 -2
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Usage/serialization.md +1 -1
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Usage/tensors.md +1 -1
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/api.md +30 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/autograd.md +1 -1
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/data.md +2 -2
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/development.md +10 -3
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/index.md +6 -9
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/publishing.md +24 -8
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/quickstart.md +1 -1
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/serialization.md +2 -2
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/tensors.md +2 -2
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/windows.md +1 -1
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/version.hpp +1 -1
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/mkdocs.yml +12 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/pyproject.toml +1 -1
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/_version.py +1 -1
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bind_tensor.cpp +14 -6
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/ops.cpp +49 -6
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/tensor.cpp +128 -6
- tensorstudio-1.0.1/test_all.py +102 -0
- tensorstudio-1.0.1/tests/test_benchmark_report.py +71 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_import.py +1 -1
- tensorstudio-1.0.0rc2/benchmarks/results.md +0 -214
- tensorstudio-1.0.0rc2/benchmarks/results_matmul.md +0 -38
- tensorstudio-1.0.0rc2/docs/Benchmarks/index.md +0 -53
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.github/workflows/wheels.yml +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.gitignore +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/.pre-commit-config.yaml +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/CONTRIBUTING.md +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/LICENSE +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/SECURITY.md +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_activations.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_autograd.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_elementwise.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_matmul.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_reductions.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_tensor_ops.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/benchmarks/bench_training_loop.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Neural Networks/modules.md +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/Usage/numpy-interop.md +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/linux.md +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/macos.md +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/nn.md +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/docs/optim.md +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/examples/basic_tensor_ops.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/examples/linear_regression.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/examples/save_load_model.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/examples/tiny_mlp.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/autograd.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/device.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/dtype.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/errors.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/module.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/ops.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/optim.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/random.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/serialization.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/shape.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/storage.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/include/tensorstudio/tensor.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/_C.pyi +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/__init__.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/autograd.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/data/__init__.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/data/dataloader.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/data/dataset.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/errors.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/grad_mode.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/nn/__init__.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/nn/functional.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/nn/losses.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/nn/modules.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/ops.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/__init__.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/adam.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/adamw.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/lr_scheduler.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/sgd.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/optim/utils.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/py.typed +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/serialization.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/tensor.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/python/tensorstudio/typing.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bind_autograd.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bind_nn.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bind_ops.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bind_optim.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bindings.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/bindings/bindings.hpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/autograd.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/device.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/dtype.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/errors.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/module.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/optim.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/random.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/serialization.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/shape.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/src/core/storage.cpp +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_autograd.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_data.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_nn.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_numpy_interop.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_ops.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_optim.py +0 -0
- {tensorstudio-1.0.0rc2 → tensorstudio-1.0.1}/tests/test_serialization.py +0 -0
- {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
|
|
@@ -6,7 +6,7 @@ on:
|
|
|
6
6
|
types: [published]
|
|
7
7
|
push:
|
|
8
8
|
tags:
|
|
9
|
-
- "
|
|
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.
|
|
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.
|
|
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.
|
|
69
|
-
|
|
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
|
|
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
|
|
223
|
-
|
|
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
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
|
246
|
-
|
|
247
|
-
| `sigmoid` | `(
|
|
248
|
-
| `mean` | `(
|
|
249
|
-
| `
|
|
250
|
-
| `
|
|
251
|
-
| `
|
|
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 `
|
|
254
|
-
TensorStudio.
|
|
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
|
|
259
|
-
|
|
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.
|
|
11
|
-
|
|
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
|
|
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
|
|
165
|
-
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
|
188
|
-
|
|
189
|
-
| `sigmoid` | `(
|
|
190
|
-
| `mean` | `(
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
| `
|
|
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 `
|
|
196
|
-
TensorStudio.
|
|
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
|
|
201
|
-
|
|
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()
|
|
@@ -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(
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
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
|
|
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 |
|
|
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'])} |
|
|
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
|
|