stackformers 4.3.1__tar.gz → 5.0.0rc8__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.
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/.gitignore +2 -1
- stackformers-5.0.0rc8/AGENTS.md +144 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/CHANGELOG.md +275 -0
- stackformers-5.0.0rc8/Justfile +27 -0
- stackformers-5.0.0rc8/PKG-INFO +319 -0
- stackformers-5.0.0rc8/README.md +270 -0
- stackformers-5.0.0rc8/examples/README.md +58 -0
- stackformers-5.0.0rc8/examples/causal_language_model.py +99 -0
- stackformers-5.0.0rc8/examples/encoder_decoder_onnxruntime.py +357 -0
- stackformers-5.0.0rc8/examples/image_encoder.py +90 -0
- stackformers-5.0.0rc8/examples/padded_and_packed.py +77 -0
- stackformers-5.0.0rc8/examples/point_cloud_encoder.py +87 -0
- stackformers-5.0.0rc8/examples/subclassed_encoder.py +153 -0
- stackformers-5.0.0rc8/pyproject.toml +51 -0
- stackformers-5.0.0rc8/pyrefly.toml +31 -0
- stackformers-5.0.0rc8/pytest.ini +4 -0
- stackformers-5.0.0rc8/ruff.toml +21 -0
- stackformers-5.0.0rc8/stackformers/DEVLOG.md +492 -0
- stackformers-5.0.0rc8/stackformers/__init__.py +262 -0
- stackformers-5.0.0rc8/stackformers/_result.py +18 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/attention/README.md +10 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/attention/__init__.py +16 -1
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/attention/bias.py +4 -1
- stackformers-5.0.0rc8/stackformers/attention/cache.py +40 -0
- stackformers-5.0.0rc8/stackformers/attention/cache_validation.py +52 -0
- stackformers-5.0.0rc8/stackformers/attention/cached.py +181 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/attention/config.py +27 -10
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/attention/cross_attn.py +35 -10
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/attention/distance_bias.py +17 -5
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/attention/factory.py +6 -2
- stackformers-5.0.0rc8/stackformers/attention/layout.py +32 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/attention/ops.py +25 -11
- stackformers-5.0.0rc8/stackformers/attention/protocols.py +46 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/attention/self_attn.py +23 -8
- stackformers-5.0.0rc8/stackformers/attention/varlen_backend.py +188 -0
- stackformers-5.0.0rc8/stackformers/cross_attender.py +183 -0
- stackformers-5.0.0rc8/stackformers/decoder.py +227 -0
- stackformers-5.0.0rc8/stackformers/decoder_cache.py +405 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/encoder.py +16 -4
- stackformers-5.0.0rc8/stackformers/feedforward/DEVLOG.md +27 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/feedforward/README.md +3 -1
- stackformers-5.0.0rc8/stackformers/feedforward/__init__.py +33 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/feedforward/config.py +28 -4
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/feedforward/factory.py +17 -2
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/feedforward/geglu.py +13 -3
- stackformers-5.0.0rc8/stackformers/feedforward/gelu.py +36 -0
- stackformers-5.0.0rc8/stackformers/feedforward/hardswish_glu.py +47 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/feedforward/protocols.py +5 -7
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/feedforward/relu_squared.py +13 -3
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/feedforward/swiglu.py +13 -3
- stackformers-5.0.0rc8/stackformers/layers.py +158 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/mlm/README.md +3 -1
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/mlm/head.py +14 -2
- stackformers-5.0.0rc8/stackformers/mlm/head_cosine.py +39 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/mlm/masking.py +10 -1
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/mlm/protocols.py +8 -11
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/mlm/wrapper.py +17 -7
- stackformers-5.0.0rc8/stackformers/norm/__init__.py +5 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/norm/config.py +4 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/norm/factory.py +6 -2
- stackformers-5.0.0rc8/stackformers/norm/protocols.py +14 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/positional/__init__.py +12 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/positional/config.py +38 -16
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/positional/factory.py +6 -2
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/positional/learned.py +6 -2
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/positional/none.py +8 -3
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/positional/protocols.py +4 -4
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/positional/rope1d.py +13 -4
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/positional/rope2d.py +16 -4
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/positional/rope_nd.py +9 -3
- stackformers-5.0.0rc8/stackformers/positional/validation.py +12 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/presets/README.md +14 -3
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/presets/__init__.py +14 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/presets/cross_attender.py +71 -18
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/presets/decoder.py +91 -29
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/presets/encoder.py +89 -23
- stackformers-5.0.0rc8/stackformers/presets/variable_width_encoder.py +363 -0
- stackformers-5.0.0rc8/stackformers/py.typed +1 -0
- stackformers-5.0.0rc8/stackformers/result/README.md +36 -0
- stackformers-5.0.0rc8/stackformers/result/__init__.py +27 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/sequence.py +6 -3
- stackformers-5.0.0rc8/tests/attention/legacy_api_rc1.json +1404 -0
- stackformers-5.0.0rc8/tests/attention/test_contracts.py +70 -0
- stackformers-5.0.0rc8/tests/attention/test_cross_attn_cache.py +135 -0
- stackformers-5.0.0rc8/tests/attention/test_empty_rows.py +72 -0
- stackformers-5.0.0rc8/tests/attention/test_geometry.py +72 -0
- stackformers-5.0.0rc8/tests/attention/test_legacy_api.py +202 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/attention/test_ops.py +42 -18
- stackformers-5.0.0rc8/tests/attention/test_sdpa_export.py +104 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/attention/test_self_attn.py +49 -0
- stackformers-5.0.0rc8/tests/attention/test_varlen_backend.py +288 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/conftest.py +41 -0
- stackformers-5.0.0rc8/tests/export_utils.py +145 -0
- stackformers-5.0.0rc8/tests/feedforward/test_gelu.py +72 -0
- stackformers-5.0.0rc8/tests/feedforward/test_hardswish_glu.py +75 -0
- stackformers-5.0.0rc8/tests/mlm/test_empty_selection.py +93 -0
- stackformers-5.0.0rc8/tests/mlm/test_head_cosine.py +48 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/mlm/test_wrapper.py +21 -0
- stackformers-5.0.0rc8/tests/norm_topology_helpers.py +87 -0
- stackformers-5.0.0rc8/tests/positional/test_cacheable.py +69 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/positional/test_rope.py +148 -44
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/positional/test_rope_nd.py +6 -3
- stackformers-5.0.0rc8/tests/presets/test_cross_attender.py +144 -0
- stackformers-5.0.0rc8/tests/presets/test_decoder.py +139 -0
- stackformers-5.0.0rc8/tests/presets/test_encoder.py +275 -0
- stackformers-5.0.0rc8/tests/presets/test_variable_width_encoder.py +566 -0
- stackformers-5.0.0rc8/tests/test_core_results.py +246 -0
- stackformers-5.0.0rc8/tests/test_cross_attender.py +287 -0
- stackformers-5.0.0rc8/tests/test_decoder.py +392 -0
- stackformers-5.0.0rc8/tests/test_decoder_cache.py +321 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/test_encoder.py +5 -1
- stackformers-5.0.0rc8/tests/test_encoder_decoder_example.py +79 -0
- stackformers-5.0.0rc8/tests/test_examples.py +57 -0
- stackformers-5.0.0rc8/tests/test_layers.py +289 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/test_norm.py +6 -2
- stackformers-5.0.0rc8/tests/test_public_api.py +143 -0
- stackformers-5.0.0rc8/tests/test_result.py +150 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/test_sequence.py +67 -22
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/uv.lock +289 -46
- stackformers-4.3.1/CLAUDE.md +0 -90
- stackformers-4.3.1/Justfile +0 -68
- stackformers-4.3.1/PKG-INFO +0 -204
- stackformers-4.3.1/README.md +0 -156
- stackformers-4.3.1/pyproject.toml +0 -72
- stackformers-4.3.1/stackformers/__init__.py +0 -150
- stackformers-4.3.1/stackformers/attention/protocols.py +0 -44
- stackformers-4.3.1/stackformers/attention/varlen_backend.py +0 -88
- stackformers-4.3.1/stackformers/cross_attender.py +0 -46
- stackformers-4.3.1/stackformers/decoder.py +0 -57
- stackformers-4.3.1/stackformers/feedforward/__init__.py +0 -5
- stackformers-4.3.1/stackformers/layers.py +0 -31
- stackformers-4.3.1/stackformers/norm/__init__.py +0 -3
- stackformers-4.3.1/stackformers/norm/protocols.py +0 -16
- stackformers-4.3.1/tests/attention/test_varlen_backend.py +0 -122
- stackformers-4.3.1/tests/presets/test_cross_attender.py +0 -36
- stackformers-4.3.1/tests/presets/test_decoder.py +0 -36
- stackformers-4.3.1/tests/presets/test_encoder.py +0 -102
- stackformers-4.3.1/tests/test_cross_attender.py +0 -118
- stackformers-4.3.1/tests/test_decoder.py +0 -141
- stackformers-4.3.1/tests/test_layers.py +0 -71
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/.claudeignore +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/.python-version +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/.vscode/settings.json +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/LICENSE +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/PLAN.md +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/run-remote-tests.sh +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/config.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/mlm/config.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/norm/README.md +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/stackformers/positional/README.md +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/__init__.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/attention/__init__.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/attention/test_cross_attn.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/attention/test_distance_bias.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/attention/test_kernels.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/feedforward/__init__.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/feedforward/test_geglu.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/feedforward/test_relu_squared.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/feedforward/test_swiglu.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/mlm/__init__.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/mlm/test_head.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/mlm/test_masking.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/positional/__init__.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/positional/test_learned_pos.py +0 -0
- {stackformers-4.3.1 → stackformers-5.0.0rc8}/tests/presets/__init__.py +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Repository guidance
|
|
2
|
+
|
|
3
|
+
## What this project is
|
|
4
|
+
|
|
5
|
+
Typed, composable, SOLID transformer library for PyTorch.
|
|
6
|
+
Behavior comes from injected dependencies, not constructor flags.
|
|
7
|
+
|
|
8
|
+
## Repository commands
|
|
9
|
+
|
|
10
|
+
Read `Justfile` before running setup, build, formatting, linting, type-checking, testing, or
|
|
11
|
+
cleanup commands. Prefer its existing recipes so local and automated workflows use the same
|
|
12
|
+
tool arguments and defaults.
|
|
13
|
+
|
|
14
|
+
Always use `uv` for Python commands.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
just fmt # ruff format
|
|
18
|
+
just lint # ruff check
|
|
19
|
+
just types # pyrefly
|
|
20
|
+
just test # pytest
|
|
21
|
+
just check # formatting check, lint, types, and tests
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Design rules
|
|
25
|
+
|
|
26
|
+
- Encode distinct modes with closed unions, not optional fields in structured records.
|
|
27
|
+
- Use null objects (e.g. `NoPosEncoding`) instead of `if self.x is not None` inside `forward()`.
|
|
28
|
+
- Do not add flags in `__init__` that change `forward()` behavior; introduce a new class.
|
|
29
|
+
- Keep `forward()` traceable by `torch.compile` and `torch.export`; avoid Python control flow
|
|
30
|
+
on tensors.
|
|
31
|
+
- Keep one concept per file; split files that cannot be described in one sentence.
|
|
32
|
+
- Annotate tensor arguments with jaxtyping shape strings using the dimension vocabulary below.
|
|
33
|
+
- Type collaborators accepted by `__init__` as protocols rather than concrete implementations.
|
|
34
|
+
|
|
35
|
+
## Python structured records
|
|
36
|
+
|
|
37
|
+
Never use `dataclasses` in this repository. PyTorch recognizes `NamedTuple` and `TypedDict`
|
|
38
|
+
reliably across pytree, export, and compilation boundaries, while dataclasses require additional
|
|
39
|
+
registration and handling.
|
|
40
|
+
|
|
41
|
+
- Use `NamedTuple` for fixed-shape records with named fields, especially tensor inputs and outputs.
|
|
42
|
+
- Use `TypedDict` when the value must retain mapping semantics.
|
|
43
|
+
- Do not introduce `dataclass`, `@dataclass`, or imports from `dataclasses`.
|
|
44
|
+
|
|
45
|
+
Ruff enforces the import restriction through `TID251`.
|
|
46
|
+
|
|
47
|
+
## Expected failures
|
|
48
|
+
|
|
49
|
+
Use `Result[T, E] = Ok[T] | Err[E]` from `stackformers.result` for recoverable core failures.
|
|
50
|
+
The alternatives are generic NamedTuples; do not add an external Result dependency or use
|
|
51
|
+
unchecked unwrap methods. Match `Ok(value=value)` / `Err(error=error)` with keyword patterns
|
|
52
|
+
for PyTorch tracing compatibility, and use `assert_never` for closed-union exhaustiveness.
|
|
53
|
+
|
|
54
|
+
Validate admission before construction instead of raising and catching expected failures.
|
|
55
|
+
Keep exception policy at public adapters for operations that cannot proceed, preserving
|
|
56
|
+
existing API contracts. Catch expected vendor exceptions at the vendor boundary, retaining
|
|
57
|
+
their original causes; unexpected programming failures may propagate.
|
|
58
|
+
|
|
59
|
+
## Dimension vocabulary
|
|
60
|
+
|
|
61
|
+
| Symbol | Meaning |
|
|
62
|
+
|--------|---------|
|
|
63
|
+
| `b` | Batch size |
|
|
64
|
+
| `n` | Query sequence length |
|
|
65
|
+
| `s` | Key/value sequence length (`n` for self-attention) |
|
|
66
|
+
| `d` | Model dimension |
|
|
67
|
+
| `h` | Number of heads |
|
|
68
|
+
| `dh` | Dimension per head |
|
|
69
|
+
| `w` | Window size |
|
|
70
|
+
| `nt` | Total tokens in a packed sequence |
|
|
71
|
+
| `m` | Number of masked tokens gathered across a batch or pack |
|
|
72
|
+
|
|
73
|
+
## File organization
|
|
74
|
+
|
|
75
|
+
- All library code lives directly under `stackformers/`. Breaking changes go in a new
|
|
76
|
+
top-level package.
|
|
77
|
+
- Keep configs next to the classes they configure, e.g. `attention/config.py` and
|
|
78
|
+
`feedforward/config.py`.
|
|
79
|
+
- Keep cross-cutting configs (`LayerConfig`, `EncoderConfig`, `DecoderConfig`) in `config.py`.
|
|
80
|
+
- Each module owns a `factory.py` with a `build_*` function that dispatches on config type
|
|
81
|
+
via `match`.
|
|
82
|
+
- Keep opinionated presets in `presets/`, with one file per preset class.
|
|
83
|
+
- Define protocols in their owning module (`attention/protocols.py`, etc.), not a central file.
|
|
84
|
+
- Implement protocols structurally; implementations do not import the protocols they implement.
|
|
85
|
+
|
|
86
|
+
## Config and factory conventions
|
|
87
|
+
|
|
88
|
+
Every union config type uses a `kind: Literal[...]` discriminator field so configs round-trip
|
|
89
|
+
through JSON unambiguously. Define the union as an
|
|
90
|
+
`Annotated[..., Field(discriminator="kind")]` alias in the same `config.py`.
|
|
91
|
+
|
|
92
|
+
Each module owns its builder in a co-located `factory.py`, with the signature
|
|
93
|
+
`build_*(config: *Config, ...) -> Protocol`. Presets call factories instead of instantiating
|
|
94
|
+
concrete classes directly.
|
|
95
|
+
|
|
96
|
+
## Module READMEs
|
|
97
|
+
|
|
98
|
+
Each module subdirectory has a `README.md`. When changing a module's design by adding a
|
|
99
|
+
variant, removing a concept, or changing a dispatch strategy, update its README in the same
|
|
100
|
+
commit. Cover its purpose, key design decisions, and how to extend it with a new variant.
|
|
101
|
+
Do not repeat information obvious from the source, such as file tables or copied signatures.
|
|
102
|
+
|
|
103
|
+
## Testing
|
|
104
|
+
|
|
105
|
+
- Mirror source directory structure, with one test file per source file.
|
|
106
|
+
- Use pytest fixtures for module construction, inputs, and sequence objects. Pure transformation
|
|
107
|
+
and assertion helpers may be ordinary functions.
|
|
108
|
+
- Parametrize compute tests over `device_dtype` (all device/dtype combinations); use `device`
|
|
109
|
+
alone with float32 for gradient tests.
|
|
110
|
+
- Test shape contracts and numerical behavior where correctness or compatibility requires it.
|
|
111
|
+
- Use `atol(dtype)` from `tests/conftest.py` for numerical tolerances; exact compatibility
|
|
112
|
+
assertions may require equality instead.
|
|
113
|
+
|
|
114
|
+
## Dependencies and PyTorch
|
|
115
|
+
|
|
116
|
+
- Prefer built-in PyTorch implementations over custom ones, especially
|
|
117
|
+
`F.scaled_dot_product_attention` and `torch.nn.attention.varlen.varlen_attn`.
|
|
118
|
+
- Do not add optional third-party kernel dependencies; kernels use PyTorch.
|
|
119
|
+
- Use Pydantic for configs. Prefer `Field(gt=0)` / `Field(ge=0)` over `@field_validator`
|
|
120
|
+
for simple bounds.
|
|
121
|
+
- Prefer `nn.Module` activations (`nn.SiLU()`, `nn.GELU()`) over `torch.nn.functional` calls.
|
|
122
|
+
- Before writing PyTorch code, check the installed version with
|
|
123
|
+
`uv run python -c "import torch; print(torch.__version__)"`.
|
|
124
|
+
- Check `.venv/lib/python3.*/site-packages/torch/nn/modules/` for available implementations.
|
|
125
|
+
|
|
126
|
+
## x-transformers reference
|
|
127
|
+
|
|
128
|
+
Use the local `x-transformers/` checkout, when available, for math and implementation details
|
|
129
|
+
only. Do not copy its architecture.
|
|
130
|
+
|
|
131
|
+
## Versioning
|
|
132
|
+
|
|
133
|
+
Maintain the version in `pyproject.toml` under `[project].version`, synchronize it with
|
|
134
|
+
`uv.lock`, and expose it at runtime through `stackformers.__version__`.
|
|
135
|
+
|
|
136
|
+
Use Semantic Versioning:
|
|
137
|
+
|
|
138
|
+
- **MAJOR** for breaking public API changes.
|
|
139
|
+
- **MINOR** for new backwards-compatible features.
|
|
140
|
+
- **PATCH** for bug fixes or internal changes without API impact.
|
|
141
|
+
|
|
142
|
+
Bump the version before committing package or behavior changes on `main`. Version bumps on
|
|
143
|
+
feature or work branches require an explicit user instruction. Changes limited to repository
|
|
144
|
+
guidance, tests, or CI do not require a bump.
|
|
@@ -6,6 +6,281 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
|
6
6
|
adheres to [Semantic Versioning](https://semver.org/): MAJOR for breaking public API changes,
|
|
7
7
|
MINOR for backwards-compatible features, PATCH for bug fixes and internal changes.
|
|
8
8
|
|
|
9
|
+
## [5.0.0rc8]
|
|
10
|
+
|
|
11
|
+
### New Features
|
|
12
|
+
|
|
13
|
+
- Allow decoder context to be omitted or passed as `None`, skipping cross-attention and
|
|
14
|
+
its normalization across all four layer topologies. Cached decoding accepts a `None`
|
|
15
|
+
cross cache without requiring context projections. Existing configs and checkpoints
|
|
16
|
+
remain compatible.
|
|
17
|
+
|
|
18
|
+
## [5.0.0rc7] — 2026-09-28
|
|
19
|
+
|
|
20
|
+
### Developers
|
|
21
|
+
|
|
22
|
+
- Tighten cached attention admission to the existing attention protocols and retain vendor
|
|
23
|
+
callable parameter/return types during response validation. Give fake kernel requests an
|
|
24
|
+
explicit TypedDict schema instead of broad `object` annotations.
|
|
25
|
+
|
|
26
|
+
## [5.0.0rc6] — 2026-09-26
|
|
27
|
+
|
|
28
|
+
### Backwards Incompatible Changes
|
|
29
|
+
|
|
30
|
+
#### Core Result values
|
|
31
|
+
|
|
32
|
+
Core outcomes now use `stackformers.result.Result[T, E]`, the union of generic NamedTuples
|
|
33
|
+
`Ok[T]` and `Err[E]`, instead of `returns.result.Result`. Consumers of core outcomes must
|
|
34
|
+
match `Ok(value=value)` / `Err(error=error)` and access the narrowed payload; `unwrap`,
|
|
35
|
+
`failure`, and `map` methods are no longer available. Public tensor/configuration returns,
|
|
36
|
+
validation exceptions, and backend fallback warnings remain compatible. Remove any reliance
|
|
37
|
+
on Stackformers installing `returns` as a transitive dependency.
|
|
38
|
+
|
|
39
|
+
### Developers
|
|
40
|
+
|
|
41
|
+
- Validate cached decoder attention admission before constructing executors, returning
|
|
42
|
+
expected failures as data instead of raising and catching constructor exceptions.
|
|
43
|
+
|
|
44
|
+
## [5.0.0rc5] — 2026-09-26
|
|
45
|
+
|
|
46
|
+
### Developers
|
|
47
|
+
|
|
48
|
+
- Consolidate repository guidance in `AGENTS.md` and remove `CLAUDE.md`.
|
|
49
|
+
- Reduce the Justfile to eight recipes. Replace `fmt-check`, `lint-fix`, `test-only`, and
|
|
50
|
+
`test-cov` with arguments to `fmt`, `lint`, and `test`; remove `fix` and `clean`.
|
|
51
|
+
Keep `check` as the full quality gate and preserve argument boundaries when forwarding flags.
|
|
52
|
+
|
|
53
|
+
## [5.0.0rc4] — 2026-09-26
|
|
54
|
+
|
|
55
|
+
### Developers
|
|
56
|
+
|
|
57
|
+
- Require kernels injected into the experimental attention core to return
|
|
58
|
+
`Result[Tensor, VarlenFallback]`. Normalize PyTorch responses and expected exceptions
|
|
59
|
+
in the vendor adapter, preserving public tensor-or-None returns, warnings, and error causes.
|
|
60
|
+
|
|
61
|
+
## [5.0.0rc3] — 2026-09-26
|
|
62
|
+
|
|
63
|
+
### New Features
|
|
64
|
+
|
|
65
|
+
- Accept shared or per-layer `dim_heads`, `heads`, `causal`, `ff_mult`, `dropout`, and
|
|
66
|
+
`norm_placement` in the variable-width encoder factory. Explicit `heads` allows independent
|
|
67
|
+
model and attention widths; omitting it retains exact `d_model // dim_head` inference.
|
|
68
|
+
|
|
69
|
+
### Bug Fixes
|
|
70
|
+
|
|
71
|
+
- Allow model widths that are not divisible by the query-head count in self- and
|
|
72
|
+
cross-attention configs. Internal query width remains `heads * dim_head`; grouped
|
|
73
|
+
attention still requires `heads` divisible by `kv_heads`.
|
|
74
|
+
|
|
75
|
+
## [5.0.0rc1] — 2026-09-26
|
|
76
|
+
|
|
77
|
+
### Backwards Incompatible Changes
|
|
78
|
+
|
|
79
|
+
#### Immutable attention configuration
|
|
80
|
+
|
|
81
|
+
`SelfAttentionConfig` and `CrossAttentionConfig` previously allowed field assignment after
|
|
82
|
+
construction. They are now immutable, preventing a shared config from reinterpreting an
|
|
83
|
+
existing model's projections. Construct a new config and model for different architecture
|
|
84
|
+
settings instead of assigning config fields.
|
|
85
|
+
|
|
86
|
+
#### Matching cross-attention layouts
|
|
87
|
+
|
|
88
|
+
Cross-attention previously accepted mixed padded/packed layouts in its annotations and failed
|
|
89
|
+
during tensor reshaping. Its type contract now requires matching layouts, and mixed layouts
|
|
90
|
+
raise `ValueError` at runtime. Narrow both inputs together when calling through the `CrossAttn`
|
|
91
|
+
protocol, or convert them to the same layout before calling.
|
|
92
|
+
|
|
93
|
+
#### Empty reconstruction selections
|
|
94
|
+
|
|
95
|
+
Custom reconstruction heads must now return a differentiable zero loss for zero selected
|
|
96
|
+
tokens; earlier head contracts left empty-input behavior unspecified. Add an empty-input guard
|
|
97
|
+
that returns `prediction.sum()` to custom heads. Independent sampling is unchanged, so callers
|
|
98
|
+
must continue to support batches in which no tokens are selected.
|
|
99
|
+
|
|
100
|
+
### Bug Fixes
|
|
101
|
+
|
|
102
|
+
- Return finite zero losses from both built-in MLM heads when no tokens are selected.
|
|
103
|
+
- Exclude masked keys completely and return zero attention contributions and gradients when
|
|
104
|
+
padding, windows, or additive bias exclude every key, including exported ONNX execution.
|
|
105
|
+
- Fix ONNX Runtime attention-mask shape errors for opsets 23–25 by explicitly expanding
|
|
106
|
+
the query dimension, including dynamic batch and sequence lengths.
|
|
107
|
+
|
|
108
|
+
### Performance
|
|
109
|
+
|
|
110
|
+
- Avoid repadding input features on the packed self-attention path when using `NoAttnBias`.
|
|
111
|
+
|
|
112
|
+
### Developers
|
|
113
|
+
|
|
114
|
+
- Include the `py.typed` marker so type checkers recognize annotations in installed wheels.
|
|
115
|
+
- Use shared `returns` Result values for core layout, geometry, cache, and backend checks.
|
|
116
|
+
Preserve public tensor/configuration returns, validation exceptions, and fallback warnings;
|
|
117
|
+
retain original backend failure detail for callers that handle outcomes directly.
|
|
118
|
+
- Apply rustic-python's strict Pyrefly and Ruff profile to the library, tests, and examples;
|
|
119
|
+
require Pyrefly 1.3.1 and Ruff 0.16.9 or newer and check Python 3.11 compatibility.
|
|
120
|
+
- Expose typed module-call signatures without replacing PyTorch's runtime hook dispatch,
|
|
121
|
+
type the experimental attention-kernel boundary, and replace stale type suppressions.
|
|
122
|
+
- Require ONNX Runtime parity at opsets 23–25 instead of accepting opset-23 failures or
|
|
123
|
+
excluding newer dynamo exports using PyTorch's legacy exporter limit.
|
|
124
|
+
|
|
125
|
+
## [4.7.0b6] — 2026-08-31
|
|
126
|
+
|
|
127
|
+
### Documentation
|
|
128
|
+
|
|
129
|
+
- Add runnable, CPU-friendly examples for equivalent padded and packed batches, causal language
|
|
130
|
+
modeling, image patches with RoPE-2D, continuous point coordinates with RoPE-ND, and both
|
|
131
|
+
focused and fully user-owned encoder subclassing.
|
|
132
|
+
|
|
133
|
+
## [4.7.0b5] — 2026-08-28
|
|
134
|
+
|
|
135
|
+
### Highlights
|
|
136
|
+
|
|
137
|
+
- Add an export-oriented decoder path that reuses cross-attention K/V projections and grows a
|
|
138
|
+
self-attention K/V cache one token at a time, while leaving existing encoder, decoder, and
|
|
139
|
+
attention APIs unchanged.
|
|
140
|
+
|
|
141
|
+
### New Features
|
|
142
|
+
|
|
143
|
+
- Add composition-only `CachedSelfAttentionWrapper`, `CachedCrossAttentionWrapper`,
|
|
144
|
+
`DecoderCrossAttentionCacheBuilder`, and `CachedDecoderWrapper` APIs. The wrappers share the
|
|
145
|
+
existing model's parameters and support every built-in positional encoding and decoder
|
|
146
|
+
normalization topology.
|
|
147
|
+
- Define a C++/ONNX Runtime-friendly tensor boundary with required, non-optional cross and self
|
|
148
|
+
caches, a required `step_i` tensor, dynamically shaped batch/source/history axes, and a returned
|
|
149
|
+
self cache for the next decoder session run. Cached self-attention currently requires global
|
|
150
|
+
causal attention with `NoAttnBias`.
|
|
151
|
+
|
|
152
|
+
### Documentation
|
|
153
|
+
|
|
154
|
+
- Add an encoder-decoder example that exports separate encoder, cross-cache builder, and cached
|
|
155
|
+
one-token decoder ONNX graphs, then verifies their autoregressive outputs with ONNX Runtime.
|
|
156
|
+
- Document cache layouts, tensor names, ownership, lifecycle, dynamic axes, and the initial
|
|
157
|
+
zero-length self-cache contract for C++ integration.
|
|
158
|
+
|
|
159
|
+
### Developers
|
|
160
|
+
|
|
161
|
+
- Add eager parity, gradient, export, ONNX Runtime, positional-encoding, and stable `4.6.0` public
|
|
162
|
+
API regression coverage for the cached path.
|
|
163
|
+
- Standardize export-facing structured records on `NamedTuple` or `TypedDict` and enforce the
|
|
164
|
+
repository's no-dataclass policy with Ruff.
|
|
165
|
+
|
|
166
|
+
## [4.7.0b4] — 2026-08-19
|
|
167
|
+
|
|
168
|
+
### Backwards Incompatible Changes
|
|
169
|
+
|
|
170
|
+
#### Variable-width encoder configuration
|
|
171
|
+
|
|
172
|
+
`VariableWidthTransformerEncoderConfig` again stores `layers: list[VariableWidthEncoderLayerConfig]`
|
|
173
|
+
instead of the `d_models`/`dim_heads` representation introduced in `4.7.0b3`. Each layer record
|
|
174
|
+
keeps its attention, feed-forward, norm, positional-encoding, and attention-bias choices explicit
|
|
175
|
+
and validates their dimensions together. Migrate direct `4.7.0b3` constructors to complete layer
|
|
176
|
+
records. The convenience config factory now requires explicit keyword arguments; replace
|
|
177
|
+
`variable_width_encoder_config(d_models, dim_heads)` with
|
|
178
|
+
`variable_width_encoder_config(d_models=d_models, dim_heads=dim_heads)`.
|
|
179
|
+
|
|
180
|
+
### New Features
|
|
181
|
+
|
|
182
|
+
- Export all concrete feed-forward configs and implementations, learned/ND positional encodings,
|
|
183
|
+
attention-bias configs, `VariableWidthEncoderLayerConfig`, and `node_encoder_config` from the
|
|
184
|
+
package root. Variable-width layers can select any public component config without subclassing.
|
|
185
|
+
|
|
186
|
+
### Developers
|
|
187
|
+
|
|
188
|
+
- Add static and dynamic PyTorch/ONNX export coverage with ONNX Runtime parity for every public
|
|
189
|
+
feed-forward variant and the existing Transformer configuration paths.
|
|
190
|
+
|
|
191
|
+
## [4.7.0b3] — 2026-08-19
|
|
192
|
+
|
|
193
|
+
### Backwards Incompatible Changes
|
|
194
|
+
|
|
195
|
+
#### Variable-width encoder configuration
|
|
196
|
+
|
|
197
|
+
`VariableWidthTransformerEncoderConfig` now represents variable block geometry as parallel
|
|
198
|
+
`d_models` and `dim_heads` arrays, with `causal`, `ff_mult`, `dropout`, and `norm_placement` stored
|
|
199
|
+
once as shared settings. Earlier beta configs stored an array of
|
|
200
|
+
`VariableWidthEncoderLayerConfig` objects under `layers`; that class and its public export are
|
|
201
|
+
removed. Explicit constructors and serialized beta configs must migrate from values such as
|
|
202
|
+
`config.layers[index].attn.dim` to `config.d_models[index]`. The preset continues to construct
|
|
203
|
+
global attention with RoPE, RMSNorm, SwiGLU, and no attention bias. Callers of
|
|
204
|
+
`variable_width_encoder_config` are unchanged.
|
|
205
|
+
|
|
206
|
+
## [4.7.0b2] — 2026-08-19
|
|
207
|
+
|
|
208
|
+
### Added
|
|
209
|
+
|
|
210
|
+
- **`HardSwishGLU`** — a bias-free, parameter-matched gated feed-forward variant using
|
|
211
|
+
`nn.Hardswish` instead of SwiGLU's `nn.SiLU`. Select it with
|
|
212
|
+
`HardSwishGLUConfig(kind="hardswish_glu")`; serialized configurations preserve the distinction
|
|
213
|
+
between the exact SwiGLU operation and its piecewise-linear HardSwish alternative.
|
|
214
|
+
|
|
215
|
+
### Compatibility
|
|
216
|
+
|
|
217
|
+
- Existing feed-forward classes, config discriminators, presets, and defaults are unchanged.
|
|
218
|
+
`HardSwishGLU` is opt-in and uses the same input/output shape and hidden-width rule as SwiGLU.
|
|
219
|
+
|
|
220
|
+
## [4.7.0b1] — 2026-08-18
|
|
221
|
+
|
|
222
|
+
### Added
|
|
223
|
+
|
|
224
|
+
- **Variable-width Transformer encoder preset** through `VariableWidthTransformerEncoder` and
|
|
225
|
+
`variable_width_encoder_config`. Callers provide one model width and head dimension per block;
|
|
226
|
+
the preset derives head counts and inserts a bias-free learned projection only where adjacent
|
|
227
|
+
model widths differ. Expanded layer configs retain explicit attention, feed-forward, norm,
|
|
228
|
+
positional-encoding, and attention-bias collaborators and support JSON round trips.
|
|
229
|
+
|
|
230
|
+
### Compatibility
|
|
231
|
+
|
|
232
|
+
- Existing uniform-width encoder classes, configs, serialized payloads, checkpoints, and defaults
|
|
233
|
+
are unchanged. Variable-width models use their own preset and state-dict structure.
|
|
234
|
+
|
|
235
|
+
## [4.6.0] — 2026-08-14
|
|
236
|
+
|
|
237
|
+
### Added
|
|
238
|
+
|
|
239
|
+
- **Configurable normalization placement** for encoder, decoder, and cross-attender presets through
|
|
240
|
+
`NormPlacement = Literal["pre", "post", "sandwich", "reordered"]`. Each topology has a focused
|
|
241
|
+
layer class while the existing `TransformerLayer`, `DecoderLayer`, and `CrossAttenderLayer`
|
|
242
|
+
remain the pre-norm implementations. `"reordered"` implements the OLMo 2 residual layout
|
|
243
|
+
(`x + norm(branch(x))`), while sandwich uses distinct norms before and after every residual
|
|
244
|
+
branch—four per encoder/cross-attender layer and six per decoder layer.
|
|
245
|
+
|
|
246
|
+
### Compatibility
|
|
247
|
+
|
|
248
|
+
- **The default remains `"pre"`.** Omitting `norm_placement` preserves the previous operation
|
|
249
|
+
order, exact outputs and gradients, positional `TransformerLayer` constructor, parameter names,
|
|
250
|
+
and state-dict shapes across encoder, decoder, and cross-attender layers. Config payloads without
|
|
251
|
+
the new field deserialize as pre-norm. The three legacy layer classes retain their original
|
|
252
|
+
constructors and module attributes.
|
|
253
|
+
- Serialized preset-config `model_dump()` output now includes
|
|
254
|
+
`"norm_placement": "pre"` unless callers request default-value exclusion. Sandwich is the only
|
|
255
|
+
mode that adds parameters because its post-branch norms must be independent.
|
|
256
|
+
|
|
257
|
+
## [4.5.0] — 2026-08-14
|
|
258
|
+
|
|
259
|
+
### Added
|
|
260
|
+
|
|
261
|
+
- **`GELUFFN`** — a standard bias-free, two-projection Transformer feed-forward network using
|
|
262
|
+
`nn.GELU(approximate="tanh")`. Select it with `GELUConfig(kind="gelu")`; its hidden width is
|
|
263
|
+
`int(dim * mult)`, matching other non-gated FFNs.
|
|
264
|
+
|
|
265
|
+
## [4.4.0] — 2026-07-17
|
|
266
|
+
|
|
267
|
+
### Added
|
|
268
|
+
|
|
269
|
+
- **`CosineHead`** (`stackformers/mlm/head_cosine.py`) — a `ReconstructionHead` that scores
|
|
270
|
+
a linear projection of the encoder's masked-position output against the target via
|
|
271
|
+
`1 - cosine_similarity`, instead of `RegressionHead`'s MSE.
|
|
272
|
+
|
|
273
|
+
### Changed
|
|
274
|
+
|
|
275
|
+
- **`MLMWrapper`'s default `head` is now `CosineHead`, not `RegressionHead`.**
|
|
276
|
+
`mlm_loss`'s target is `input.x`, and nothing constrains its scale: once the tokenizer
|
|
277
|
+
trains purely under the main task (`mlm_loss` has zero gradient into it, per 4.3.1),
|
|
278
|
+
its output distribution is free to drift arbitrarily over training. MSE is sensitive
|
|
279
|
+
to that drift — matching magnitude is part of what it scores — while cosine
|
|
280
|
+
similarity scores direction only, so it stays meaningful regardless of where the
|
|
281
|
+
target's scale currently sits. `RegressionHead` is unaffected and still available;
|
|
282
|
+
pass `MLMWrapper(..., head=RegressionHead(dim))` to keep the previous behaviour.
|
|
283
|
+
|
|
9
284
|
## [4.3.1] — 2026-07-17
|
|
10
285
|
|
|
11
286
|
### Fixed
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
set dotenv-load := false
|
|
2
|
+
set positional-arguments
|
|
3
|
+
|
|
4
|
+
python_sources := "stackformers/ tests/ examples/"
|
|
5
|
+
|
|
6
|
+
default:
|
|
7
|
+
@just --list
|
|
8
|
+
|
|
9
|
+
sync:
|
|
10
|
+
uv sync --group dev
|
|
11
|
+
|
|
12
|
+
build:
|
|
13
|
+
uv build --clear
|
|
14
|
+
|
|
15
|
+
fmt *args:
|
|
16
|
+
uv run ruff format {{ python_sources }} "$@"
|
|
17
|
+
|
|
18
|
+
lint *args:
|
|
19
|
+
uv run ruff check {{ python_sources }} "$@"
|
|
20
|
+
|
|
21
|
+
types:
|
|
22
|
+
uv run pyrefly check {{ python_sources }}
|
|
23
|
+
|
|
24
|
+
test *args:
|
|
25
|
+
uv run pytest -q "$@"
|
|
26
|
+
|
|
27
|
+
check: (fmt "--check") lint types test
|