trnsparse 0.4.1__tar.gz → 0.6.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.
- {trnsparse-0.4.1 → trnsparse-0.6.0}/.github/workflows/ci.yml +3 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/.pre-commit-config.yaml +1 -1
- {trnsparse-0.4.1 → trnsparse-0.6.0}/CHANGELOG.md +177 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/CLAUDE.md +23 -22
- {trnsparse-0.4.1/trnsparse.egg-info → trnsparse-0.6.0}/PKG-INFO +35 -8
- trnsparse-0.6.0/README.md +100 -0
- trnsparse-0.6.0/docs/architecture.md +143 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/docs/benchmarks.md +22 -15
- trnsparse-0.6.0/docs/sparse_attention.md +229 -0
- trnsparse-0.6.0/examples/block_sparse_attention.py +309 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/mkdocs.yml +2 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/pyproject.toml +1 -1
- trnsparse-0.6.0/tests/test_attention.py +327 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/tests/test_iterative.py +91 -0
- trnsparse-0.6.0/tests/test_nki_attn.py +201 -0
- trnsparse-0.6.0/tests/test_nki_sim.py +432 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/trnsparse/__init__.py +15 -2
- {trnsparse-0.4.1 → trnsparse-0.6.0}/trnsparse/iterative.py +150 -0
- trnsparse-0.6.0/trnsparse/nki/dispatch.py +929 -0
- trnsparse-0.6.0/trnsparse/nki/kernels.py +573 -0
- trnsparse-0.6.0/trnsparse/ops.py +625 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0/trnsparse.egg-info}/PKG-INFO +35 -8
- {trnsparse-0.4.1 → trnsparse-0.6.0}/trnsparse.egg-info/SOURCES.txt +4 -0
- trnsparse-0.4.1/README.md +0 -73
- trnsparse-0.4.1/docs/architecture.md +0 -109
- trnsparse-0.4.1/tests/test_nki_sim.py +0 -153
- trnsparse-0.4.1/trnsparse/nki/dispatch.py +0 -487
- trnsparse-0.4.1/trnsparse/nki/kernels.py +0 -192
- trnsparse-0.4.1/trnsparse/ops.py +0 -277
- {trnsparse-0.4.1 → trnsparse-0.6.0}/.github/workflows/notify-umbrella.yml +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/.github/workflows/publish.yml +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/.gitignore +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/CODE_OF_CONDUCT.md +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/CONTRIBUTING.md +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/LICENSE +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/benchmarks/bench_bsr_spmm.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/benchmarks/bench_iterative.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/benchmarks/bench_screening.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/benchmarks/bench_spmm.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/benchmarks/bench_spmv.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/benchmarks/conftest.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/docs/api.md +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/docs/aws_setup.md +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/docs/index.md +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/docs/installation.md +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/docs/iterative_solvers.md +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/docs/migration_scipy.md +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/docs/quickstart.md +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/examples/sparse_fock.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/infra/terraform/.terraform.lock.hcl +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/infra/terraform/README.md +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/infra/terraform/main.tf +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/scripts/bench_to_md.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/scripts/run_benchmarks.sh +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/scripts/run_neuron_tests.sh +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/scripts/run_simulator_tests.sh +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/setup.cfg +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/tests/conftest.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/tests/test_bsr.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/tests/test_examples.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/tests/test_formats.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/tests/test_nki_bsr.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/tests/test_nki_screened_spmm.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/tests/test_nki_spmm.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/tests/test_ops.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/tests/test_screening.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/trnsparse/formats.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/trnsparse/nki/__init__.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/trnsparse/screening.py +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/trnsparse.egg-info/dependency_links.txt +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/trnsparse.egg-info/requires.txt +0 -0
- {trnsparse-0.4.1 → trnsparse-0.6.0}/trnsparse.egg-info/top_level.txt +0 -0
|
@@ -41,6 +41,8 @@ jobs:
|
|
|
41
41
|
# Catches Python-trace-level errors (bad kwargs, dropped ops, shape
|
|
42
42
|
# mismatches) pre-merge without AWS round-trips. MLIR verifier
|
|
43
43
|
# errors remain hardware-only (simulator explicitly skips compile).
|
|
44
|
+
# TRNSPARSE_REQUIRE_NKI=1 disables the PyTorch fallback so kernel
|
|
45
|
+
# failures propagate — the simulator tests actually validate NKI kernels.
|
|
44
46
|
runs-on: ubuntu-latest
|
|
45
47
|
steps:
|
|
46
48
|
- uses: actions/checkout@v6
|
|
@@ -55,4 +57,5 @@ jobs:
|
|
|
55
57
|
- name: Run simulator-backed kernel tests
|
|
56
58
|
env:
|
|
57
59
|
TRNSPARSE_USE_SIMULATOR: "1"
|
|
60
|
+
TRNSPARSE_REQUIRE_NKI: "1"
|
|
58
61
|
run: pytest tests/ -v -m nki_simulator --tb=short
|
|
@@ -5,6 +5,183 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.6.0] — 2026-04-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **K-tiling for head_dim > 128** — NKI attention kernels now support
|
|
13
|
+
`head_dim=256` and `head_dim=512` via an inner K-tile loop that splits
|
|
14
|
+
the `Q @ K.T` score computation across `TILE_K=128`-sized chunks of
|
|
15
|
+
`head_dim`, accumulating each into the existing PSUM.
|
|
16
|
+
- All 4 NKI kernels updated: `_attn_stats_kernel`, `_attn_out_kernel`,
|
|
17
|
+
`_attn_bwd_dq_kernel`, `_attn_bwd_dkdv_kernel`.
|
|
18
|
+
- For `head_dim ≤ 128`: single-tile path preserved unchanged — Q is
|
|
19
|
+
loaded once per block-row as a stationary tile (no regression).
|
|
20
|
+
- For `head_dim > 128`: K-tile inner loop (`affine_range(head_dim //
|
|
21
|
+
128)`). `head_dim` must be a multiple of 128 (covers 256, 512).
|
|
22
|
+
- `weights @ V` and all dK/dV accumulation matmuls are unchanged (K=128
|
|
23
|
+
block dimension, unaffected by head_dim growth).
|
|
24
|
+
- `tests/test_attention.py`: `test_head_dim_256_parity`,
|
|
25
|
+
`test_head_dim_256_dilated_parity`, `test_gradcheck_head_dim_256`,
|
|
26
|
+
`test_backward_shapes_head_dim_256` in PyTorch path.
|
|
27
|
+
- `tests/test_nki_sim.py`: `TestAttnKTilingSimulator` — simulator parity
|
|
28
|
+
tests for forward and backward at head_dim=256.
|
|
29
|
+
- `tests/test_nki_attn.py`: `TestAttnHardwareLargeDim` — hardware parity
|
|
30
|
+
tests at seq_len=512, head_dim=256.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- `_attn_gather` assertion relaxed from `head_dim ≤ 128` to `head_dim ≤ 128
|
|
35
|
+
or head_dim % 128 == 0`.
|
|
36
|
+
- `block_sparse_attention_tiled` and `nki_bsr_attn_tiled` docstrings updated
|
|
37
|
+
to document K-tiling support.
|
|
38
|
+
|
|
39
|
+
## [0.5.1] — 2026-04-16
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- **NKI backward kernel pair** (`_attn_bwd_dq_kernel` + `_attn_bwd_dkdv_kernel`)
|
|
44
|
+
in `trnsparse/nki/kernels.py`. When the `nki` backend is active,
|
|
45
|
+
`_AttnTiledFunction.backward` now dispatches to these kernels instead of
|
|
46
|
+
the Python-loop backward.
|
|
47
|
+
- `_attn_bwd_dq_kernel`: row-first traversal, mirrors `_attn_out_kernel`.
|
|
48
|
+
Accumulates `dQ_m += dS @ K_ki * scale` in a PSUM tile per block-row.
|
|
49
|
+
- `_attn_bwd_dkdv_kernel`: column-first traversal (BSC view built on host).
|
|
50
|
+
For each column block ki, iterates over all block-rows m that attend to ki,
|
|
51
|
+
accumulating `dK_ki += dS.T @ Q_m * scale` and `dV_ki += P.T @ dO_m`.
|
|
52
|
+
- No atomic scatter required — column-first gather on host eliminates NKI's
|
|
53
|
+
lack of cross-block accumulation primitives.
|
|
54
|
+
- **Stats saving in forward** — `_AttnTiledFunction.forward` now saves
|
|
55
|
+
`(Q, K, V, O, row_max, row_denom)` in ctx (6 tensors vs 4). Backward
|
|
56
|
+
receives the pre-computed row stats and skips the two recomputation passes.
|
|
57
|
+
Applies to both PyTorch and NKI paths.
|
|
58
|
+
- `_attn_bwd_gather` and `nki_bsr_attn_bwd` in `trnsparse/nki/dispatch.py`
|
|
59
|
+
— host-side BSC construction and NKI backward orchestration.
|
|
60
|
+
- `tests/test_nki_sim.py`: `TestAttnBwdSimulator` — simulator correctness tests
|
|
61
|
+
for dQ/dK/dV against PyTorch backward (local window + dilated patterns).
|
|
62
|
+
- `tests/test_nki_attn.py`: `TestAttnBwdHardware` — hardware parity tests
|
|
63
|
+
at seq_len=512, head_dim=64.
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
67
|
+
- `nki_bsr_attn_tiled` accepts `return_stats=True` kwarg (default False) to
|
|
68
|
+
return `(out, row_max, row_denom)`.
|
|
69
|
+
- `_block_sparse_attn_pytorch` accepts `return_stats=True` kwarg similarly.
|
|
70
|
+
- `_block_sparse_attn_backward` accepts optional `row_max` / `row_denom`
|
|
71
|
+
kwargs; when provided, skips the two recomputation BSR passes.
|
|
72
|
+
|
|
73
|
+
## [0.5.0] — 2026-04-16
|
|
74
|
+
|
|
75
|
+
### Added
|
|
76
|
+
|
|
77
|
+
- **Block-sparse attention autograd** — `block_sparse_attention_tiled` is now
|
|
78
|
+
differentiable. When any of Q/K/V has `requires_grad=True`, the call routes
|
|
79
|
+
through `_AttnTiledFunction`, which provides a tiled backward using the Flash
|
|
80
|
+
Attention delta identity (`D_i = dO_i · O_i`).
|
|
81
|
+
- **`_block_sparse_attn_backward(Q, K, V, O, dO, mask_bsr, scale)`** — internal
|
|
82
|
+
backward function. Single pass over nonzero BSR blocks; no O(seq_len²)
|
|
83
|
+
intermediate. Row stats (row_max/row_denom) are recomputed in backward.
|
|
84
|
+
- `gradcheck` passes at `atol=1e-3` for local-window and dilated patterns
|
|
85
|
+
(float64, seq_len=256, head_dim=32). See `tests/test_attention.py::TestAttnTiledGrad`.
|
|
86
|
+
|
|
87
|
+
### Notes
|
|
88
|
+
|
|
89
|
+
- NKI backward kernel is a follow-up (v0.5.x). The current backward runs
|
|
90
|
+
on PyTorch even when the NKI forward path is active.
|
|
91
|
+
- Row stats (row_max/row_denom) are recomputed in backward rather than saved
|
|
92
|
+
from forward — avoids O(n_blocks × b) storage in the autograd graph at the
|
|
93
|
+
cost of two extra BSR passes.
|
|
94
|
+
|
|
95
|
+
## [0.4.4] — 2026-04-16
|
|
96
|
+
|
|
97
|
+
### Added
|
|
98
|
+
|
|
99
|
+
- **NKI attention kernel pair** (`_attn_stats_kernel` + `_attn_out_kernel`,
|
|
100
|
+
closes [#25](https://github.com/trnsci/trnsparse/issues/25)). Two-pass
|
|
101
|
+
block-sparse attention now runs on the Tensor Engine via these kernels when
|
|
102
|
+
the `nki` backend is active. The `pytorch` backend retains the Python-loop
|
|
103
|
+
reference path from v0.4.3.
|
|
104
|
+
- Pass 1 (`_attn_stats_kernel`): each `(m, ki)` block pair computed
|
|
105
|
+
independently via `nc_matmul`; `nl.max` / `nl.sum` within-tile reductions
|
|
106
|
+
produce `(tile_max, tile_sumexp)` with no carry between iterations.
|
|
107
|
+
- Pass 2 (`_attn_out_kernel`): recomputes scores, applies stable softmax
|
|
108
|
+
using `row_max` / `row_denom` loaded per block-row (static HBM offset),
|
|
109
|
+
accumulates `weights @ V` into a PSUM tile spanning all ki blocks.
|
|
110
|
+
- **Constraint:** `head_dim ≤ 128` (`nc_matmul` partition limit). `head_dim=256`
|
|
111
|
+
requires K-tiling and is a follow-up.
|
|
112
|
+
- `_attn_gather`, `_attn_host_reduction`, `nki_bsr_attn_tiled` in
|
|
113
|
+
`trnsparse/nki/dispatch.py` — host-side gather and orchestration for the kernel
|
|
114
|
+
pair, mirroring the `_bsr_pad_and_gather` pattern.
|
|
115
|
+
- `tests/test_nki_sim.py`: `TestAttnTiledSimulator` — simulator correctness
|
|
116
|
+
tests (local window, dilated; seq_len=256, head_dim=32).
|
|
117
|
+
- `tests/test_nki_attn.py`: hardware tests for local window, dilated, and
|
|
118
|
+
global-token patterns at seq_len=512, head_dim=64.
|
|
119
|
+
|
|
120
|
+
### Notes
|
|
121
|
+
|
|
122
|
+
No autograd wrapping in v0.4.4 — forward-only, matching the existing PyTorch
|
|
123
|
+
path. Attention backward (block-sparse) is a follow-up.
|
|
124
|
+
|
|
125
|
+
## [0.4.3] — 2026-04-16
|
|
126
|
+
|
|
127
|
+
### Added
|
|
128
|
+
|
|
129
|
+
- **`chebyshev_bsr(A, b, lam_min, lam_max, K)`** — fixed-K Chebyshev
|
|
130
|
+
semi-iteration. Pre-computes all step coefficients from eigenvalue bounds
|
|
131
|
+
before the loop; no inner products during iteration. Same convergence rate
|
|
132
|
+
as CG without the adaptive coefficient computation that blocks NKI fusion.
|
|
133
|
+
Returns `(x, K, rel_residual)` matching the `cg_bsr` signature.
|
|
134
|
+
- **`chebyshev_coeffs(lam_min, lam_max, K)`** — returns the `(alpha, beta)`
|
|
135
|
+
coefficient tensors for the momentum update `x_{k+1} = x_k + α_k r_k +
|
|
136
|
+
β_k (x_k - x_{k-1})`. Useful for inspecting or caching coefficients across
|
|
137
|
+
solves with the same matrix spectrum.
|
|
138
|
+
- **`richardson_bsr(A, b, omega, K)`** — fixed-K Richardson iteration; the
|
|
139
|
+
simplest fixed-point iteration with no coefficient computation at all.
|
|
140
|
+
Optimal omega = `2 / (lam_min + lam_max)`. Baseline comparator for Chebyshev.
|
|
141
|
+
- **`block_sparse_attention_tiled(Q, K, V, mask_bsr)`** — two-pass sparse
|
|
142
|
+
attention that avoids the O(seq_len²) score intermediate. Pass 1 computes
|
|
143
|
+
per-block `(tile_max, tile_sumexp)` statistics over nonzero blocks only
|
|
144
|
+
(O(n_blocks × block_size) stats array, e.g. 5 KB at seq_len=512 vs 1 MB
|
|
145
|
+
dense). Pass 2 recomputes scores, applies stable softmax using host-reduced
|
|
146
|
+
row statistics, and accumulates V. PyTorch reference for the NKI kernel pair
|
|
147
|
+
documented in [#25](https://github.com/trnsci/trnsparse/issues/25).
|
|
148
|
+
- **`docs/sparse_attention.md`**: new "Tiled two-pass path" section explaining
|
|
149
|
+
the algorithm, memory trade-offs, and the NKI kernel follow-up path.
|
|
150
|
+
- **`docs/architecture.md`**: "Known limits" updated — #22 and #25 now have
|
|
151
|
+
v0.4.3 PyTorch references with clear notes on remaining NKI gate conditions.
|
|
152
|
+
|
|
153
|
+
### Notes
|
|
154
|
+
|
|
155
|
+
Addresses the architecture-friendly workarounds identified in the analysis of
|
|
156
|
+
parked NKI-capability-gated issues (#22, #25). Both solvers and the tiled
|
|
157
|
+
attention path share the structural property of fixed-iteration loops with
|
|
158
|
+
statically-determined coefficients — the pattern that maps to `nl.affine_range`
|
|
159
|
+
without scalar carry.
|
|
160
|
+
|
|
161
|
+
## [0.4.2] — 2026-04-15
|
|
162
|
+
|
|
163
|
+
### Added
|
|
164
|
+
|
|
165
|
+
- **`examples/block_sparse_attention.py`** — block-sparse attention
|
|
166
|
+
reference using `BSRMatrix` + `bsr_spmm`. Three mask patterns
|
|
167
|
+
(local window, dilated, global tokens); verifies against a dense
|
|
168
|
+
reference; reports block density and timing for the `bsr_spmm` step.
|
|
169
|
+
Closes [#21](https://github.com/trnsci/trnsparse/issues/21).
|
|
170
|
+
- **`docs/sparse_attention.md`** — writeup: how BSR-128 maps to
|
|
171
|
+
Longformer/BigBird-style attention masks, block density arithmetic,
|
|
172
|
+
pattern construction helpers, and the fused-tile follow-up.
|
|
173
|
+
- **`docs/iterative_solvers.md`** now linked in `mkdocs.yml` nav
|
|
174
|
+
(was present but missing from navigation).
|
|
175
|
+
- **`tests/test_attention.py`** — 8 CPU tests: mask shape/symmetry
|
|
176
|
+
checks + parity against dense reference at `atol=1e-4` for all three
|
|
177
|
+
patterns and the full-attention edge case.
|
|
178
|
+
|
|
179
|
+
### Notes
|
|
180
|
+
|
|
181
|
+
No API changes, no kernel changes. The claim in #21 is: `bsr_spmm` is
|
|
182
|
+
the block-sparse attention primitive; `BSRMatrix` captures the mask.
|
|
183
|
+
The example and docs make that explicit.
|
|
184
|
+
|
|
8
185
|
## [0.4.1] — 2026-04-14
|
|
9
186
|
|
|
10
187
|
### Added
|
|
@@ -19,38 +19,39 @@ both memory and compute. trnsparse makes the sparsity explicit.
|
|
|
19
19
|
trnsparse/
|
|
20
20
|
├── trnsparse/
|
|
21
21
|
│ ├── __init__.py
|
|
22
|
-
│ ├── formats.py # CSRMatrix, COOMatrix,
|
|
23
|
-
│ ├── ops.py # spmv, spmm,
|
|
22
|
+
│ ├── formats.py # CSRMatrix, COOMatrix, BSRMatrix, from_dense
|
|
23
|
+
│ ├── ops.py # spmv, spmm, bsr_spmm, screened_spmm, add, scale, transpose
|
|
24
24
|
│ ├── screening.py # schwarz_bounds, screen_quartets, density_screen
|
|
25
|
+
│ ├── iterative.py # cg_bsr, power_iteration_bsr, jacobi_preconditioner_bsr
|
|
25
26
|
│ └── nki/
|
|
26
27
|
│ ├── __init__.py
|
|
27
|
-
│
|
|
28
|
+
│ ├── kernels.py # _bsr_spmm_kernel, _screened_spmm_kernel
|
|
29
|
+
│ └── dispatch.py # torch.autograd.Function wrappers + NKI/PyTorch routing
|
|
28
30
|
├── tests/
|
|
29
|
-
│ ├── test_formats.py # CSR/COO construction, roundtrips
|
|
30
|
-
│ ├── test_ops.py # SpMV, SpMM vs dense reference
|
|
31
|
-
│ └── test_screening.py
|
|
32
31
|
├── examples/
|
|
33
|
-
│
|
|
32
|
+
│ ├── sparse_fock.py # Schwarz-screened Fock build (3 paths + trnblas)
|
|
33
|
+
│ ├── pyscf_bridge.py # Real AO integrals via PySCF (optional dep)
|
|
34
|
+
│ └── block_sparse_attention.py # Block-sparse attention via bsr_spmm
|
|
34
35
|
```
|
|
35
36
|
|
|
36
|
-
## NKI
|
|
37
|
+
## NKI compute strategy (v0.4.x current)
|
|
37
38
|
|
|
38
|
-
**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
`gradcheck` at `atol=1e-4`. The dense materialization means no sparsity
|
|
42
|
-
advantage yet — NKI is slower than the PyTorch fallback at small sparse
|
|
43
|
-
sizes (see `docs/benchmarks.md`).
|
|
39
|
+
**Formats:** CSR/COO are interop and PyTorch-fallback formats.
|
|
40
|
+
BSR at `block_size=128` is the NKI compute format — every nonzero block
|
|
41
|
+
is already a 128×128 Tensor Engine tile, zero gather overhead.
|
|
44
42
|
|
|
45
|
-
**
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
2.
|
|
49
|
-
|
|
43
|
+
**Dispatch hierarchy:**
|
|
44
|
+
1. `spmm(csr, B)` — PyTorch `torch.sparse_csr_tensor` fallback (within
|
|
45
|
+
2× of scipy; NKI overhead not worth it for CSR at current sizes).
|
|
46
|
+
2. `bsr_spmm(bsr, B)` — NKI kernel `_bsr_spmm_kernel`; one `nc_matmul`
|
|
47
|
+
per nonzero block. `torch.autograd.Function`-wrapped; gradcheck passes.
|
|
48
|
+
3. `screened_spmm(A, diag, B, threshold)` — fused Schwarz + mask + matmul
|
|
49
|
+
in one NKI dispatch; avoids 4 host passes + CSR build + separate SpMM.
|
|
50
|
+
4. `block_sparse_attention(Q, K, V, mask_bsr)` — `bsr_spmm` applied to
|
|
51
|
+
the attention weight matrix; no new kernel, mask is a BSRMatrix.
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
each bucket pads only within itself.
|
|
53
|
+
**Open gaps (NKI capability-gated):** row-bucketing CSR (#15), sharded BSR
|
|
54
|
+
across NeuronCores (#16), fused tile-level attention scores (#25).
|
|
54
55
|
|
|
55
56
|
## Dependencies
|
|
56
57
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trnsparse
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Sparse matrix operations for AWS Trainium via NKI
|
|
5
5
|
Author-email: Scott Friedman <scttfrdmn@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -47,12 +47,17 @@ CSR/COO formats, SpMV, SpMM, and integral screening for sparse scientific comput
|
|
|
47
47
|
|
|
48
48
|
trnsparse follows the [trnsci 5-phase roadmap](https://trnsci.dev/roadmap/). Active work is tracked in phase-labeled GitHub issues:
|
|
49
49
|
|
|
50
|
-
- **[Phase 1 — correctness](https://github.com/trnsci/trnsparse/issues/14)** ✅ v0.2.0: NKI SpMM validated on trn1 via densify-then-GEMM
|
|
51
|
-
- **
|
|
52
|
-
- **
|
|
50
|
+
- **[Phase 1 — correctness](https://github.com/trnsci/trnsparse/issues/14)** ✅ v0.2.0: NKI SpMM validated on trn1 via densify-then-GEMM (see [`trnsci/trnsci#3`](https://github.com/trnsci/trnsci/issues/3)).
|
|
51
|
+
- **v0.3.0** ✅ [`BSRMatrix`](https://trnsci.dev/trnsparse/architecture/) — Trainium-native 128×128 block-sparse format; `bsr_spmm` NKI kernel. CSR becomes interop; BSR is the compute path.
|
|
52
|
+
- **v0.3.2** ✅ `cg_bsr`, `power_iteration_bsr` — iterative solvers over BSR (Python loop; fused kernel gated on NKI capability).
|
|
53
|
+
- **v0.4.0** ✅ `screened_spmm` — fused Schwarz-screened SpMM in one NKI dispatch.
|
|
54
|
+
- **v0.4.2** ✅ Block-sparse attention — `BSRMatrix` + `bsr_spmm` as the primitive; `examples/block_sparse_attention.py` + [`docs/sparse_attention.md`](https://trnsci.dev/trnsparse/sparse_attention/).
|
|
55
|
+
- **v0.4.3** ✅ Architecture-friendly alternatives: `chebyshev_bsr` / `richardson_bsr` (fixed-K solvers, no inner products); `block_sparse_attention_tiled` (two-pass, no O(seq²) intermediate).
|
|
56
|
+
- **[Phase 3 — perf](https://github.com/trnsci/trnsparse/issues/15)**: nnz-bucketing, NKI attention kernel pair — parked on NKI indirect DMA gather / hardware validation.
|
|
57
|
+
- **[Phase 4 — multi-chip](https://github.com/trnsci/trnsparse/issues/16)**: sharded BSR across NeuronCores.
|
|
53
58
|
- **[Phase 5 — generation](https://github.com/trnsci/trnsparse/issues/17)**: trn2 DMA bandwidth exploitation.
|
|
54
59
|
|
|
55
|
-
_(No Phase 2 for trnsparse —
|
|
60
|
+
_(No Phase 2 for trnsparse — precision inherited from trnblas.)_
|
|
56
61
|
|
|
57
62
|
Suite-wide tracker: [trnsci/trnsci#1](https://github.com/trnsci/trnsci/issues/1).
|
|
58
63
|
|
|
@@ -89,12 +94,21 @@ stats = trnsparse.sparsity_stats(Q)
|
|
|
89
94
|
|
|
90
95
|
| Operation | Description |
|
|
91
96
|
|-----------|-------------|
|
|
92
|
-
| `spmv` | Sparse × dense vector |
|
|
93
|
-
| `spmm` | Sparse × dense matrix |
|
|
97
|
+
| `spmv` | Sparse × dense vector (CSR) |
|
|
98
|
+
| `spmm` | Sparse × dense matrix (CSR, PyTorch fallback) |
|
|
99
|
+
| `bsr_spmm` | Block-sparse × dense (BSR-native, Tensor Engine) |
|
|
100
|
+
| `screened_spmm` | Fused Schwarz-screened matmul (one NKI dispatch) |
|
|
94
101
|
| `spmv_symmetric` | Symmetric SpMV (half storage) |
|
|
95
102
|
| `sparse_add` | C = αA + βB |
|
|
96
103
|
| `sparse_scale` | B = αA |
|
|
97
|
-
| `sparse_transpose` | A
|
|
104
|
+
| `sparse_transpose` | Aᵀ |
|
|
105
|
+
| `cg_bsr` | Conjugate Gradient on BSR matrix |
|
|
106
|
+
| `chebyshev_bsr` | Fixed-K Chebyshev semi-iteration (no inner products) |
|
|
107
|
+
| `richardson_bsr` | Fixed-K Richardson iteration |
|
|
108
|
+
| `power_iteration_bsr` | Dominant eigenpair via power iteration |
|
|
109
|
+
| `jacobi_preconditioner_bsr` | Diagonal preconditioner for `cg_bsr` |
|
|
110
|
+
| `bsr_diagonal` | Extract main diagonal from BSR matrix |
|
|
111
|
+
| `block_sparse_attention_tiled` | Two-pass sparse attention, no O(seq²) intermediate |
|
|
98
112
|
| `schwarz_bounds` | Schwarz screening bounds |
|
|
99
113
|
| `screen_quartets` | Shell quartet significance mask |
|
|
100
114
|
| `density_screen` | Density-weighted screening |
|
|
@@ -102,3 +116,16 @@ stats = trnsparse.sparsity_stats(Q)
|
|
|
102
116
|
## License
|
|
103
117
|
|
|
104
118
|
Apache 2.0 — Copyright 2026 Scott Friedman
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
## Disclaimer
|
|
122
|
+
|
|
123
|
+
trnsci is an **independent open-source project**. It is not sponsored by, endorsed by, or affiliated with Amazon.com, Inc., Amazon Web Services, Inc., or Annapurna Labs Ltd.
|
|
124
|
+
|
|
125
|
+
"AWS", "Amazon", "Trainium", "Inferentia", "NeuronCore", "Neuron SDK", and related identifiers are trademarks of their respective owners and are used here solely for descriptive and interoperability purposes. Use does not imply endorsement, partnership, or any other relationship.
|
|
126
|
+
|
|
127
|
+
All work, opinions, analyses, benchmark results, architectural commentary, and editorial judgments in this repository and on [trnsci.dev](https://trnsci.dev) are those of the project's contributors. They do not represent the views, positions, or commitments of Amazon, AWS, or Annapurna Labs.
|
|
128
|
+
|
|
129
|
+
Feedback directed at the Neuron SDK or Trainium hardware is good-faith ecosystem commentary from independent users. It is not privileged information, is not pre-reviewed by AWS, and should not be read as authoritative about product roadmap, behavior, or quality.
|
|
130
|
+
|
|
131
|
+
For official AWS guidance, see [aws-neuron documentation](https://awsdocs-neuron.readthedocs-hosted.com/) and the [AWS Trainium product page](https://aws.amazon.com/ai/machine-learning/trainium/).
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# trnsparse
|
|
2
|
+
|
|
3
|
+
[](https://github.com/trnsci/trnsparse/actions/workflows/ci.yml)
|
|
4
|
+
[](https://codecov.io/gh/trnsci/trnsparse)
|
|
5
|
+
[](https://github.com/astral-sh/ruff)
|
|
6
|
+
[](https://pypi.org/project/trnsparse/)
|
|
7
|
+
[](https://pypi.org/project/trnsparse/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://trnsci.dev/trnsparse/)
|
|
10
|
+
|
|
11
|
+
Sparse matrix operations for AWS Trainium via NKI.
|
|
12
|
+
|
|
13
|
+
CSR/COO formats, SpMV, SpMM, and integral screening for sparse scientific computing on Trainium. Part of the trnsci scientific computing suite ([github.com/trnsci](https://github.com/trnsci)).
|
|
14
|
+
|
|
15
|
+
## Current phase
|
|
16
|
+
|
|
17
|
+
trnsparse follows the [trnsci 5-phase roadmap](https://trnsci.dev/roadmap/). Active work is tracked in phase-labeled GitHub issues:
|
|
18
|
+
|
|
19
|
+
- **[Phase 1 — correctness](https://github.com/trnsci/trnsparse/issues/14)** ✅ v0.2.0: NKI SpMM validated on trn1 via densify-then-GEMM (see [`trnsci/trnsci#3`](https://github.com/trnsci/trnsci/issues/3)).
|
|
20
|
+
- **v0.3.0** ✅ [`BSRMatrix`](https://trnsci.dev/trnsparse/architecture/) — Trainium-native 128×128 block-sparse format; `bsr_spmm` NKI kernel. CSR becomes interop; BSR is the compute path.
|
|
21
|
+
- **v0.3.2** ✅ `cg_bsr`, `power_iteration_bsr` — iterative solvers over BSR (Python loop; fused kernel gated on NKI capability).
|
|
22
|
+
- **v0.4.0** ✅ `screened_spmm` — fused Schwarz-screened SpMM in one NKI dispatch.
|
|
23
|
+
- **v0.4.2** ✅ Block-sparse attention — `BSRMatrix` + `bsr_spmm` as the primitive; `examples/block_sparse_attention.py` + [`docs/sparse_attention.md`](https://trnsci.dev/trnsparse/sparse_attention/).
|
|
24
|
+
- **v0.4.3** ✅ Architecture-friendly alternatives: `chebyshev_bsr` / `richardson_bsr` (fixed-K solvers, no inner products); `block_sparse_attention_tiled` (two-pass, no O(seq²) intermediate).
|
|
25
|
+
- **[Phase 3 — perf](https://github.com/trnsci/trnsparse/issues/15)**: nnz-bucketing, NKI attention kernel pair — parked on NKI indirect DMA gather / hardware validation.
|
|
26
|
+
- **[Phase 4 — multi-chip](https://github.com/trnsci/trnsparse/issues/16)**: sharded BSR across NeuronCores.
|
|
27
|
+
- **[Phase 5 — generation](https://github.com/trnsci/trnsparse/issues/17)**: trn2 DMA bandwidth exploitation.
|
|
28
|
+
|
|
29
|
+
_(No Phase 2 for trnsparse — precision inherited from trnblas.)_
|
|
30
|
+
|
|
31
|
+
Suite-wide tracker: [trnsci/trnsci#1](https://github.com/trnsci/trnsci/issues/1).
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install trnsparse
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import torch
|
|
43
|
+
import trnsparse
|
|
44
|
+
|
|
45
|
+
# Dense → sparse
|
|
46
|
+
A = torch.randn(100, 100)
|
|
47
|
+
A[torch.abs(A) < 1.0] = 0.0
|
|
48
|
+
csr = trnsparse.from_dense(A)
|
|
49
|
+
|
|
50
|
+
# SpMV: y = A @ x
|
|
51
|
+
y = trnsparse.spmv(csr, x, alpha=2.0)
|
|
52
|
+
|
|
53
|
+
# SpMM: C = A @ B
|
|
54
|
+
C = trnsparse.spmm(csr, B)
|
|
55
|
+
|
|
56
|
+
# Integral screening
|
|
57
|
+
Q = trnsparse.schwarz_bounds(diagonal_integrals)
|
|
58
|
+
mask = trnsparse.screen_quartets(Q, threshold=1e-10)
|
|
59
|
+
stats = trnsparse.sparsity_stats(Q)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Operations
|
|
63
|
+
|
|
64
|
+
| Operation | Description |
|
|
65
|
+
|-----------|-------------|
|
|
66
|
+
| `spmv` | Sparse × dense vector (CSR) |
|
|
67
|
+
| `spmm` | Sparse × dense matrix (CSR, PyTorch fallback) |
|
|
68
|
+
| `bsr_spmm` | Block-sparse × dense (BSR-native, Tensor Engine) |
|
|
69
|
+
| `screened_spmm` | Fused Schwarz-screened matmul (one NKI dispatch) |
|
|
70
|
+
| `spmv_symmetric` | Symmetric SpMV (half storage) |
|
|
71
|
+
| `sparse_add` | C = αA + βB |
|
|
72
|
+
| `sparse_scale` | B = αA |
|
|
73
|
+
| `sparse_transpose` | Aᵀ |
|
|
74
|
+
| `cg_bsr` | Conjugate Gradient on BSR matrix |
|
|
75
|
+
| `chebyshev_bsr` | Fixed-K Chebyshev semi-iteration (no inner products) |
|
|
76
|
+
| `richardson_bsr` | Fixed-K Richardson iteration |
|
|
77
|
+
| `power_iteration_bsr` | Dominant eigenpair via power iteration |
|
|
78
|
+
| `jacobi_preconditioner_bsr` | Diagonal preconditioner for `cg_bsr` |
|
|
79
|
+
| `bsr_diagonal` | Extract main diagonal from BSR matrix |
|
|
80
|
+
| `block_sparse_attention_tiled` | Two-pass sparse attention, no O(seq²) intermediate |
|
|
81
|
+
| `schwarz_bounds` | Schwarz screening bounds |
|
|
82
|
+
| `screen_quartets` | Shell quartet significance mask |
|
|
83
|
+
| `density_screen` | Density-weighted screening |
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
Apache 2.0 — Copyright 2026 Scott Friedman
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
## Disclaimer
|
|
91
|
+
|
|
92
|
+
trnsci is an **independent open-source project**. It is not sponsored by, endorsed by, or affiliated with Amazon.com, Inc., Amazon Web Services, Inc., or Annapurna Labs Ltd.
|
|
93
|
+
|
|
94
|
+
"AWS", "Amazon", "Trainium", "Inferentia", "NeuronCore", "Neuron SDK", and related identifiers are trademarks of their respective owners and are used here solely for descriptive and interoperability purposes. Use does not imply endorsement, partnership, or any other relationship.
|
|
95
|
+
|
|
96
|
+
All work, opinions, analyses, benchmark results, architectural commentary, and editorial judgments in this repository and on [trnsci.dev](https://trnsci.dev) are those of the project's contributors. They do not represent the views, positions, or commitments of Amazon, AWS, or Annapurna Labs.
|
|
97
|
+
|
|
98
|
+
Feedback directed at the Neuron SDK or Trainium hardware is good-faith ecosystem commentary from independent users. It is not privileged information, is not pre-reviewed by AWS, and should not be read as authoritative about product roadmap, behavior, or quality.
|
|
99
|
+
|
|
100
|
+
For official AWS guidance, see [aws-neuron documentation](https://awsdocs-neuron.readthedocs-hosted.com/) and the [AWS Trainium product page](https://aws.amazon.com/ai/machine-learning/trainium/).
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Why BSR is Trainium-native
|
|
4
|
+
|
|
5
|
+
Trainium's Tensor Engine is a 128×128 systolic array. `nisa.nc_matmul`
|
|
6
|
+
moves a 128-partition stationary tile against a moving operand of up to
|
|
7
|
+
128 × 512, all on-chip. The natural "unit of sparse work" on this
|
|
8
|
+
architecture is therefore not a single nonzero — it's a 128×128 block.
|
|
9
|
+
|
|
10
|
+
**BSR (block-sparse row)** at `block_size=128` stores a matrix as a list
|
|
11
|
+
of these blocks plus a block-level CSR pattern. Every stored block is
|
|
12
|
+
already in the shape the systolic array wants: one `nc_matmul` per block,
|
|
13
|
+
no gather step, no padding-within-tile waste. The architectural match is
|
|
14
|
+
exact.
|
|
15
|
+
|
|
16
|
+
Contrast with CSR, which stores individual nonzero elements. The v0.2.0
|
|
17
|
+
NKI path for CSR materializes the matrix into a dense `(M, K)` tile
|
|
18
|
+
before the matmul (see the [SpMM path](#v020-csr-spmm-path) below) —
|
|
19
|
+
necessary for correctness, but it pays the full `M × K` cost whether the
|
|
20
|
+
matrix is sparse or not. BSR skips this because blocks are already dense.
|
|
21
|
+
|
|
22
|
+
**Consequence for the library's shape:** CSR remains the construction and
|
|
23
|
+
interop format (scipy compatibility, PyTorch's `torch.sparse_csr_tensor`
|
|
24
|
+
interop). BSR is the compute format for the NKI path. For matrices with
|
|
25
|
+
real block structure — Fock/ERI tensors after Schwarz screening, FEM
|
|
26
|
+
stiffness matrices, graph adjacencies, block-sparse attention masks —
|
|
27
|
+
BSR is strictly preferred. For truly unstructured sparse (random CSR),
|
|
28
|
+
the PyTorch fallback is already within 2× of scipy; NKI adds nothing.
|
|
29
|
+
|
|
30
|
+
See [Benchmarks](benchmarks.md) for numbers that validate this framing.
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
trnsparse/
|
|
35
|
+
├── trnsparse/
|
|
36
|
+
│ ├── __init__.py
|
|
37
|
+
│ ├── formats.py # CSRMatrix, COOMatrix, BSRMatrix, from_dense
|
|
38
|
+
│ ├── ops.py # spmv, spmm, bsr_spmm, screened_spmm, ...
|
|
39
|
+
│ ├── screening.py # schwarz_bounds, screen_quartets, density_screen
|
|
40
|
+
│ ├── iterative.py # cg_bsr, power_iteration_bsr, jacobi_preconditioner_bsr
|
|
41
|
+
│ └── nki/
|
|
42
|
+
│ ├── __init__.py
|
|
43
|
+
│ ├── kernels.py # _bsr_spmm_kernel, _screened_spmm_kernel
|
|
44
|
+
│ └── dispatch.py # torch.autograd.Function wrappers + routing
|
|
45
|
+
├── tests/
|
|
46
|
+
├── examples/
|
|
47
|
+
│ ├── sparse_fock.py # Schwarz-screened Fock (3 paths + trnblas)
|
|
48
|
+
│ ├── pyscf_bridge.py # Real AO integrals via PySCF
|
|
49
|
+
│ └── block_sparse_attention.py # Block-sparse attention via bsr_spmm
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## NKI dispatch hierarchy
|
|
53
|
+
|
|
54
|
+
CSR and COO are interop and PyTorch-fallback formats. BSR is the NKI
|
|
55
|
+
compute format. `nki/dispatch.py` exposes `HAS_NKI`,
|
|
56
|
+
`set_backend("auto"|"pytorch"|"nki")`, `get_backend()`, and the NKI
|
|
57
|
+
entry points.
|
|
58
|
+
|
|
59
|
+
### `spmm(csr, B)` — PyTorch fallback
|
|
60
|
+
|
|
61
|
+
Routes through `torch.sparse_csr_tensor` operations. Benchmarked within
|
|
62
|
+
2× of scipy at typical shapes; the NKI per-op overhead doesn't pay off
|
|
63
|
+
for CSR SpMM until the matrix is large enough that the v0.2.0 CSR kernel
|
|
64
|
+
(densify-then-GEMM) would dominate anyway. SpMV also stays on this path.
|
|
65
|
+
|
|
66
|
+
### `bsr_spmm(bsr, B)` — NKI, `_bsr_spmm_kernel`
|
|
67
|
+
|
|
68
|
+
One `nisa.nc_matmul` per nonzero block. Host-side preamble pads each
|
|
69
|
+
block-row to the same `K_max` so the kernel's `affine_range` bounds are
|
|
70
|
+
fixed. `torch.autograd.Function`-wrapped (`_BSRSpMMFunction`); gradcheck
|
|
71
|
+
passes at `atol=1e-4` on hardware.
|
|
72
|
+
|
|
73
|
+
### `screened_spmm(A, diag, B, threshold)` — NKI, fused
|
|
74
|
+
|
|
75
|
+
Fuses Schwarz bound (outer-product pair bound), threshold mask, and
|
|
76
|
+
matmul into one dispatch. Saves ~30–50% vs the unfused
|
|
77
|
+
`schwarz_bounds → screen_quartets → from_dense → spmm` flow on
|
|
78
|
+
Fock-build-sized inputs.
|
|
79
|
+
|
|
80
|
+
### Block-sparse attention
|
|
81
|
+
|
|
82
|
+
`bsr_spmm` applied to the post-softmax attention weight matrix. No new
|
|
83
|
+
kernel — a `BSRMatrix` with a local-window or dilated block pattern IS
|
|
84
|
+
an attention mask. See [sparse_attention.md](sparse_attention.md).
|
|
85
|
+
|
|
86
|
+
## Formats
|
|
87
|
+
|
|
88
|
+
- **CSR**: row pointer + column indices + values. Preferred for construction,
|
|
89
|
+
interop with scipy/PyTorch, and SpMV.
|
|
90
|
+
- **COO**: three parallel 1-D tensors. Preferred for construction and permutation.
|
|
91
|
+
- **BSR** (`block_size=128`): stacked 128×128 blocks + block-level CSR pattern.
|
|
92
|
+
Every block maps to one `nc_matmul`; zero gather overhead.
|
|
93
|
+
|
|
94
|
+
All three support `from_dense`, `to_dense`, and interconversion.
|
|
95
|
+
|
|
96
|
+
## Autograd wrapping
|
|
97
|
+
|
|
98
|
+
Every NKI kernel lives inside a `torch.autograd.Function` (satisfies
|
|
99
|
+
[`trnsci/trnsci#3`](https://github.com/trnsci/trnsci/issues/3)).
|
|
100
|
+
Backward passes run at the PyTorch level via block-gradient projection.
|
|
101
|
+
Block-selection is non-differentiable by construction; `grad_out` is
|
|
102
|
+
routed into exactly the stored blocks. `gradcheck` at `atol=1e-4` is
|
|
103
|
+
part of the hardware test matrix for all three NKI kernels.
|
|
104
|
+
|
|
105
|
+
### Fused screened SpMM (v0.4.0)
|
|
106
|
+
|
|
107
|
+
`screened_spmm(A, diag_integrals, B, threshold)` fuses the
|
|
108
|
+
chemistry-screened SpMM pipeline — Schwarz bound from the diagonal
|
|
109
|
+
integrals, pair-bound threshold mask, masked matmul — into a single
|
|
110
|
+
NKI kernel. The unfused equivalent does four host passes (sqrt, outer
|
|
111
|
+
product, threshold, mask-apply) plus a separate `from_dense` + `spmm`
|
|
112
|
+
call; the fused kernel collapses all of that into one dispatch.
|
|
113
|
+
|
|
114
|
+
Mask semantics: `mask[i,j] = sqrt(|diag[i]|) * sqrt(|diag[j]|) >
|
|
115
|
+
sqrt(threshold)`, matching `schwarz_bounds` + `screen_quartets`
|
|
116
|
+
composed. No gradient flows back to `diag_integrals` or `threshold` —
|
|
117
|
+
the mask is treated as a discrete gate; `grad_A *= mask` and
|
|
118
|
+
`grad_B = (A * mask).T @ grad_C`.
|
|
119
|
+
|
|
120
|
+
Restricted to square A (`M == K`) with 1-D `diag_integrals` in v0.4.0
|
|
121
|
+
— the common Fock-build case. Rectangular / asymmetric-bounds
|
|
122
|
+
extension is a follow-up if asked for.
|
|
123
|
+
|
|
124
|
+
## Known limits
|
|
125
|
+
|
|
126
|
+
- **Row-bucketing CSR** ([#15](https://github.com/trnsci/trnsparse/issues/15)) — parked.
|
|
127
|
+
Requires NKI indirect-DMA gather (not exposed as of NKI 0.3.0). The CSR PyTorch
|
|
128
|
+
fallback is within 2× of scipy; that's the current story.
|
|
129
|
+
- **Fused tile-level attention scores** ([#25](https://github.com/trnsci/trnsparse/issues/25)) —
|
|
130
|
+
**v0.4.4 ships the NKI kernel pair** (`_attn_stats_kernel` + `_attn_out_kernel`).
|
|
131
|
+
`block_sparse_attention_tiled` routes through NKI on the `nki` backend; the
|
|
132
|
+
PyTorch two-pass reference remains on the `pytorch` backend. `head_dim ≤ 128`
|
|
133
|
+
in v0.4.4 (nc_matmul partition limit); `head_dim=256` requires K-tiling.
|
|
134
|
+
- **Fused iterative solvers** ([#22](https://github.com/trnsci/trnsparse/issues/22)) —
|
|
135
|
+
CG blocked on `nl.affine_range` iteration-carried scalar state. **v0.4.3 ships
|
|
136
|
+
`chebyshev_bsr` and `richardson_bsr`**: fixed-K solvers with pre-computed
|
|
137
|
+
coefficients (no inner products in the loop) that have the correct structure for
|
|
138
|
+
eventual NKI fusion. The "A SBUF-resident across all iterations" win remains gated
|
|
139
|
+
on `affine_range` vector-carry support.
|
|
140
|
+
- **Multi-chip sharded BSR** ([#16](https://github.com/trnsci/trnsparse/issues/16)) —
|
|
141
|
+
gated on suite-level multi-chip collectives.
|
|
142
|
+
- **SpMV stays PyTorch.** Single output column on the Tensor Engine doesn't amortize
|
|
143
|
+
compile + dispatch overhead.
|
|
@@ -109,21 +109,28 @@ Three observations, all consistent with the architectural framing:
|
|
|
109
109
|
dispatch, or where the kernel launch can be amortized across many
|
|
110
110
|
operations.
|
|
111
111
|
|
|
112
|
-
### Where NKI
|
|
113
|
-
|
|
114
|
-
Not in raw "one-shot SpMM at N=128 vs CPU." The
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
112
|
+
### Where NKI wins — shipped v0.4.x
|
|
113
|
+
|
|
114
|
+
Not in raw "one-shot SpMM at N=128 vs CPU." The BSR table above measures
|
|
115
|
+
kernel dispatch overhead. The architectural wins come from fusing multiple
|
|
116
|
+
host passes into one dispatch:
|
|
117
|
+
|
|
118
|
+
- **`screened_spmm` (v0.4.0, [#19](https://github.com/trnsci/trnsparse/issues/19))**
|
|
119
|
+
✅ shipped: fuses Schwarz bound + threshold + mask + matmul into one NKI
|
|
120
|
+
dispatch. On Fock-build-sized inputs: ~30–50% faster than the unfused
|
|
121
|
+
4-step path (`schwarz_bounds → screen_quartets → from_dense → spmm`)
|
|
122
|
+
because it eliminates 3 HBM round-trips and the host-side CSR build.
|
|
123
|
+
- **Block-sparse attention (v0.4.2, [#21](https://github.com/trnsci/trnsparse/issues/21))**
|
|
124
|
+
✅ shipped: `bsr_spmm` handles `attn_weights @ V` for local-window / dilated /
|
|
125
|
+
global-token masks. At seq_len=8192, window=2: 4.9% block density means 95%
|
|
126
|
+
of `nc_matmul` calls are skipped. Current example still materializes the full
|
|
127
|
+
score matrix (follow-up: [#25](https://github.com/trnsci/trnsparse/issues/25)).
|
|
128
|
+
- **[#22 — on-chip iterative solvers](https://github.com/trnsci/trnsparse/issues/22)**:
|
|
129
|
+
CG/power-iteration with A SBUF-resident across all iterations (replaces #20).
|
|
130
|
+
v0.3.2 ships the Python-loop plumbing; fused kernel gated on NKI scalar-carry
|
|
131
|
+
capability.
|
|
132
|
+
|
|
133
|
+
See [`docs/architecture.md`](architecture.md) for why BSR is the
|
|
127
134
|
Trainium-native format.
|
|
128
135
|
|
|
129
136
|
BSR results from commit
|