如何提取量化模型的权重以在硬件上使用?

Chr*_*sso 7 python quantization deep-learning tensorflow pytorch

编辑:附加一些代码以帮助生成类似的结果(附加在末尾)

我有一个非常小的模型,其架构[2, 3, 6]中的隐藏层使用 ReLU,它是用于多类分类的 softmax 激活。离线训练并静态量化到 qint8。我现在想做的是提取权重,以便我可以通过矩阵乘法/加法在其他硬件上使用它们。我遇到的问题是它似乎没有按预期运行。以 state_dict() 的 GraphModule 输出为例:

OrderedDict([('input_layer_input_scale_0', tensor(0.0039)),
             ('input_layer_input_zero_point_0', tensor(0)),
             ('input_layer.scale', tensor(0.0297)),
             ('input_layer.zero_point', tensor(0)),
             ('input_layer._packed_params.dtype', torch.qint8),
             ('input_layer._packed_params._packed_params',
              (tensor([[-0.1180,  0.1180],
                       [-0.2949, -0.5308],
                       [-3.3029, -7.5496]], size=(3, 2), dtype=torch.qint8,
                      quantization_scheme=torch.per_tensor_affine, scale=0.05898105353116989,
                      zero_point=0),
               Parameter containing:
               tensor([-0.4747, -0.3563,  7.7603], requires_grad=True))),
             ('out.scale', tensor(1.5963)),
             ('out.zero_point', tensor(243)),
             ('out._packed_params.dtype', torch.qint8),
             ('out._packed_params._packed_params',
              (tensor([[  0.4365,   0.4365, -55.4356],
                       [  0.4365,   0.0000,   1.3095],
                       [  0.4365,   0.0000, -13.9680],
                       [  0.4365,  -0.4365,   4.3650],
                       [  0.4365,   0.4365,  -3.0555],
                       [  0.4365,   0.0000,  -1.3095],
                       [  0.4365,   0.0000,   3.0555]], size=(7, 3), dtype=torch.qint8,
                      quantization_scheme=torch.per_tensor_affine, scale=0.43650051951408386,
                      zero_point=0),
               Parameter containing:
               tensor([ 19.2761,  -1.0785,  14.2602, -22.3171,  10.1059,   7.2197, -11.7253],
                      requires_grad=True)))])
Run Code Online (Sandbox Code Playgroud)

如果我按照我认为应该喜欢的方式直接访问权重:

input_weights = np.array(
[[-0.1180,  0.1180],
 [-0.2949, -0.5308],
 [-3.3029, -7.5496]])
inputs_scale = 0.05898105353116989
inputs_zero_point = 0

W1=np.clip(np.round(input_weights/inputs_scale+ inputs_zero_scale), -127, 128)
b1=np.clip(np.round(np.array([-0.4747, -0.3563,  7.7603])/inputs_scale + inputs_zer_scale), -127, 128)

output_weights = np.array(
[[  0.4365,   0.4365, -55.4356],
 [  0.4365,   0.0000,   1.3095],
 [  0.4365,   0.0000, -13.9680],
 [  0.4365,  -0.4365,   4.3650],
 [  0.4365,   0.4365,  -3.0555],
 [  0.4365,   0.0000,  -1.3095],
 [  0.4365,   0.0000,   3.0555]])

outputs_scale=0.43650051951408386
outputs_zero_point=0
W1=np.clip(np.round(output_weights/outputs_scale+ outputs_zero_scale), -127, 128)
W2=np.clip(np.round(np.array([ 19.2761,  -1.0785,  14.2602, -22.3171,  10.1059,   7.2197, -11.7253])/outputs_scale + outputs_zero_scale), -127, 128)
Run Code Online (Sandbox Code Playgroud)

然后我给它一些数据:

inputs = np.array(
       [[1.  , 1.  ], # class 0 example
       [1.  , 0.  ], # class 1 example
       [0.  , 1.  ],
       [0.  , 0.  ],
       [0.  , 0.9 ],
       [0.  , 0.75],
       [0.  , 0.25]]) # class 6 example
Run Code Online (Sandbox Code Playgroud)

如果每一行都是一个示例,那么我希望能够对行进行矩阵乘法和 argmax 以获得结果。然而,这样做给了我这个:

>>> (ReLU((inputs @ W1.T) + b1) @ W2.T + b2).argmax(axis=0)
array([0, 3, 0, 3, 0, 0, 3])
Run Code Online (Sandbox Code Playgroud)

这是不对的。当我在 pytorch 中测试量化模型的准确性时,它的准确性足够高,应该可以让所有示例都正确。那么我在访问这些权重/偏差方面存在什么误解?

编辑:添加代码来帮助人们搞乱量化。现在从技术上讲,如何生成此代码并不重要 - 量化模型的 OrderedDict 将保持相似。如果您想搞乱它,这里有一些代码来生成模型并在 XOR 问题上对其进行量化。请注意,我仍然使用多类分类来帮助坚持我的原始模型。无论如何....给你...

inputs = np.array(
       [[1.  , 1.  ], # class 0 example
       [1.  , 0.  ], # class 1 example
       [0.  , 1.  ],
       [0.  , 0.  ],
       [0.  , 0.9 ],
       [0.  , 0.75],
       [0.  , 0.25]]) # class 6 example
Run Code Online (Sandbox Code Playgroud)

现在假设您保存了 qmodel 供以后使用,您可以通过调用来查看与我类似的参数qmodel.state_dict()

小智 0

quantize_model()最后应用。该技术降低了预测的质量。
尝试查看量化感知训练(QAT)
https://pytorch.org/blog/introduction-to-quantization-on-pytorch/#quantization-aware-training