Heimdall: a constant-memory hybrid, trained on one GPU.
A from-scratch research codebase for training small language models efficiently on a single consumer AMD GPU, with latent-free 1-bit feed-forward layers and a hybrid recurrent and attention backbone.
Abstract
Heimdall combines three ideas. First, a hybrid backbone: three Gated DeltaNet layers, which keep a fixed-size recurrent memory, for every one global-attention layer, so the inference cache is about 12× smaller than a same-size Transformer’s (by calculation). Second, a latent-free 1-bit and 1.58-bit training engine: binary (±1) or ternary weights are the only copy of the weights, with no fp32 shadow weights and no Adam state, and a custom optimizer called BitFlip flips the strongest-gradient weights directly. Third, a conversion method that turns a pretrained open Transformer into a constant-memory model by training only about 2 % new parameters.
Everything was measured on one workstation: an AMD Radeon RX 9070 XT (16 GB) with a Ryzen 7 7800X3D. The largest model trained from scratch, Heimdall-Bit, has 337M parameters and saw 3.7B tokens. Unless stated otherwise, comparisons are single runs, so differences of about 0.03 nats or less are noise.
How to read this page
We publish what the model does and what it does not. The scores place Heimdall-Bit at roughly GPT-2-small and Pythia-160M level. Whether the 1-bit layers or the hybrid layout helps or hurts at this scale is unknown, because there is no dense baseline yet.
Architecture
Every fourth layer is global attention; the other three are Gated DeltaNet. A DeltaNet layer reads and writes a fixed-size matrix memory with the delta rule, so its state does not grow with the sequence. Only the attention layers keep a key-value cache.
Measured on the 337M model: the cache is 18.7 MB at 512 tokens and 109 MB at 8,192 tokens, growing about 11.8 KB per token because only the attention layers grow. The DeltaNet layers are constant. On a toy associative-recall task (MQAR, about 100K parameters, 8 CPU-minutes, one seed) trained at gaps up to 64 tokens and tested up to 16K, attention-only fell from 15.6 % to 0.8 %, pure DeltaNet reached about 14.8 %, and the hybrid scored 99.9 to 100 %. Small and noisy, but consistent with the design.
Latent-free 1-bit training
Question tested: can a model whose feed-forward weights are 1-bit match a dense model with half as many parameters? Validation loss in nats per token at equal data, lower is better.
| Scale (bit model vs dense half-size) | Dense, N/2 params | Bit model, N params |
|---|---|---|
| 6M vs 3M (2 seeds) | 2.056 / 1.937 | 1.842 / 1.764 (ternary), 1.840 / 1.752 (binary) |
| 46M vs 23M (20M tokens) | 1.646 / 1.635 | 1.651 / 1.656 |
| 98M vs 52M (40M tokens) | 1.309 | 1.330 |
At small scale the bit model is clearly ahead; around 50M it ties; at about 100M it is slightly behind (+0.02 nats). We do not claim the target is met at scale. Binary and ternary FFN weights were equally good in these tests.
Training throughput on one 16 GB GPU
| Model | Tokens | Speed | Memory | Wall-clock |
|---|---|---|---|---|
| Heimdall-Bit 98M | 800M | 47.4K tok/s | 13.3 GB | 4.7 h, no crash |
| Heimdall-Bit 337M | 3.7B | ~11.2K tok/s | 11.3 GB | ~92 h, resumed from checkpoints |
torch.compile on the ROCm 10.1 and PyTorch 2.14 stack gave 2.9× faster training and 2.4× lower memory than eager mode on a 5.8M model (90K to 264K tok/s, 3.1 to 1.3 GB) with unchanged validation loss.
Design study: where to put the bits
6M scale, 10M tokens. Most of the quality loss comes from binarizing the attention and DeltaNet projections. Keeping those dense and adding a small dense low-rank corrector next to each bit matrix recovers most of it. In the final design 58 % of parameters are 1-bit.
| Variant | Params | Val loss | vs dense |
|---|---|---|---|
| Dense | 5.8M | 1.785 | — |
| All matrices ternary | 5.8M | 2.093 | +0.308 |
| All matrices binary | 5.8M | 2.128 | +0.343 |
| All ternary, 25 % wider | 8.0M | 1.994 | +0.209 |
| All ternary + rank-16 corrector | 6.3M | 1.997 | +0.212 |
| FFN-only ternary | 5.8M | 1.916 | +0.131 |
| FFN ternary + rank-16 corrector (final) | 6.1M | 1.842 | +0.057 |
Converting a pretrained Transformer
SmolLM2-135M (30 layers), sliding window of 64 tokens plus 4 attention-sink tokens plus a delta-rule memory, 0.8M training tokens (about 4 minutes on the GPU). WikiText perplexity at 2K context:
| Stage | Perplexity |
|---|---|
| Original (full attention) | 14.09 |
| Window only, no memory | 25.76 |
| Converted, untrained | 26.70 |
| After layer-wise attention transfer | 22.43 |
| After end-to-end distillation | 17.61 |
About 70 % of the gap between window-only and the original is closed, with a 5.7 MB cache at any length (the original needs 180 MB at 8K tokens and about 22 GB at 1M). It is not at parity (+25 % perplexity) and long-context retrieval has not been established. 4-bit teacher weights cost +7 % perplexity on Qwen3-0.6B at 318 MB. Our reimplementation of the teacher matches Hugging Face transformers logits exactly on SmolLM2-135M and Qwen3-0.6B.
Kernels
Triton kernels for int8 and packed 1/2-bit matrix products. Single-token decoding, 4096×4096, RX 9070 XT, ROCm 10.1:
| Kernel | Latency | Speedup | Rel. error |
|---|---|---|---|
| bf16 | 0.228 ms | 1× | — |
| int8 Triton | 0.081 ms | 2.8× | 0.8 % |
| packed 1-bit | 0.090 ms | 2.5× | 0.17 % |
| packed 2-bit | 0.083 ms | 2.7× | 0.17 % |
For prefill and training shapes our kernels are slower than bf16 (0.33 to 0.72×), so training uses plain bf16. These are layer benchmarks, not end-to-end generation speed.
Results
Final validation loss of the 337M run, in nats per token with our 8K-vocabulary tokenizer (not comparable to other models’ perplexities): FineWeb-Edu 2.707 and 2.668 (two splits), GitHub code 0.743 and 0.606, Cosmopedia 1.773. The code losses are optimistic because of boilerplate and near-duplicates. Samples are fluent English and plausible Python structure, with wrong facts, wrong logic and loops under greedy decoding: it is a base model with no instruction tuning.
Beyond the training length
| Position (tokens) | 512–1024 | 1024–2048 | 2048–4096 | 4096–8192 |
|---|---|---|---|---|
| Loss (nats) | 0.658 | 0.592 | 0.546 | 0.817 |
Trained at 2,048 tokens. Loss keeps falling to about 4K, then rises. Passkey retrieval (a 5-digit number planted in filler text, 15 trials per length): 100 % at 512, 1K, 2K and 4K, and 80 % at 8K, where a far-placed key fails (2 of 5). Small samples on an easy test.
Standard benchmarks against GPT-2, Pythia and SmolLM2
Limitations
What is not shown
- Scale: the largest scratch-trained model is 337M parameters on 3.7B tokens, below the roughly 20 tokens-per-parameter heuristic. No dense or Transformer baseline exists at this scale, so the effect of the 1-bit FFN and the hybrid layout on scores is unknown.
- The 1-bit advantage over a half-size dense model does not persist at about 100M parameters in our tests.
- Training memory is not 1-bit: bit weights cost about 6 bytes per parameter during training versus 16 to 18 for AdamW with fp32 master weights. Only the FFN (58 %) is 1-bit, so inference memory is roughly that of a half-size dense bf16 model (a calculation, not a measurement).
- Most comparisons use one seed. Long-context results are small-sample and single-checkpoint.
- Multi-GPU training, a production deployment record and quantized serving of the full model are not implemented.
Next steps
- Scale study: train the binary-FFN hybrid and a dense baseline at 300M to 1B parameters on at least 10B tokens, several seeds, to learn whether the bit-vs-dense gap closes at scale.
- Evaluate converted models on standard benchmarks and long-context retrieval (RULER-style).
- Convert larger open models (Qwen3 1.7B to 8B, 4-bit teacher) with the Heimdall conversion and measure long-context quality and serving cost.
- Fused low-bit training kernels and end-to-end inference throughput measurements.
These depend on compute. If you can help, talk to us.
Reproduce
git clone https://github.com/valeroisai/heimdall && cd heimdall/Heimdall
for t in heimdall bifrost bit bitkernel planla arayuz; do python tests/test_$t.py; done
# small training run
python -m heimdall.train --preset temel --arch bit --bits 1 \
--data ../stream_coder_100k.bin --tokens 40e6 --out runs/demo
# bit vs half-size dense, 46M vs 23M
bash bench/hedef.sh orta
License: source-available for review only (read, evaluate, and run unmodified to verify the reported results). No usage rights are granted at this time. Code comments, CLI flags and some log messages are in Turkish; the repository README has a glossary.
title={Heimdall: a constant-memory hybrid trained on one consumer GPU},
author={{Valerois}}, year={2026},
howpublished={\url{https://github.com/valeroisai/heimdall}}
}
Go on. Try it.
Nova is free to start. No card, no setup afternoon. Or talk to us about the research.