Thomas Piacentini
← Atelier

Exercice Python

Sweep the quantization bit width

Texte original · anglais30 min

Quantization stores each weight as a small integer and one float scale. Fewer bits save memory, but each bit removed doubles the rounding step. One large outlier makes it worse, because the outlier sets the scale. In this lab you sweep the bit width from 2 to 8 on a weight matrix with outliers. You measure the error with one scale for the whole matrix and with one scale for each row.

support.py gives make_weights(seed). It returns a (64, 128) matrix of normal weights with standard deviation 0.02, and six outliers near \pm 0.25 in six different rows. It also gives the grid BITS and the error limit THRESHOLD = 0.05. The starter gives qrange(num_bits), which returns the signed range (q_{min}, q_{max}) = (-2^{b-1}, 2^{b-1} - 1).

Task

Write six helper functions and answers().

  1. quantize_symmetric(tensor, num_bits) returns (quantized, scale). The scale is s = \max \lvert W \rvert / q_{max}. If \max \lvert W \rvert = 0, use s = 1.0. The codes are round(W / s) clipped to [q_{min}, q_{max}], as integers. Use np.round, which rounds a halfway value to the even integer.
  2. quantize_per_row(tensor, num_bits) does the same with one scale for each row. It returns the codes and a float array of shape (rows,). A row of zeros gets the scale 1.0.
  3. dequantize(quantized, scale) returns the float array quantized * scale. If scale is a 1D array, row i uses scale[i].
  4. relative_error(original, reconstructed) returns \lVert W - \hat W \rVert_F / \lVert W \rVert_F.
  5. bit_sweep(tensor, bits, per_row) returns a float array with one relative error for each bit width in bits. It uses quantize_per_row when per_row is True, else quantize_symmetric.
  6. smallest_bits(bits, errors, threshold) returns the smallest bit width whose error is less than or equal to threshold. If no bit width passes, it returns None.

Then do the experiment in answers().

  1. Make the weights with make_weights(seed=0).
  2. Change the bit width over BITS. Measure the relative error with one scale for the matrix.
  3. Do step 2 again with one scale for each row.
  4. Report the smallest bit width under THRESHOLD for each method as smallest_bits_per_tensor and smallest_bits_per_row.
  5. Report the 4 bit errors as error_4bit_per_tensor and error_4bit_per_row. Report their ratio, per tensor divided by per row, as per_row_gain_4bit.

Input and output

Name Type Shape Meaning
tensor float array (rows, cols) the weight matrix
num_bits int scalar the bit width b, from 2 to 8
quantized int array (rows, cols) the integer codes
scale float or float array scalar or (rows,) one scale, or one scale for each row
bits list of ints (k,) the bit widths of the sweep, in increasing order
errors list or float array (k,) one error for each bit width
  • quantize_symmetric returns an int array and a Python float.
  • quantize_per_row returns an int array and a float array of shape (rows,).
  • dequantize returns a float array of shape (rows, cols).
  • relative_error returns a float. bit_sweep returns a float array of shape (k,).
  • answers() returns a dict with the five keys above. Each value is a Python float.

Constraints

  • 1 <= rows, cols <= 256. The original matrix in relative_error is not all zeros.
  • Do not change the input arrays.
  • Do not round the answers. The checks accept a relative difference of 1e-6 from the reference run.
  • Use numpy and the standard library only.

Examples

python
W = np.array([[0.5, -1.0, 0.25], [0.0, 0.0, 0.0]])
quantize_symmetric(W, 4)
text
(array([[ 4, -7,  2],
       [ 0,  0,  0]], dtype=int32), 0.14285714285714285)

The value 0.5 / s = 3.5 is halfway, so it rounds to the even integer 4.

python
quantize_per_row(W, 4)[1]
text
[0.14285714 1.        ]
python
relative_error(np.array([3.0, 4.0]), np.array([3.0, 3.0]))
text
0.2
python
bit_sweep(make_weights(0), [4, 8], per_row=True)
text
[0.18284473 0.0099937 ]
Code et livrables 15
Ce que vous en retenez

Enregistré dans votre carnet sur cet appareil.

Sources et limites

Les repères de lecture sont déclaratifs. Les résultats de tests sont enregistrés séparément ; ils valent pour les cas exécutés.

AI Engineering from Scratch · 3f9715c · MIT

Télécharger ce fichier ↓