SJ-KVaRN

Staged, Journaled KVarN: a KV-cache codec built for quality per bit, at about 2.9 to 4.5 effective bits per value (at 104K tokens). At 4/4 bits it has lower error than paper-faithful KVarN and than the other 4- and 5-bit cache formats we tested.

37%
lower KL divergence than paper-faithful KVarN, run as its public port recommends (a 1,024-token exact tail), at 4-bit keys and 4-bit values. Paired 95% CI 27–47%. Lower on 9 of 9 real histories.
48%
lower KL than paper-faithful KVarN with its 1,024-token tail, at 3/3 bits (CI 37–56%, 9 of 9 histories)
76%
lower KL than paper-faithful KVarN with its 1,024-token tail, at 3/2 bits (76.3%, CI 70.6–81.0%, 9 of 9 histories; current build, trellis body). Not equal bytes: on these short histories ours used 4.76 bits per value against 4.43 (section 5.1)
41%
lower KL than the next closest cache format tested (tq5_0 keys / turbo4 values) on ~100K-token trajectories, with 2% more memory (section 6)
Also measured Against the same paper-faithful port with no extra exact tail (tail 0, the closest match to the KVarN reference configuration): 49% lower KL at 4/4 (CI 38–59%), 58% lower at 3/3 (CI 48–67%) and 81% lower at 3/2 (81.4%, CI 77.5–84.8%; not equal bytes: 4.76 vs 3.19 bits per value), 9 of 9 histories each.

On a 12 GB card: with SJ-KVaRN 3/2t, a 27B model quantized to fit a 12 GB card ran a full 204,800-token context within an 11 GB budget, and within a stricter 11,000 MiB (measured on a 24 GB card, calibrated to a 12 GB RTX 3060). Computed from format sizes, 3/2t leaves room for about 2.7 times the context of an 8-bit cache in that budget, at higher KL than the 4-bit formats measured so far; the closest same-memory alternative, turbo3 / turbo3, is still being scored (section 7).

In plain terms: at 4/4, SJ-KVaRN changed the model's most likely next token at 6 of 964 scored positions, against 14 for paper-faithful KVarN with its 1,024-token tail and 12 with no tail. Each side is compared with its own 16-bit-cache run.

Headline setup: Qwen3.8 27B (4-bit weights), nine real agentic, coding and retrieval histories of 9.4K–15K tokens, 964 scored generated-token positions. KL is measured against each engine's own 16-bit-cache reference. The 4/4 and 3/3 figures use the plain scalar body on both sides; the 3/2 figure uses our current build and its default trellis body against the stock scalar body. On that same footing, 3/3t is 64.4% lower than the 1,024-tail configuration (section 5.1), so the 48% and 76% cards are not directly comparable. "Paper-faithful" means a public third-party llama.cpp port of KVarN (credits). Read the caveats: at this depth our cache stores more exact tokens, so this compares default configurations, not equal bytes. The 41% figure is a separate, matched run on ~100K-token trajectories.

1. What a KV cache is, and what KL in nats means

A language model writes one token at a time. To write the next token, each attention layer looks back at every earlier token. It does not recompute them. It keeps two vectors per earlier token per layer, a key and a value, in a store called the KV cache.

The cache grows with every token. Model weights are a fixed size. So at long context the cache becomes the part of memory that decides whether a job fits on the card.

A concrete case. Qwen3.8 27B is a hybrid model: only 16 of its layers use full attention and keep a KV cache. Each of those layers stores 1,024 numbers for the key and 1,024 for the value, per token. Stored as 16-bit floats, that is 65,536 bytes per token. At a 110,592-token context the cache alone is 6.75 GB. A common 8-bit format roughly halves this, to 3.59 GB. These two figures are computed from the format sizes. SJ-KVaRN at 4/4 bits allocates 1.99 GB at the same context, measured on the card (section 8.4).

Throughout, GB means 1,024 MiB, the convention GPU tools use.

The cost of compression: KL divergence in nats

Fewer bits per value means each key and value is stored a little wrong. The question is how much that changes what the model says. We measure it directly:

  1. Run the model once with a high-precision cache. Record its full probability distribution over the vocabulary at each generated token. This is the reference, p.
  2. Replay the exact same token stream with the compressed cache. Record its distribution, q, at the same positions.
  3. Compute the KL divergence KL(p ‖ q) at each position, in nats, and average.

Zero means identical predictions. Bigger numbers mean the compressed model drifts from the reference more often or by more.

What the numbers mean in practice. A second measure is easier to picture: how often the compressed model's single most likely next token is the same one the reference model picks. On the 100K-token test set in section 6, against an 8-bit reference: KL also counts shifts in the probabilities that do not change the top token, which is why it separates formats that look alike on top-1 agreement.

We score generated tokens only. Prompt-text positions produce rare, very large spikes under any numeric change, and those spikes dominate a mean. Where we have them, we also report medians and high percentiles, because KL distributions are heavy-tailed.

This note is about quality per bit. Speed depends on the engine and its kernels and is not covered here.

2. How the codec works

