ssmforge 0.1.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.
- ssmforge-0.1.0/LICENSE +9 -0
- ssmforge-0.1.0/PKG-INFO +467 -0
- ssmforge-0.1.0/README.md +427 -0
- ssmforge-0.1.0/pyproject.toml +57 -0
- ssmforge-0.1.0/setup.cfg +4 -0
- ssmforge-0.1.0/src/ssmforge/__init__.py +10 -0
- ssmforge-0.1.0/src/ssmforge/benchmark/__init__.py +4 -0
- ssmforge-0.1.0/src/ssmforge/benchmark/long_context.py +43 -0
- ssmforge-0.1.0/src/ssmforge/benchmark/quality.py +27 -0
- ssmforge-0.1.0/src/ssmforge/cli.py +71 -0
- ssmforge-0.1.0/src/ssmforge/config.py +41 -0
- ssmforge-0.1.0/src/ssmforge/converters/__init__.py +17 -0
- ssmforge-0.1.0/src/ssmforge/converters/base.py +56 -0
- ssmforge-0.1.0/src/ssmforge/converters/llama_to_hybrid.py +61 -0
- ssmforge-0.1.0/src/ssmforge/converters/mistral_to_hybrid.py +26 -0
- ssmforge-0.1.0/src/ssmforge/converters/weight_init.py +54 -0
- ssmforge-0.1.0/src/ssmforge/distillation/__init__.py +12 -0
- ssmforge-0.1.0/src/ssmforge/distillation/calibration.py +82 -0
- ssmforge-0.1.0/src/ssmforge/distillation/collator.py +31 -0
- ssmforge-0.1.0/src/ssmforge/distillation/loss.py +47 -0
- ssmforge-0.1.0/src/ssmforge/distillation/trainer.py +106 -0
- ssmforge-0.1.0/src/ssmforge/exceptions.py +282 -0
- ssmforge-0.1.0/src/ssmforge/export/__init__.py +12 -0
- ssmforge-0.1.0/src/ssmforge/export/gguf_writer.py +53 -0
- ssmforge-0.1.0/src/ssmforge/export/llama_quantize.py +41 -0
- ssmforge-0.1.0/src/ssmforge/export/manifest.py +47 -0
- ssmforge-0.1.0/src/ssmforge/models/__init__.py +7 -0
- ssmforge-0.1.0/src/ssmforge/models/hybrid_llama_mamba.py +120 -0
- ssmforge-0.1.0/src/ssmforge/pipeline.py +243 -0
- ssmforge-0.1.0/src/ssmforge/recipes/__init__.py +25 -0
- ssmforge-0.1.0/src/ssmforge/recipes/base.py +66 -0
- ssmforge-0.1.0/src/ssmforge/recipes/hybrid_25.py +67 -0
- ssmforge-0.1.0/src/ssmforge/recipes/hybrid_50.py +58 -0
- ssmforge-0.1.0/src/ssmforge/recipes/pure_mamba.py +58 -0
- ssmforge-0.1.0/src/ssmforge/result.py +14 -0
- ssmforge-0.1.0/src/ssmforge.egg-info/PKG-INFO +467 -0
- ssmforge-0.1.0/src/ssmforge.egg-info/SOURCES.txt +58 -0
- ssmforge-0.1.0/src/ssmforge.egg-info/dependency_links.txt +1 -0
- ssmforge-0.1.0/src/ssmforge.egg-info/entry_points.txt +2 -0
- ssmforge-0.1.0/src/ssmforge.egg-info/requires.txt +17 -0
- ssmforge-0.1.0/src/ssmforge.egg-info/top_level.txt +1 -0
- ssmforge-0.1.0/tests/test_benchmark.py +37 -0
- ssmforge-0.1.0/tests/test_calibration.py +43 -0
- ssmforge-0.1.0/tests/test_cli.py +53 -0
- ssmforge-0.1.0/tests/test_convert.py +65 -0
- ssmforge-0.1.0/tests/test_converters.py +71 -0
- ssmforge-0.1.0/tests/test_distillation.py +63 -0
- ssmforge-0.1.0/tests/test_distillation_trainer.py +37 -0
- ssmforge-0.1.0/tests/test_exceptions.py +57 -0
- ssmforge-0.1.0/tests/test_export.py +71 -0
- ssmforge-0.1.0/tests/test_gguf_export.py +61 -0
- ssmforge-0.1.0/tests/test_hybrid_model.py +54 -0
- ssmforge-0.1.0/tests/test_import.py +3 -0
- ssmforge-0.1.0/tests/test_manifest.py +50 -0
- ssmforge-0.1.0/tests/test_mistral_converter.py +37 -0
- ssmforge-0.1.0/tests/test_property.py +109 -0
- ssmforge-0.1.0/tests/test_recipes_base.py +78 -0
- ssmforge-0.1.0/tests/test_recipes_hybrid_25.py +40 -0
- ssmforge-0.1.0/tests/test_recipes_hybrid_50.py +36 -0
- ssmforge-0.1.0/tests/test_recipes_pure_mamba.py +27 -0
ssmforge-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
ssmforge-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ssmforge
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Convert pretrained transformers to hybrid SSM/attention models. Export quantized GGUF.
|
|
5
|
+
Author: SSMForge Contributors
|
|
6
|
+
License: Apache License
|
|
7
|
+
Version 2.0, January 2004
|
|
8
|
+
http://www.apache.org/licenses/
|
|
9
|
+
|
|
10
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
11
|
+
you may not use this file except in compliance with the License.
|
|
12
|
+
You may obtain a copy of the License at
|
|
13
|
+
|
|
14
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
15
|
+
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
21
|
+
Classifier: Operating System :: OS Independent
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: torch>=2.3
|
|
26
|
+
Requires-Dist: transformers>=4.45
|
|
27
|
+
Requires-Dist: huggingface_hub>=0.24
|
|
28
|
+
Requires-Dist: pydantic>=2.0
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
32
|
+
Requires-Dist: hypothesis>=6.0; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
34
|
+
Provides-Extra: mamba
|
|
35
|
+
Requires-Dist: mamba-ssm>=2.0; extra == "mamba"
|
|
36
|
+
Requires-Dist: causal-conv1d>=1.4; extra == "mamba"
|
|
37
|
+
Provides-Extra: export
|
|
38
|
+
Requires-Dist: gguf>=0.6; extra == "export"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# SSMForge
|
|
42
|
+
|
|
43
|
+
**Convert any pretrained transformer into a hybrid SSM/attention model. Smaller, faster, longer context. Exports quantized GGUF.**
|
|
44
|
+
|
|
45
|
+
[](https://pypi.org/project/ssmforge/)
|
|
46
|
+
[](https://pypi.org/project/ssmforge/)
|
|
47
|
+
[](https://github.com/lordxmen2k/SSMForge/blob/main/LICENSE)
|
|
48
|
+
[](https://pypi.org/project/ssmforge/#files)
|
|
49
|
+
[](https://github.com/lordxmen2k/SSMForge)
|
|
50
|
+
[](https://www.python.org/downloads/)
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install "ssmforge[mamba,export]"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from ssmforge import convert
|
|
58
|
+
|
|
59
|
+
result = convert(
|
|
60
|
+
source="meta-llama/Llama-3.1-8B-Instruct",
|
|
61
|
+
recipe="hybrid-25",
|
|
62
|
+
quantize="Q4_K_M",
|
|
63
|
+
output_dir="./out",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
print(f"GGUF: {result.gguf_path}")
|
|
67
|
+
print(f"Manifest: {result.manifest_path}")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The result loads in `llama.cpp`, `ollama`, `LM Studio`, `Jan`, and any other
|
|
71
|
+
GGUF-compatible runtime.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## What SSMForge does
|
|
76
|
+
|
|
77
|
+
SSMForge implements the recipes and pipeline described in the published
|
|
78
|
+
literature on hybrid SSM/attention models:
|
|
79
|
+
|
|
80
|
+
- **MambaInLlama** (NeurIPS 2024) — recipe for `hybrid-25`
|
|
81
|
+
- **Jamba** (AI21, 2024) — recipe for `hybrid-50`
|
|
82
|
+
- **"Attention to Mamba"** (2025) — recipe for `pure-mamba`
|
|
83
|
+
|
|
84
|
+
Given a pretrained dense transformer (HuggingFace model id or local path),
|
|
85
|
+
SSMForge:
|
|
86
|
+
|
|
87
|
+
1. Loads the teacher model
|
|
88
|
+
2. Plans which layers become Mamba2 vs stay as attention (per recipe)
|
|
89
|
+
3. Performs state-dict surgery: copies embeddings/MLP/LayerNorm verbatim,
|
|
90
|
+
replaces marked attention layers with freshly-initialized Mamba2 weights
|
|
91
|
+
4. Distills the result against the teacher using KL divergence
|
|
92
|
+
5. Exports the final model as a quantized GGUF that loads in llama.cpp
|
|
93
|
+
6. Writes a manifest JSON with provenance (source SHA, recipe, layer mapping,
|
|
94
|
+
output file SHA)
|
|
95
|
+
|
|
96
|
+
**The pipeline is real and tested.** 70 unit + integration + property tests
|
|
97
|
+
pass. The CLI works. A real GGUF file is produced and round-trips through
|
|
98
|
+
`gguf-py`. The dry run works on a real HuggingFace model end-to-end.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## What SSMForge doesn't have (yet)
|
|
103
|
+
|
|
104
|
+
**No benchmark numbers.** The tables below say "TBD" because we haven't run
|
|
105
|
+
a full conversion on a real large model. The qualitative claims (SSM layers
|
|
106
|
+
have no KV cache, so they save memory at long context) are well-established
|
|
107
|
+
in the literature, but **the specific numbers depend on the model, hardware,
|
|
108
|
+
and distillation recipe** and we cannot honestly quote them for SSMForge
|
|
109
|
+
output without measuring.
|
|
110
|
+
|
|
111
|
+
**Specific things we don't know yet:**
|
|
112
|
+
- How much speedup SSMForge's `hybrid-25` gets vs the paper's `hybrid-25` on
|
|
113
|
+
the same hardware (we use a lightweight `torch.optim` distillation loop,
|
|
114
|
+
not the paper's full step-wise + DPO recipe)
|
|
115
|
+
- Actual quality retention vs the teacher (MMLU, HellaSwag on a real
|
|
116
|
+
converted model)
|
|
117
|
+
- Whether `pure-mamba` lands at the paper's reported 60-80% retention or worse
|
|
118
|
+
with our distillation implementation
|
|
119
|
+
|
|
120
|
+
**To get real numbers:**
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Run a real conversion
|
|
124
|
+
ssmforge convert meta-llama/Llama-3.1-8B-Instruct \
|
|
125
|
+
--recipe hybrid-25 \
|
|
126
|
+
--quantize Q4_K_M \
|
|
127
|
+
--output ./out
|
|
128
|
+
|
|
129
|
+
# Benchmark the output
|
|
130
|
+
python -c "
|
|
131
|
+
from ssmforge.benchmark import benchmark_long_context
|
|
132
|
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
133
|
+
model = AutoModelForCausalLM.from_pretrained('./out/<model-name>')
|
|
134
|
+
tokenizer = AutoTokenizer.from_pretrained('meta-llama/Llama-3.1-8B-Instruct')
|
|
135
|
+
results = benchmark_long_context(model, tokenizer, context_lengths=[4096, 32768, 131072])
|
|
136
|
+
for ctx, stats in results.items():
|
|
137
|
+
print(f'{ctx:>8}: {stats.get(\"tokens_per_sec\", 0):.1f} tok/s, {stats.get(\"peak_memory_mb\", 0):.1f} MB')
|
|
138
|
+
"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
PRs with real numbers welcome — that's the highest-value contribution.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Disk size (we know this part)
|
|
146
|
+
|
|
147
|
+
Disk size is dominated by parameter count, not architecture. Every recipe
|
|
148
|
+
keeps the same number of weight parameters, so disk size is determined by
|
|
149
|
+
quant type alone.
|
|
150
|
+
|
|
151
|
+
| Quant | Llama-3.2-1B | Llama-3.1-8B | Llama-3.1-70B |
|
|
152
|
+
|-------|--------------|--------------|---------------|
|
|
153
|
+
| F16 | ~2.5 GB | ~16 GB | ~140 GB |
|
|
154
|
+
| Q8_0 | ~1.3 GB | ~8.5 GB | ~75 GB |
|
|
155
|
+
| Q5_K_M | ~900 MB | ~5.7 GB | ~50 GB |
|
|
156
|
+
| Q4_K_M | ~700 MB | ~4.6 GB | ~40 GB |
|
|
157
|
+
| Q4_K_S | ~600 MB | ~4.0 GB | ~35 GB |
|
|
158
|
+
|
|
159
|
+
These are computable from parameter count. The disk size of an SSMForge
|
|
160
|
+
GGUF at any quant level will match the dense GGUF at the same quant level
|
|
161
|
+
(because both have the same number of weights).
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Runtime VRAM at long context (TBD — we haven't measured)
|
|
166
|
+
|
|
167
|
+
| Variant | Recipe | VRAM @ 4K ctx | VRAM @ 128K ctx | VRAM @ 1M ctx |
|
|
168
|
+
|---------|--------|---------------|------------------|---------------|
|
|
169
|
+
| Llama-3.1-8B dense | — | TBD | TBD | TBD |
|
|
170
|
+
| Llama-3.1-8B hybrid-25 | hybrid-25 | TBD | TBD (expected to be lower than dense) | TBD |
|
|
171
|
+
| Llama-3.1-8B hybrid-50 | hybrid-50 | TBD | TBD | TBD |
|
|
172
|
+
| Llama-3.1-8B pure-mamba | pure-mamba | TBD | TBD (~flat across context, no KV cache) | TBD |
|
|
173
|
+
|
|
174
|
+
The qualitative claim — SSM recipes use less memory at long context because
|
|
175
|
+
they have fewer KV-cache-producing attention layers — is correct. **The
|
|
176
|
+
specific numbers** depend on the model, batch size, KV cache dtype, and
|
|
177
|
+
distillation-induced differences in the attention layers. We don't have
|
|
178
|
+
SSMForge-specific numbers. Run the benchmark snippet above to get them.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Quality retention (TBD)
|
|
183
|
+
|
|
184
|
+
| Recipe | Quality vs teacher |
|
|
185
|
+
|--------|--------------------|
|
|
186
|
+
| dense Q4_K_M (baseline) | TBD (typically ~98% for dense models with llama.cpp's quant) |
|
|
187
|
+
| hybrid-25 | TBD (paper claims ~95-98%, our impl unverified) |
|
|
188
|
+
| hybrid-50 | TBD (paper claims ~90-95%, our impl unverified) |
|
|
189
|
+
| pure-mamba | TBD (paper claims ~60-80%, our impl unverified) |
|
|
190
|
+
|
|
191
|
+
Run `ssmforge convert ... --verify` and benchmark on lm-evaluation-harness to
|
|
192
|
+
get real numbers for your model.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Install
|
|
197
|
+
|
|
198
|
+
### Quick install
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
python3 -m venv .venv
|
|
202
|
+
source .venv/bin/activate
|
|
203
|
+
python -m pip install --upgrade pip
|
|
204
|
+
pip install "ssmforge[mamba,export]"
|
|
205
|
+
ssmforge --help
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Full install (with `llama-quantize` for Q4_K_M and friends)
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# 1. Virtual env
|
|
212
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
213
|
+
|
|
214
|
+
# 2. Upgrade pip (some envs default to a broken mirror)
|
|
215
|
+
python -m pip install --upgrade pip
|
|
216
|
+
python -m pip config set global.index-url https://pypi.org/simple/
|
|
217
|
+
|
|
218
|
+
# 3. Install SSMForge
|
|
219
|
+
pip install "ssmforge[mamba,export]"
|
|
220
|
+
|
|
221
|
+
# 4. Install llama-quantize binary (needed for non-F16 quant)
|
|
222
|
+
pip install llama-cpp-python
|
|
223
|
+
# OR build from source:
|
|
224
|
+
# git clone https://github.com/ggerganov/llama.cpp.git
|
|
225
|
+
# cd llama.cpp && make llama-quantize
|
|
226
|
+
# export LLAMA_QUANTIZE_BIN="$(pwd)/llama-quantize"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Verify
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
ssmforge list-recipes
|
|
233
|
+
python -c "import ssmforge; print(ssmforge.__version__)"
|
|
234
|
+
ssmforge convert hf-internal-testing/tiny-random-LlamaForCausalLM --dry-run
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
If all of those work, you're ready.
|
|
238
|
+
|
|
239
|
+
See [INSTALL.md on GitHub](https://github.com/lordxmen2k/SSMForge/blob/main/docs/INSTALL.md)
|
|
240
|
+
for the complete guide including troubleshooting, CUDA setup, and PyPI publishing steps.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Usage examples
|
|
245
|
+
|
|
246
|
+
### Example 1: Convert a HuggingFace model to Q4_K_M (most common)
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
ssmforge convert meta-llama/Llama-3.1-8B-Instruct \
|
|
250
|
+
--recipe hybrid-25 \
|
|
251
|
+
--quantize Q4_K_M \
|
|
252
|
+
--output ./out
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Output:
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
./out/meta-llama_Llama-3.1-8B-Instruct.HYBRID-25.Q4_K_M.gguf
|
|
259
|
+
./out/meta-llama_Llama-3.1-8B-Instruct.HYBRID-25.Q4_K_M.manifest.json
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Example 2: Python API
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
from pathlib import Path
|
|
266
|
+
from ssmforge import convert
|
|
267
|
+
|
|
268
|
+
result = convert(
|
|
269
|
+
source="meta-llama/Llama-3.1-8B-Instruct",
|
|
270
|
+
recipe="hybrid-25", # hybrid-25 | hybrid-50 | pure-mamba
|
|
271
|
+
quantize="Q4_K_M", # F16 | Q8_0 | Q5_K_M | Q4_K_M | Q4_K_S
|
|
272
|
+
output_dir=Path("./out"),
|
|
273
|
+
calibration_data=None, # None = built-in default; or path/dataset id
|
|
274
|
+
verify=False, # Stage 6 forward-pass sanity check
|
|
275
|
+
dry_run=False, # True = plan + surgery only
|
|
276
|
+
experimental=False, # True = allow pure-mamba recipe
|
|
277
|
+
)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Example 3: Dry run — plan only, no distillation or export
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
ssmforge convert meta-llama/Llama-3.1-8B-Instruct \
|
|
284
|
+
--recipe hybrid-25 \
|
|
285
|
+
--dry-run
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Prints the full layer mapping and exits in ~10 seconds without writing anything.
|
|
289
|
+
|
|
290
|
+
### Example 4: Custom calibration data
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
ssmforge convert meta-llama/Llama-3.1-8B-Instruct \
|
|
294
|
+
--recipe hybrid-25 \
|
|
295
|
+
--quantize Q4_K_M \
|
|
296
|
+
--calibration-data /path/to/my-text-corpus.txt \
|
|
297
|
+
--output ./out
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
The file format is one sample per line. Empty lines are skipped.
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
ssmforge convert meta-llama/Llama-3.1-8B-Instruct \
|
|
304
|
+
--recipe hybrid-50 \
|
|
305
|
+
--quantize Q5_K_M \
|
|
306
|
+
--calibration-data HuggingFaceH4/ultrachat_200k \
|
|
307
|
+
--output ./out
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Any HF dataset id with a `text` field works.
|
|
311
|
+
|
|
312
|
+
### Example 5: Long-context benchmark (this gives real numbers)
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
from ssmforge.benchmark import benchmark_long_context
|
|
316
|
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
|
317
|
+
|
|
318
|
+
model = AutoModelForCausalLM.from_pretrained("path/to/converted-model-dir")
|
|
319
|
+
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B-Instruct")
|
|
320
|
+
|
|
321
|
+
results = benchmark_long_context(
|
|
322
|
+
model,
|
|
323
|
+
tokenizer,
|
|
324
|
+
context_lengths=[4_096, 32_768, 131_072],
|
|
325
|
+
)
|
|
326
|
+
for ctx, stats in results.items():
|
|
327
|
+
if "error" in stats:
|
|
328
|
+
print(f"{ctx:>8}: ERROR {stats['error']}")
|
|
329
|
+
else:
|
|
330
|
+
print(f"{ctx:>8}: {stats['tokens_per_sec']:.1f} tok/s, {stats['peak_memory_mb']:.1f} MB")
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Example 6: Pure Mamba (experimental)
|
|
334
|
+
|
|
335
|
+
Requires `--experimental` flag. **Expect significant quality loss — the
|
|
336
|
+
research paper reports 60-80% retention vs teacher for the full recipe;
|
|
337
|
+
SSMForge's lightweight distillation impl is unverified.**
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
ssmforge convert meta-llama/Llama-3.2-1B \
|
|
341
|
+
--recipe pure-mamba \
|
|
342
|
+
--quantize Q4_K_M \
|
|
343
|
+
--experimental \
|
|
344
|
+
--output ./out
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Example 7: Custom recipe
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
# my_recipe.py
|
|
351
|
+
from ssmforge.recipes import Recipe, register_recipe
|
|
352
|
+
from ssmforge.config import LayerSpec, LayerType, DistillationConfig, TrainingStage
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
@register_recipe
|
|
356
|
+
class Hybrid75Recipe(Recipe):
|
|
357
|
+
"""Custom: keep 75% attention, only convert middle layers sparsely."""
|
|
358
|
+
name = "hybrid-75"
|
|
359
|
+
description = "Sparser SSM replacement — ~12.5% of layers converted"
|
|
360
|
+
requires_attention_fraction = 0.875
|
|
361
|
+
|
|
362
|
+
def plan(self, model):
|
|
363
|
+
num_layers = model.config.num_hidden_layers
|
|
364
|
+
return [
|
|
365
|
+
LayerSpec(
|
|
366
|
+
layer_type=LayerType.SSM if (i % 8 == 4) else LayerType.ATTENTION,
|
|
367
|
+
index=i,
|
|
368
|
+
)
|
|
369
|
+
for i in range(num_layers)
|
|
370
|
+
]
|
|
371
|
+
|
|
372
|
+
def distillation_config(self):
|
|
373
|
+
return DistillationConfig(
|
|
374
|
+
stages=[TrainingStage(name="e2e", epochs=2, learning_rate=5e-5)]
|
|
375
|
+
)
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
ssmforge convert <model> --recipe hybrid-75 --quantize Q4_K_M --output ./out
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Example 8: Load the output in llama.cpp / ollama / LM Studio
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
# ollama
|
|
386
|
+
echo 'FROM ./out/Llama-3.1-8B-Instruct.HYBRID-25.Q4_K_M.gguf' > Modelfile
|
|
387
|
+
ollama create my-hybrid-model -f Modelfile
|
|
388
|
+
ollama run my-hybrid-model
|
|
389
|
+
|
|
390
|
+
# llama.cpp
|
|
391
|
+
./llama-cli -m ./out/Llama-3.1-8B-Instruct.HYBRID-25.Q4_K_M.gguf -p "Hello!"
|
|
392
|
+
|
|
393
|
+
# LM Studio — just open the GGUF file in the UI
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Recipes
|
|
399
|
+
|
|
400
|
+
| Recipe | SSM ratio | Best for |
|
|
401
|
+
|--------|-----------|----------|
|
|
402
|
+
| `hybrid-25` (default, production) | ~25% | Production deployments |
|
|
403
|
+
| `hybrid-50` (production) | ~50% (1:1 alternation) | Aggressive long-context optimization |
|
|
404
|
+
| `pure-mamba` (experimental, requires `--experimental`) | 100% | Edge deployment, ultra-long context research |
|
|
405
|
+
|
|
406
|
+
All three preserve the original tokenizer and chat template.
|
|
407
|
+
|
|
408
|
+
See [recipes.md on GitHub](https://github.com/lordxmen2k/SSMForge/blob/main/docs/recipes.md)
|
|
409
|
+
for the full catalog and customization guide.
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## Architecture
|
|
414
|
+
|
|
415
|
+
```
|
|
416
|
+
┌─────────────────┐
|
|
417
|
+
│ 1. Load │ HuggingFace AutoModelForCausalLM
|
|
418
|
+
└────────┬────────┘
|
|
419
|
+
▼
|
|
420
|
+
┌─────────────────┐
|
|
421
|
+
│ 2. Recipe plan │ Decide which layers become SSM
|
|
422
|
+
└────────┬────────┘
|
|
423
|
+
▼
|
|
424
|
+
┌─────────────────┐
|
|
425
|
+
│ 3. Surgery │ State-dict manipulation
|
|
426
|
+
└────────┬────────┘
|
|
427
|
+
▼
|
|
428
|
+
┌─────────────────┐
|
|
429
|
+
│ 4. Distillation │ KL divergence training
|
|
430
|
+
└────────┬────────┘
|
|
431
|
+
▼
|
|
432
|
+
┌─────────────────┐
|
|
433
|
+
│ 5. Export │ gguf-py → llama-quantize
|
|
434
|
+
└────────┬────────┘
|
|
435
|
+
▼
|
|
436
|
+
┌─────────────────┐
|
|
437
|
+
│ 6. Verify │ Optional forward-pass check
|
|
438
|
+
└─────────────────┘
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
See [architecture.md on GitHub](https://github.com/lordxmen2k/SSMForge/blob/main/docs/architecture.md)
|
|
442
|
+
and the [design spec on GitHub](https://github.com/lordxmen2k/SSMForge/blob/main/docs/superpowers/specs/2026-09-21-ssmforge-design.md)
|
|
443
|
+
for the full design.
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## Supported models (v0.1.0)
|
|
448
|
+
|
|
449
|
+
- **Llama** family (1B / 3B / 8B) — `meta-llama/Llama-3.1-*`, `meta-llama/Llama-3.2-*`
|
|
450
|
+
- **Mistral** family — `mistralai/Mistral-7B-*`
|
|
451
|
+
|
|
452
|
+
Adding new architectures: subclass `ArchitectureConverter`, register it. See
|
|
453
|
+
[architecture.md on GitHub](https://github.com/lordxmen2k/SSMForge/blob/main/docs/architecture.md).
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## License
|
|
458
|
+
|
|
459
|
+
Apache 2.0. See [LICENSE](https://github.com/lordxmen2k/SSMForge/blob/main/LICENSE).
|
|
460
|
+
|
|
461
|
+
## Links
|
|
462
|
+
|
|
463
|
+
- **Repo:** https://github.com/lordxmen2k/SSMForge
|
|
464
|
+
- **PyPI:** https://pypi.org/project/ssmforge/
|
|
465
|
+
- **Issues:** https://github.com/lordxmen2k/SSMForge/issues
|
|
466
|
+
- **Spec:** [design spec on GitHub](https://github.com/lordxmen2k/SSMForge/blob/main/docs/superpowers/specs/2026-09-21-ssmforge-design.md)
|
|
467
|
+
- **Plan:** [implementation plan on GitHub](https://github.com/lordxmen2k/SSMForge/blob/main/docs/superpowers/plans/2026-09-21-ssmforge-implementation.md)
|