使用 numpy 操作使用 pytorch 的量化张量再现算术

Reproducing arithmetic with pytorch's quantized tensors with numpy operations

我想知道我必须执行哪些精确的算术运算才能在 pytorch 中重现量化运算的结果。

这几乎是重复的问题: I want to use Numpy to simulate the inference process of a quantized MobileNet V2 network, but the outcome is different with pytorch realized one

但我什至会用添加两个量化张量的例子来简化它。 例如,在 Resnet 架构中添加两个量化张量,我使用 nn.quantized.FloatFunctional().

self.skip_add = nn.quantized.FloatFunctional()

在推理过程中,我可以通过

添加两个张量
out1 = self.skip_add.add(x1, x2)

其中 x1 和 x2 是 torch.Tensor 类型的张量,在 post 训练量化过程中使用 fbgemm 后端进行量化。

我预计 out2_int = x1.int_repr() + x2.int_repr() 应该与 out1.int_repr() 相同(可能需要在所需范围内进行限制)。 然而事实并非如此。 下面我转储示例输出。

所以我想知道如何通过整数运算得到 out1?

>print(x1)
      ...,
      [-0.0596, -0.0496, -0.1390,  ..., -0.0596, -0.0695, -0.0099],
      [-0.0893,  0.0000, -0.0695,  ...,  0.0596, -0.0893, -0.0298],
      [-0.1092,  0.0099,  0.0000,  ..., -0.0397, -0.0794, -0.0199]]]],
   size=(1, 256, 14, 14), dtype=torch.quint8,
   quantization_scheme=torch.per_tensor_affine, scale=0.009925744496285915,
   zero_point=75)
print(x2)
      ...,
      [ 0.1390, -0.1669, -0.0278,  ..., -0.2225, -0.0556, -0.1112],
      [ 0.0000, -0.1669, -0.0556,  ...,  0.0556,  0.1112, -0.2781],
      [ 0.1390,  0.1669,  0.0278,  ...,  0.2225,  0.4171,  0.0834]]]],
   size=(1, 256, 14, 14), dtype=torch.quint8,
   quantization_scheme=torch.per_tensor_affine, scale=0.02780967578291893,
   zero_point=61)
print(x1.int_repr())
      ...,
      [69, 70, 61,  ..., 69, 68, 74],
      [66, 75, 68,  ..., 81, 66, 72],
      [64, 76, 75,  ..., 71, 67, 73]]]], dtype=torch.uint8)
print(x2.int_repr())
      ...,
      [66, 55, 60,  ..., 53, 59, 57],
      [61, 55, 59,  ..., 63, 65, 51],
      [66, 67, 62,  ..., 69, 76, 64]]]], dtype=torch.uint8)

打印(out1)

      ...,
      [ 0.0904, -0.2109, -0.1808,  ..., -0.2712, -0.1205, -0.1205],
      [-0.0904, -0.1808, -0.1205,  ...,  0.1205,  0.0301, -0.3013],
      [ 0.0301,  0.1808,  0.0301,  ...,  0.1808,  0.3314,  0.0603]]]],
   size=(1, 256, 14, 14), dtype=torch.quint8,
   quantization_scheme=torch.per_tensor_affine, scale=0.03012925386428833,
   zero_point=56)
print(out1.int_repr())
      ...,
      [59, 49, 50,  ..., 47, 52, 52],
      [53, 50, 52,  ..., 60, 57, 46],
      [57, 62, 57,  ..., 62, 67, 58]]]], dtype=torch.uint8)
 print(out2_int)
      [135, 125, 121,  ..., 122, 127, 131],
      [127, 130, 127,  ..., 144, 131, 123],
      [130, 143, 137,  ..., 140, 143, 137]]]], dtype=torch.uint8)

答案是双重的:

  1. 考虑到 int8 数字引用不同的域,实现了整数运算。卷积(或一般的 matrix-matrix 乘法)是根据这个事实实现的,我在这里的回答 I want to use Numpy to simulate the inference process of a quantized MobileNet V2 network, but the outcome is different with pytorch realized one 对我有用。
  2. pytorch中的加法是在float中实现的。您需要从 int 转换为 float,进行加法运算,然后再转换回 int。
def manual_addition(xq1_int, scale1, zp1, xq2_int, scale2, zp2,
scale_r, zp_r):

  xdq = scale1 * (xq1_int.astype(np.float) - zp1)
  ydq = scale2 * (xq2_int.astype(np.float) - zp2)
  zdq = xdq + ydq
  zq_manual_int = (((zdq / scale_r).round()) + zp_r).round() 
  return zq_manual_int #clipping might be needed