SJ-KVaRN is built on KVarN, a KV-cache quantization method from Huawei's CSL group (credits). KVarN compresses keys and values in groups of 128 tokens. Before quantizing, it rotates and rebalances each group so that plain rounding works well. SJ-KVaRN keeps that core and changes what happens around it: where new tokens live before compression, at what precision, and when they get compressed.

2.1 The life of a token

Every token passes through up to four regions. The attention kernel reads all of them in one pass.

Position in the context → (oldest left, newest right) Sink Sealed body (128-token records) Exact tail staged at ~6 bits 128 tokens kept at 16 bits, never compressed 4/4: 4.28 bits · 3/3: 3.28 · 3/2: 2.78 rotated, balanced, quantized; one record per KV head per 128 tokens 4,096 to 8,192 newest tokens held in a staging ring at 6.125 bits/value, not yet sealed The journal cycle (adaptive tail) 1. Append new token is rotated, written to the ring 2. Grow tail grows 4,096 → 8,192; nothing is sealed 3. Commit at 8,192: seal all but the newest 4,096 in one batch Idle commit server seals back to 4,096 while no request runs
Figure 1. Token lifecycle in SJ-KVaRN, default configuration. The sink is the first 128 tokens of the context. The body grows in whole 128-token records. The newest tokens stay in an exact tail that is committed (sealed) into the body in batches, like a filesystem journal.
  1. Sink. The first 128 tokens stay at 16 bits for the whole run. Attention puts outsized weight on the first few tokens of a context, so compressing them is costly. The KVarN reference keeps the same 128-token sink.
  2. Staging. A new token's key and value are rotated (see 2.2) and written to a ring buffer in a 6.125-bit format (tq6_0, a rotated 6-bit format: 98 bytes per 128 values; tq5_0 and turbo4, used as comparators below, are 5-bit and 4-bit relatives). This is the "Staged" in the name.
  3. Exact tail. The newest tokens stay in that ring, uncompressed by KVarN, so recent context is read at near-full precision.
  4. Seal. When the tail reaches its maximum, every full 128-token group older than the newest 4,096 tokens is compressed into body records in one batch. This is the "Journaled" in the name: like a write-ahead log, recent writes sit in a precise journal and are committed to compact storage in batches.

2.2 Rotation and balancing

Plain rounding fails when a few channels carry values much larger than the rest. One outlier sets the scale, and every small value rounds to zero. KVarN fixes this in two steps before rounding.

Raw key tile a few outlier channels 1. Hadamard rotation energy spread over all channels 2. Sinkhorn balancing rows and columns scaled to equal spread row scales column scales Then: asymmetric round-to-nearest per row (scale + zero point). The balancing scales fold into the record's per-row and per-column fp16 factors, so decoding is one multiply-add and one multiply per value. Queries get the same rotation, so dot products are unchanged.
Figure 2. Before rounding, each 128-token group is rotated and rebalanced. Illustration only; bar heights are not data.

2.3 Two body types: scalar and trellis

Scalar body each value rounds to its own nearest level error is independent per value Trellis body a whole run of values is coded as one path best path chosen by Viterbi search over 64 states
Figure 3. A scalar body rounds each value on its own. A trellis body chooses a sequence of codewords for a run of values jointly, which lowers total squared error at the same bit count. Illustration only.

Scalar body. Plain rounding, as described above.

Trellis body. Trellis-coded quantization treats a run of values as one path through a small state machine. Each step emits a few bits; the state picks which part of a trained codebook those bits index. A Viterbi search with 64 states finds the path with the lowest squared error. The 3-bit codebook has 512 trained entries and the 2-bit codebook has 256, both trained offline for mean squared error. After coding, each row's scale and offset are refit so the decoded values match the original mean and spread. The default in our current development build (not yet released) runs the trellis along the token axis of each tile. Earlier versions ran it along the channel axis; section 4 shows the difference.

Trellis and scalar records have exactly the same size. The trellis places the same bits better. By default the trellis is used for 3/3, 3/2 and 2/2, and 4/4 stays scalar.

3. Bits per value

"4/4" means 4-bit keys and 4-bit values; "3/2" means 3-bit keys and 2-bit values. A "t" marks a trellis body. Each 128-token record also stores fp16 scales, 2,304 bytes per record per KV head, which adds 0.28125 bits per value.

ConfigRecord (bytes, D=256)Body bits/valueEffective at 32KEffective at 104KEffective at 200K
4/435,0724.281254.58–4.814.38–4.454.33–4.37
3/326,8803.281253.71–4.073.42–3.533.35–3.41
3/222,7842.78125 (K 3.28, V 2.28)3.28–3.692.94–3.072.86–2.93
2/218,6882.281252.84–3.322.46–2.612.37–2.45
8-bit (q8_0) reference–8.58.58.58.5
16-bit float–16161616

Effective bits average over the whole occupied cache: the body, the 6.125-bit tail (4,096 tokens just after a seal, up to 8,192 just before one), and the 128-token sink. Formula: [(N − 128 − t) × body + t × 6.125 + 128 × (6.125 + 16)] / N, for N cached tokens and tail length t. The range shows t = 4,096 to 8,192. The staging ring is allocated at full size up front, so actual allocated memory is a little higher than the occupied figure (section 8.4).

