訓練後的量化是一種轉換技術,可縮減模型大小,同時改善 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 Microcontrollers 和 Coral 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 的委派介面,並實作此處所述的量化配置。