INT4 Quantization › Group-Wise Quantization
Language AI HandbookAll chapters INT4 Quantization › Group-Wise QuantizationOne section · Sections in this chapter3 / 11 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
The solution to the outlier problem at 4-bit precision is group-wise quantization, also called block-wise quantization. This technique represents a major change in how we approach the quantization problem: instead of asking "what single scale factor best represents this entire weight matrix?" we ask "what scale factor best represents each small neighborhood of weights?" Instead of using a single scale factor for an entire tensor or even a channel, we divide weights into small groups and compute separate scale factors for each group. This localized approach isolates the impact of outliers, preventing them from corrupting the quantization of the entire weight matrix.
Think of group-wise quantization as applying a different "zoom level" to different regions of the weight matrix. The parts of the matrix that contain mostly small, closely clustered weights get a fine-grained zoom that can distinguish subtle differences. The parts that happen to contain outliers get a wider zoom to accommodate them, but only those parts are affected. The rest of the matrix continues to benefit from fine resolution, oblivious to the outliers elsewhere.
This approach works because of a key statistical fact about how outliers appear in trained neural networks. Outlier weights do not distribute themselves uniformly throughout a weight matrix. They appear sporadically, concentrated in particular rows, columns, or small regions. When they do appear, they are surrounded by many non-outlier weights that have similar small magnitudes. By working with groups of 32, 64, or 128 consecutive weights, we ensure that any given group likely contains either zero or a small number of outliers. The groups containing outliers sacrifice precision for range; the groups without outliers maintain fine-grained precision. This spatial separation of outlier influence is the core mechanism that makes group-wise quantization so effective.
The memory overhead of group-wise quantization is modest and well-controlled. Each group requires one additional scale factor, typically stored in FP16 (16 bits). For a group of 128 weights, this adds 16 bits amortized over 128 four-bit weights, which is extra bits per weight. The total effective bit rate becomes bits per weight, barely above the nominal INT4 rate. As we will see with double quantization later in this chapter, even this small overhead can be further reduced.
The Group Quantization Concept
To understand why group-wise quantization works so effectively, consider the spatial distribution of outliers within a weight tensor. In trained neural networks, outliers typically do not occur uniformly throughout a tensor. Instead, they appear sporadically, concentrated in certain locations while leaving large regions of the tensor relatively outlier-free. By using small groups, an outlier affects only the quantization of its own group, not the entire layer. The remaining groups, free from outlier contamination, can use their 16 quantization levels efficiently to represent their local weight distribution with high fidelity.
For a weight tensor, group-wise quantization proceeds through the following steps:
- Divide the weights into groups of size , where common choices are 32, 64, or 128 elements per group
- Compute a separate scale factor (and optionally zero-point) for each group based only on the weights within that group
- Quantize each group independently using its own scale factor
The key insight is statistical: within any sufficiently small group of weights, the probability of encountering an extreme outlier is much lower than across the entire tensor. When an outlier does appear in a group, it affects only the weights in that group, leaving the thousands or millions of other weights in the tensor unaffected. Containing outlier damage makes 4-bit quantization practical.
The formal description of group-wise symmetric quantization is straightforward. For a group of weights , we compute:
where:
- : the scale factor for group , computed from the weights in that group only
- : the maximum absolute weight value within the group
- : the maximum representable integer (7 for signed INT4 with range -7 to 7)
- : the quantized integer representation of weight
- : rounding to the nearest integer
- : clamping to the valid integer range
Reconstruction is simply the inverse operation: . The stored representation is the collection of integers along with the per-group scale factors .
Smaller groups provide better quantization accuracy because outliers affect fewer weights. However, smaller groups require storing more scale factors, increasing memory overhead. A group size of 128 is common, adding roughly 0.125 bits per weight in overhead (one FP16 scale per 128 4-bit weights). Choosing a group size involves balancing accuracy and storage. The best choice depends on the model and memory constraints, though 64 or 128 has emerged as the practical sweet spot for most LLM deployments.
def group_quantize_int4(weights, group_size=128):
"""
Group-wise INT4 quantization.
Returns quantized values and scale factors per group.
"""
# Flatten weights for grouping
flat_weights = weights.flatten()
n = len(flat_weights)
# Pad to multiple of group_size
pad_len = (group_size - n % group_size) % group_size
if pad_len > 0:
flat_weights = np.concatenate([flat_weights, np.zeros(pad_len)])
# Reshape into groups
n_groups = len(flat_weights) // group_size
groups = flat_weights.reshape(n_groups, group_size)
# Compute scale per group (symmetric quantization)
max_vals = np.max(np.abs(groups), axis=1, keepdims=True)
scales = max_vals / 7.0 # Symmetric INT4: -7 to +7
scales = np.where(scales == 0, 1.0, scales) # Avoid division by zero
# Quantize each group
q_groups = np.round(groups / scales).astype(np.int8)
q_groups = np.clip(q_groups, -8, 7)
return q_groups.flatten()[:n], scales.flatten()
def group_dequantize_int4(q_weights, scales, group_size=128):
"""Dequantize group-wise quantized weights."""
n = len(q_weights)
pad_len = (group_size - n % group_size) % group_size
if pad_len > 0:
q_weights = np.concatenate([q_weights, np.zeros(pad_len)])
n_groups = len(q_weights) // group_size
q_groups = q_weights.reshape(n_groups, group_size)
scales = scales.reshape(-1, 1)
deq_groups = q_groups * scales
return deq_groups.flatten()[:n]Now let's compare uniform quantization versus group-wise quantization on our weights with outliers. This comparison will demonstrate the dramatic improvement that group-wise quantization provides when outliers are present in the data.
# Compare quantization approaches
group_size = 32 # Small groups for this example
# Group-wise quantization
q_grouped, scales = group_quantize_int4(weights_with_outliers, group_size)
reconstructed_grouped = group_dequantize_int4(q_grouped, scales, group_size)
# Calculate errors for comparison
mse_uniform = np.mean((weights_with_outliers - reconstructed) ** 2)
mse_grouped = np.mean((weights_with_outliers - reconstructed_grouped) ** 2)Quantization Error Comparison: Uniform INT4 MSE: 0.00039370 Group-wise INT4 MSE: 0.00000743 Error reduction: 98.1% Number of scale factors stored: 32