4. What SJ-KVaRN changes over KVarN

Each change below lists what it buys and what it costs, with the measured cells it rests on. Where the effect has not been measured in isolation, we say so.

4.1 Staging precision: a 6-bit tail instead of 16-bit

What it is. Tokens waiting to be sealed are stored at 6.125 bits (tq6_0) instead of 16-bit floats. The sink keeps a 16-bit copy.

What it buys. Memory. Each 4,096 tokens of tail costs 98 MiB across Qwen's 16 attention layers in this format, against 256 MiB in 16-bit floats (computed from the formats). That is what makes a 4,096 to 8,192-token exact tail affordable.

What it costs. A little accuracy in the tail. Two measured comparisons:

So 6-bit staging has about 11–15% higher KL at 4/4 and 3/3t than 8-bit staging, in exchange for the smaller ring.

4.2 Journaled exact tail

What it is. The newest tokens are not compressed by KVarN at all. The reference compresses each 128-token group as soon as it fills, so its exact suffix is 0 to 127 tokens.

What it buys. The most recent context is usually what the model attends to most. On 3/2t at a 102K depth (vs an 8-bit reference, one corpus, 6,141 positions, RTX 3090):

Fixed tail lengthMean KLMedianp99Change
00.0044030.0000550.0643–
4,0960.0032820.0000380.0487−25.5% vs 0
8,1920.0031640.0000390.0435−3.6% vs 4,096

What it costs. Memory for the ring (section 8.4), and the tail is part of every attention read.

4.3 Adaptive tail

What it is. The tail is not a fixed length. It grows from 4,096 to 8,192 tokens with nothing sealed, then everything older than the newest 4,096 is sealed in one batch. An idle server also seals back to 4,096 between requests. This is the default at every bit width.

How it behaves. Sealing happens once every ~4,096 tokens in one batch instead of once every 128 tokens. On average the tail holds more exact tokens than a fixed 4,096 tail, with the ring sized for 8,192 tokens plus margin.

Measured: on the nine short histories, the 4,096/8,192 adaptive tail cut 4/4 KL by 49% against a 512/1,024 adaptive tail (0.001045 vs 0.002049), and 3/3t KL by 43% (0.001878 vs 0.003314). At 9.4K–15K tokens a larger tail means a much larger share of the cache is exact, so this mostly measures "more exact tokens", not the adaptive policy itself.

Measurement pendingAdaptive 4,096/8,192 against a fixed tail of the same average size, at 100K depth, generated-token KL, has not been measured.

4.4 Trellis bodies

What it buys. Lower KL at the same bytes for 3-bit and 2-bit bodies. Measured cells, all paired on the same positions and reference:

ComparisonDataKL ratio95% CI
3/3t token axis ÷ 3/3t channel axis6 × ~100K trajectories0.7690.725–0.819
3/2t token axis ÷ 3/2t channel axis6 × ~100K trajectories0.7720.730–0.823
3/3t token axis ÷ 3/3 scalar2 × ~100K trajectories0.646not computed
3/2t token axis ÷ 3/2 scalar2 × ~100K trajectories0.469not computed
3/3t channel axis ÷ 3/3 scalar3 × 32K trajectories0.873–
3/2t channel axis ÷ 3/2 scalar3 × 32K trajectories0.718–
2/2t channel axis ÷ 2/2 scalar3 × 32K trajectories0.804–
3/3t channel axis ÷ 3/3 scalar9 short histories0.8720.75–1.02

Not the default at 4/4. A 4-bit trellis exists. On the token axis it lowered 4/4 KL (ratio 0.844, CI 0.804–0.889, one run), but 4/4 stays on the scalar body by default for reasons outside the scope of this note.

4.5 Tiered edge layers (measured, not enabled)

We tested keeping the first and last layers of the model at 4/4 while the middle runs at 3/3t or 3/2t. At 32K, the ratios against the uniform config were 0.928 (CI 0.77–1.10) for 3/3t and 0.850 (CI 0.64–1.09) for 3/2t. Both intervals include 1, so tiering is available as an option and is not the default.

5. Headline: versus paper-faithful KVarN

What was compared.

SJ-KVaRNPaper-faithful, 1,024-token tail (README)Paper-faithful, tail 0
Figure 4. Mean KL (nats) on 964 generated positions, each engine against its own 16-bit-cache run. Lower is better.
BitsSJ-KVaRNPaper-faithful, 1,024 tailSJ-KVaRN lower byPaper-faithful, tail 0SJ-KVaRN lower byHistories won
4/40.0009870.00156637.0% (26.7–46.5)0.00194449.2% (38.4–59.0)9 of 9 (both)
3/30.0022730.00433847.6% (36.8–56.4)0.00544458.3% (48.4–66.7)9 of 9 (both)

