Quantizzazione post-addestramento

La quantizzazione post-addestramento è una tecnica di conversione che può ridurre le dimensioni del modello migliorando al contempo la latenza della CPU e dell'acceleratore hardware, con un leggero peggioramento dell'accuratezza del modello. Puoi quantificare un modello TensorFlow già addestrato quando lo converti in formato TensorFlow Lite utilizzando TensorFlow Lite Converter.

Metodi di ottimizzazione

Sono disponibili diverse opzioni di quantizzazione post-addestramento tra cui scegliere. Ecco una tabella di riepilogo delle opzioni e dei vantaggi che offrono:

Tecnica Vantaggi Hardware
quantizzazione dell'intervallo dinamico 4 volte più piccola, velocità 2x-3x CPU
quantizzazione di interi interi 4 volte più piccola, 3 volte più veloce CPU, Edge TPU, microcontroller
quantizzazione in Float16 L'accelerazione GPU è 2 volte più piccola CPU, GPU

Il seguente albero decisionale può aiutarti a determinare quale metodo di quantizzazione post-addestramento è il più adatto al tuo caso d'uso:

opzioni di ottimizzazione post-addestramento

Nessuna quantizzazione

La conversione in un modello TFLite senza quantizzazione è un punto di partenza consigliato. Verrà generato un modello TFLite in virgola mobile.

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

Ti consigliamo di eseguire questa operazione come passaggio iniziale per verificare che gli operatori del modello TF originale siano compatibili con TFLite e che possano essere utilizzati anche come base per eseguire il debug degli errori di quantizzazione introdotti dai successivi metodi di quantizzazione dopo l'addestramento. Ad esempio, se un modello TFLite quantizzato produce risultati imprevisti, mentre il modello TFLite in virgola mobile è accurato, possiamo limitare il problema agli errori introdotti dalla versione quantizzata degli operatori TFLite.

quantizzazione dell'intervallo dinamico

La quantizzazione dell'intervallo dinamico offre un utilizzo ridotto della memoria e un calcolo più rapido, senza che tu debba fornire un set di dati rappresentativo per la calibrazione. Questo tipo di quantizzazione, quantifica in modo statico solo i pesi da virgola mobile a numero intero al momento della conversione, fornendo 8 bit di precisione:

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()

Per ridurre ulteriormente la latenza durante l'inferenza, gli operatori "Dynamic Range" quantificano dinamicamente le attivazioni in base al loro intervallo fino a 8 bit ed eseguono calcoli con pesi e attivazioni a 8 bit. Questa ottimizzazione fornisce latenze vicine alle inferenze a punto completamente fisso. Tuttavia, gli output vengono comunque archiviati utilizzando la virgola mobile, per cui la maggiore velocità delle operazioni con intervallo dinamico è inferiore a un calcolo completo a punto fisso.

quantizzazione di interi interi

Puoi ottenere ulteriori miglioramenti della latenza, riduzioni dei picchi di utilizzo della memoria e compatibilità con acceleratori o dispositivi hardware solo con numeri interi assicurando che tutti i calcoli matematici del modello siano quantificati in numeri interi.

Per la quantizzazione completa dei numeri interi, devi calibrare o stimare l'intervallo, ad esempio (min, max) di tutti i tensori a virgola mobile nel modello. A differenza dei tensori costanti come ponderazioni e bias, i tensori variabili come l'input del modello, le attivazioni (output degli strati intermedi) e l'output del modello non possono essere calibrati se non eseguiamo alcuni cicli di inferenza. Di conseguenza, il convertitore richiede un set di dati rappresentativo per calibrarlo. Questo set di dati può essere un piccolo sottoinsieme (circa 100-500 campioni) dei dati di addestramento o convalida. Fai riferimento alla funzione representative_dataset() di seguito.

A partire dalla versione TensorFlow 2.7, puoi specificare il set di dati rappresentativo tramite una firma, come nell'esempio seguente:

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

Se il modello TensorFlow specificato include più firme, puoi specificare più set di dati specificando le chiavi di firma:

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,
      },
    )

Puoi generare il set di dati rappresentativo fornendo un elenco di tensori di input:

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

A partire dalla versione TensorFlow 2.7, consigliamo di utilizzare l'approccio basato su firme rispetto all'approccio basato su elenco di tensori di input, perché l'ordinamento dei tensori di input può essere facilmente capovolto.

A scopo di test, puoi utilizzare un set di dati fittizio come segue:

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

Numero intero con numero in virgola mobile di riserva (con input/output predefinito in virgola mobile)

Per quantificare un modello in numeri interi, ma utilizzare operatori in virgola mobile quando non è presente un'implementazione di numeri interi (per garantire che la conversione avvenga senza problemi), segui questi passaggi:

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()

Solo numero intero

