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

问题描述 投票:2回答:1

我正在用TF1.12尝试TF-lite转换器,发现TF-lite量化后的精度不正确。MNIST 例如,如果用下面的命令转换为f32,运行时仍然可以判断出正确的。卷积测试_lite.pyconv_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的数据时。运行时,精度似乎不正确 卷积测试_lite.pyconv_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.commvhsinTF-liteblobmastermnistconvolution_test_lite.py.

有谁知道原因吗?非常感谢大家的帮助

tensorflow mnist tensorflow-lite quantization
1个回答
1
投票

我相信这里面埋藏着多个问题。让我来逐一解决这些问题。

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,所以去量化的步骤并不重要。如果你想看到实际的软最大值加起来是1,你应该对输出进行去量化。

2. 缺少实际的min-max范围值

即使你正确地做了输入量化,模型的精度也会明显下降。这是因为该模型没有使用量化感知训练技术(您在评论中链接的)进行训练。量化感知训练可以让你实际捕捉到正确的全整数量化所需的中间值的真实最小-最大范围。

由于模型没有使用这种技术进行训练,我们能做的最好的就是提供默认的最小-最大范围,即是...。--default_ranges_min, --default_ranges_max 值。这就是所谓的 哑巴量化,预计模型的准确率会显著下降。

如果你使用量化感知训练,你就不需要提供默认值,完全量化的模型会产生准确的结果。

3. 量化范围

这将是一个比较小的问题,但由于MNIST的输入值范围是[0,1],所以最好使用。

  • mean_value 0
  • std_dev_value 255

这样一来,int值 0 地图到 0.0255 地图到 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 版本小得多。

你可以用运行 float32 模型的同样方式运行这个模型。convolution_test_lite.py.

希望能帮到你

© www.soinside.com 2019 - 2024. All rights reserved.