Brackets are paired-position bootstrap 95% CIs. A task-level bootstrap over the nine histories gives 30.5–46.0% (4/4) and 41.2–56.9% (3/3) against the 1,024-tail configuration, and 41.4–54.3% and 45.6–66.3% against tail 0. Medians at 4/4: SJ-KVaRN 9.57e-6 vs 1.99e-5 for tail 0. Against tail 0, SJ-KVaRN is lower at 687 of 964 positions (4/4) and 732 of 964 (3/3).

Most likely next token changed (of 964 positions)SJ-KVaRNPaper-faithful, 1,024 tailPaper-faithful, tail 0
4/46 (99.4% same)14 (98.5% same)12 (98.8% same)
3/37 (99.3% same)21 (97.8% same)19 (98.0% same)

Counts are summed over the nine histories. They are small, so read them as an illustration of the KL result, not a separate test.

Caveats on the headline.

5.1 At 3/2 bits, with the current default

The same nine histories and 964 positions, rerun on our current default build. Our 3/3 and 3/2 sides use the default trellis body on the token axis; the stock port has no trellis, so its 3/3 and 3/2 bodies are scalar. This is a comparison of default configurations, body coding included. Our 16-bit references are fresh on this build. The stock side uses the same port, flags and 16-bit references as section 5; four of those references were regenerated and are byte-identical to the originals.

ComparisonSJ-KVaRNPaper-faithfulSJ-KVaRN lower by (CI)Task CIHistories wonBits per value, ours vs stock
3/2t vs 3/2, 1,024 tail0.0022410.00945076.3% (70.6–81.0)74.0–80.89 of 94.76 vs 4.43
3/2t vs 3/2, tail 00.0022410.01203081.4% (77.5–84.8)78.6–86.19 of 94.76 vs 3.19
3/3t vs 3/3, 1,024 tail0.0015420.00433864.4% (55.5–71.7)60.7–71.39 of 94.98 vs 4.87
3/3t vs 3/3, tail 00.0015420.00544471.7% (65.0–77.1)67.6–74.89 of 94.98 vs 3.67

"Lower by" = 1 − mean(ours) ÷ mean(stock). Brackets are stratified paired-position bootstrap 95% CIs; "Task CI" resamples the nine histories. Bits per value are averaged over the scored positions and computed from each engine's allocation rules. At 3/2 ours has the lower KL at 822 of 964 positions against the 1,024-tail configuration and 866 against tail 0.

Most likely next token changed (of 964 positions)SJ-KVaRNPaper-faithful, 1,024 tailPaper-faithful, tail 0
3/282429
3/362119
Caveat: not equal bytes. As at 4/4, our 4,096 to 8,192-token staging tail is a large share of the cache on these short histories. Ours 3/2t used 4.76 bits per value, against 4.43 for stock 3/2 with its 1,024-token tail and 3.19 at tail 0. At 3/3t, ours used 4.98 against 4.87 (1,024 tail, within 2%) and 3.67 (tail 0). At a 110,592-token context the tail is a small share, and the same 3/2t configuration allocates 3.27 bits per value (section 6); paper-faithful KVarN has not been scored at that depth. So these figures compare default configurations, not equal memory. The next subsection gives the closest equal-bytes readings.

5.2 Closer to equal bytes

Two ways to bring the bytes closer on the same nine histories: give the stock side a longer 16-bit tail, or compare our lower-bit configuration with stock at 4/4. Same positions, references and statistics as 5.1.

ComparisonBits per value, ours vs stockSJ-KVaRN lower by (CI)Task CIHistories won
SJ-KVaRN 3/3t vs stock 4/4, tail 04.98 vs 4.6520.7% (3.3–35.1)11.2–34.09 of 9
SJ-KVaRN 3/2t vs stock 4/4, tail 04.76 vs 4.65−15.3%, not significant (−42.4 to 8.5)−34.7 to 8.24 of 9
SJ-KVaRN 4/4 vs stock 4/4, 4,096 tail5.42 vs 9.0720.2% (5.9–32.4)12.7–29.89 of 9
SJ-KVaRN 4/4 vs stock 4/4, 8,192 tail5.42 vs 13.49−3.9%, not significant (−23.8 to 12.8)−18.3 to 9.25 of 9

Reading it.

5.3 At long range: the 200K needle study

A second study placed 8 facts ("needles") in each of 6 long documents and asked for them back at look-back distances of 5K, 10K, 20K, 50K, 75K, 100K, 150K and 200K tokens. We scored KL on the answer tokens (4,806 positions per arm), with each engine measured against its own 8-bit-cache run. The model was a fine-tuned variant of the same Qwen3.8 27B. Our trellis arms in this study used the earlier channel-axis trellis.

Results are pooled across all 8 look-back distances: the ratio is mean answer-token KL over every answer position, ours ÷ stock. The 95% intervals come from a nested cluster bootstrap: the 6 haystacks are resampled, then the needles within each one (10,000 resamples). The same method was applied to every pair, and nothing was excluded.

