トレーニング後の量子化

トレーニング後の量子化は、モデルの精度をほとんど低下させることなく、モデルサイズを小さくしながら CPU とハードウェア アクセラレータのレイテンシを改善できる変換手法です。TensorFlow Lite コンバータを使用して TensorFlow Lite 形式に変換する場合は、トレーニング済みの浮動小数点 TensorFlow モデルを量子化できます。

最適化手法

トレーニング後の量子化オプションはいくつかあります。次の表に、選択肢とそれぞれのメリットを示します。

技術 利点 ハードウェア
ダイナミック レンジ量子化 4 分の 1 サイズ、2 ~ 3 倍の高速化 CPU
完全整数量子化 サイズが 4 分の 1、速度が 3 倍以上 CPU、Edge TPU、マイクロコントローラ
Float16 量子化 2 分の 1 の GPU アクセラレーション CPU、GPU

次のディシジョン ツリーは、ユースケースに最適なトレーニング後の量子化方法を判断するのに役立ちます。

トレーニング後の最適化オプション

量子化なし

開始点として、量子化を使用せずに TFLite モデルに変換することをおすすめします。これにより、浮動小数点型の TFLite モデルが生成されます。

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
tflite_quant_model = converter.convert()

これを最初のステップとして、元の TF モデルの演算子が TFLite と互換性があり、その後のトレーニング後の量子化方法によって生じる量子化エラーをデバッグするためのベースラインとして使用できることを検証することをおすすめします。たとえば、量子化 TFLite モデルが予期しない結果をもたらす場合、浮動小数点 TFLite モデルは正確ですが、TFLite 演算子の量子化バージョンによって生じるエラーに問題を絞り込めます。

ダイナミック レンジの量子化

ダイナミック レンジの量子化により、キャリブレーション用の代表的なデータセットを用意しなくても、メモリ使用量を減らし、計算を高速化できます。このタイプの量子化では、変換時に浮動小数点から整数への重みのみを静的に量子化します。これにより、8 ビットの精度が得られます。

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_quant_model = converter.convert()

推論時のレイテンシをさらに短縮するために、「ダイナミック レンジ」演算子は 8 ビットの範囲に基づいて活性化を動的に量子化し、8 ビットの重みと活性化を使用して計算を実行します。この最適化により、完全固定小数点推論に近いレイテンシが得られます。ただし、出力は引き続き浮動小数点数を使用して保存されるため、ダイナミック レンジ演算の速度の向上は、完全な固定小数点計算よりも少なくなります。

完全整数量子化

すべてのモデル計算を整数量子化することで、レイテンシのさらなる改善、ピークメモリ使用量の削減、整数のみのハードウェア デバイスまたはアクセラレータとの互換性を実現できます。

完全な整数量子化では、範囲のキャリブレーションまたは推定が必要です。つまり、モデル内のすべての浮動小数点テンソルの (min, max)。重みやバイアスなどの定数テンソルとは異なり、モデル入力、活性化(中間レイヤの出力)、モデル出力などの変数テンソルは、推論サイクルを数回実行しない限り調整できません。そのため、コンバータには、キャリブレーションのために代表的なデータセットが必要になります。このデータセットは、トレーニング データまたは検証データの小さなサブセット(約 100 ~ 500 サンプル)にできます。以下の representative_dataset() 関数をご覧ください。

TensorFlow 2.7 バージョンからは、次の例のように、署名を使用して代表的なデータセットを指定できます。

def representative_dataset():
  for data in dataset:
    yield {
      "image": data.image,
      "bias": data.bias,
    }

特定の TensorFlow モデルに複数の署名がある場合は、署名キーを指定して複数のデータセットを指定できます。

def representative_dataset():
  # Feed data set for the "encode" signature.
  for data in encode_signature_dataset:
    yield (
      "encode", {
        "image": data.image,
        "bias": data.bias,
      }
    )

  # Feed data set for the "decode" signature.
  for data in decode_signature_dataset:
    yield (
      "decode", {
        "image": data.image,
        "hint": data.hint,
      },
    )

入力テンソルのリストを指定して、代表的なデータセットを生成できます。

def representative_dataset():
  for data in tf.data.Dataset.from_tensor_slices((images)).batch(1).take(100):
    yield [tf.dtypes.cast(data, tf.float32)]

TensorFlow 2.7 バージョン以降では、入力テンソルのリストベースのアプローチではなく、シグネチャベースのアプローチを使用することをおすすめします。これは、入力テンソルの順序を簡単に反転できるためです。

テスト目的で、次のようにダミー データセットを使用できます。

def representative_dataset():
    for _ in range(100):
      data = np.random.rand(1, 244, 244, 3)
      yield [data.astype(np.float32)]
 