La creazione di modelli solo interi è un caso d'uso comune per TensorFlow Lite per microcontroller e le TPU Coral Edge.

Inoltre, per garantire la compatibilità con dispositivi che utilizzano solo numeri interi (ad esempio i microcontroller a 8 bit) e acceleratori (come la TPU Coral Edge), puoi applicare la quantizzazione completa dei numeri interi per tutte le operazioni, inclusi input e output, utilizzando i seguenti passaggi:

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()

quantizzazione in Float16

Per ridurre le dimensioni di un modello in virgola mobile, puoi quantificare i pesi in virgola mobile16, lo standard IEEE per i numeri in virgola mobile a 16 bit. Per attivare la quantizzazione delle ponderazioni in 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()

I vantaggi della quantizzazione di float16 sono i seguenti:

  • Riduce le dimensioni del modello fino alla metà (poiché tutti i pesi diventano la metà delle dimensioni originali).
  • Causa una perdita minima di precisione.
  • Supporta alcuni delegati (ad esempio il delegato GPU) che possono operare direttamente su dati float16, con un'esecuzione più rapida rispetto ai calcoli float32.

Gli svantaggi della quantizzazione di float16 sono i seguenti:

  • Non riduce la latenza tanto quanto una quantizzazione in un calcolo matematico a punto fisso.
  • Per impostazione predefinita, un modello quantizzato float16 "dequantizza" i valori dei pesi in float32 quando viene eseguito sulla CPU. Tieni presente che il delegato GPU non eseguirà questa dequantizzazione, poiché può operare su dati float16.

Solo numero intero: attivazioni a 16 bit con pesi a 8 bit (sperimentale)

Questo è uno schema di quantizzazione sperimentale. È simile allo schema di "solo numero intero", ma le attivazioni vengono quantizzate in base al loro intervallo fino a 16 bit, i pesi sono quantificati in numeri interi a 8 bit e i bias vengono quantificati in numeri interi a 64 bit. Questa è definita quantizzazione 16x8.

Il vantaggio principale di questa quantizzazione è che può migliorare notevolmente l'accuratezza, ma può aumentare di poco le dimensioni del modello.

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()

Se alcuni operatori nel modello non supportano la quantizzazione 16:8, il modello può comunque essere quantizzato, ma gli operatori non supportati vengono mantenuti in virgola mobile. Per consentirlo, è necessario aggiungere la seguente opzione a 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()

Esempi di casi d'uso in cui i miglioramenti dell'accuratezza forniti da questo schema di quantizzazione includono:

  • super-resolution,
  • elaborazione dei segnali audio come la cancellazione del rumore e il beamforming,
  • riduzione del rumore nell'immagine,
  • Ricostruzione HDR da una singola immagine.

Lo svantaggio di questa quantizzazione è:

  • Attualmente l'inferenza è notevolmente più lenta del numero intero intero a 8 bit a causa della mancanza di un'implementazione del kernel ottimizzata.
  • Attualmente non è compatibile con i delegati TFLite con accelerazione hardware esistenti.

Puoi trovare un tutorial per questa modalità di quantizzazione qui.

Precisione del modello

Poiché i pesi sono quantificati dopo l'addestramento, potrebbe verificarsi una perdita di accuratezza, in particolare per le reti più piccole. I modelli completamente quantizzati preaddestrati vengono forniti per reti specifiche in TensorFlow Hub. È importante controllare l'accuratezza del modello quantizzato per verificare che il peggioramento dell'accuratezza rientri nei limiti accettabili. Esistono strumenti per valutare l'accuratezza del modello TensorFlow.

In alternativa, se il calo dell'accuratezza è troppo elevato, valuta la possibilità di utilizzare l'addestramento sensibile alla quantizzazione. Tuttavia, questo processo richiede modifiche durante l'addestramento del modello per aggiungere nodi di quantizzazione falsi, mentre le tecniche di quantizzazione post-addestramento in questa pagina utilizzano un modello preaddestrato esistente.

Rappresentazione dei tensori quantizzati

La quantizzazione a 8 bit approssima i valori in virgola mobile utilizzando la seguente formula.

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

La rappresentazione ha due parti principali:

  • Pesi per asse (noti anche come per canale) o per tensore rappresentati da valori di completamento di int8 two nell'intervallo [-127, 127] con punto zero uguale a 0.

  • Attivazioni/input per tensore rappresentati da valori di complemento a due di int8 nell'intervallo [-128, 127], con un punto zero nell'intervallo [-128, 127].

Per una visione dettagliata del nostro schema di quantizzazione, consulta le specifiche di quantizzazione. I fornitori di hardware che desiderano collegarsi all'interfaccia di delega di TensorFlow Lite sono invitati a implementare lo schema di quantizzazione qui descritto.