ComparisonKL ratio, ours ÷ stock (95% CI)ReadingHaystacks won
SJ-KVaRN 4/4 vs stock 4/4, tail 00.20 (0.10–0.73)79.7% lower5 of 6
SJ-KVaRN 4/4 vs stock 4/4, 1,024 tail0.18 (0.09–0.92)82.1% lower6 of 6
SJ-KVaRN 3/3t vs stock 3/3, tail 01.94 (0.36–5.44)not significant3 of 6
SJ-KVaRN 3/3t vs stock 3/3, 1,024 tail1.79 (0.29–5.64)not significant3 of 6
SJ-KVaRN 3/2t vs stock 3/2, tail 00.25 (0.06–1.10)not significant5 of 6
SJ-KVaRN 3/2t vs stock 3/2, 1,024 tail0.29 (0.09–0.91)70.7% lower5 of 6

Bits per value for the stock side at these contexts are not reported here, so this compares default configurations, not equal bytes. The 3/3t and 3/2t rows also compare our trellis body with the stock scalar body. Weighting each distance equally instead of each position gives the same significance calls (for example 4/4 vs tail 0: 0.20, CI 0.10–0.73).

Reading it. Over 5K–200K look-back, SJ-KVaRN 4/4 had 79.7% lower answer-token KL than paper-faithful KVarN 4/4 (CI 27–90%) and 82.1% lower than the 1,024-tail configuration (CI 8–91%). 3/2t was lower than stock 3/2 with its 1,024-token tail (70.7%, CI 9–91%). Against stock 3/2 at tail 0 the difference was not significant. 3/3t was not significantly different from either stock 3/3 config, but its point estimates favour stock. Answer-token KL is heavy-tailed: in every arm, the 10 largest of 4,806 positions carry 60–90% of the total, so these ratios mostly compare rare large errors, and with 6 haystacks the intervals are wide. All arms, ours and stock, returned the gold answer as the top-1 token at 99.6% or more of answer positions at every distance.

6. Versus other cache formats: quality per bit on ~100K-token trajectories

How does SJ-KVaRN compare with the other KV-cache formats someone could pick today? We ran every format on the same data in one matched test.

41%
lower KL: SJ-KVaRN 4/4 vs the next closest format, tq5_0 / turbo4 (0.000665 vs 0.001128; CI 39–43%), with 2% more memory (1.99 vs 1.95 GB)
68%
lower KL: SJ-KVaRN 4/4 vs turbo4 / turbo4 (0.000665 vs 0.002071; CI 66–69%), with 14% more memory (1.99 vs 1.74 GB)
18%
lower KL with less memory: SJ-KVaRN 3/3t vs 4-bit turbo4 / turbo4 (0.001694 vs 0.002071; CI 15–22%), using 9% less memory (1.58 vs 1.74 GB)

Percentages use unrounded means; 41% is 1 − 0.000665/0.001128. CIs are paired bootstrap 95% intervals over the 37,502 positions; neighbouring positions are correlated, so these intervals are somewhat optimistic.

SJ-KVaRNOther cache formatsPending
Figure 5. Quality per bit, Qwen3.8 27B, ~100K-token trajectories. X: allocated KV memory at a 110,592-token context, in bits per stored key/value number. Y: mean KL against the 8-bit cache, log scale. Down and to the left is better. The 8-bit reference has zero KL by definition and is drawn on the bottom axis.
Cache (keys / values)Format bits K / VAllocated bits per valueKV memory at 110,592 tokensMean KLMedianp99Same top token
q8_0 / q8_0 (reference)8.5 / 8.58.53.59 GB (computed)0 (reference)––100%
q8_0 / q5_18.5 / 6.07.253.06 GB (computed)0.0003292.3e-60.004899.59%
q8_0 / turbo48.5 / 4.1256.312.66 GB (computed)measurement pending
tq5_0 / turbo45.125 / 4.1254.631.95 GB (measured)0.0011286.5e-60.016999.22%
SJ-KVaRN 4/4body 4.284.721.99 GB (measured)0.0006653.6e-60.010799.39%
turbo4 / turbo44.125 / 4.1254.1251.74 GB (computed)0.0020711.0e-50.032598.97%
SJ-KVaRN 3/3tbody 3.283.761.58 GB (measured)0.0016949.3e-60.029699.15%
SJ-KVaRN 3/2tbody 3.28 / 2.28 (mean 2.78)3.271.38 GB (measured)0.0033251.8e-50.057298.78%

Format bits come from the block layouts: q8_0 stores 34 bytes per 32 values (8.5 bits), q5_1 24 bytes per 32 (6.0), tq5_0 82 bytes per 128 (5.125), turbo4 66 bytes per 128 (4.125). Measured memory is the allocated KV cache at a 110,592-token context (section 8.4); computed rows are format size × 110,592 tokens × 16 layers × 2,048 values; the measured tq5_0 / turbo4 allocation matches its computed size. Allocated bits = memory ÷ (110,592 × 16 × 2,048) values. The SJ-KVaRN memory figures come from the current build; the build that produced these KL rows allocated slightly more (0.04 to 0.07 GB) because of an over-sized record pool that has since been fixed; the extra records were never written, so KL is unaffected.

Reading it.

