訓練後的量化

訓練後的量化是一種轉換技術,可縮減模型大小,同時改善 CPU 和硬體加速器的延遲時間,同時盡量降低模型準確率。當您使用 TensorFlow Lite Converter,將已經訓練的浮點值 TensorFlow 模型轉換為 TensorFlow Lite 格式時,可以量化。

最佳化方法

有多種訓練後的量化選項可供選擇。以下摘要表格列出該選項及其優點:

做法 優點 硬體
動態範圍量化 小 4 倍、2 倍至 3 倍的速度 CPU
完整整數量化 4 倍小、3 倍以上加速 CPU、Edge TPU、微控制器
Float16 量化 小 2 倍、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 位元權重和啟動執行運算作業。此最佳化作業可提供接近完全固定點推論的延遲時間。但是,輸出內容仍會使用浮點值儲存,因此動態範圍運算的加快速度,不會比完整的固定點運算作業來得少。

完整整數量化

只要確保所有模型數學運算均為整數,就能進一步改善延遲、降低尖峰記憶體用量,以及與僅整數硬體裝置或加速器相容。

如需完整整數量化,必須校正或估算範圍,即(最小值、最大值) 模型中所有浮點張量。與權重和偏誤等常數張量不同,除非我們執行幾次推論週期,否則無法校正模型輸入、啟用 (中間層的輸出內容) 和模型輸出內容等變數張量。因此,轉換工具需要一個代表資料集來進行校正。這個資料集可以是訓練或驗證資料的一小部分 (約 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 量化

您可以將權重量化為 float16,藉此降低浮點模型的大小,這是 16 位元浮點數的 IEEE 標準。如要啟用權重的 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 量化的缺點如下:

  • 這不會像定點數學的量化一樣縮短延遲時間。
  • 根據預設,在 CPU 上執行時,float16 量化模型會將權重值「去量化」為 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\]

此表示法包含兩個主要部分:

  • 每軸 (即每個管道) 或每個張量權重,由 int8 2 的補充值在範圍 [-127, 127] 內,零點等於 0。

  • 個別張量啟用/輸入項目,以 [-128, 127] 範圍中的 int82 的互補值表示,其中 [-128, 127] 範圍為零點。

如需量化配置的詳細視圖,請參閱量化規格。建議硬體供應商導入 TensorFlow Lite 的委派介面,並實作此處所述的量化配置。