TensorFlow量子化トレーニング

4287 ワード

この間、tfliteと量子化に関する操作を研究し、特に専門的なDSP加速を有するハードウェア(例えばMTK 8183)において、試験量子化は、約3 Xの向上に優れた加速効果を有する.
tensorflowはtflite変換ツールtocoを提供し、コマンドを使用すると大体次のようになります.
bazel-bin/tensorflow/contrib/lite/toco/toco --input_file=mobilenet_v1_1.0_128_frozen.pb \
  --input_format=TENSORFLOW_GRAPHDEF \
  --output_format=TFLITE \
  --output_file=/tmp/mobilenet_v1_1.0_128.tflite \
  --inference_type=FLOAT \
  --input_data_types=FLOAT \
  --input_arrays=input \
  --output_arrays=MobilenetV1/Predictions/Reshape_1 \
  --input_shapes=1,128,128,3 \
  --logtostderr

この中で出会った穴の一つは、pipで直接インストールされているtensorflowを発見し、このコマンドを実行するとerrorをパッケージします:、optionの名前が違うので、それはpythonで再パッケージされ、ソースコードからtocoをコンパイルする(公式のbazelツールで)はC++です.
上記のコマンドはtfliteのフォーマットに変換されるだけで、量子化が必要な場合は、次のように変更する必要があります.
bazel-bin/tensorflow/contrib/lite/toco/toco --input_file=mobilenet_v1_1.0_128_frozen.pb \
  --input_format=TENSORFLOW_GRAPHDEF \
  --output_format=TFLITE \
  --output_file=/tmp/mobilenet_v1_1.0_128.tflite \
  --inference_type=QUANTIZED_UINT8 \
  --input_data_types=QUANTIZED_UINT8 \
  --input_arrays=input \
  --output_arrays=MobilenetV1/Predictions/Reshape_1 \
  --input_shapes=1,128,128,3 \
  --logtostderr

では、一般的なモデルでは、MinMaxの範囲が提供されていないため、エラーが報告されます(量子化にはこの2つの値をスケールする必要があります).タイプによって、この2つの値の取得方法が異なり、中のweightsには比較的容易で、最大最小値を統計すればいいのですが、graphの他のtensorでは、入力が異なるため、各層の出力値も異なります.ここでは訓練時にnodeの[Min,Max]を統計する必要がある.もちろん、この文で手動で範囲を決めることができますが、精度に大きな影響を与える可能性があります.
tf.quantization.fake_quant_with_min_max_args
 toco :
--reorder_across_fake_quant=true

あるいはtocoを使うときに加えることもできます.
--default_ranges_min=0 \
--default_ranges_max=1

しかし、これはさらに悪化し、[Min,Max]のないすべてのnodeにデフォルト値として使用されます.
 
だから、私たちは知っています.
1)我々は訓練時に統計をとる必要がある[Min,Max]
2)量子化の精度を向上させるために,励起関数としてrelu 6を用いたbest practiseのいくつかは,比較的小さな範囲内であることが望ましい[Min,Max]とした.b)batch normalizationの使用
 
Googleはquantization-awareのトレーニング方法を提供しており、参考にすることができますhttps://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/quantize
簡単にまとめると、
1)ネットワーク構造を定義した上で
tf.contrib.quantize.create_training_graph(input_graph=g,
                                          quant_delay=2000000)

ネットワークを再改造し、具体的にはtensorboarを見ることができます.
この中、quant_に注意delayというパラメータは、このパラメータの意味がその前に、ネットワークはfloatを使って正常な訓練を行い、比較的良いレベルに収束します.その後、fake-quantの操作が実行されます.
改造前のボリューム:
改造後のボリューム:
重要な操作はact_ですquantノードは、最大最小値を統計し、量子化操作を実行します.最上位のdelay_quantにはswitch opが2つ入っていて、設定に従ったquant_delayは量子化の結果を用いてforwardを行うかどうかを決定する
2)正常な方法でcheckpointを保存します.
3)eval用のネットワークをエクスポートします.これは別のファイルにあるほうがいいです(そうでないと、この問題が発生する可能性があります.https://github.com/tensorflow/tensorflow/issues/19936)をクリックします.
tf.contrib.quantize.create_eval_graph(input_graph=g)

そしてload checkpoint、最後にgraphと新しいcheckpointを保存します.
tf.train.write_graph(sess.graph_def, output_dir, 'graph.pb', as_text=True)
saver = tf.train.Saver(max_to_keep=100)
saver.save(sess, './workspace/'+args.model+'/chk', global_step=1)

4) freeze graph
python3 -m tensorflow.python.tools.freeze_graph \
--input_graph=./graph.pb \
--output_graph=exported_freezed_inference_graph.pb \
--input_checkpoint=./chk-1 \
--output_node_names="your_output_name"

5)tocoコマンドを用いて量子化モデルを導出できるようになった.
 
以上の操作を実行すると、自分のモデルにnodeがまだ報告されているか[Min,Max]がないかがわかるかもしれませんが、私の観察によると、場合によっては(具体的には不明)、BatchNormが追加されたレイヤだけがcerate_を呼び出していることがわかります.train_graphの時にfakeが追加されますquant; でも時々BatchNormがいらなくてもいいのがおかしい~
 
最後に、このコマンドを使用して、tflite量子化モデルのopと[Min,Max]の範囲を表示することもできます.
bazel-bin/tensorflow/contrib/lite/toco/toco \
--input_file=exported_freezed_inference_graph.pb \
--input_format=TENSORFLOW_GRAPHDEF   \
--output_format=GRAPHVIZ_DOT   \
--output_file=exported_freezed_inference_graph_opt.dot   \
--inference_type=QUANTIZED_UINT8 \
--input_data_types=QUANTIZED_UINT8  \
--input_arrays=image   \
--output_arrays=Openpose/MConv_Stage1_L_5_pointwise/Conv2D \
--input_shapes=1,128,128,3   \
--logtostderr \
--default_ranges_min=0 \
--default_ranges_max=1

dot -Tpdf exported_freezed_inference_graph_opt.dot -o exported_freezed_inference_graph_opt.pdf