web-dev-qa-db-ja.com

量子化後にTF-liteの精度が正しくない理由

TF1.12でTF-liteコンバーターを試しています。そして、TF-liteの精度は、量子化後に正しくないことがわかりました。 [〜#〜] mnist [〜#〜] を例に取ると、次のコマンドでf32に変換した場合でも、実行時に正しいことがわかりますconvolution_test_lite.pywithconv_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.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.com/mvhsin/TF-lite/blob/master/mnist/convolution_test_lite.py

誰かがその理由を知っていますか?助けてくれてありがとう!

3
S.H

これには複数の問題が潜んでいると思います。これらを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

これを入力値のallに適用します。

したがって、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.実際の最小-最大範囲値がありません

入力量子化を正しく行っても、モデルの精度は大幅に低下します。これは、モデルが(コメントでリンクした)量子化対応トレーニング手法を使用してトレーニングされなかったためです。量子化対応トレーニングでは、適切な完全整数量子化に必要な中間値の実際の最小-最大範囲を実際にキャプチャできます。

モデルはこの手法でトレーニングされていないため、最善の方法は、--default_ranges_min--default_ranges_maxの値であるデフォルトの最小-最大範囲を提供することです。これはダミー量子化と呼ばれ、モデルの精度が大幅に低下することが予想されます。

量子化対応トレーニングを使用した場合、デフォルト値を提供する必要はなく、完全に量子化されたモデルは正確な結果を生成します。

3.量子化範囲

これは比較的小さな問題ですが、MNISTの入力値の範囲は[0、1]であるため、次のように使用することをお勧めします。

  • mean_value 0
  • std_dev_value 255

したがって、int値00.0にマップされ、2551.0にマップされます。

代替案:トレーニング後の量子化を試す

トレーニング後の量子化では、重みの値が量子化されるだけなので、モデルのサイズが大幅に縮小されます。この場合、入力/出力は量子化されないため、基本的に、float32モデルの代わりにトレーニング後の量子化されたtfliteモデルを使用できます。

あなたが試すことができます:

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モデルを実行するのと同じ方法で実行できます。

お役に立てれば。

1
yyoon