BitSparse — Lossless sparse activation cache — What does it mean?
The news. On October 15, 2026, a Cambridge and Oxford team posted BitSparse, a lossless way to store ReLU-family feed-forward activations during training. The authors report 31% lower VRAM per token on Modded-NanoGPT and 30% on Nemotron-H, with overhead of no more than 1% at practical sequence lengths. Read the paper →
Picture the training step as a coat-check room. Every forward pass hangs a coat on a hanger for each activation, and each coat must stay on the rail until the backward pass reaches that layer. The rail grows with every token in the batch, so a bigger batch means a longer rail, and the rail is what runs the GPU out of memory first. See the HBM step of the GPU memory hierarchy for why that memory is the scarce resource.
Now look at the rail. Squared ReLU (used in the Nemotron family and Modded-NanoGPT) turns every negative input into an exact zero, so most hangers are empty but still reserve their slot. The paper's own illustration shows a row where 93% of entries are zero. A dense cache pays for all of them.
BitSparse keeps a short list instead: one tick box per hanger, plus only the coats that exist. Because the tick boxes cost one bit each and a BF16 coat costs 16, the room shrinks by a large factor wherever hangers are mostly empty. And the backward pass loses nothing, since the gradient needs only the positive values and their positions.
Here is the format. The tensor is cut into tiles, and each tile stores three things: a bitmask (512 bytes per tile), a packed array of its nonzero values, and a 32-bit prefix count telling a reader where that tile's values start. The prefix is the number on the rack: with it, every tile can be decoded in parallel, with no scan through earlier tiles.
Two extra tricks matter. First, a squared-ReLU or ReLU output is never negative, so the sign bit of every stored value is redundant; the optional sign-bit packing drops it, so BF16 values take 15 bits and FP8 values take 7. Second, the number of nonzeros is only known on the GPU, and asking the CPU to allocate exactly that much would force host synchronization. BitSparse instead appends every layer's values to one large preallocated buffer and records offsets on the device, which keeps the queue full and works with torch.compile. Compression and decoding are custom Triton kernels fused into an autograd function (see how Triton works and operator fusion).
| Approach | What it keeps for the backward pass | Exact? | What it costs |
|---|---|---|---|
| Dense cache | Every activation value | Yes | Most memory |
| Activation checkpointing | Nothing; recomputes the forward pass | Yes | Extra compute: in the paper's MLP batch-size sweep a checkpointed step took 4,268 ms versus 3,604 ms for BitSparse at 32,000 rows (Table 4) |
| Lossy compression (for example random projections) | An approximation of the values | No | Changed gradients |
| BitSparse | Bitmask, nonzero values, per-tile prefix | Yes | Needs ReLU-family zeros; covers feed-forward layers only |
Now the worked example, using the paper's format with numbers I chose (illustrative). Take one tile of 4,096 BF16 activations at 90% zeros. Dense storage costs 4,096 × 2 bytes = 8,192 bytes. BitSparse stores a 512-byte bitmask, a 4-byte prefix, and about 410 nonzero values × 2 bytes = 820 bytes, about 1,336 bytes in total, roughly a 6.1× smaller cache for that tile. Sign-bit packing trims the values to about 769 bytes, giving about 1,285 bytes (roughly 6.4×). At 50% zeros the same tile costs about 4,612 bytes, only 1.8× smaller, because the fixed bitmask now matters. Working it out from the format, the break-even is near 6% zeros for BF16: below that, the bitmask costs more than the empty slots save.
Why then is the measured saving only about 30% per token, not 6×? Only the feed-forward activation cache shrinks. Attention, Mamba layers and other tensors are untouched. The paper measures 0.402 MiB per token falling to 0.277 MiB on Modded-NanoGPT, and 2.719 MiB to 1.894 MiB on Nemotron-H.
Two honest limits. The gain depends on exact zeros, so it follows the fate of ReLU-family activations; gated activations such as SwiGLU are left to future work. And checkpointing still uses less memory in the LLM runs, but at a notable runtime cost; BitSparse sits at a different point on the memory-versus-compute curve, with decoding reaching 97.4% of attainable memory bandwidth in the paper's benchmark. In a full Modded-NanoGPT training run, the paper reports a validation loss virtually identical to the original recipe, and a larger microbatch that ran out of memory with standard storage fit with BitSparse.
Goes deeper in: GPU & CUDA → Memory Hierarchy → HBM: Where Your Model Lives