AWQ › Salient Weight Preservation

Michael BrenndoerferJanuary 14, 20269 min read
Language AI HandbookAll chapters
Part 42 of 67Inference Optimization
Chapter 321AWQ › Salient Weight Preservation
Reading section 2 of 11 · Salient Weight Preservation · 9 minSection 2 of 11 · 9 min

Book contents

Section 2 of 11 · 9 min read

AWQ › Salient Weight PreservationOne section · Sections in this chapter2 / 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 observation underlying AWQ comes from analyzing weight and activation distributions in transformer models. To understand why some weights matter more than others, consider the forward pass through a neural network. Every linear layer performs a weighted sum of its inputs, but not all terms in that sum contribute equally to the final result.

Consider a linear layer computing the transformation:

y=Wx\mathbf{y} = \mathbf{W}\mathbf{x}

where:

  • y\mathbf{y}: the output vector containing the results of the linear transformation
  • W\mathbf{W}: the weight matrix containing the layer's learnable parameters
  • x\mathbf{x}: the input activation vector representing the features from the previous layer

The contribution of weight wijw_{ij} to output element yiy_i is precisely wij⋅xjw_{ij} \cdot x_j. This means a weight's actual impact on the output depends on its own magnitude and on the magnitude of the activation it multiplies. A weight with value 0.5 that consistently multiplies activations of magnitude 10 contributes far more to the output than a weight with value 2.0 that typically multiplies activations near zero. This observation forms the conceptual foundation of AWQ: the importance of a weight cannot be assessed in isolation but must be understood in the context of the activations it operates upon during real inference.

Think of it as the difference between a valve and a flow rate. The valve position (the weight) matters only in proportion to the water pressure behind it (the activation magnitude). A nearly closed valve on a high-pressure line can still let more water through than a wide-open valve on a trickle. Standard quantization treats all valves as equally important regardless of the pressure behind them. AWQ accounts for pressure.

Salient Weights

Weights that consistently multiply large activation values across the calibration dataset. These weights have disproportionate influence on model outputs, making their quantization errors more harmful to overall model quality. In practice, salient weights correspond to columns of weight matrices in input channels that carry strong signals, often comprising 0.1% to 1% of all weights in a given layer.

Empirical analysis of large language models reveals that activation distributions are highly non-uniform across input channels. Some channels consistently produce large activations across many different inputs, while others typically remain near zero. This non-uniformity is not random; it shows the learned structure of the model, where certain feature dimensions have become more important during training. The model has, through the optimization process, channeled important information into specific dimensions while leaving others largely inactive.

This non-uniformity creates an opportunity for more intelligent quantization. If channel jj always has small activations, quantization errors in the weights connecting to that channel have minimal impact on the final computation. Even a large relative error in those weights produces a small absolute error in the output because the activation magnitude amplifying the error is tiny. But if channel jj consistently produces large activations, those weights are salient and require protection because any error in their representation will be amplified by the large activation values during every forward pass.

The key insight is that the actual harm caused by quantizing a weight is not the raw quantization error ∣w−w^∣|w - \hat{w}| but the output error ∣w−w^∣⋅∣xj∣|w - \hat{w}| \cdot |x_j|. Standard quantization minimizes the raw error uniformly. AWQ minimizes the output-weighted error, putting precision where the errors hurt most.

Out[4]:
Visualization
Bar chart of activation magnitudes across 256 channels, with a few tall red bars showing salient channels amid many short blue bars.
Activation magnitude distribution across 256 input channels, illustrating the highly non-uniform structure that AWQ exploits. Most channels (blue) produce near-zero average activations, while roughly ten salient channels (red) consistently exhibit magnitudes five to fifteen times larger. AWQ identifies these outlier channels and applies stronger scaling protection to the weights that feed into them.

The simplest approach to protecting salient weights would be to keep them in higher precision, creating a mixed-precision representation where important weights use 8 or 16 bits while less important weights use 4 bits. However, mixed-precision schemes complicate hardware implementation and sacrifice some of the memory and speed benefits we seek from quantization. Inference kernels optimized for uniform 4-bit weights cannot efficiently handle a mix of precisions, and the irregular memory access patterns that result from mixed precision degrade performance. AWQ takes a more clever approach: it uses per-channel scaling factors to effectively "hide" more precision in the quantized representation for salient weights while maintaining a uniform bit width throughout the model.

The Scaling Factor Insight

To understand AWQ's approach, recall from our earlier discussion of quantization basics that the quantization error for a weight ww scales with the quantization step size. The step size determines how far apart adjacent representable values are in the quantized representation. When we quantize to bb bits with scale ss, the maximum error is approximately s/2s/2, since any real value can be at most half a step away from the nearest quantization level.

