Почему точность TF-lite некорректна после квантования - PullRequest
3 голосов
/ 26 мая 2020

Я пробую конвертер TF-lite с TF1.12. И обнаружил, что точность 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 Ответ

1 голос
/ 26 мая 2020

Я считаю, что в этом кроется множество проблем. Позвольте мне обратиться к ним по порядку.

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. Отсутствуют реальные значения диапазона min-max

Даже если вы правильно выполните квантование входных данных, точность модели значительно снизится. Это связано с тем, что модель не была обучена с использованием метода обучения с учетом квантования (который вы указали в своем комментарии). Обучение с учетом квантования позволяет вам фактически захватывать реальные минимальные и максимальные диапазоны промежуточных значений, необходимых для правильного полностью целочисленного квантования. укажите минимальные и максимальные диапазоны по умолчанию, которые являются значениями --default_ranges_min, --default_ranges_max. Это называется фиктивным квантованием , и ожидается, что точность модели значительно упадет.

Если вы использовали обучение с учетом квантования, вам не нужно было бы предоставлять значения по умолчанию, и полностью квантованная модель даст точные результаты.

3. Диапазон квантования

Это будет относительно незначительной проблемой, но поскольку диапазон входных значений MNIST составляет [0, 1], лучше использовать:

  • mean_value 0
  • std_dev_value 255

Таким образом, значение int 0 соответствует 0.0, а 255 соответствует 1.0.

Альтернатива: попробуйте post- обучающее квантование

Послетренировочное квантование просто квантует значения весовых коэффициентов и, таким образом, значительно уменьшает размер модели. Поскольку в этом случае входные / выходные данные не квантуются, вы могли бы использовать модель 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 .

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...