Binary quantization compresses each vector into a packed bit vector. Each input value becomes one bit, and each bit records whether the value is greater than a threshold.
Use binary quantization when you want very compact vectors for workflows based on bitwise distances such as Hamming distance. It is a strong compression step, so it trades away most magnitude information for much smaller storage and faster bitwise comparisons.
C API | C++ API | Python API
Training is needed when thresholds are learned from data, such as per-dimension means or sampled medians. The Python API currently exposes the direct zero-threshold transform path.
Transforming packs every group of eight input dimensions into one byte. In C and C++, use the trained quantizer when using learned thresholds. Python uses a zero threshold and sets a bit when the corresponding input value is positive.
Binary quantization compares each value with a threshold. If the value is greater than the threshold, the output bit is set to 1; otherwise it is set to 0.
The threshold can be fixed at zero, learned as a per-dimension mean, or learned as a sampled per-dimension median. The output is packed into bytes, so a vector with D features needs ceil(D / 8) bytes.
Use binary quantization when compact storage and bitwise comparison speed matter more than preserving floating-point magnitude. It is especially useful for binary vector search with bitwise Hamming distance.
Avoid binary quantization when vector magnitude or fine-grained distance information is important. Because each value becomes only one bit, this is the most aggressive quantizer in the preprocessing guide.
Use zero when the data is already centered or when you want the fastest path. Use mean when dimensions have different offsets. Use sampling_median when outliers skew the mean and a more robust threshold is needed.
Increase sampling_ratio only when the sampled median is unstable. It does not affect the compressed size, only threshold quality and training cost.
Binary quantization is usually dominated by the input matrix and the packed output matrix.
Variables:
The scratch term covers temporary packing buffers, threshold-training buffers, allocator padding, CUDA library workspaces, and memory held by the active memory resource. Use H = 0.10 for direct transform and H = 0.20 when training learned thresholds. If you can measure a representative run, use:
Hmeasured=observed_peak−formula_without_scratchformula_without_scratchH_{\text{measured}} = \frac{\text{observed\_peak} - \text{formula\_without\_scratch}} {\text{formula\_without\_scratch}}Then set:
Musable=(Mfree−Mother)⋅(1−H)M_{\text{usable}} = (M_{\text{free}} - M_{\text{other}}) \cdot (1 - H)The capacity variables in this subsection are:
The packed output is still linear in N. Rewrite the selected peak as:
peak_without_scratch(N)=N⋅Bper_row+Bfixed\text{peak\_without\_scratch}(N) = N \cdot B_{\text{per\_row}} + B_{\text{fixed}}and solve:
Nmax=⌊Musable−BfixedBper_row⌋N_{\max} = \left\lfloor \frac{M_{\text{usable}} - B_{\text{fixed}}} {B_{\text{per\_row}}} \right\rfloorEach row stores one bit per input feature:
packed_dim=⌈D8⌉codes_size=N⋅packed_dim\begin{aligned} \text{packed\_dim} &= \left\lceil \frac{D}{8} \right\rceil \\ \text{codes\_size} &= N \cdot \text{packed\_dim} \end{aligned}Learned thresholds store one threshold per input dimension:
threshold_size≈D⋅Bt\text{threshold\_size} \approx D \cdot B_tThe zero-threshold path does not need a learned threshold vector.
The transform peak is approximately:
transform_peak≈ N⋅D⋅Bx+codes_size+threshold_size+scratch\begin{aligned} \text{transform\_peak} \approx&\ N \cdot D \cdot B_x + \text{codes\_size} \\ &+ \text{threshold\_size} + \text{scratch} \end{aligned}