6.1 The format with lower KL in this test: q8_0 / q5_1

In this test one format beats SJ-KVaRN 4/4 on KL: 8-bit keys with 5-bit q5_1 values. (Higher-bit formats such as q8_0 / q8_0 and tq6_0 / tq6_0 also have lower KL than 4/4 in the other tests below.) Its mean KL is about half of ours, 0.000329 against 0.000665 nats. The absolute gap is 0.00034 nats. In top-token terms it agrees with the reference at 99.59% of positions against 99.39%, about 2 more agreements per 1,000 positions.

It pays for that with memory: 3.06 GB against 1.99 GB at a 110,592-token context, 7.25 against 4.72 bits per value. Put the other way: SJ-KVaRN 4/4 gets within 0.00034 nats of an 8-bit-key, 5-bit-value cache in 65% of its memory; q8_0 / q5_1 needs 1.54 times the memory for that last 0.00034 nats.

Measurement pendingq8_0 / turbo4 (8-bit keys, 4-bit values, 6.31 bits per value) is being scored on the same six trajectories and will be added to Figure 5 and the table when it lands. Its reference is a regenerated 8-bit run from the same build; if that reference differs from the one above, the row will be marked as not directly matched.

7. 12 GB cards: SJ-KVaRN 3/2t

On a 12 GB card the KV cache decides how much context a 27B model can hold. This section asks two questions: how much context each cache option leaves room for, and what each option costs in quality. The short answer: SJ-KVaRN 3/2t ran a full 204,800-token context for a 27B model quantized to fit a 12 GB card, with about 0.74 GB of the 11 GB budget to spare and about 0.48 GB under the stricter 11,000 MiB (calibrated to an RTX 3060). It buys that context with higher KL than the 4-bit formats measured so far.

204,800
tokens, measured. A 27B model quantized to fit a 12 GB card, with SJ-KVaRN 3/2t, peaked at 10.32 GB of process memory over a full 204,800-token run (about 10.26 GB calibrated to an RTX 3060). Budget: 11 GB.
2.7×
the context of an 8-bit cache in the same 11 GB: about 261K tokens for 3/2t against about 96K for q8_0 / q8_0 (computed, table below)
224K
tokens for SJ-KVaRN 3/3t (computed), which also has 18% lower KL than turbo4 / turbo4 (section 6); turbo4 / turbo4 reaches about 193K

7.1 The measured fit

Where the memory goes at 204,800 tokensGB
Model weights6.81
KV cache (SJ-KVaRN 3/2t, including sink and staging tail)2.36
Recurrent-layer state (16-bit)0.38
Compute buffer (0.20 GB of it is the attention mask, which grows with context)0.31
CUDA context (after a 0.11 GB cut in the stack reservation)0.15
Draft head and its cache0.18
Everything else (scratch pool, kernels, graphs, libraries)0.13
Process peak, measured10.32
Calibrated to an RTX 3060about 10.26
Headroom to 11 GB / to 11,000 MiB (calibrated)about 0.74 / 0.48

"Everything else" is the measured total minus the listed items. Ledger items are measured allocations on the 24 GB card. The RTX 3060 calibration is applied to the card-level peak minus idle (10.33 GB), not to the process figure. 1 GB = 1,024 MiB.

7.2 How much context each cache option allows

Only the SJ-KVaRN 3/2t row was run at 204,800 tokens. The other rows are computed: we take the measured memory of the run above without its cache and without its attention mask (7.77 GB), and add each option's cache size and the mask (1 KiB per token of context, which matches the measured compute buffers at 65,536, 131,072 and 204,800 tokens). That assumes the rest of the memory is the same for every cache format; we have not measured that for the other formats on this setup.

SJ-KVaRNOther cache formats
Figure 6. Largest context that fits within 11 GB for a 27B model quantized to fit a 12 GB card, by KV cache option, in thousands of tokens. Computed from format sizes and the measured non-cache memory; the SJ-KVaRN 3/2t fit at 204,800 tokens is measured.
Cache (keys / values)Bits per valueCache at 204,800 tokensTotal at 204,800Largest context, 11 GBLargest context, 11,000 MiBMean KL, 100K testSame top token
q8_0 / q8_08.56.64 GB14.61 GB96K88K0 (reference)100%
q8_0 / q5_17.255.66 GB13.63 GB112K103K0.00032999.59%
q8_0 / turbo46.314.93 GB12.90 GB128K118Kpending
tq5_0 / turbo44.633.61 GB11.58 GB173K159K0.00112899.22%
q4_0 / q4_04.53.52 GB11.48 GB178K163Kpending
SJ-KVaRN 4/4body 4.283.53 GB11.50 GB176K161K0.00066599.39%
turbo4 / turbo44.1253.22 GB11.19 GB193K177K0.00207198.97%
SJ-KVaRN 3/3tbody 3.282.76 GB10.73 GB224K205K0.00169499.15%
turbo3 / turbo33.1252.44 GB10.41 GB250K230Kpending
SJ-KVaRN 3/2tbody 2.782.36 GB (measured)10.32 GB (measured)261K238K0.00332598.78%

