我正在尝试使用 TF1.12 的 TF-lite 转换器。
并发现量化后TF-lite的准确度不正确。
拿 MNIST例如,如果使用以下命令转换为 f32,运行 时仍然可以判断正确。卷积_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 的数据时。运行 时精度似乎不正确卷积_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. 输入值应该被量化。
您的测试代码 ( 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 模型一样运行此模型。 .希望这可以帮助。
关于tensorflow - 为什么量化后TF-lite的精度不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62015923/