Pull requests / #2941

#2941 kv: mixed K16V8 (FP16 K, INT8 V)

open · @iskamag · 0 comments · View on GitHub

BenchmarksMulti-GPUAMD / HIPNVIDIA / CUDAModels & quantsDocumentationWindows

Description

## Title
kv: mixed K16V8 (FP16 K, INT8 V)

Issue: Resolves # (none)

## Summary
Adds `--kv k16v8`, a KV cache format between `int8` and `fp16`: **FP16 K + INT8 V** (codes plus one FP16 scale per 64 values). It keeps FP16 precision for the attention scores while keeping the V-side memory saving: **1,552 B/cell** vs 1,056 for int8 and 2,048 for fp16.

The format streams with `--kv-resident` (three runs: FP16 K, V codes, V scales), works with the MTP drafter (the drafter stays plain INT8, as under k8v4), and is independent of the SCR/suffix-reuse work.

Full write-up and assets: [`docs/K16V8.md`](https://github.com/iskamag/Strata/blob/feat/k16v8/docs/K16V8.md)

## What changed
- `include/strata/core/layer.hpp`, `src/core/layer.cpp`: `kv_f16k_q8v` state flag, format tag 4, pool sizing, elastic/streamed host allocation, zeroing, `qsa_attn_pools`, decode append.
- `src/kernels/cuda/qsa_decode_attn.cu`: decode-attention mode 4 (FP16 K, INT8 V) across `step`, `batch`, `slots` and `rows`.
- `src/kernels/cuda/kv_stream.cu`, `include/strata/kernels/kv_stream.hpp`: 3-run block movers and the folded K/V host helpers for appends.
- `src/prefill/prefill.cpp`, `src/core/verify.cpp`, `src/core/mtp.cpp`: prefill/verify append paths; drafter forced to INT8 under k16v8.
- `src/core/conversation_snapshot.cpp`: per-side K/V sizes and format tag 4 (modes 0/1/2).
- `src/program/generate.cpp`: `--kv k16v8` parsing and help.
- `src/kernels/kv_stream_parity.cpp`, `src/core/conversation_snapshot_test.cpp`: mixed-format coverage.
- `docs/K16V8.md`, `docs/media/k16v8/`: results and the SVG output comparison.

## Extra Notes

### Performance
Controlled A/B: same engine, IQ3_S, RX 6800 (gfx1030), HIP, `STRATA_HIP_PROMPT_F16=1`, MTP spec 4, 13,109-token prompt, fully resident KV.

| KV | prefill tok/s | decode tok/s | bytes/cell |
| --- | ---: | ---: | ---: |
| `int8` | 919.2 | 32.15 | 1,056 |
| `k16v8` | 917.9 | 34.48 | 1,552 |
| `fp16` | 906.6 | 33.90 | 2,048 |

The three are within run-to-run/draft-acceptance noise. K16V8 is effectively int8 speed with FP16 K, and 24% smaller than fp16.

At 96k context and 12 QSA layers: 1.71 GiB host KV (vs ~1.16 GiB int8 / ~2.25 GiB fp16); 32,768 resident cells use ~610 MB VRAM (vs ~415 MB / ~805 MB). The extra VRAM against int8 can reduce the expert cache by roughly 200 MB.

### Output length on the same prompt
Prompt: `Make an animated SVG of an anthropomorphic cat holding a sword`

| KV | output tokens |
| --- | ---: |
| `int8` | 37k |
| `k16v8` | 29k |
| `fp16` | 25k |

On this workload, higher KV precision correlated with fewer output tokens: int8 produced the longest response, fp16 the shortest, and k16v8 sat between them — consistent with **less overthinking** when the cache is more precise. This is one observation, not a general quality or latency guarantee.

<table>
<tr>
<td align="center"><b>int8</b> — 37k output tokens<br><img src="https://raw.githubusercontent.com/iskamag/Strata/feat/k16v8/docs/media/k16v8/int8.png" width="260" alt="int8 SVG output"></td>
<td align="center"><b>k16v8</b> — 29k output tokens<br><img src="https://raw.githubusercontent.com/iskamag/Strata/feat/k16v8/docs/media/k16v8/k16v8.png" width="260" alt="k16v8 SVG output"></td>
<td align="center"><b>fp16</b> — 25k output tokens<br><img src="https://raw.githubusercontent.com/iskamag/Strata/feat/k16v8/docs/media/k16v8/fp16.png" width="260" alt="fp16 SVG output"></td>
</tr>
</table>

Animated originals: [int8](https://raw.githubusercontent.com/iskamag/Strata/feat/k16v8/docs/media/k16v8/int8.svg), [k16v8](https://raw.githubusercontent.com/iskamag/Strata/feat/k16v8/docs/media/k16v8/k16v8.svg), [fp16](https://raw.githubusercontent.com/iskamag/Strata/feat/k16v8/docs/media/k16v8/fp16.svg).

### Compatibility
Exercised: `--kv-resident 0` and `32768`, `--mtp`/`--spec 4`, `--prompt-cache` prefix reuse, 96k context, vision, control vectors, `--adapt-async`, `--expert-cache auto`, HIP gfx1030.

`--no-fast-attn` and `--native-flash-attn-short` fall back to the fused decode attention for k16v8; the gather/native path is not implemented for this format.

Not yet exercised: `--batch`, `--layer-split`, `--pipeline-windows`, `--kv-grow` (elastic), and CUDA. Batch slots/rows and elastic allocation are implemented. On CUDA the prompt attention falls back to the decode kernel; gfx1030 already uses that path for most formats. `--cache-suffix-reuse` and `--kv-pool-tokens` are not in `main`, so this change is independent of SCR.

### Tests
- `kv_stream_parity`: all five formats pass; k16v8 streamed-vs-resident is bitwise and the ring restore is identical.
- `conversation_snapshot_test`: 4,872 checks pass, including k16v8 modes 0/1/2.
- Live model: 13k and 63k-token retrieval prompts, 96k service profile, MTP drafts accepted.

Related on this site

Quick links to related pages.