K = 1,000 tokens, rounded down. "Bits per value" for SJ-KVaRN is the body size; counting the sink and staging ring, the allocated figure at 204,800 tokens is about 4.52 (4/4), 3.54 (3/3t) and 3.02 (3/2t, measured). Format sizes come from the block layouts: q4_0 stores 18 bytes per 32 values (4.5 bits) and turbo3 50 bytes per 128 values (3.125 bits); the others are listed in section 6. Computed cache size = bits per value × 4,096 ÷ 8 bytes per token (16 layers × 2,048 values). SJ-KVaRN rows use the rule that reproduces the measured allocations in section 8.4: body bytes per token × (context − 4,224) + 259 MiB for the sink, staging rows and ring. For 3/2t at 204,800 tokens that rule gives 2.38 GB, against 2.36 GB measured, so the computed SJ-KVaRN rows are slightly conservative. The largest-context columns for SJ-KVaRN use the same rule. The KL and top-token columns are from the matched 100K test of section 6, which used Qwen3.8 27B with 4-bit weights, not the 12 GB weights, and the earlier channel-axis trellis.

Reading it.

Measurement pendingLow-memory pairs. turbo3 / turbo3 (3.125 bits) and q4_0 / q4_0 (4.5 bits), along with q8_0 / turbo4 (section 6), are being scored on the same six ~100K trajectories. Their KL will fill the pending rows above. turbo3 / turbo3 is the closest competitor to 3/2t on context, so it decides whether 3/2t is the best quality available at that memory. If their reference differs from section 6's, the rows will be marked as not directly matched.

Against paper-faithful KVarN at 3/2. On the nine short histories of section 5, 3/2t had 76.3% lower KL than paper-faithful KVarN 3/2 with its 1,024-token tail, and 81.4% lower at tail 0 (section 5.1). Those histories are short, so our side used more bits per value than the stock side there (4.76 vs 4.43 and 3.19); stock has not been scored at 100K or on the 12 GB weights. Our side used the trellis body, which the stock port lacks. At about equal bytes on the same histories (3/2t at 4.76 vs stock 4/4 tail 0 at 4.65 bits), there was no significant difference (−15.3%, CI −42.4 to 8.5, 4 of 9; section 5.2).

Not measuredKL with the 12 GB weights. The KL figures above come from the 4-bit-weight model. KL for each cache option on the 12 GB weights, and the full 204,800-token run on a physical 12 GB card, have not been measured.

8. More results on Qwen3.8 27B

Model: Qwen3.8 27B, hybrid architecture with 16 full-attention layers, 4 KV heads of 256 dims each, 4-bit weights. GPU: RTX 3090 Ti, 24 GB, except where a subsection says otherwise. All KL is on generated tokens.

8.1 The current default (token-axis trellis) at 100K

A later run on a newer build scored SJ-KVaRN on the same six ~100K trajectories with both trellis axes, against its own regenerated 8-bit reference, with a block bootstrap. Its reference differs from section 6's, which moves arm KL by up to about 10% per history, so compare rows within this table, not with section 6.

Figure 7. Mean KL vs an 8-bit cache, ~100K-token trajectories, later run. Teal: token axis (current default). Orange: channel axis (earlier).
CacheBody bitsMean KL95% CIMedianp99Same top token
SJ-KVaRN 4/44.280.0006640.000533–0.0008103.8e-60.010899.36%
SJ-KVaRN 3/3t, token axis (default)3.280.0012970.00103–0.001607.7e-60.022199.23%
SJ-KVaRN 3/3t, channel axis (earlier)3.280.0016870.00129–0.002139.4e-60.029199.16%
SJ-KVaRN 3/2t, token axis (default)2.780.0025560.00207–0.003131.55e-50.044398.91%
SJ-KVaRN 3/2t, channel axis (earlier)2.780.0033100.00258–0.004131.78e-50.055898.75%

The token axis lowered KL by 23% at both 3/3t and 3/2t (paired ratios 0.769 and 0.772, section 4.4). The 4/4 cell, 0.000664, is close to the section 6 run's 0.00066.

8.2 At 32K, against a 16-bit reference

Three trajectories to 32K generated tokens, 3,074 positions, reference = 16-bit cache. Channel-axis trellis.

Figure 8. Mean KL vs a 16-bit cache at 32K, Qwen3.8 27B. Scalar and trellis bodies at the same bit widths.

8.3 Same harness as Gemma

To compare the two models directly, we ran the Gemma harness (section 9) on a fine-tuned variant of Qwen3.8 27B: three prompts generating up to 25K tokens each, 74,873 generated tokens, reference = 16-bit cache, channel-axis trellis, one seed.

CacheMean KLMedianp90Top-1 agree
q8_0 / q8_00.000239e-60.0006799.49%
tq6_0 / tq6_00.000421.6e-50.0011599.37%
SJ-KVaRN 4/40.000822.9e-50.0022099.17%
SJ-KVaRN 3/3t0.001805.1e-50.0045198.81%
SJ-KVaRN 3/2t0.003178.7e-50.0079798.54%