For a standard per-tensor or per-channel quantization scheme, the scale is determined by the range of values being quantized. Let the minimum and maximum weights in a group be wmin⁡w_{\min} and wmax⁡w_{\max}. Then:

sq=wmax⁡−wmin⁡2b−1s_q = \frac{w_{\max} - w_{\min}}{2^b - 1}

where:

  • sqs_q: the quantization scale (step size), determining the distance between adjacent representable values in the integer grid
  • wmax⁡w_{\max}: the maximum value in the weight tensor, defining the upper bound of the dynamic range
  • wmin⁡w_{\min}: the minimum value in the weight tensor, defining the lower bound of the dynamic range
  • bb: the quantization bit width (4 for INT4 quantization)
  • 2b−12^b - 1: the number of quantization intervals, which equals the maximum representable integer with bb bits

This formula reveals an important insight: the quantization error is determined by how much of the available integer range each weight occupies. Weights near the extremes of the distribution (close to wmax⁡w_{\max} or wmin⁡w_{\min}) effectively receive finer resolution because they use more of the available quantization levels. Weights in the middle of the distribution share the interior levels and receive the same granularity. The range is the control point: changing the quantized range changes the resolution that all weights receive.

Now consider what happens when we multiply a weight by a constant k>1k > 1 before quantization, then divide by kk after dequantization. The weight's contribution to the output is unchanged because the scaling operations cancel out exactly. But its quantization behavior shifts in a favorable way. The scaled weight k⋅wk \cdot w occupies proportionally more of the quantization range, effectively getting finer granularity in the discrete representation. When we dequantize and divide by kk, the quantization error is also divided by kk, meaning the effective error in the original weight space is reduced by the same factor kk.

The catch is that scaling up one weight affects the overall range, potentially increasing quantization error for other weights in the same quantization group. If we scale up salient weights without adjusting anything else, the quantization scale sqs_q increases to accommodate the larger values, and non-salient weights receive coarser quantization as a result. This is where the activation-awareness becomes important. If weight wijw_{ij} multiplies activations that are on average kk times larger than typical, scaling that weight up by kk while scaling down the corresponding activation channel by kk preserves the computation while reducing quantization error for that salient weight. The inverse scaling on the activation side can be absorbed into preceding layers, making the transformation invisible at inference time.

Mathematically, for an input channel jj, we can introduce a scaling factor sjs_j applied to the weights while absorbing the inverse into the incoming activations:

yi=∑jwij⋅xj(standard linear layer)=∑j(wij⋅sj)⋅(xjsj)(insert scaling factor sj)=∑jw~ij⋅x~j(scaled weight and activation)\begin{aligned} y_i &= \sum_j w_{ij} \cdot x_j && \text{(standard linear layer)} \\ &= \sum_j (w_{ij} \cdot s_j) \cdot \left(\frac{x_j}{s_j}\right) && \text{(insert scaling factor } s_j \text{)} \\ &= \sum_j \tilde{w}_{ij} \cdot \tilde{x}_j && \text{(scaled weight and activation)} \end{aligned}

where:

  • yiy_i: the output value for neuron ii, which remains mathematically unchanged
  • wijw_{ij}: the original weight connecting input channel jj to output ii
  • xjx_j: the input activation at channel jj
  • sjs_j: the per-channel scaling factor applied to weights in column jj
  • w~ij=wij⋅sj\tilde{w}_{ij} = w_{ij} \cdot s_j: the scaled weight that will be quantized
  • x~j=xj/sj\tilde{x}_j = x_j / s_j: the inverse-scaled activation, which compensates for the weight scaling

The key insight is that we want sjs_j to be larger for channels with larger typical activations, protecting those salient weights with more precision in the quantized representation. Channels with large activations have their weights scaled up, giving those weights more quantization levels to stand for fine-grained distinctions. Channels with small activations have their weights left mostly unchanged or scaled down slightly. The net effect is a redistribution of quantization precision from where it is wasted (low-activation channels where quantization errors barely affect outputs) to where it matters most (high-activation channels where the same error level would cause significant output distortion).

The inverse scaling 1/sj1/s_j applied to x~j\tilde{x}_j must be applied somewhere to preserve the original computation. In transformer models, AWQ handles this elegantly by fusing the inverse scaling into the preceding layer's normalization. Since LayerNorm and RMSNorm layers output directly to the input channels of the subsequent linear layer, multiplying the normalization scale by 1/sj1/s_j for each output channel reaches the needed compensation without adding any runtime overhead. At inference time, the model runs exactly as fast as a standard INT4 model with no extra computations.