Group-wise quantization substantially reduces quantization error because outliers no longer dominate the scale factor for the majority of weights. Each group operates with a scale factor tailored to its local distribution. This keeps the 16 available quantization levels are deployed where they provide the most benefit for that particular subset of weights. The scatter plot makes this concrete: with uniform quantization, many near-zero weights collapse to the same reconstructed value, appearing as horizontal bands on the plot. With group-wise quantization, the reconstruction tracks the original faithfully even for tiny weights.
Optimal Group Size Selection
The choice of group size balances accuracy against memory overhead, and understanding this trade-off is needed for making informed deployment decisions. Smaller groups provide finer-grained adaptation to local weight statistics, but each group requires its own scale factor. These scale factors, typically stored in FP16 format (16 bits each), add to the overall memory footprint. Let's examine this trade-off quantitatively:
# Test different group sizes
group_size_rng = np.random.default_rng(42)
test_weights = group_size_rng.standard_normal(4096) * 0.02
# Add some outliers
test_weights[100] = 0.5
test_weights[200] = -0.4
test_weights[1500] = 0.45
group_sizes = [16, 32, 64, 128, 256, 512]
results = []
for gs in group_sizes:
q, s = group_quantize_int4(test_weights, gs)
recon = group_dequantize_int4(q, s, gs)
mse = np.mean((test_weights - recon) ** 2)
# Calculate effective bits per weight
n_scales = len(s)
scale_bits = n_scales * 16 # FP16 scales
weight_bits = len(test_weights) * 4 # INT4 weights
total_bits = scale_bits + weight_bits
effective_bpw = total_bits / len(test_weights)
results.append(
{
"group_size": gs,
"mse": mse,
"effective_bpw": effective_bpw,
"n_scales": n_scales,
}
)Group Size vs. Accuracy Trade-off:
-------------------------------------------------------
Group Size MSE Bits/Weight Scales
-------------------------------------------------------
16 0.00000579 5.000 256
32 0.00000980 4.500 128
64 0.00001644 4.250 64
128 0.00002944 4.125 32
256 0.00004181 4.062 16
512 0.00007915 4.031 8
Group sizes of 32-128 typically offer the best balance between quantization fidelity and storage efficiency. Smaller groups provide diminishing returns in accuracy while significantly increasing the number of scale factors to store. The sweet spot depends on the specific model and hardware constraints, but 64 or 128 elements per group has emerged as a common choice in practice. This provides good accuracy with manageable overhead. Beyond group size 128, the memory savings from a larger group become marginal because scale factor overhead was already small, while accuracy continues to degrade as more diverse weights share a single scale.