Repository navigation
Conversation
…+ a FP16 scale per 64 values) The q36 caches were FP32 (2 KB/cell per store), so a 128K context left no VRAM for expert slots (0/256 in VRAM; 34 tok/s vs 55 with the caches quantized). The default stays FP32 and the FP32 kernels are unchanged; --kv int8 stores both caches as int8 codes with one FP16 scale per 64 values, k8v32 / k32v8 quantize one of the two stores. STRATA_Q36_KV=int8 stays as the environment fallback. Decode, prompt and the MTP block dequantize on the fly (kKVG=64; head_dim must be a multiple of it). PR Niko1221#21's q4_0 / k8v4 rotation modes are not part of this change.
…-block V weight table) Decode at filled contexts on the RTX 3060: 2K 45.4 -> 55.7, 8K 33.9 -> 48.5, 26K 19.0 -> 35.8 tok/s (FP32 at the same prompts: 33.2 / 41.5 / 4.9). The long-context decode was instruction bound: 8 int8 codes per uint2 load with one scale per 64-dim group, and sc[k] * group scale folded into a shared table once per block. The FP32 stores are untouched (bit for bit).
|
Update: engine-reported measurements for the int8 KV cache The decode numbers in the description and in the second commit's message were measured with client-side timing (total request time, and differences between two runs). As built here, the standalone q36 engine has no prompt cache - every request re-reads the whole prompt ( What the table in the description actually measures: it used a short prompt with the KV cache allocated for 64K / 128K, so it shows the VRAM win (experts back in VRAM: 18 -> 46 at 64K, 0 -> 31 at 128K), not the decode speed at a filled context. A tiny-context run today reproduces the int8 number (~59.5 tok/s at ~50 tokens of context with Engine-verified numbers - same machine (RTX 3060 12 GB, Qwen3.6-35B-A3B UD-Q4_K_XL, 128K mode,
|
|
V100-PCIe 32 GB (sm_70), the #2464 setup: Qwen3.6-35B-A3B UD-Q4_K_XL (setup's pinned file), Decode, tok/s:
The short-context dip comes from the packed Q8_0 decode copies, not from int8. At |
|
A second data point from a different architecture. RTX 3060 12 GB (sm_86), Qwen3.6-35B-A3B UD-Q4_K_XL, q36 standalone engine with the int8 KV path from #2698,
Same PC, llama.cpp (LM Studio 2.55 runtime, no drafts): 45.9 / 37.7 / 39.4 / 28.2 @ 2K/8K/26K/64K. And the main engine with a Flash-Next-class model on this box is flat 37-46 all the way to 128K. So the falloff is not Volta — it shows the same shape on sm_86 (-52% from 2K to 64K here, against -64% from 256 to 16K on the V100). Two notes on the mechanism, from our side:
Two practical traps we hit while measuring, in case they matter for other reports:
Our int8 KV branch plus both patches (the attention A/B above, and the conversation checkpoint) are available if they are useful — they sit on top of #2698. |
|
Thanks for the second data point. I can run both patches on the V100 with the same setup as above (decode at 256 to 64K, the needle check), plus a 64K follow-up turn for the conversation checkpoint. If you push the branch, I'll post the numbers here. |
|
Thanks for the pull request. We're resetting the tracker for 0.2.0-beta. There are more than 1,300 open issues and pull requests, too many for us to review properly, so we're closing everything that isn't being worked on right now. Closed here does not mean rejected. To reopen it takes about two minutes:
The rules are in CONTRIBUTING.md. |
Implements the int8 K/V cache for the q36 (qwen35moe) engine's own attention path as
--kv(strata's namefor the stores:
fp32default,int8for both stores,k8v32/k32v8for one of the two). The q36 cacheswere FP32 (2 KiB per cell per store), so a 128K context ran out of VRAM for expert slots: 0/256 experts in
VRAM, 34 tok/s. This is the same effect issue #2464 reports for the V100 (the q36 decode falling from 154 to
56 tok/s as the context fills; llama.cpp quantizes the cache, this engine does not).
What it does
--kv int8: K and V stored as int8 codes with one FP16 scale per 64 values (group absmax / 127), ~3.9xsmaller cache (528 B/cell vs 2048 B at head_dim 256);
k8v8is an alias;k8v32/k32v8quantize onestore only;
fp32(the default) runs bit for bit the old kernels.STRATA_Q36_KV=int8stays as the environment fallback (--kvwins).k_attn_part), prompt chunk (k_kv_f16-> cuBLAS) and the MTP block dequantize on the fly; theverify windows go through the same kernels, the commit/rollback of the cache is unchanged.
k_attn_prep/k_attn_part/k_kv_f16aretemplate <bool KI8, bool VI8>; a smallkv4()dispatcherin
Enginelaunches the right specialization, sokc/vcstay FP32 pointers and the int8 codes + scaleslive in
kc8/vc8/ks8/vs8.kKVG = 64;head_dimmust be a multiple of it (the host says so and staysFP32 otherwise).
Measurements
RTX 3060 12 GB, Qwen3.6-35B-A3B UD-Q4_K_XL (experts 18.75 GiB, streaming),
--mtp 2, same machine, tworuns each, 120 tokens per run:
--kv int8At 128K the freed VRAM (~4 GiB) brings 31 experts back into the VRAM, which is where the +53% comes from.
The FP32 build reproduces the installed engine (50.1 vs 50.3 / 33.9 vs 35.8), so the difference is the patch,
not the toolchain.
Needle-in-the-haystack, 52.8K-token prompt, 128K mode, max_tokens 250, temperature 0: both FP32 and int8
find the hidden number; the int8 run took 91 s vs 159 s end to end (1.75x). A chat answer at the same
context is qualitatively equal between the two.
--kv k8v32/k32v8smoke tested at 64K: each quantizes one store, so they land between FP32 and int8 —32 experts in VRAM (FP32: 18, int8: 46) and 54.8 / 53.8 tok/s (FP32: 50.1, int8: 59.7).
Not in this PR
--kv q4_0andk8v4(PR #21's Hadamard rotation over head_dim 256) are not wired into the q36 kernelsyet;
--kvrefuses them with a note. The FWHT-256/Q4_0 pieces already exist in the repo(
src/kernels/cuda/kv_q4.cu,include/strata/kernels/kv_q4.hpp), so a follow-up can add them the same way(rotate K after RoPE and V, rotate the queries, rotate the output back).
How it was tested
installed engine was not touched.
--kv int8end to end throughserve/server.py(the config's args carry--kv int8).q36reffp32 path is untouched (the FP32 template instantiation is the previous kernel code).