trntensor 0.17.0__tar.gz → 0.18.0__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.
- {trntensor-0.17.0 → trntensor-0.18.0}/.github/workflows/ci.yml +6 -4
- {trntensor-0.17.0 → trntensor-0.18.0}/CHANGELOG.md +91 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/CLAUDE.md +4 -1
- {trntensor-0.17.0/trntensor.egg-info → trntensor-0.18.0}/PKG-INFO +35 -3
- trntensor-0.17.0/PKG-INFO → trntensor-0.18.0/README.md +26 -32
- trntensor-0.18.0/docs/api/nki.md +174 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/api/quantum.md +15 -5
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/contraction_patterns.md +12 -10
- {trntensor-0.17.0 → trntensor-0.18.0}/pyproject.toml +25 -7
- {trntensor-0.17.0 → trntensor-0.18.0}/scripts/autotune_dispatch.py +162 -12
- trntensor-0.18.0/scripts/bench_native_einsum.py +396 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/tests/conftest.py +6 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/tests/test_einsum.py +2 -2
- trntensor-0.18.0/tests/test_native_dispatch.py +732 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/tests/test_nki_kernels.py +74 -45
- trntensor-0.18.0/tests/test_nki_native.py +176 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/tests/test_plan.py +17 -1
- {trntensor-0.17.0 → trntensor-0.18.0}/tests/test_quantum.py +24 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/tests/test_sr_runtime.py +3 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor/__init__.py +4 -2
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor/einsum.py +26 -14
- trntensor-0.18.0/trntensor/nki/_native.py +85 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor/nki/dispatch.py +413 -49
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor/plan.py +17 -6
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor/quantum.py +48 -20
- trntensor-0.17.0/README.md → trntensor-0.18.0/trntensor.egg-info/PKG-INFO +64 -1
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor.egg-info/SOURCES.txt +4 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor.egg-info/requires.txt +10 -1
- {trntensor-0.17.0 → trntensor-0.18.0}/uv.lock +1 -1
- trntensor-0.17.0/docs/api/nki.md +0 -78
- {trntensor-0.17.0 → trntensor-0.18.0}/.github/workflows/notify-umbrella.yml +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/.github/workflows/publish.yml +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/.gitignore +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/.pre-commit-config.yaml +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/CODE_OF_CONDUCT.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/CONTRIBUTING.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/LICENSE +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/benchmarks/__init__.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/benchmarks/bench_einsum.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/api/decompose.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/api/einsum.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/api/index.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/api/plan.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/architecture.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/aws_setup.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/benchmarks.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/design/matmul_dispatch_findings.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/design/matmul_kernel_profile.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/developing_kernels.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/index.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/installation.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/quickstart.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/docs/tutorial_df_mp2.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/examples/df_mp2_einsum.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/infra/terraform/README.md +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/infra/terraform/main.tf +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/mkdocs.yml +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/scripts/bench_to_md.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/scripts/run_benchmarks.sh +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/scripts/run_neuron_profile.sh +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/scripts/run_neuron_tests.sh +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/scripts/run_reduce_parallel_multirank.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/scripts/run_simulator_tests.sh +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/setup.cfg +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/tests/test_decompose.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/tests/test_nki.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/tests/test_nki_compile.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/tests/test_nki_sim.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/tests/test_parallel.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor/decompose.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor/nki/__init__.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor/nki/_kernels.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor/nki/collectives.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor/parallel.py +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor/py.typed +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor.egg-info/dependency_links.txt +0 -0
- {trntensor-0.17.0 → trntensor-0.18.0}/trntensor.egg-info/top_level.txt +0 -0
|
@@ -30,8 +30,10 @@ jobs:
|
|
|
30
30
|
- uses: astral-sh/setup-uv@v6
|
|
31
31
|
with:
|
|
32
32
|
python-version: ${{ matrix.python-version }}
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
# uv pip (not uv sync): sync resolves every extra, and [torchneuron]'s nki>=0.6
|
|
34
|
+
# lives only on the Neuron index.
|
|
35
|
+
- run: uv venv && uv pip install -e ".[dev]"
|
|
36
|
+
- run: uv run --no-sync pytest tests/ -v -x --tb=short -m "not neuron and not nki_simulator" --cov=trntensor --cov-report=xml
|
|
35
37
|
|
|
36
38
|
- name: Upload coverage reports to Codecov
|
|
37
39
|
uses: codecov/codecov-action@v5
|
|
@@ -50,10 +52,10 @@ jobs:
|
|
|
50
52
|
- uses: astral-sh/setup-uv@v6
|
|
51
53
|
with:
|
|
52
54
|
python-version: "3.12"
|
|
53
|
-
- run: uv
|
|
55
|
+
- run: uv venv && uv pip install -e ".[dev]"
|
|
54
56
|
- name: Install NKI simulator
|
|
55
57
|
run: uv pip install --extra-index-url https://pip.repos.neuron.amazonaws.com "nki>=0.3.0"
|
|
56
58
|
- name: Run simulator-backed kernel tests
|
|
57
59
|
env:
|
|
58
60
|
TRNTENSOR_USE_SIMULATOR: "1"
|
|
59
|
-
run: uv run pytest tests/ -v -m nki_simulator --tb=short
|
|
61
|
+
run: uv run --no-sync pytest tests/ -v -m nki_simulator --tb=short
|
|
@@ -7,12 +7,103 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.18.0] — 2026-10-30
|
|
11
|
+
|
|
12
|
+
Native TorchNeuron dispatch (Trn2/Trn3) alongside the PyTorch/XLA path (Trn1, maintenance); validated on Trn2 (trn2.3xlarge, Neuron SDK 2.33.0) — see trnsci/trnsci#35.
|
|
13
|
+
|
|
14
|
+
Headline performance: native `"auto"` routes to aten on the device, and the planner contraction-order fix takes the DF-MP2 AO→MO transform (`mi,na,mnP->iaP`, nb=256) from 70 to 1.16 ms (#49).
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **Native dispatch thresholds are now measured (#41).** They were measured
|
|
19
|
+
on trn2.3xlarge (SDK 2.33, NKI 0.7.0) with `scripts/bench_native_einsum.py`
|
|
20
|
+
and `scripts/autotune_dispatch.py`.
|
|
21
|
+
- On device-resident operands, aten `torch.matmul` / `torch.bmm` beat the
|
|
22
|
+
NKI matmul and batched-matmul kernels at every size (128³ to 4096³, fp32
|
|
23
|
+
and bf16). The native pinned threshold now defaults to `never`, so
|
|
24
|
+
device work runs as aten on `neuron`.
|
|
25
|
+
- Host operands at or above `TRNTENSOR_MIN_NKI_FLOPS_NATIVE` (now
|
|
26
|
+
500 M multiply-adds, previously a provisional 1 G) are offloaded to
|
|
27
|
+
aten on the device instead of to the NKI kernel.
|
|
28
|
+
- Thresholds accept `never` / `inf`.
|
|
29
|
+
- The XLA path is unchanged.
|
|
30
|
+
- **Native `"auto"` runs the fused quantum primitives as aten.** This covers
|
|
31
|
+
`mp2_energy` and `ao_to_mo_transform`. On Trn2 the AO→MO kernel measured
|
|
32
|
+
6–20× slower than aten, and the MP2 kernel 1.0–1.5× slower.
|
|
33
|
+
`set_backend("nki")` still runs both kernels, and the XLA path is
|
|
34
|
+
unchanged.
|
|
35
|
+
- **`mp2_energy` reference path is vectorized.** Without NKI it now uses
|
|
36
|
+
aten ops chunked over `i` instead of a nocc² Python loop. That is 10–40×
|
|
37
|
+
faster on device. On an Apple M-series CPU it is 3× faster at small sizes
|
|
38
|
+
and about even (±10%) at `nocc=32, nvir=128, naux=512`.
|
|
39
|
+
- **`ao_to_mo_transform` reference path** is now two explicit binary
|
|
40
|
+
contractions.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- **Greedy contraction path no longer starts with an outer product.** For
|
|
45
|
+
example, `einsum("mi,na,mnP->iaP")` used to contract `mi,na` first,
|
|
46
|
+
building a 4-index intermediate. Pairs that share an index are now
|
|
47
|
+
preferred.
|
|
48
|
+
- **`scripts/autotune_dispatch.py` now reports M·K·N**, the quantity dispatch
|
|
49
|
+
compares, where it used to report 2·M·K·N. On the native path it now
|
|
50
|
+
derives both thresholds: host vs device offload, and NKI vs aten on device.
|
|
51
|
+
|
|
10
52
|
## [0.17.0] — 2026-10-28
|
|
11
53
|
|
|
12
54
|
Validated on Trn2 (trn2.3xlarge, Neuron SDK 2.33.0, native TorchNeuron device) — see trnsci/trnsci#35.
|
|
13
55
|
|
|
14
56
|
### Added
|
|
15
57
|
|
|
58
|
+
- **Native PyTorch dispatch on TorchNeuron (#41, trnsci/trnsci#35).** On
|
|
59
|
+
TorchNeuron (Neuron SDK 2.33+, `torch-neuronx` 2.14, PyTorch 2.14,
|
|
60
|
+
Trn2/Trn3) every host-wrapper NKI kernel is a PyTorch custom op registered
|
|
61
|
+
with `torch_neuronx.nki_op` and launched on `device="neuron"`, with no
|
|
62
|
+
`torch_xla` import: `trntensor::matmul`, `batched_matmul`, `mp2_energy`,
|
|
63
|
+
`ao_to_mo_transform`. Kernel bodies are unchanged. The PyTorch/XLA path
|
|
64
|
+
(Trn1) is unchanged.
|
|
65
|
+
- The dispatch path is detected on the first kernel launch, not at
|
|
66
|
+
import: native when `torch_neuronx` exports `nki_op` and
|
|
67
|
+
`torch_neuronx.device_count() > 0`, XLA when `torch_xla` is installed,
|
|
68
|
+
otherwise none. `TRNSCI_NKI_DISPATCH=auto|native|xla` (suite-wide)
|
|
69
|
+
forces a path; forcing an unavailable one raises.
|
|
70
|
+
- The ops are registered lazily (`trntensor/nki/_native.py` is imported
|
|
71
|
+
only on the native path). Every launch goes through one helper,
|
|
72
|
+
`dispatch._launch`. That covers `einsum` (matmul/bmm/path steps),
|
|
73
|
+
`multi_einsum` (batched and per-contraction), `ao_to_mo_transform`,
|
|
74
|
+
`mp2_energy`, and `precision="sr"` (which passes `use_sr=True` to the op).
|
|
75
|
+
`precision="kahan"` stays a host fp64 contraction, and `"dd"` still
|
|
76
|
+
raises on NKI hosts (trnblas#22). The reduce-parallel `nki.collectives`
|
|
77
|
+
all-reduce from Phase 4 is unchanged.
|
|
78
|
+
- New `to_device` / `from_device` place tensors on the active path's
|
|
79
|
+
device (`neuron` or XLA). `to_xla` / `from_xla` stay public. On the
|
|
80
|
+
native path `to_xla` places on `neuron`, so existing residency code keeps
|
|
81
|
+
working. `multi_einsum` pre-pins shared operands on either device.
|
|
82
|
+
- FLOP dispatch thresholds are path-aware. The XLA values are unchanged
|
|
83
|
+
(2 GFLOPs unpinned, 1 GFLOPs pinned). The native path uses provisional
|
|
84
|
+
1 GFLOPs / 128 MFLOPs, because eager native dispatch costs about 0.2 ms
|
|
85
|
+
per launch. Override them with `TRNTENSOR_MIN_NKI_FLOPS_NATIVE[_PINNED]`
|
|
86
|
+
or the `trntensor_min_nki_flops_native[_pinned]` autotune cache keys.
|
|
87
|
+
`scripts/autotune_dispatch.py` measures and writes the native keys on a
|
|
88
|
+
TorchNeuron host.
|
|
89
|
+
- Dormant deprecation hook: with `TRNSCI_XLA_DEPRECATION=1` (off by
|
|
90
|
+
default), selecting the XLA path and calling `to_xla` / `from_xla` each
|
|
91
|
+
emit a one-time `DeprecationWarning`. Migration: replace `to_xla` with
|
|
92
|
+
`to_device` and `from_xla` with `from_device` (docs/api/nki.md).
|
|
93
|
+
- The `mp2_energy` CPU fallback copies `neuron`-resident operands to the
|
|
94
|
+
host before its scalar loop, then moves the result back.
|
|
95
|
+
- New extras: `[torchneuron]` (`torch>=2.14`, `torch-neuronx>=2.14`,
|
|
96
|
+
`nki>=0.6`) and `[neuron]` for the XLA lineage (`torch-neuronx>=2.9`,
|
|
97
|
+
`nki>=0.3.0`).
|
|
98
|
+
- Tests: `tests/conftest.py` sets `NKI_ENABLE_TRACE_CACHE=0` by default.
|
|
99
|
+
New CPU tests in `tests/test_native_dispatch.py` cover path selection,
|
|
100
|
+
launch routing for every entry point, lazy registration, op schemas,
|
|
101
|
+
fake shapes, thresholds, and the deprecation hook. New
|
|
102
|
+
`@pytest.mark.neuron` tests in `tests/test_nki_native.py` have not yet
|
|
103
|
+
run on hardware. `TestXlaResidency::test_matmul_stays_on_xla` is now
|
|
104
|
+
path-aware: it expects `neuron` on TorchNeuron and `xla` on Trn1, and
|
|
105
|
+
still checks residency.
|
|
106
|
+
|
|
16
107
|
- **Reduce-parallel sharding on real multi-rank all-reduce (Phase 4 prototype).**
|
|
17
108
|
Before this change, reduce-parallel and mixed output/reduce-parallel einsums
|
|
18
109
|
raised `NotImplementedError` whenever `HAS_NKI` was true.
|
|
@@ -24,7 +24,10 @@ trntensor/
|
|
|
24
24
|
│ ├── decompose.py # cp_decompose, tucker_decompose (HOSVD)
|
|
25
25
|
│ └── nki/
|
|
26
26
|
│ ├── __init__.py
|
|
27
|
-
│
|
|
27
|
+
│ ├── _kernels.py # @nki.jit kernels
|
|
28
|
+
│ ├── _native.py # TorchNeuron custom ops (nki_op), loaded lazily
|
|
29
|
+
│ ├── collectives.py # nki.collectives all-reduce (reduce-parallel)
|
|
30
|
+
│ └── dispatch.py # host wrappers, dispatch-path selection, _launch
|
|
28
31
|
├── tests/
|
|
29
32
|
│ ├── test_einsum.py # Matmul, bmm, 4-index transform, DF-MP2 pattern
|
|
30
33
|
│ └── test_decompose.py # CP rank-1/low-rank, Tucker orthogonality
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trntensor
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.18.0
|
|
4
4
|
Summary: Tensor contractions for AWS Trainium via NKI
|
|
5
5
|
Author-email: Scott Friedman <scttfrdmn@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -18,8 +18,15 @@ Description-Content-Type: text/markdown
|
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: torch>=2.1
|
|
20
20
|
Requires-Dist: numpy>=1.24
|
|
21
|
+
Provides-Extra: neuron
|
|
22
|
+
Requires-Dist: nki>=0.3.0; extra == "neuron"
|
|
23
|
+
Requires-Dist: torch-neuronx>=2.9; extra == "neuron"
|
|
24
|
+
Provides-Extra: torchneuron
|
|
25
|
+
Requires-Dist: torch>=2.14; extra == "torchneuron"
|
|
26
|
+
Requires-Dist: torch-neuronx>=2.14; extra == "torchneuron"
|
|
27
|
+
Requires-Dist: nki>=0.6; extra == "torchneuron"
|
|
21
28
|
Provides-Extra: dev
|
|
22
|
-
Requires-Dist: pytest
|
|
29
|
+
Requires-Dist: pytest<9,>=7.0; extra == "dev"
|
|
23
30
|
Requires-Dist: pytest-benchmark>=4.0; extra == "dev"
|
|
24
31
|
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
25
32
|
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
@@ -59,8 +66,32 @@ Suite-wide tracker: [trnsci/trnsci#1](https://github.com/trnsci/trnsci/issues/1)
|
|
|
59
66
|
|
|
60
67
|
```bash
|
|
61
68
|
pip install trntensor
|
|
69
|
+
|
|
70
|
+
# Trn2/Trn3 with TorchNeuron (native PyTorch, Neuron SDK 2.33+)
|
|
71
|
+
pip install "trntensor[torchneuron]" --extra-index-url https://pip.repos.neuron.amazonaws.com
|
|
72
|
+
|
|
73
|
+
# Trn1 / PyTorch-XLA lineage
|
|
74
|
+
pip install "trntensor[neuron]" --extra-index-url https://pip.repos.neuron.amazonaws.com
|
|
62
75
|
```
|
|
63
76
|
|
|
77
|
+
Kernels dispatch on whichever Neuron PyTorch lineage is installed:
|
|
78
|
+
|
|
79
|
+
- **TorchNeuron (native)**: Trn2/Trn3, Neuron SDK 2.33+, Python ≥ 3.12,
|
|
80
|
+
`torch` 2.14, `torch-neuronx` 2.14.*. Each kernel is a PyTorch custom op
|
|
81
|
+
(`torch.ops.trntensor.*`) on the `neuron` device; no `torch_xla`.
|
|
82
|
+
- **PyTorch/XLA**: Trn1 (and any host on the `torch-neuronx` 2.9 lineage).
|
|
83
|
+
Kernels dispatch through `torch_xla`, unchanged.
|
|
84
|
+
|
|
85
|
+
trntensor picks the native path when the native `torch_neuronx` and a
|
|
86
|
+
`neuron` device are present, and the XLA path when `torch_xla` is
|
|
87
|
+
installed; otherwise it runs on PyTorch. Set `TRNSCI_NKI_DISPATCH=native`
|
|
88
|
+
or `xla` (shared by all trnsci libraries) to force a path. Pin operands on
|
|
89
|
+
the device with `to_device` / `from_device`; the older `to_xla` /
|
|
90
|
+
`from_xla` still work on both lineages (see the
|
|
91
|
+
[migration note](docs/api/nki.md#migrating-from-to_xla-from_xla)). With an
|
|
92
|
+
editable install (`pip install -e`), set `NKI_ENABLE_TRACE_CACHE=0`: the NKI
|
|
93
|
+
kernel cache only versions installed wheels and can serve stale kernels.
|
|
94
|
+
|
|
64
95
|
## Usage
|
|
65
96
|
|
|
66
97
|
```python
|
|
@@ -103,7 +134,8 @@ core, factors = trntensor.tucker_decompose(tensor, ranks=(5, 5, 5))
|
|
|
103
134
|
- [x] Tucker decomposition (HOSVD)
|
|
104
135
|
- [x] DF-MP2 einsum example
|
|
105
136
|
- [x] NKI fused contraction kernels (`mp2_energy`, `ao_to_mo_transform`)
|
|
106
|
-
- [x]
|
|
137
|
+
- [x] Device operand residency (`to_device` / `from_device`; `to_xla` / `from_xla` kept)
|
|
138
|
+
- [x] Native TorchNeuron dispatch (Trn2/Trn3, `torch.ops.trntensor.*`) alongside PyTorch/XLA (Trn1)
|
|
107
139
|
- [x] NKI CPU simulator + `nki-simulator` CI gate
|
|
108
140
|
- [x] Optimal contraction ordering — greedy path search for 3+ operands
|
|
109
141
|
- [x] Multi-contraction shared-operand XLA pre-pinning
|
|
@@ -1,34 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: trntensor
|
|
3
|
-
Version: 0.17.0
|
|
4
|
-
Summary: Tensor contractions for AWS Trainium via NKI
|
|
5
|
-
Author-email: Scott Friedman <scttfrdmn@gmail.com>
|
|
6
|
-
License-Expression: Apache-2.0
|
|
7
|
-
Project-URL: Homepage, https://github.com/trnsci/trntensor
|
|
8
|
-
Project-URL: Documentation, https://trnsci.dev/trntensor/
|
|
9
|
-
Project-URL: Repository, https://github.com/trnsci/trntensor
|
|
10
|
-
Project-URL: Issues, https://github.com/trnsci/trntensor/issues
|
|
11
|
-
Classifier: Development Status :: 3 - Alpha
|
|
12
|
-
Classifier: Intended Audience :: Science/Research
|
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Topic :: Scientific/Engineering
|
|
15
|
-
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
16
|
-
Requires-Python: >=3.10
|
|
17
|
-
Description-Content-Type: text/markdown
|
|
18
|
-
License-File: LICENSE
|
|
19
|
-
Requires-Dist: torch>=2.1
|
|
20
|
-
Requires-Dist: numpy>=1.24
|
|
21
|
-
Provides-Extra: dev
|
|
22
|
-
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
23
|
-
Requires-Dist: pytest-benchmark>=4.0; extra == "dev"
|
|
24
|
-
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
25
|
-
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
26
|
-
Requires-Dist: pre-commit>=3.7; extra == "dev"
|
|
27
|
-
Requires-Dist: scipy>=1.11; extra == "dev"
|
|
28
|
-
Requires-Dist: mkdocs>=1.5; extra == "dev"
|
|
29
|
-
Requires-Dist: mkdocs-material>=9.0; extra == "dev"
|
|
30
|
-
Dynamic: license-file
|
|
31
|
-
|
|
32
1
|
# trntensor
|
|
33
2
|
|
|
34
3
|
[](https://github.com/trnsci/trntensor/actions/workflows/ci.yml)
|
|
@@ -59,8 +28,32 @@ Suite-wide tracker: [trnsci/trnsci#1](https://github.com/trnsci/trnsci/issues/1)
|
|
|
59
28
|
|
|
60
29
|
```bash
|
|
61
30
|
pip install trntensor
|
|
31
|
+
|
|
32
|
+
# Trn2/Trn3 with TorchNeuron (native PyTorch, Neuron SDK 2.33+)
|
|
33
|
+
pip install "trntensor[torchneuron]" --extra-index-url https://pip.repos.neuron.amazonaws.com
|
|
34
|
+
|
|
35
|
+
# Trn1 / PyTorch-XLA lineage
|
|
36
|
+
pip install "trntensor[neuron]" --extra-index-url https://pip.repos.neuron.amazonaws.com
|
|
62
37
|
```
|
|
63
38
|
|
|
39
|
+
Kernels dispatch on whichever Neuron PyTorch lineage is installed:
|
|
40
|
+
|
|
41
|
+
- **TorchNeuron (native)**: Trn2/Trn3, Neuron SDK 2.33+, Python ≥ 3.12,
|
|
42
|
+
`torch` 2.14, `torch-neuronx` 2.14.*. Each kernel is a PyTorch custom op
|
|
43
|
+
(`torch.ops.trntensor.*`) on the `neuron` device; no `torch_xla`.
|
|
44
|
+
- **PyTorch/XLA**: Trn1 (and any host on the `torch-neuronx` 2.9 lineage).
|
|
45
|
+
Kernels dispatch through `torch_xla`, unchanged.
|
|
46
|
+
|
|
47
|
+
trntensor picks the native path when the native `torch_neuronx` and a
|
|
48
|
+
`neuron` device are present, and the XLA path when `torch_xla` is
|
|
49
|
+
installed; otherwise it runs on PyTorch. Set `TRNSCI_NKI_DISPATCH=native`
|
|
50
|
+
or `xla` (shared by all trnsci libraries) to force a path. Pin operands on
|
|
51
|
+
the device with `to_device` / `from_device`; the older `to_xla` /
|
|
52
|
+
`from_xla` still work on both lineages (see the
|
|
53
|
+
[migration note](docs/api/nki.md#migrating-from-to_xla-from_xla)). With an
|
|
54
|
+
editable install (`pip install -e`), set `NKI_ENABLE_TRACE_CACHE=0`: the NKI
|
|
55
|
+
kernel cache only versions installed wheels and can serve stale kernels.
|
|
56
|
+
|
|
64
57
|
## Usage
|
|
65
58
|
|
|
66
59
|
```python
|
|
@@ -103,7 +96,8 @@ core, factors = trntensor.tucker_decompose(tensor, ranks=(5, 5, 5))
|
|
|
103
96
|
- [x] Tucker decomposition (HOSVD)
|
|
104
97
|
- [x] DF-MP2 einsum example
|
|
105
98
|
- [x] NKI fused contraction kernels (`mp2_energy`, `ao_to_mo_transform`)
|
|
106
|
-
- [x]
|
|
99
|
+
- [x] Device operand residency (`to_device` / `from_device`; `to_xla` / `from_xla` kept)
|
|
100
|
+
- [x] Native TorchNeuron dispatch (Trn2/Trn3, `torch.ops.trntensor.*`) alongside PyTorch/XLA (Trn1)
|
|
107
101
|
- [x] NKI CPU simulator + `nki-simulator` CI gate
|
|
108
102
|
- [x] Optimal contraction ordering — greedy path search for 3+ operands
|
|
109
103
|
- [x] Multi-contraction shared-operand XLA pre-pinning
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# NKI dispatch
|
|
2
|
+
|
|
3
|
+
Backend selection between the PyTorch fallback and the NKI-accelerated
|
|
4
|
+
path on Trainium. Kernels live in `trntensor.nki._kernels`; the
|
|
5
|
+
public-facing dispatch is in `trntensor.nki.dispatch`.
|
|
6
|
+
|
|
7
|
+
## `set_backend(backend: str)`
|
|
8
|
+
|
|
9
|
+
- `"auto"` — use NKI if `nki` is importable, else PyTorch
|
|
10
|
+
- `"pytorch"` — always use `torch.matmul` / `torch.einsum`
|
|
11
|
+
- `"nki"` — require NKI; raises `RuntimeError` on non-Neuron hosts
|
|
12
|
+
|
|
13
|
+
## `get_backend() -> str`
|
|
14
|
+
|
|
15
|
+
Return the current backend selection.
|
|
16
|
+
|
|
17
|
+
## `HAS_NKI: bool`
|
|
18
|
+
|
|
19
|
+
Module-level flag set at import time. `True` when `nki` (0.3.0+) is
|
|
20
|
+
importable, otherwise `False`.
|
|
21
|
+
|
|
22
|
+
## Dispatch path
|
|
23
|
+
|
|
24
|
+
On Neuron hardware, kernels run on one of two `torch-neuronx` lineages,
|
|
25
|
+
detected on the first kernel launch (never at import):
|
|
26
|
+
|
|
27
|
+
- **Native (TorchNeuron, Trn2/Trn3, Neuron SDK 2.33+)** — chosen when
|
|
28
|
+
`torch_neuronx` exports `nki_op` and a `neuron` device is available
|
|
29
|
+
(`torch_neuronx.device_count() > 0`). Each kernel is a PyTorch custom op
|
|
30
|
+
on `device="neuron"`, also callable directly and inside
|
|
31
|
+
`torch.compile(backend="neuron")`: `torch.ops.trntensor.matmul`,
|
|
32
|
+
`batched_matmul`, `mp2_energy`, `ao_to_mo_transform`. The ops are
|
|
33
|
+
registered only once this path is selected, and this path never imports
|
|
34
|
+
`torch_xla`.
|
|
35
|
+
- **XLA (Trn1)** — chosen when `torch_xla` is installed and the native
|
|
36
|
+
path is unavailable. Kernels run on the `torch_xla` device, unchanged.
|
|
37
|
+
- Otherwise there is no device path: the host wrappers fall back to
|
|
38
|
+
`torch` (or raise under `TRNTENSOR_REQUIRE_NKI=1`), as before.
|
|
39
|
+
|
|
40
|
+
`set_backend` is unaffected: it still chooses NKI vs PyTorch. Set the
|
|
41
|
+
suite-wide `TRNSCI_NKI_DISPATCH=native` or `xla` to force a path; forcing an
|
|
42
|
+
unavailable path raises `RuntimeError`.
|
|
43
|
+
|
|
44
|
+
The reduce-parallel all-reduce kernel (`trntensor.nki.collectives`) is
|
|
45
|
+
native-only already; it keeps its `torch_neuronx.wrap_nki` launch because
|
|
46
|
+
its `ReplicaGroup` argument is a compile-time constant that a custom-op
|
|
47
|
+
schema cannot carry.
|
|
48
|
+
|
|
49
|
+
Precision modes follow the same launch: `precision="sr"` passes
|
|
50
|
+
`use_sr=True` to the `matmul` / `batched_matmul` op (stochastic rounding
|
|
51
|
+
still needs `NEURON_RT_STOCHASTIC_ROUNDING_EN=1` at process start and warns
|
|
52
|
+
once otherwise); `precision="kahan"` contracts in true fp64 on the host
|
|
53
|
+
(Trainium has no fp64 datapath) on both paths; `precision="dd"` still
|
|
54
|
+
raises on NKI hosts pending trnblas#22.
|
|
55
|
+
|
|
56
|
+
## `to_device(tensor) -> Tensor` / `from_device(tensor) -> Tensor`
|
|
57
|
+
|
|
58
|
+
Pin an operand on the Trainium device of the active dispatch path —
|
|
59
|
+
`neuron` on TorchNeuron, the XLA device on Trn1 — so repeated trntensor
|
|
60
|
+
calls skip the host↔device transfer that otherwise dominates dispatch
|
|
61
|
+
overhead.
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import trntensor
|
|
65
|
+
|
|
66
|
+
# One-time transfer onto the accelerator.
|
|
67
|
+
eri_d = trntensor.to_device(eri)
|
|
68
|
+
C_occ_d = trntensor.to_device(C_occ)
|
|
69
|
+
C_vir_d = trntensor.to_device(C_vir)
|
|
70
|
+
eps_occ_d = trntensor.to_device(eps_occ)
|
|
71
|
+
eps_vir_d = trntensor.to_device(eps_vir)
|
|
72
|
+
|
|
73
|
+
# Full DF-MP2 pipeline — B_d never leaves the device.
|
|
74
|
+
B_d = trntensor.ao_to_mo_transform(eri_d, C_occ_d, C_vir_d)
|
|
75
|
+
E_d = trntensor.mp2_energy(B_d, eps_occ_d, eps_vir_d)
|
|
76
|
+
|
|
77
|
+
# Pull the scalar back when we actually need it in Python.
|
|
78
|
+
E = trntensor.from_device(E_d)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- `to_device`: no-op when the tensor is already on a Neuron device.
|
|
82
|
+
Raises `RuntimeError` on hosts without the NKI runtime.
|
|
83
|
+
- `from_device`: no-op when the tensor is already on CPU.
|
|
84
|
+
|
|
85
|
+
When every operand is already on the device, dispatch skips the per-call
|
|
86
|
+
transfer, uses the lower "pinned" FLOP threshold, and returns the result on
|
|
87
|
+
the device — the caller controls when to pull back.
|
|
88
|
+
|
|
89
|
+
## `to_xla(tensor) -> Tensor` / `from_xla(tensor) -> Tensor`
|
|
90
|
+
|
|
91
|
+
The original names, kept for compatibility. On Trn1 they behave exactly as
|
|
92
|
+
before. On TorchNeuron there is no XLA device, so `to_xla` places the
|
|
93
|
+
tensor on `neuron` instead (residency works the same way) and `from_xla`
|
|
94
|
+
moves it back to CPU.
|
|
95
|
+
|
|
96
|
+
### Migrating from `to_xla` / `from_xla`
|
|
97
|
+
|
|
98
|
+
Replace `to_xla` with `to_device` and `from_xla` with `from_device`. Same
|
|
99
|
+
behaviour on Trn1; on Trn2/Trn3 the new names say what they do. Checks such
|
|
100
|
+
as `t.device.type == "xla"` become `t.device.type in ("xla", "neuron")`.
|
|
101
|
+
|
|
102
|
+
`to_xla` / `from_xla` stay available. When the suite-wide
|
|
103
|
+
`TRNSCI_XLA_DEPRECATION=1` is set (off by default; trnsci turns it on at
|
|
104
|
+
TorchNeuron GA), each emits a one-time `DeprecationWarning` pointing at the
|
|
105
|
+
new names, and selecting the XLA dispatch path emits: "the PyTorch/XLA path
|
|
106
|
+
is deprecated on Trn2/Trn3; use TorchNeuron (native). Trn1/Inf2 remain
|
|
107
|
+
supported in maintenance mode."
|
|
108
|
+
|
|
109
|
+
## Environment variables
|
|
110
|
+
|
|
111
|
+
| Variable | Effect |
|
|
112
|
+
|---|---|
|
|
113
|
+
| `TRNTENSOR_REQUIRE_NKI=1` | Re-raise kernel exceptions instead of falling back to PyTorch. Useful in the validation loop to surface silent kernel breakage. |
|
|
114
|
+
| `TRNTENSOR_MIN_NKI_FLOPS=<int>` | XLA path: override the FLOP threshold (M·K·N) below which dispatch skips NKI and uses `torch.matmul` / `torch.bmm` directly. Default: `2_000_000_000`. Set to `0` to force NKI for kernel validation. |
|
|
115
|
+
| `TRNTENSOR_MIN_NKI_FLOPS_PINNED=<int>` | XLA path, operands already on the device. Default: `1_000_000_000`. |
|
|
116
|
+
| `TRNTENSOR_MIN_NKI_FLOPS_NATIVE=<int>` | Native (TorchNeuron) path, operands on CPU: M·K·N at which the work leaves the host for the `neuron` device. Below it, `torch.matmul` / `torch.bmm` run on the host. Above it, the operands are offloaded. The offload runs aten unless the pinned threshold below selects NKI. Default: `500_000_000` (measured on Trn2, see below). |
|
|
117
|
+
| `TRNTENSOR_MIN_NKI_FLOPS_NATIVE_PINNED=<int>\|never` | Native path: M·K·N at which the NKI kernel replaces aten on the device. Below it, device-resident operands run `torch.matmul` / `torch.bmm` (aten) on `neuron`. Default: `never`, because on Trn2 aten beat the NKI kernels at every measured size. |
|
|
118
|
+
| `TRNSCI_NKI_DISPATCH=auto\|native\|xla` | Suite-wide. Force the native or XLA dispatch path; `auto` (default) detects. Forcing an unavailable path raises. |
|
|
119
|
+
| `TRNSCI_XLA_DEPRECATION=1` | Suite-wide, off by default. Emit the one-time XLA-path and `to_xla` / `from_xla` deprecation warnings. |
|
|
120
|
+
| `NKI_ENABLE_TRACE_CACHE=0` | TorchNeuron setting (not trntensor's). Turns off the cross-process NKI kernel cache, which cannot version editable installs and may serve a stale kernel after a source edit. Set it with `pip install -e`; the test suite sets it by default. |
|
|
121
|
+
| `TRNTENSOR_FORCE_BACKEND=pytorch\|nki\|auto` | Override the backend selection at runtime without calling `set_backend()`. Used by benchmarks to sweep both paths on the same machine. |
|
|
122
|
+
| `TRNTENSOR_USE_SIMULATOR=1` | Route kernel dispatch through `nki.simulate(kernel)(numpy_args)` on CPU instead of XLA → NEFF → hardware. Catches Python-trace-level errors without AWS round-trips. MLIR verifier errors remain hardware-only. |
|
|
123
|
+
|
|
124
|
+
### Native thresholds: measured on Trn2
|
|
125
|
+
|
|
126
|
+
These were measured on a trn2.3xlarge (Neuron SDK 2.33, NKI 0.7.0), using one
|
|
127
|
+
NeuronCore and two host threads, with `scripts/bench_native_einsum.py` and
|
|
128
|
+
`scripts/autotune_dispatch.py` (#41):
|
|
129
|
+
|
|
130
|
+
- **Pinned operands: NKI never beats aten.** On device-resident operands,
|
|
131
|
+
aten `torch.matmul` / `torch.bmm` beat the trntensor NKI matmul and
|
|
132
|
+
batched-matmul kernels at every size from 128³ to 4096³, in both fp32 and
|
|
133
|
+
bf16. Examples:
|
|
134
|
+
- 4096³ bf16: 1.38 ms with aten, 6.82 ms with NKI.
|
|
135
|
+
- 1024³ fp32: 0.20 ms with aten, 0.55 ms with NKI.
|
|
136
|
+
|
|
137
|
+
The eager launch floor is about 0.13 ms for an aten op and about 0.24 ms for
|
|
138
|
+
an NKI custom op.
|
|
139
|
+
- **Host operands: offload to aten from about 0.5 G multiply-adds.**
|
|
140
|
+
Offloading to aten (upload, run on device, download) beats offloading
|
|
141
|
+
through the NKI kernel at every size. It also beats host torch:
|
|
142
|
+
- fp32: from about 134 M multiply-adds (512³) when the host has two
|
|
143
|
+
threads.
|
|
144
|
+
- bf16: from about 0.5 to 1 G multiply-adds.
|
|
145
|
+
|
|
146
|
+
The default of 500 M sits between these. A host with more threads moves the
|
|
147
|
+
crossover up. Re-measure on your host with `scripts/autotune_dispatch.py`.
|
|
148
|
+
|
|
149
|
+
Under `"auto"` on the native path, the fused quantum kernels (`mp2_energy`,
|
|
150
|
+
`ao_to_mo_transform`) also run as aten, because both measured slower than
|
|
151
|
+
aten on the device:
|
|
152
|
+
|
|
153
|
+
- AO→MO was 6–20× slower.
|
|
154
|
+
- MP2 energy was 1.0–1.5× slower, reaching parity at best.
|
|
155
|
+
|
|
156
|
+
`set_backend("nki")` still runs the NKI kernels. The kernels are unchanged,
|
|
157
|
+
and the XLA path keeps them under `"auto"`.
|
|
158
|
+
|
|
159
|
+
## Kernels (internal)
|
|
160
|
+
|
|
161
|
+
- `matmul_kernel(a, b)` — 2-index matmul with stationary-A tile reuse.
|
|
162
|
+
Tile constants: `TILE_M=128`, `TILE_K=128`, `TILE_N=512`.
|
|
163
|
+
- `batched_matmul_kernel(a, b)` — per-batch-slice matmul. Batch dim
|
|
164
|
+
iterated via `nl.affine_range`; each slice reuses the stationary-A
|
|
165
|
+
tile layout.
|
|
166
|
+
|
|
167
|
+
The DF-MP2 pair pattern `einsum("ap,bp->ab")` is served by
|
|
168
|
+
`matmul_kernel` through the planner's `transB=True` route — no
|
|
169
|
+
dedicated kernel needed. Fused energy-denominator kernel is tracked
|
|
170
|
+
in [#13][i13].
|
|
171
|
+
|
|
172
|
+
[i13]: https://github.com/trnsci/trntensor/issues/13
|
|
173
|
+
|
|
174
|
+
[m2]: https://github.com/trnsci/trntensor/milestone/2
|
|
@@ -40,9 +40,15 @@ print(f"E_MP2 = {E.item():.6f}")
|
|
|
40
40
|
|
|
41
41
|
### Backend behaviour
|
|
42
42
|
|
|
43
|
-
- **CPU
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
- **CPU, and native TorchNeuron under `"auto"`**: aten ops on the operands' device.
|
|
44
|
+
`T[i, j, a, b]` is contracted with `torch.einsum` in chunks over `i`, which
|
|
45
|
+
bounds peak memory to about 64 MiB of `T` at a time. The `T`-weighted sum is
|
|
46
|
+
vectorized. This replaces the former Python loop over `(i, j)` pairs, which
|
|
47
|
+
ran 10–40× slower on a Trainium device.
|
|
48
|
+
On Trn2 the aten form matched or beat the fused kernel. For example, with
|
|
49
|
+
`nocc=32, nvir=128, naux=512` it took 3.1 ms, against 4.5 ms for the
|
|
50
|
+
kernel (#41).
|
|
51
|
+
- **Trainium (NKI): the PyTorch/XLA path, or `set_backend("nki")`**: dispatches a single `@nki.jit` program that
|
|
46
52
|
- accumulates `T` in PSUM via `nisa.nc_matmul`,
|
|
47
53
|
- builds `Δ` on the Vector Engine from SBUF-resident `ε` tiles,
|
|
48
54
|
- folds the energy into a scalar accumulator in SBUF,
|
|
@@ -85,8 +91,12 @@ E = trntensor.mp2_energy(B, eps_occ, eps_vir)
|
|
|
85
91
|
|
|
86
92
|
### Backend behaviour
|
|
87
93
|
|
|
88
|
-
- **CPU
|
|
89
|
-
|
|
94
|
+
- **CPU, and native TorchNeuron under `"auto"`**: two explicit aten steps,
|
|
95
|
+
`einsum("mi,mnP->inP")` then `einsum("na,inP->iaP")`, on the operands'
|
|
96
|
+
device. On Trn2 this was 6–20× faster than the fused kernel. For example,
|
|
97
|
+
with `nbasis=128, nocc=16, naux=256` it took 0.82 ms, against 16.4 ms for
|
|
98
|
+
the kernel (#41).
|
|
99
|
+
- **Trainium (NKI): the PyTorch/XLA path, or `set_backend("nki")`**: dispatches a single `@nki.jit` program that
|
|
90
100
|
- loads `C_occ` and `C_vir` once, SBUF-resident across all P iterations,
|
|
91
101
|
- for each auxiliary index P: two sequential `nisa.nc_matmul` calls with the intermediate `(i, ν)` tile round-tripping through kernel-scratch HBM to handle the partition-dim change,
|
|
92
102
|
- writes one `(nocc, nvir)` slice per P to the output HBM tensor.
|
|
@@ -15,7 +15,7 @@ as the primary design surface.
|
|
|
15
15
|
| Multiple `Plan` objects with HBM intermediates | `multi_einsum()` with shared-operand pre-pinning |
|
|
16
16
|
| `cutensorDecompositionCreate` (Tucker HOSVD) | `tucker_decompose()` |
|
|
17
17
|
| Custom THC / Cholesky-factored ERIs | `cp_decompose()` (tensor hypercontraction) |
|
|
18
|
-
| CUDA stream + `cudaMemcpy` to pin device memory | `
|
|
18
|
+
| CUDA stream + `cudaMemcpy` to pin device memory | `to_device(tensor)` / `from_device(tensor)` (formerly `to_xla` / `from_xla`) |
|
|
19
19
|
|
|
20
20
|
## 2-Operand contractions — the generic path
|
|
21
21
|
|
|
@@ -119,12 +119,14 @@ XLA-resident copy is used for all subsequent contractions in the batch.
|
|
|
119
119
|
|
|
120
120
|
On CPU (no NKI), `multi_einsum` behaves exactly like a loop over `einsum()`.
|
|
121
121
|
|
|
122
|
-
##
|
|
122
|
+
## Device residency: `to_device` / `from_device`
|
|
123
123
|
|
|
124
|
-
The NKI dispatch path always transfers operands to the Trainium
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
The NKI dispatch path always transfers operands to the Trainium device
|
|
125
|
+
(`neuron` on TorchNeuron, the XLA device on Trn1) before kernel launch. For a
|
|
126
|
+
single large matmul this cost is negligible; for a tight loop of small
|
|
127
|
+
contractions it dominates. `to_device` / `from_device` expose the transfer
|
|
128
|
+
explicitly so callers can control when it happens. `to_xla` / `from_xla` are
|
|
129
|
+
the older names for the same thing and still work on both lineages:
|
|
128
130
|
|
|
129
131
|
```python
|
|
130
132
|
# Cold path: B transferred on every call (3 transfers for 3 calls)
|
|
@@ -132,17 +134,17 @@ for _ in range(3):
|
|
|
132
134
|
result = trntensor.einsum("ij,jk->ik", A, B)
|
|
133
135
|
|
|
134
136
|
# Residency path: B transferred once, result stays on device until needed
|
|
135
|
-
A_x = trntensor.
|
|
136
|
-
B_x = trntensor.
|
|
137
|
+
A_x = trntensor.to_device(A)
|
|
138
|
+
B_x = trntensor.to_device(B)
|
|
137
139
|
for _ in range(3):
|
|
138
140
|
result_x = trntensor.einsum("ij,jk->ik", A_x, B_x) # zero transfer cost
|
|
139
|
-
result = trntensor.
|
|
141
|
+
result = trntensor.from_device(result_x)
|
|
140
142
|
```
|
|
141
143
|
|
|
142
144
|
The residency API maps to the CUDA concept of a device-pinned buffer, but with
|
|
143
145
|
explicit Python-level transfer rather than stream-implicit staging.
|
|
144
146
|
|
|
145
|
-
`to_xla` raises `RuntimeError` on hosts without `nki` installed.
|
|
147
|
+
`to_device` (like `to_xla`) raises `RuntimeError` on hosts without `nki` installed.
|
|
146
148
|
|
|
147
149
|
## 3+ operand einsums: contraction-path search
|
|
148
150
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "trntensor"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.18.0"
|
|
8
8
|
description = "Tensor contractions for AWS Trainium via NKI"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -25,8 +25,24 @@ dependencies = [
|
|
|
25
25
|
]
|
|
26
26
|
|
|
27
27
|
[project.optional-dependencies]
|
|
28
|
+
neuron = [
|
|
29
|
+
# PyTorch/XLA lineage (Trn1, and Trn2 on PyTorch 2.9). NKI 0.3.0 Stable
|
|
30
|
+
# (Neuron SDK 2.29) promotes `nki.*` as the canonical namespace. Ships with
|
|
31
|
+
# the Deep Learning AMI Neuron or via https://pip.repos.neuron.amazonaws.com.
|
|
32
|
+
"nki>=0.3.0",
|
|
33
|
+
"torch-neuronx>=2.9",
|
|
34
|
+
]
|
|
35
|
+
torchneuron = [
|
|
36
|
+
# TorchNeuron / native PyTorch (Neuron SDK 2.33+, Trn2/Trn3; torch-neuronx
|
|
37
|
+
# 2.14 itself requires Python >= 3.12). Install with
|
|
38
|
+
# --extra-index-url https://pip.repos.neuron.amazonaws.com. The nki floor
|
|
39
|
+
# also keeps pip off the unrelated `nki` 0.0.1 on public PyPI.
|
|
40
|
+
"torch>=2.14",
|
|
41
|
+
"torch-neuronx>=2.14",
|
|
42
|
+
"nki>=0.6",
|
|
43
|
+
]
|
|
28
44
|
dev = [
|
|
29
|
-
"pytest>=7.0",
|
|
45
|
+
"pytest>=7.0,<9", # pytest-benchmark 5.3 breaks on pytest 9 (Function._nodeid)
|
|
30
46
|
"pytest-benchmark>=4.0",
|
|
31
47
|
"pytest-cov>=4.0",
|
|
32
48
|
"ruff>=0.6",
|
|
@@ -47,11 +63,13 @@ include = ["trntensor*"]
|
|
|
47
63
|
|
|
48
64
|
# Neuron SDK note: on-hardware runs use the AWS Deep Learning AMI's
|
|
49
65
|
# pre-built venv at /opt/aws_neuronx_venv_pytorch_*, which bundles
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
66
|
+
# the NKI runtime. The DLAMI's terraform `most_recent = true` pulls the
|
|
67
|
+
# current image and its venv tracks the current SDK. Outside the DLAMI, use
|
|
68
|
+
# the `[torchneuron]` (Trn2/Trn3, native) or `[neuron]` (Trn1, PyTorch/XLA)
|
|
69
|
+
# extra with the Neuron pip repo. Both lineages publish a package named
|
|
70
|
+
# `torch-neuronx`, so pip markers cannot pick between them; choose the extra
|
|
71
|
+
# that matches the instance. The base dependency set stays CPU-only and
|
|
72
|
+
# resolves cleanly from PyPI.
|
|
55
73
|
|
|
56
74
|
[tool.ruff]
|
|
57
75
|
# Match the rest of the trnsci suite. Line length 100 is a compromise
|