Multiply a batch of activations by a weight matrix in int8 under jax.jit, with one symmetric scale for every output column of the weights and one for every row of the activations, and accumulate the integer products in int32.
The input x has shape (B, D_in), with one token per row, and the weight w has shape (D_in, D_out), with one output channel per column. The scale of column j of w and the scale of row b of x are
sjw=127maxi∣wij∣,sbx=127maxi∣xbi∣,and a column or row that is entirely zero gets the scale 1 instead. The int8 codes are
qijw=clip(round(sjwwij),−127,127),qbix=clip(round(sbxxbi),−127,127),where round goes to the nearest integer. The output is
abj=i∑qbixqijw,ybj=abjsbxsjw,where abj is the integer sum of code products, computed from the int8 codes with an int32 accumulator, and ybj is entry (b, j) of the float32 result, which approximates x times w.
Return a dict of JAX arrays with the keys w_q (int8, shape (D_in, D_out)), w_scales (float32, shape (D_out,)), x_q (int8, shape (B, D_in)), x_scales (float32, shape (B,)) and y (float32, shape (B, D_out)).
Input: x = [[1.2,2.0,-0.9]], w = [[0.5,-0.023],[-1.27,0.011],[0.3,0.041]]
Output: {"w_q":[[50,-71],[-127,34],[30,127]],"w_scales":[0.01,0.000323],"x_q":[[76,127,-57]],"x_scales":[0.015748],"y":[[-2.210866,-0.042284]]}
Explanation: The row of x has absmax 2.0, so its scale is 2 / 127, about 0.015748, and its codes are [76,127,-57]. Column 0 of w has absmax 1.27 and scale 0.01, while column 1 gets its own much smaller scale, about 0.000323, from its absmax of 0.041. The int32 sums of code products are -14039 and -8317, and multiplying each by the row scale and its column scale gives y, which is close to the float product [-2.21,-0.0425].
Input: x = [[0.0,0.0],[0.5,2.0]], w = [[0.8,0.0,-0.31],[-0.45,0.0,0.66]]
Output: {"w_q":[[127,0,-60],[-71,0,127]],"w_scales":[0.006299,1.0,0.005197],"x_q":[[0,0],[32,127]],"x_scales":[1.0,0.015748],"y":[[0.0,0.0,0.0],[-0.491339,0.0,1.162867]]}
Input: x = [[1.0,1.0,1.0,1.0],[0.7,-0.5,0.3,1.2]], w = [[0.5,0.25],[0.5,-0.25],[0.5,0.25],[0.5,0.1]]
Output: {"w_q":[[127,127],[127,-127],[127,127],[127,51]],"w_scales":[0.003937,0.001969],"x_q":[[127,127,127,127],[74,-53,32,127]],"x_scales":[0.007874,0.009449],"y":[[2.0,0.350394],[0.850394,0.496063]]}
jnp.max(jnp.abs(v), axis=k) reduces over axis k, so choose k to get one value per column or row.
jnp.round, jnp.clip(v, -127, 127) and .astype(jnp.int8) turn scaled values into int8 codes.
jnp.matmul(a, b, preferred_element_type=jnp.int32) multiplies two int8 arrays and keeps every sum in int32.
Accepts: array
Accepts: array
Multiply a batch of activations by a weight matrix in int8 under jax.jit, with one symmetric scale for every output column of the weights and one for every row of the activations, and accumulate the integer products in int32.
The input x has shape (B, D_in), with one token per row, and the weight w has shape (D_in, D_out), with one output channel per column. The scale of column j of w and the scale of row b of x are
sjw=127maxi∣wij∣,sbx=127maxi∣xbi∣,and a column or row that is entirely zero gets the scale 1 instead. The int8 codes are
qijw=clip(round(sjwwij),−127,127),qbix=clip(round(sbxxbi),−127,127),where round goes to the nearest integer. The output is
abj=i∑qbixqijw,ybj=abjsbxsjw,where abj is the integer sum of code products, computed from the int8 codes with an int32 accumulator, and ybj is entry (b, j) of the float32 result, which approximates x times w.
Return a dict of JAX arrays with the keys w_q (int8, shape (D_in, D_out)), w_scales (float32, shape (D_out,)), x_q (int8, shape (B, D_in)), x_scales (float32, shape (B,)) and y (float32, shape (B, D_out)).
Input: x = [[1.2,2.0,-0.9]], w = [[0.5,-0.023],[-1.27,0.011],[0.3,0.041]]
Output: {"w_q":[[50,-71],[-127,34],[30,127]],"w_scales":[0.01,0.000323],"x_q":[[76,127,-57]],"x_scales":[0.015748],"y":[[-2.210866,-0.042284]]}
Explanation: The row of x has absmax 2.0, so its scale is 2 / 127, about 0.015748, and its codes are [76,127,-57]. Column 0 of w has absmax 1.27 and scale 0.01, while column 1 gets its own much smaller scale, about 0.000323, from its absmax of 0.041. The int32 sums of code products are -14039 and -8317, and multiplying each by the row scale and its column scale gives y, which is close to the float product [-2.21,-0.0425].
Input: x = [[0.0,0.0],[0.5,2.0]], w = [[0.8,0.0,-0.31],[-0.45,0.0,0.66]]
Output: {"w_q":[[127,0,-60],[-71,0,127]],"w_scales":[0.006299,1.0,0.005197],"x_q":[[0,0],[32,127]],"x_scales":[1.0,0.015748],"y":[[0.0,0.0,0.0],[-0.491339,0.0,1.162867]]}
Input: x = [[1.0,1.0,1.0,1.0],[0.7,-0.5,0.3,1.2]], w = [[0.5,0.25],[0.5,-0.25],[0.5,0.25],[0.5,0.1]]
Output: {"w_q":[[127,127],[127,-127],[127,127],[127,51]],"w_scales":[0.003937,0.001969],"x_q":[[127,127,127,127],[74,-53,32,127]],"x_scales":[0.007874,0.009449],"y":[[2.0,0.350394],[0.850394,0.496063]]}
jnp.max(jnp.abs(v), axis=k) reduces over axis k, so choose k to get one value per column or row.
jnp.round, jnp.clip(v, -127, 127) and .astype(jnp.int8) turn scaled values into int8 codes.
jnp.matmul(a, b, preferred_element_type=jnp.int32) multiplies two int8 arrays and keeps every sum in int32.
Accepts: array
Accepts: array