TurboQuant: Online Vector Quantization with Near-optimal Distortion Rate
A random rotation lets one fixed quantizer compress any vector to within 2.7× of the best possible error.
TurboQuant rotates each vector by a random orthogonal matrix, rounds every coordinate to the nearest entry of a small precomputed table, and adds a 1-bit correction when inner products have to come out unbiased. It needs no training data and no calibration.
Explaining the paperTurboQuant: Online Vector Quantization with Near-optimal Distortion RateThe paper also proves a lower bound that holds for any quantizer, keeps a Llama-3.1-8B KV cache at 3.5 bits per channel with no drop in LongBench average, and encodes 100,000 search vectors in 0.7 to 2.1 milliseconds.
A language model's KV cache stores one key vector and one value vector per token, per attention head, per layer. For Llama-3.1-8B a head vector has 128 numbers; in 16-bit floating point that is 2,048 bits, and a 100,000-token context holds millions of them. A vector database for retrieval-augmented generation holds millions of embeddings of 1,536 or 3,072 numbers each. Both are expensive in memory, and on a GPU the time to move them from memory to the arithmetic units often costs more than the arithmetic. Storing each number in 2 to 4 bits instead of 16 cuts both costs by 4 to 8 times, if the vectors survive the rounding.
TurboQuant (Zandieh, Daliri, Hadian and Mirrokni, from Google Research, Google DeepMind and NYU) is a vector quantizer with three properties at once. It is online: the same fixed map applies to each vector the moment it arrives, with nothing fitted to the data. Its error is provably within a constant factor of the least error any quantizer can reach at the same number of bits. And it runs as a matrix multiply plus a table lookup, which a GPU does quickly. The page builds it in the order the paper does: what error to measure, why a random rotation makes one fixed quantizer sufficient, how to quantize a single coordinate, how close that gets to the information-theoretic floor, and why inner products need a second, 1-bit stage.
What a vector quantizer has to preserve
The input is a vector with coordinates and a budget of bits per coordinate, the bit-width. A quantizer is a pair of maps: an encoder that turns into a code of bits, and a decoder that turns the code back into a reconstruction . TurboQuant's encoder is randomized (it draws a random rotation once), so its errors are stated as expectations over that randomness, for a fixed input.
The first error measure is the squared distance between the vector and its reconstruction, the mean-squared error:
Most uses of these vectors are dot products. Attention scores a query against every cached key by their inner product (see Attention Is All You Need), and a nearest-neighbour search ranks database vectors by their inner product with a query. So the second measure is the squared error of an inner product with an arbitrary query :
For inner products the paper also asks that the estimate be unbiased: averaged over the quantizer's randomness, it equals the true value exactly.
Squared error and bias behave differently when estimates are combined. If a thousand inner products each carry independent zero-mean noise, the noise in their sum grows as while the sum grows as 1000, so the relative error of the sum is about 32 times smaller than that of one term. If each carries the same bias, say every estimate is 10% too small, the sum is 10% too small no matter how many terms there are. The paper therefore gives two algorithms: one minimizes (1), and the other keeps (2) small while staying unbiased.
Two constraints shape the design. The input is worst-case: the guarantees must hold for every unit vector, with no assumption that the data follows a friendly distribution. And the quantizer is data-oblivious, which the paper also calls online: it cannot look at the dataset first. The usual alternative, product quantization, fits a codebook to the data with k-means, which needs a preprocessing pass over the whole dataset and has to be redone when the data changes. A KV cache changes with every generated token, so a quantizer for it has to encode each new key and value immediately, with the same fixed map.
The theorems assume . A vector of any other length is stored as its floating-point norm plus the quantized unit vector, and rescaled after decoding. For a 128-dimensional key at , the code is bits plus one norm, against 2,048 bits in 16-bit floating point, about 5 times smaller.
Why TurboQuant rotates every vector first
The simplest vector quantizer rounds each coordinate on its own against a fixed list of allowed values. That list has to be chosen for some expected spread of coordinate values, and a worst-case input can always violate it. Take and a unit vector whose length is all in one coordinate: one entry equals 1 and the other 63 are 0. A list designed for coordinates of typical size has its largest entry near 0.19 (the exact 2-bit values come in the next section), so the 1 is stored as 0.19, and the zeros are stored as because the list has no zero. The squared error is 0.66 from the spike plus 0.20 from the 63 zeros, 0.86 in total. At one bit it is 1.44, worse than storing nothing (reconstructing the zero vector costs exactly 1). A list designed for spikes would do badly on a vector spread evenly across all coordinates.
TurboQuant multiplies by a random rotation before quantizing, and by after decoding. A random rotation is an orthogonal matrix drawn uniformly; the paper builds one from the QR decomposition of a matrix of i.i.d. Gaussian entries. Orthogonal matrices preserve every length and every angle, so and the squared error is the same measured before or after the rotation. What changes is the coordinates. For any fixed unit vector , the rotated vector is a uniformly random point on the unit sphere. The spike above becomes a vector whose 64 coordinates all have typical size 0.125, and so does every other input. The same is used for every vector, so it is drawn once and costs nothing per vector.
Lemma 1 of the paper gives the exact distribution of one coordinate of a uniform point on the unit sphere in dimensions:
The shape follows from geometry. The points of the sphere whose first coordinate equals form a smaller sphere of radius in one fewer dimension. The density is proportional to that sphere's surface area, , times for the slope of the sphere at that height, which gives , the shape of a rescaled Beta distribution. Its mean is 0 because the density is symmetric about zero. Its variance is , because the squared coordinates of a unit vector sum to 1 and all have the same distribution. As grows the density approaches a Gaussian ; at the standard deviation is 0.088.
In Figure 1, the top row shows an input vector and one random rotation of it, and the histogram pools the rotated coordinates over many rotations. Switch between the three input shapes and the top-left stems change completely while the histogram stays on the same curve. Lower to 4 to see the Beta shape, which at small is visibly flatter than a Gaussian.
The per-coordinate approach also needs the coordinates to be close to independent of each other, so that quantizing them one at a time loses little against quantizing them jointly. They cannot be exactly independent, since their squares sum to 1. In high dimensions they are nearly independent: Diaconis and Freedman (1987) showed that any coordinates of a uniform point on the sphere in dimensions are close to independent Gaussians, with an error that grows like . The statement is an approximation that holds while is much smaller than , and the paper's analysis uses it in that high-dimensional sense.
How TurboQuant quantizes one coordinate
After the rotation, every coordinate of every input is a draw from the same density . The design problem reduces to one dimension: choose values, the centroids , and round each coordinate to the nearest one, so that the expected squared error is as small as possible. With a known density, this is the problem the Lloyd-Max quantizer solves, k-means on a continuous distribution in one dimension. An optimal solution satisfies two conditions. Each value goes to its nearest centroid, so cell boundaries sit at the midpoints between neighbouring centroids. And each centroid is the mean of the values that fall in its cell, since the mean minimizes squared error within a cell. The paper writes the problem as
and solves it numerically, once, for each bit-width it needs. Lloyd's algorithm alternates the two conditions (move boundaries to midpoints, move centroids to cell means) until nothing changes, and produces a table of numbers that every vector shares. For large , in units of , the one-bit centroids are and the two-bit centroids are and .
A worked example at , : the centroids are and , with cell boundaries at 0 and . A rotated coordinate equal to 0.100 lies above 0.087, so it gets the index of the top centroid, is stored as the 2-bit code 11, and decodes to 0.134, an error of 0.033. A coordinate equal to −0.020 decodes to −0.040.
In Figure 2, the curve is in units of , the amber ticks are the centroids and the dashed lines are the cell boundaries. Click or drag on the plot to place a value and read its error. At one bit the quantizer keeps only the sign of the coordinate; each added bit doubles the number of cells.
Why Lloyd-Max levels and not evenly spaced ones, or levels at equal-probability quantiles? Evenly spaced levels waste resolution in the tails, where few coordinates fall. Quantile levels, which is how QLoRA's NF4 format spaces its 16 values for normally distributed weights, give every level the same share of the values, which maximizes the entropy of the index but does not minimize squared error. Lloyd-Max levels minimize squared error, which is the quantity both theorems bound. Their indices are then not equally likely: at the index distribution has entropy about 3.8 bits, so an entropy coder could shrink the code by about 5%. The paper leaves that out to keep encoding simple and fast.
Put together, the MSE quantizer is Algorithm 1 of the paper:
# TurboQuant_mse (Algorithm 1): b bits per coordinate, d-dim unit vector x
# set-up, once per (d, b), shared by every vector:
Pi = qr(randn(d, d)).Q # random rotation
cb = lloyd_max(b) / sqrt(d) # 2^b sorted centroids, solved offline
def quant(x): # x is unit norm; store ||x|| separately
y = Pi @ x # each y[j] ~ N(0, 1/d) for large d
return argmin_k |y[j] - cb[k]| # one b-bit index per coordinate
def dequant(idx):
return Pi.T @ cb[idx] # look up centroids, rotate backFigure 3 runs exactly this on a 64-dimensional unit vector, with the rotation switched on or off. The top panel shows the numbers the quantizer rounds, with the allowed values as dashed lines. The bottom panel shows the decoded vector in the original coordinates. With the one-spike input and the rotation off, the spike sits far above every allowed value. Switch the rotation on and the error drops from 0.86 to about the average 0.117 at 2 bits, and draw new rotations to see how little it varies. The ramp input shows the other side: its unrotated coordinates happen to fit the table well (0.077 at 2 bits), and the rotation gives that up for the same 0.117 on every input.
How close TurboQuant gets to the optimal distortion
All rotated coordinates have the same distribution, so the vector's expected squared error is times the error of one coordinate, . Theorem 1 bounds it:
and, from the numerical solution of (4), gives the values , 0.117, 0.03 and 0.009 at , 2, 3 and 4. These are fractions of the vector's squared length: at 4 bits the reconstruction error is under 1% of it. The constant comes from the Panter-Dite high-resolution formula, which approximates the optimal error when there are many small cells, applied to the Gaussian limit of .
The error falls by a factor of 4 per bit once there are many cells. One more bit doubles the number of centroids, which roughly halves the width of every cell. The error inside a cell is proportional to the square of its width, so halving the width divides the error by 4. At small the cells are wide and the factor is smaller: with unrounded Lloyd-Max values the error falls by 3.1, 3.4 and 3.6 from one bit to two, two to three, and three to four.
Theorem 3 shows that no quantizer can do much better. For every randomized quantizer that uses bits per coordinate, there is a unit vector on which its expected error is at least
A counting argument shows where comes from. A code of bits can name at most distinct reconstructions. To bring every point of the sphere within distance of one of them takes on the order of points, so points reach , and a squared error of . The paper's proof is the rigorous version: the Shannon lower bound from rate-distortion theory gives the floor for a vector drawn uniformly from the sphere, and Yao's minimax principle turns that average-case floor into a worst-case one for any randomized algorithm.
The upper bound is and the floor is , so TurboQuant is within a factor of of optimal at every bit-width. The actual values sit closer: at one bit the ratio is , and it rises toward 2.7 as grows. Figure 4 plots the floor, the guarantee and the achieved values on a log scale, where a constant factor is a constant vertical gap between two parallel lines.
Several pieces of this are high-dimensional limits: the Gaussian shape of , the near-independence of coordinates, the constant (computed on the Gaussian), and the clean floor (the exact Shannon bound for the sphere carries a dimension-dependent factor that tends to 1, via Stirling's approximation). At finite the coordinate density is exactly the Beta of Lemma 1, so "within 2.7×" is a large- statement. At the dimensions in the experiments (128 per head, 1,536 and 3,072 for embeddings) the paper's measured errors match the predicted ones closely.
Why the MSE quantizer biases inner products
A reconstruction with small squared error gives inner products with small squared error, but they are not unbiased. The one-bit case shows the mechanism. The centroids are , so the quantizer stores and decodes to . For large , the expected inner product of that reconstruction with a query is
so every inner product comes out about 36% too small on average. The shrinkage comes from the centroid condition: a centroid is the mean of the values in its cell, and that mean lies inside the cell, closer to zero than the values near its outer edge. Replacing each coordinate by its cell's mean keeps the direction of the vector and shrinks its length.
The shrinkage has an exact value at every bit-width. Because each centroid is the conditional mean of its cell, the rounding error is uncorrelated with the centroid, which gives for a coordinate and its centroid . For coordinates scaled to unit variance, the slope of the estimate against the truth is
which is at one bit, 0.883 at two, 0.965 at three and 0.990 at four. The paper states only the one-bit value and that the bias shrinks as grows; the formula for is our derivation from the Lloyd-Max conditions.
A concrete consequence for attention: if every query-key score were shrunk by the same factor 0.64, the softmax would behave as if its temperature had been raised by . Two keys with scores 4 and 2 get attention weights 0.88 and 0.12; scaled to 2.56 and 1.28 they get 0.78 and 0.22. Figure 5 shows the MSE estimates along a line of slope instead of the diagonal, with the gap growing in proportion to the true inner product.
How the two-stage inner-product quantizer works
TurboQuant removes the bias with a 1-bit estimator that is unbiased by construction: QJL, the Quantized Johnson-Lindenstrauss transform, published in 2024 by two of the same authors with Insu Han. The Johnson-Lindenstrauss lemma says that projecting vectors onto a modest number of random Gaussian directions approximately preserves their lengths and inner products. QJL keeps only the sign of each projection. With a matrix of i.i.d. entries, it stores , one bit per row, and decodes as
Multiplying by makes the estimate unbiased. For one Gaussian row and a unit vector , write . The part of orthogonal to is independent of and averages to zero, so . Summing over rows and multiplying by leaves exactly on average, so the inner-product estimate is unbiased for every . Its variance is bounded (Lemma 4 of the paper) by
which is large for a single bit per coordinate: for a unit query at , a standard deviation up to 0.11, comparable to typical inner products between unrelated unit vectors in that dimension.
The MSE quantizer has low variance and a bias; QJL has no bias and high variance. TurboQuant's inner-product quantizer (Algorithm 2) uses both, at a total of bits per coordinate:
Stage one: run the MSE quantizer at bits and decode it to . The residual is the part of the vector this stage missed; its expected squared norm is , 0.117 at .
Stage two: spend the last bit per coordinate on QJL of the residual, , and store the scalar alongside, because the signs record only the residual's direction.
The estimate of an inner product adds the two parts:
To see that it is unbiased, fix the first stage's output. QJL is unbiased on the residual, so the second term averages to , and the sum averages to
whatever the first stage produced; averaging over the first stage then changes nothing. The variance is QJL's, scaled by the squared norm of what it sketches. The residual is small, so the paper bounds the inner-product error by
With (no first stage at , so the residual is ) this gives, for a unit query, , 0.56/, 0.18/ and 0.047/ at to 4, the values Theorem 2 lists. Its closed-form bound is and the floor from Theorem 3 is , so the inner-product guarantee is within a factor of about 17 of optimal, and the achieved values at to 4 sit 6 to 12 times above the floor. The inner-product toggle on Figure 4 plots them.
Bit accounting for a 128-dimensional key at : a 2-bit index per coordinate (256 bits), one QJL sign per coordinate (128 bits), the residual norm and the vector's norm. That is the same 384 bits per vector as the 3-bit MSE quantizer, plus one extra float.
# TurboQuant_prod (Algorithm 2): b bits per coordinate, unbiased
S = randn(d, d) # i.i.d. N(0,1), fixed and shared
def quant_prod(x):
idx = quant(x) # TurboQuant_mse at b-1 bits
r = x - dequant(idx) # residual
return idx, sign(S @ r), norm(r)
def dequant_prod(idx, qjl, gamma):
x_mse = dequant(idx)
x_qjl = sqrt(pi / 2) / d * gamma * (S.T @ qjl)
return x_mse + x_qjl # E[<y, result>] = <y, x> for every yWhy put the bits into a coarser MSE stage instead of spending all of them on QJL? QJL with sign bits is also unbiased, and its variance falls only as . The two-stage estimator's variance falls as , by a factor of 3 to 4 per bit. Figure 6 measures all three options on 2,000 random pairs of unit vectors at . The readouts give the mean error (bias) and times the mean squared error, which is directly comparable with the paper's 1.57, 0.56, 0.18, 0.047.
The readouts show three things. At the two-stage quantizer is QJL, with times the squared error near 1.57 when the true inner product is near zero. From on it is narrower than spending every bit on QJL: about 0.054 against 0.39 at four bits. And the MSE quantizer's histogram is narrower still at two or more bits, but shifted off zero by a bias that grows with the true inner product; at an inner product of 0.3 and one bit its mean error is about −0.11, and at an inner product of 1 and two bits the bias alone makes its squared error more than four times the two-stage quantizer's. The paper's Figure 3 finds the same crossover on DBpedia embeddings: the two-stage quantizer has lower inner-product error at low bit-widths and the MSE quantizer overtakes it as bits increase.
TurboQuant results on KV cache compression and vector search
All experiments run on a single NVIDIA A100 GPU. The first set checks the theory on 100,000 DBpedia entity embeddings of dimension 1,536 with 1,000 queries: the measured MSE and inner-product errors fall between the floor and the guarantee across bit-widths, the MSE quantizer's inner-product bias shrinks with and grows with the average inner product, and the two-stage quantizer's error spread stays the same as the inner product changes.
KV cache
A decoder keeps every past token's keys and values so that each new token can attend to them; at long context the cache dominates memory (the motivation behind PagedAttention and multi-query attention, which shrink it in other ways). Compressing it fits TurboQuant's two constraints: keys arrive one token at a time, and attention consumes them through inner products. TurboQuant also quantizes the tokens produced during generation, which KIVI and PolarQuant leave in full precision.
On the needle-in-a-haystack test, a sentence is hidden at some depth in a document of 4k to 104k tokens and the model must retrieve it. With Llama-3.1-8B-Instruct and every method held to 25% of the full KV cache memory, the recall scores were:
- Full precision 0.997, TurboQuant 0.997, PolarQuant 0.995.
- KIVI, a scalar quantizer without formal guarantees, 0.981.
- PyramidKV 0.895 and SnapKV 0.858, which evict tokens instead of quantizing them.
The paper attributes the ordering to theoretical guarantees: PolarQuant and TurboQuant have them, and KIVI and the eviction methods do not.
On LongBench-E, a set of long-context tasks (question answering over one or several documents, summarization, few-shot learning, synthetic retrieval, code completion), the paper reports Table 1:
| Method | KV bits | SingleQA | MultiQA | Summ. | Few-shot | Synth. | Code | Avg |
|---|---|---|---|---|---|---|---|---|
| Llama-3.1-8B, full cache | 16 | 45.29 | 45.16 | 26.55 | 68.38 | 59.54 | 46.28 | 50.06 |
| KIVI | 3 | 43.38 | 37.99 | 27.16 | 68.38 | 59.50 | 44.68 | 48.50 |
| KIVI | 5 | 45.04 | 45.70 | 26.47 | 68.57 | 59.55 | 46.41 | 50.16 |
| PolarQuant | 3.9 | 45.18 | 44.48 | 26.23 | 68.25 | 60.07 | 45.24 | 49.78 |
| TurboQuant | 2.5 | 44.16 | 44.96 | 24.80 | 68.01 | 59.65 | 45.76 | 49.44 |
| TurboQuant | 3.5 | 45.01 | 45.31 | 26.00 | 68.63 | 59.95 | 46.17 | 50.06 |
| Ministral-7B, full cache | 16 | 47.53 | 49.06 | 26.09 | 66.83 | 53.50 | 47.90 | 49.89 |
| TurboQuant | 2.5 | 48.38 | 49.22 | 24.91 | 66.69 | 53.17 | 46.83 | 49.62 |
At 3.5 bits TurboQuant matches the full cache's average exactly (50.06). At 2.5 bits it loses 0.62 points on Llama and 0.27 on Ministral, with the largest single drop on summarization, and still beats KIVI at 3 bits by almost a point. The fractional bit-widths come from an outlier split, the same observation SmoothQuant builds on: a few channels of each head carry much larger values. TurboQuant divides each head's 128 channels into an outlier set and the rest, and runs two independent instances at different bit-widths; 64 channels at 3 bits plus 64 at 2 bits average 2.5. The paper reports compressing the quantized vectors by at least 4.5× (16/3.5 ≈ 4.6, and 16/2.5 = 6.4).
Nearest-neighbour search
The search experiments use DBpedia embeddings from OpenAI's text-embedding-3-large at and , and GloVe at , with 100,000 database vectors each. The baselines are product quantization (PQ), which learns its codebooks with k-means on the dataset, and RaBitQ, a quantizer with theoretical guarantees that projects a uniform grid onto the sphere (the multi-bit version, which extends the 1-bit RaBitQ of 2024). The metric is recall@1@k: how often the true best match is among the top results by estimated inner product. TurboQuant has higher recall than both at 2 and 4 bits on all three datasets, although PQ was trained and evaluated on the same vectors, which favours it.
Figure 7 plots the encoding (indexing) time from Table 2 at 4 bits. PQ spends 37 to 494 seconds running k-means. RaBitQ spends 597 to 3,957 seconds; it has no GPU implementation, so in this comparison it runs on the CPU. TurboQuant takes 0.0007 to 0.0021 seconds, a rotation and a table lookup on the GPU, between about 53,000 and 1.9 million times faster.
What the guarantees cover
The theorems bound expected error over the random rotation (and the random QJL matrix), for the worst unit input. A particular rotation can do slightly better or worse on a particular vector, as the new-rotation button in Figure 3 shows. The constants are high-dimensional limits, and the 2.7 factor applies to squared error; the inner-product guarantee is within about 17 of its floor.
The KV-cache results use an outlier split that sits outside the theory: the theorems cover a single quantizer at an integer bit-width on unit vectors, and choosing which channels are outliers is a separate step that the paper does not describe. The paper reports two models, Llama-3.1-8B-Instruct and Ministral-7B-Instruct, and one GPU type. It compares search recall in figures only, and the timing comparison with RaBitQ is GPU against CPU. The paper does not report end-to-end decoding speed for the KV-cache experiments.
Questions you might still have
Why rotate the vector before quantizing it?
A fixed per-coordinate quantizer has to assume what a typical coordinate looks like. A worst-case input, such as a vector with all its length in one coordinate, breaks any such assumption: at 2 bits and d = 64 the spike is stored as 0.19 instead of 1 and the squared error is 0.86. A random rotation preserves every length and angle but turns any unit vector into a uniformly random point on the sphere, whose coordinates follow one known bell of variance 1/d. One codebook designed for that bell then works for every input, with average error 0.117 at 2 bits.
Is the rotation matrix stored per vector?
No. Pi (and the QJL matrix S) is drawn once and shared by every vector the quantizer ever sees, so it costs nothing per vector. What is stored per vector is b bits per coordinate plus one floating-point norm, and for the inner-product variant one more float, the residual norm. Encoding costs one d x d matrix-vector product (16,384 multiply-adds at d = 128). To score many stored keys against one query, rotate the query once instead of decoding every key: because Pi is orthogonal, <y, Pi^T c> = <Pi y, c>, so the inner product can be taken directly against the table values c.
Why does the MSE-optimal quantizer get inner products wrong?
Each code is the average of the values in its cell, and an average sits closer to zero than the values at the outer edge of the cell. The reconstruction is therefore a shrunken copy of the vector, by a factor 1 - D_mse(b) on average: 2/pi = 0.64 at one bit, 0.88 at two, 0.99 at four. Every inner product inherits the same shrinkage, so the error is a systematic bias that averaging does not remove.
If the MSE quantizer has lower squared error, why use the two-stage version?
At two or more bits the MSE quantizer often does have lower squared inner-product error, and the paper's own Figure 3 shows it overtaking the two-stage quantizer as bits increase. The two-stage version trades some variance for zero bias, which matters when many estimates are summed or compared, or when a shrunken score changes a softmax.
What does "within 2.7x of optimal" mean exactly?
Theorem 3 shows that for any randomized quantizer at b bits per coordinate there is a unit vector whose expected squared error is at least 1/4^b. Theorem 1 shows TurboQuant's expected squared error is at most 2.72/4^b on every unit vector. The ratio of the two bounds is sqrt(3) pi/2, about 2.72; the actual ratio is 1.45 at one bit. Both are high-dimensional statements. For inner products the ratio of the bounds is larger, sqrt(3) pi^2, about 17.
Why is indexing time close to zero?
There is no codebook to fit. Product quantization runs k-means over the dataset before it can encode anything; TurboQuant multiplies by a fixed rotation and looks each coordinate up in a 2^b-entry table. On the paper's 100,000-vector sets at 4 bits that took 0.0007 to 0.0021 seconds, against 37 to 494 seconds for product quantization and 597 to 3,957 seconds for RaBitQ.
How does TurboQuant get 2.5 or 3.5 bits per channel?
It splits the channels of each attention head into a high-magnitude outlier set and the rest, and runs two independent TurboQuant instances at different bit-widths. With 128 channels, 64 at 3 bits and 64 at 2 bits average 2.5 bits. The paper's own example, 32 at 3 bits and 96 at 2, averages 2.25.
Footnotes & further reading
- The paper: Zandieh, Daliri, Hadian, Mirrokni, TurboQuant: Online Vector Quantization with Near-optimal Distortion Rate (arXiv 2504.19874, April 2025).
- The 1-bit inner-product sketch used in stage two: Zandieh, Daliri, Han, QJL: 1-Bit Quantized JL Transform for KV Cache Quantization with Zero Overhead (2024).
- Optimal scalar quantization: Lloyd (1957, published 1982) and Max (1960). The high-resolution formula is Panter & Dite (Proc. IRE, 1951), the paper's citation; Gray & Neuhoff, Quantization (IEEE Trans. Information Theory, 1998), surveys both and gives the Gaussian constant .
- The Shannon lower bound is standard rate-distortion theory; see Cover & Thomas, Elements of Information Theory, ch. 13.
- Near-independence of a few coordinates of a high-dimensional sphere point: Diaconis & Freedman (1987) and Stam (1982). The paper cites Vershynin, High-Dimensional Probability (2018), which proves the one-coordinate limit and pairwise uncorrelatedness.
- The search baselines: Jégou, Douze, Schmid, Product Quantization for Nearest Neighbor Search (2011); Gao, Gou, Xu, Yang, Long, Wong, Practical and Asymptotically Optimal Quantization of High-Dimensional Vectors in Euclidean Space for Approximate Nearest Neighbor Search (2024, the RaBitQ version benchmarked); and its 1-bit predecessor, Gao & Long, RaBitQ (SIGMOD 2024).
- Related explainers: QLoRA quantizes model weights to a 4-bit normal-float format; SmoothQuant moves activation outliers into the weights before 8-bit quantization; PagedAttention manages KV-cache memory without compressing it.
How could this explainer be improved? Found an error, or something unclear? I read every message.