为什么TF-lite的精度在量化后不正确

时间:2020-05-26 06:27:53

标签: tensorflow mnist tensorflow-lite quantization

我正在尝试使用TF1.12的TF-lite转换器。 并发现量化后TF-lite的准确性不正确。 以MNIST为例,如果使用以下命令转换为f32,则当使用 运行 convolution_test_lite.py 时,仍可以判断正确conv_net_f32.tflite

*tflite_convert --output_file model_lite/conv_net_f32.tflite \
--graph_def_file frozen_graphs/conv_net.pb  \
--input_arrays "input" \
--input_shapes "1,784" \
--output_arrays output \
--output_format TFLITE*

但是当我使用以下脚本以0-255转换和输入数据时。在 convolution_test_lite.py conv_net_uint8.tflite 一起运行时,准确性似乎不正确。

*UINT8:
tflite_convert --output_file model_lite/conv_net_uint8.tflite \
--graph_def_file frozen_graphs/conv_net.pb  \
--input_arrays "input" \
--input_shapes "1,784" \
--output_arrays output \
--output_format TFLITE \
--mean_values 128 \
--std_dev_values 128 \
--default_ranges_min 0 \
--default_ranges_max 6 \
--inference_type QUANTIZED_UINT8 \
--inference_input_type QUANTIZED_UINT8*

更多代码在这里上传: https://github.com/mvhsin/TF-lite/blob/master/mnist/convolution_test_lite.py

有人知道原因吗?非常感谢您的帮助!

1 个答案:

答案 0 :(得分:3)

我认为其中存在多个问题。让我一一解决。

1。输入值应量化。

您的测试代码(convolution_test_lite.py)无法正确量化输入值。

对于QUANTIZED_UINT8量化:

real_input_value = (quantized_input_value - mean_value) / std_dev_value

这意味着要将输入值[0,1]转换为量化的int值,您需要:

quantized_input_value = real_input_value * std_dev_value + mean_value

并将其应用于所有输入值。

因此,在您的convolution_test_lite.py中,尝试更改:

input_data = input_data.astype(np.uint8)

# Use the same values provided to the converter
mean_value = 0
std_dev_value = 255

input_data = input_data * std_dev_value + mean_value
input_data = input_data.astype(np.uint8)

相同适用于输出。您应该通过以下方式对输出进行量化:

real_output_value = (quantized_output_value - mean_value) / std_dev_value

话虽这么说,因为您只是获得argmax,所以后续步骤并不那么重要。如果您希望看到实际的softmaxed值加起来为1,则应该对输出进行反量化。

2。缺少实际的最小-最大范围值

即使正确地进行了输入量化,模型的准确性也会大大下降。这是因为未使用量化感知训练技术(已在注释中链接到该模型)来训练模型。借助量化感知训练,您可以实际捕获适当的全整数量化所需的中间值的实际最小-最大范围。

由于未使用此技术训练模型,因此我们能做的最好是提供默认的最小-最大范围,即--default_ranges_min--default_ranges_max值。这称为<模拟>虚拟量化,预计该模型的准确性会大大下降。

如果使用了量化感知训练,则无需提供默认值,并且完全量化的模型将产生准确的结果。

3。量化范围

这是一个相对较小的问题,但是由于MNIST输入值范围为[0,1],因此最好使用:

  • mean_value 0
  • std_dev_value 255

因此int值0映射到0.0,而255映射到1.0

替代:尝试训练后量化

训练后量化仅量化权重值,从而显着减小模型大小。由于在这种情况下无法对输入/输出进行量化,因此基本上可以使用训练后量化的tflite模型代替float32模型。

您可以尝试:

tflite_convert --output_file model_lite/conv_net_post_quant.tflite \
  --graph_def_file frozen_graphs/conv_net.pb  \
  --input_arrays "input" \
  --input_shapes "1,784" \
  --output_arrays output \
  --output_format TFLITE \
  --post_training_quantize 1

通过提供--post_training_quantize 1选项,您可以看到与常规的float32版本相比,它产生的模型要小得多。

您可以按照在convolution_test_lite.py中运行float32模型的相同方式来运行此模型。

希望这会有所帮助。