Skip to content

Commit 0b37448

Browse files
TheTomclaude
andcommitted
WIP: add TurboQuant KV cache types (turbo3, turbo4)
New types: GGML_TYPE_TURBO3_0 (3-bit) and GGML_TYPE_TURBO4_0 (4-bit) Implements PolarQuant + QJL compression per the ICLR 2026 paper. Block size = 128 (matching head_dim for optimal rotation Gaussianization) turbo3: 52 bytes per 128 values = 3.25 bits/value (4.9× vs fp16) turbo4: 68 bytes per 128 values = 4.25 bits/value (3.8× vs fp16) Status: - ✅ Type definitions in ggml.h - ✅ Block structures in ggml-common.h - ✅ Quantize/dequantize C implementation in ggml-turbo-quant.c - ✅ Registered in ggml.c type traits - ✅ Added to kv_cache_types in arg.cpp - ✅ Builds successfully - ✅ Shows in --help output - ❌ Metal SET_ROWS kernel not implemented (blocks GPU inference) - ❌ Needs Metal dequantize kernels for attention computation Co-Authored-By: tturney@psyguard.ai Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b3d7587 commit 0b37448

7 files changed

Lines changed: 546 additions & 1 deletion

File tree

common/arg.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@ const std::vector<ggml_type> kv_cache_types = {
390390
GGML_TYPE_IQ4_NL,
391391
GGML_TYPE_Q5_0,
392392
GGML_TYPE_Q5_1,
393+
GGML_TYPE_TURBO3_0,
394+
GGML_TYPE_TURBO4_0,
393395
};
394396

395397
static ggml_type kv_cache_type_from_str(const std::string & s) {

ggml/include/ggml.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,9 @@ extern "C" {
429429
GGML_TYPE_MXFP4 = 39, // MXFP4 (1 block)
430430
GGML_TYPE_NVFP4 = 40, // NVFP4 (4 blocks, E4M3 scale)
431431
GGML_TYPE_Q1_0 = 41,
432-
GGML_TYPE_COUNT = 42,
432+
GGML_TYPE_TURBO3_0 = 42, // TurboQuant 3-bit KV cache: 2-bit PolarQuant + 1-bit QJL
433+
GGML_TYPE_TURBO4_0 = 43, // TurboQuant 4-bit KV cache: 3-bit PolarQuant + 1-bit QJL
434+
GGML_TYPE_COUNT = 44,
433435
};
434436

435437
// precision

ggml/src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ add_library(ggml-base
206206
ggml-threading.h
207207
ggml-quants.c
208208
ggml-quants.h
209+
ggml-turbo-quant.c
209210
gguf.cpp)
210211

211212
set_target_properties(ggml-base PROPERTIES

ggml/src/ggml-common.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,31 @@ typedef struct {
277277
} block_tq2_0;
278278
static_assert(sizeof(block_tq2_0) == sizeof(ggml_half) + QK_K / 4, "wrong tq2_0 block size/padding");
279279

280+
// TurboQuant 3-bit: 2-bit PolarQuant indices + 1-bit QJL signs
281+
// Block size = 128 (matches typical head_dim for optimal rotation Gaussianization)
282+
// Per block: norm(fp16) + residual_norm(fp16) + 2-bit indices (32 bytes) + 1-bit signs (16 bytes)
283+
// = 52 bytes per 128 values = 3.25 bits/value → 4.9× compression vs fp16
284+
#define QK_TURBO3 128
285+
typedef struct {
286+
ggml_half norm; // 2 bytes: vector L2 norm (for rescaling)
287+
ggml_half rnorm; // 2 bytes: QJL residual L2 norm
288+
uint8_t qs[QK_TURBO3 / 4]; // 32 bytes: 2-bit PolarQuant indices (4 per byte)
289+
uint8_t signs[QK_TURBO3 / 8]; // 16 bytes: 1-bit QJL signs (8 per byte)
290+
} block_turbo3_0; // 52 bytes total
291+
static_assert(sizeof(block_turbo3_0) == 2*sizeof(ggml_half) + QK_TURBO3/4 + QK_TURBO3/8, "wrong turbo3_0 block size/padding");
292+
293+
// TurboQuant 4-bit: 3-bit PolarQuant indices + 1-bit QJL signs
294+
// Per block: norm(fp16) + residual_norm(fp16) + 3-bit indices (48 bytes) + 1-bit signs (16 bytes)
295+
// = 68 bytes per 128 values = 4.25 bits/value → 3.8× compression vs fp16
296+
#define QK_TURBO4 128
297+
typedef struct {
298+
ggml_half norm; // 2 bytes
299+
ggml_half rnorm; // 2 bytes
300+
uint8_t qs[QK_TURBO4 * 3 / 8]; // 48 bytes: 3-bit PolarQuant indices
301+
uint8_t signs[QK_TURBO4 / 8]; // 16 bytes: 1-bit QJL signs
302+
} block_turbo4_0; // 68 bytes total
303+
static_assert(sizeof(block_turbo4_0) == 2*sizeof(ggml_half) + QK_TURBO4*3/8 + QK_TURBO4/8, "wrong turbo4_0 block size/padding");
304+
280305
//
281306
// Super-block quantization structures
282307
//

ggml/src/ggml-quants.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ GGML_API size_t quantize_q8_0(const float * GGML_RESTRICT src, void * GGML_RESTR
102102
GGML_API size_t quantize_mxfp4(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix);
103103
GGML_API size_t quantize_nvfp4(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix);
104104

105+
// TurboQuant KV cache compression (arXiv 2504.19874)
106+
GGML_API void quantize_row_turbo3_0_ref(const float * GGML_RESTRICT x, block_turbo3_0 * GGML_RESTRICT y, int64_t k);
107+
GGML_API void quantize_row_turbo4_0_ref(const float * GGML_RESTRICT x, block_turbo4_0 * GGML_RESTRICT y, int64_t k);
108+
GGML_API void dequantize_row_turbo3_0(const block_turbo3_0 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k);
109+
GGML_API void dequantize_row_turbo4_0(const block_turbo4_0 * GGML_RESTRICT x, float * GGML_RESTRICT y, int64_t k);
110+
GGML_API size_t quantize_turbo3_0(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix);
111+
GGML_API size_t quantize_turbo4_0(const float * GGML_RESTRICT src, void * GGML_RESTRICT dst, int64_t nrows, int64_t n_per_row, const float * imatrix);
112+
105113
GGML_API void iq2xs_init_impl(enum ggml_type type);
106114
GGML_API void iq2xs_free_impl(enum ggml_type type);
107115
GGML_API void iq3xs_init_impl(int grid_size);

0 commit comments

Comments
 (0)