Symmetric int8 quantization

ImplementMedium20 min13 checks

quantizationint8inference

Problem

Quantization stores weights as small integers and one float scale for each group of values. Symmetric int8 quantization maps the value with the largest magnitude to 127 and maps 0 to 0. A per-tensor scale uses one number for the whole matrix. A per-row scale uses one number for each row, so a row with an outlier does not reduce the precision of the other rows.

Task

Write four functions.

  1. quantize_symmetric(tensor) returns (quantized, scale) with one scale for the whole tensor.
  2. dequantize_symmetric(quantized, scale) returns the float tensor.
  3. quantize_per_channel(tensor) returns (quantized, scales) with one scale for each row of a 2D tensor.
  4. dequantize_per_channel(quantized, scales) returns the float tensor.

For a group of values x (the whole tensor, or one row):

\text{scale} = \max |x| / 127, \quad q = \text{clip}(\text{round}(x / \text{scale}), -127, 127)

Use np.round. It rounds a value that is exactly halfway to the nearest even integer, so 2.5 becomes 2. The dequantized value is q \cdot \text{scale}.

When \max |x| = 0, the scale of that group is 1.0. All its quantized values are then 0.

Input and output

NameTypeShapeMeaning
tensorfloat arrayany shape for quantize_symmetric, (R, C) for quantize_per_channelthe values to quantize
quantizedint8 arraysame as tensorthe integer values
scalefloatthe per-tensor scale
scalesfloat array(R,)the scale of each row
  • quantize_symmetric returns a tuple (quantized, scale). quantized is an np.int8 array with the shape of tensor. scale is a Python float.
  • quantize_per_channel returns a tuple (quantized, scales). quantized is an np.int8 array of shape (R, C). scales is a float array of shape (R,), also when R is 1.
  • Both dequantize functions return a float64 array with the shape of quantized.

Constraints

  • 1 <= R, C <= 256. All values are finite.
  • Do not change the input arrays.
  • Use numpy only.

Examples

pythontensor = np.array([[0.5, -1.0, 0.25], [2.0, 0.1, -0.04]])
q, scale = quantize_symmetric(tensor)
textq
[[ 32 -64  16]
 [127   6  -3]]
scale
0.015748031496062992
dequantize_symmetric(q, scale)
[[ 0.50393701 -1.00787402  0.2519685 ]
 [ 2.          0.09448819 -0.04724409]]
pythonq, scales = quantize_per_channel(tensor)
textq
[[  64 -127   32]
 [ 127    6   -3]]
scales
[0.00787402 0.01574803]
dequantize_per_channel(q, scales)
[[ 0.50393701 -1.          0.2519685 ]
 [ 2.          0.09448819 -0.04724409]]
pythonquantize_per_channel(np.array([[0.0, 0.0], [1.0, -3.0]]))
textq
[[   0    0]
 [  42 -127]]
scales
[1.         0.02362205]

Hints

4 hints

    Solution and notes

    Locked

    Pass every check with Submit to open the reference solution and the notes.

    Run it on your computer

    Clone the repository, install numpy and run the same checks in a terminal:

    python3 scripts/practice/run.py int8-quantization my_answer.py
    python3 scripts/practice/run.py int8-quantization my_answer.py --examples

    Start my_answer.py from starter.py.

    Your code

    Python loads on the first run

    Your code is saved in this browser as you type. On a phone you can read and edit the code, but the checks are easier to use on a desktop.

    Keyboard shortcuts
    Ctrl Enter
    Run the examples
    Ctrl Shift Enter
    Submit
    Tab / Shift Tab
    Indent or outdent the lines
    Esc then Tab
    Move the focus out of the editor
    Alt H
    Show the next hint

    On a Mac, use Cmd in place of Ctrl.

    Select Run to check the examples, or Submit to run every check.