8.4 Memory

KV cache memory measured on the card at a 110,592-token context, Qwen3.8 27B (16 attention layers). The 16-bit and 8-bit rows are computed from the format sizes for comparison.

CacheBytes per tokenKV memory at 110,592Source
16-bit float65,5366.75 GBcomputed
q8_0 / q8_034,8163.59 GBcomputed
tq5_0 / turbo4–1.95 GBmeasured
SJ-KVaRN 4/417,536 (body)1.99 GBmeasured
SJ-KVaRN 3/313,440 (body)1.58 GBmeasured
SJ-KVaRN 3/211,392 (body)1.38 GBmeasured

The SJ-KVaRN rows are body plus a fixed 259 MiB (0.25 GB) for the sink, the staging rows and a ring sized for 8,192 tokens plus margin, which is allocated in full up front. At this context, 4/4 uses about the same memory as tq5_0/turbo4. The fixed ring cost shrinks as a share of the cache as context grows.

8.5 Task accuracy

GPQA Diamond and LiveCodeBench v6 questions, a fine-tuned variant of Qwen3.8 27B with 4-bit weights, temperature 0.6, 4 repetitions. "Shallow" questions start from an empty context (100 questions × 4 = 400 answers). "Deep" questions are asked after a 100K-token real prefix (20 × 4 = 80 answers). Channel-axis trellis. Run on RTX 3090 (24 GB) cards; the 8-bit reference answers were reused from an earlier run with identical model, prompts and sampler. Deltas are paired against the 8-bit cache, with 95% paired-bootstrap intervals.

CacheShallowΔ shallowDeep (100K)Δ deep
q8_0 / q8_060.5%–72.5%–
SJ-KVaRN 4/458.8%−1.75 [−5.50, +2.00]75.0%+2.50 [−6.25, +11.25]
SJ-KVaRN 3/3t62.5%+2.00 [−2.50, +6.50]67.5%−5.00 [−16.25, +6.25]
SJ-KVaRN 3/2t62.3%+1.75 [−2.50, +6.25]77.5%+5.00 [−5.00, +13.75]

No arm shows a detected loss: every interval includes zero. That is not a proof of equivalence; the deep cohort is small. 3/3t on GPQA deep had a point estimate of −12.5 points (CI −27.5 to 0.0), which deserves a larger follow-up. One 3/3t deep answer failed with a server text-encoding error and is scored as wrong.

9. Results on Gemma 4 31B

Gemma 4 31B (4-bit weights) has 60 layers. Every sixth layer, 10 in all, uses full attention with 4 KV heads of 512 dims. The other 50 use sliding-window attention over 1,024 tokens. SJ-KVaRN compresses only the 10 full-attention layers. The sliding-window cache is 8-bit (q8_0) in every arm, including the reference arms. Each 512-dim head is rotated as two 256-point halves.

9.1 KL divergence

Three prompts (agentic, coding, retrieval) generating up to 25K tokens each, 70,912 generated tokens, one seed. Reference: 16-bit cache. Channel-axis trellis. ± is the token-level standard error, which understates the true error because neighbouring tokens are correlated.

Figure 9. Mean KL vs a 16-bit cache, Gemma 4 31B, generated tokens. SJ-KVaRN arms in teal.
Cache (full-attention layers)Mean KLp90Top-1 agreeAgentic / coding / retrieval
q8_0 / q8_00.00078 ± 0.000120.0011599.53%.00082 / .00073 / .00078
tq6_0 / tq6_00.00135 ± 0.000060.0025199.28%.00166 / .00103 / .00141
SJ-KVaRN 4/40.00127 ± 0.000130.0019799.34%.00122 / .00123 / .00134
SJ-KVaRN 3/3t0.00215 ± 0.000090.0035999.06%.00199 / .00172 / .00277
SJ-KVaRN 3/2t0.00366 ± 0.000150.0061398.83%.00326 / .00299 / .00474

Reading it.

9.2 Memory and maximum context

Gemma 4 31B with a multi-token-prediction draft model loaded, on a 24 GB RTX 3090 Ti, under a 23 GB whole-card cap. About 1.05 GB of the card was used by other processes during these runs; the process peaks below exclude it.

Cache (full-attention layers)Process peak at 32,768Process peak at 102,400Largest tested context that fitSmallest tested that did not
q8_0 / q8_018.80 GBdid not start32,76893,184
tq6_0 / tq6_018.19 GB21.39 GB112,640262,144
tq5_0 / turbo417.86 GB20.55 GB102,400143,360
SJ-KVaRN 4/417.89 GB19.38 GB216,064262,144
SJ-KVaRN 3/3t17.74 GB18.93 GB262,144 (model max)–
SJ-KVaRN 3/2t17.69 GB18.69 GB262,144 (model max)–

Under this cap, SJ-KVaRN 4/4 fits about 1.9× the largest tested 6-bit context (216,064 vs 112,640), and 3/3t and 3/2t reach the model's full 262,144-token window.

9.3 What is not yet measured on Gemma

Measurement pending

10. Limitations

11. Credits and references