浮動小数点数によるフォールバックありの整数(デフォルトの浮動小数点入力/出力を使用)

モデルを完全に整数化し、整数実装がない場合に浮動小数点演算子を使用する(変換をスムーズに行うため)には、次の手順を使用します。

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
tflite_quant_model = converter.convert()

整数のみ

整数のみのモデルの作成は、TensorFlow Lite for MicrocontrollersCoral Edge TPU の一般的なユースケースです。

さらに、整数のみのデバイス(8 ビット マイクロコントローラなど)やアクセラレータ(Coral Edge TPU など)との互換性を確保するために、次の手順で、入力と出力を含むすべてのオペレーションに完全な整数の量子化を適用できます。

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8  # or tf.uint8
converter.inference_output_type = tf.int8  # or tf.uint8
tflite_quant_model = converter.convert()

Float16 量子化

16 ビット浮動小数点数の IEEE 標準である float16 に重みを量子化することで、浮動小数点モデルのサイズを小さくできます。重みの float16 量子化を有効にするには、次の手順を行います。

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]
tflite_quant_model = converter.convert()

float16 の量子化の利点は次のとおりです。

  • モデルサイズを最大半分に削減できます(すべての重みが元のサイズの半分になるため)。
  • 精度の低下は最小限に抑えられます。
  • float16 データを直接操作できる一部のデリゲート(GPU デリゲートなど)をサポートしているため、float32 の計算よりも高速に実行されます。

float16 の量子化のデメリットは次のとおりです。

  • 固定小数点計算の量子化ほどレイテンシは短縮されません。
  • デフォルトでは、float16 量子化モデルは、CPU で実行すると重み値を float32 に「逆量子化」します。(GPU デリゲートは float16 データに対して処理できるため、この逆量子化は行いません)。

整数のみ: 8 ビットの重みで 16 ビットのアクティベーション(試験運用版)

これは試験運用中の量子化スキームです。これは「整数のみ」のスキームに似ていますが、活性化は 16 ビットの範囲に基づいて量子化され、重みは 8 ビット整数で量子化され、バイアスは 64 ビット整数に量子化されます。これを 16x8 量子化と呼びます。

この量子化の主な利点は、精度を大幅に向上できるが、モデルサイズをわずかに増加させるだけです。

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]
tflite_quant_model = converter.convert()

モデル内の一部の演算子で 16x8 の量子化がサポートされていない場合、モデルは引き続き量子化できますが、サポートされていない演算子は浮動小数点数で保持されます。このためには、target_spec に次のオプションを追加する必要があります。

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8,
tf.lite.OpsSet.TFLITE_BUILTINS]
tflite_quant_model = converter.convert()

この量子化スキームによって精度が向上するユースケースの例は次のとおりです。

  • super-resolution,
  • オーディオ信号処理(ノイズ キャンセリングやビームフォーミング、
  • 画像ノイズ除去、
  • 単一の画像からの HDR 再構成。

この量子化の欠点は次のとおりです。

  • 現時点では、最適化されたカーネル実装がないため、推論は 8 ビットの完全整数よりも著しく遅くなります。
  • 現在、ハードウェア アクセラレーションされている既存の TFLite デリゲートとは互換性がありません。

この量子化モードのチュートリアルについては、こちらをご覧ください。

モデルの精度

重みはトレーニング後に量子化されるため、特に小規模なネットワークでは精度が低下する可能性があります。事前トレーニング済みの完全に量子化されたモデルは、特定のネットワーク用に Kaggle モデルで提供されています。量子化モデルの精度をチェックして、精度の低下が許容範囲内であることを確認することが重要です。TensorFlow Lite モデルの精度を評価するツールがあります。

また、精度の低下が高すぎる場合は、量子化認識トレーニングの使用を検討してください。ただし、これを行うには、偽の量子化ノードを追加するようにモデルのトレーニング中に変更を加える必要がありますが、このページのトレーニング後の量子化手法では、既存の事前トレーニング済みモデルを使用します。

量子化テンソルの表現

8 ビットの量子化では、次の式を使用して浮動小数点値を近似します。

\[real\_value = (int8\_value - zero\_point) \times scale\]

この表現は、主に次の 2 つの部分で構成されています。

  • 軸ごと(チャンネルごと)またはテンソルごとの重み。ゼロ点が 0 で、範囲 [-127, 127] の int8 2 の補数値によって表されます。

  • テンソルごとの活性化/入力。これは、範囲 [-128, 127] の int8 の 2 の補数値で表され、範囲 [-128, 127] にはゼロ点があります。

量子化スキームの詳細については、量子化仕様をご覧ください。TensorFlow Lite のデリゲート インターフェースに接続するハードウェア ベンダーは、ここで説明する量子化スキームを実装することをおすすめします。