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 peggioramento dell'accuratezza del modello. Puoi quantificare un numero in virgola mobile già addestrato il modello TensorFlow quando lo converti in formato LiteRT utilizzando Convertitore LiteRT.

Metodi di ottimizzazione

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

Tecnica Vantaggi Hardware
Intervallo dinamico quantizzazione 4 volte più piccola, velocità 2x-3x CPU
Numero intero intero quantizzazione 4 volte più piccola, 3 volte più veloce CPU, Edge TPU Microcontrollori
quantizzazione in Float16 2 volte più piccola, GPU accelerazione CPU, GPU

Il seguente albero decisionale può aiutare a determinare quale quantizzazione post-addestramento più adatto al tuo caso d'uso:

opzioni di ottimizzazione post-addestramento

Nessuna quantizzazione

La conversione a un modello TFLite senza la quantizzazione è consigliata per iniziare punto di accesso. 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 primo passaggio per verificare che l'originale Gli operatori del modello TF sono compatibili con TFLite e possono essere utilizzati anche come per eseguire il debug degli errori di quantizzazione introdotti dal successivo addestramento metodi di quantizzazione. Ad esempio, se un modello TFLite quantizzato genera risultati imprevisti, mentre il modello TFLite in virgola mobile è accurato, possiamo il problema degli errori introdotti dalla versione quantizzata degli operatori TFLite.

quantizzazione dell'intervallo dinamico

La quantizzazione dell'intervallo dinamico consente di ridurre l'utilizzo della memoria e velocizzare il calcolo senza dover fornire un set di dati rappresentativo per la calibrazione. Questo tipo di quantizzazione, quantifica in modo statico solo i pesi in virgola mobile a un valore intero al momento della conversione, che fornisce 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, operatori quantificare dinamicamente le attivazioni in base all'intervallo fino a 8 bit ed eseguire con pesi a 8 bit e attivazioni. Questa ottimizzazione fornisce le latenze vicine alle inferenze a punto completamente fisso. Tuttavia, gli output sono comunque memorizzati utilizzando la rappresentazione in virgola mobile, in modo che la maggiore velocità delle operazioni con intervallo dinamico sia minore rispetto 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, assicurandosi tutta la matematica del modello è quantificata in numero intero.

Per la quantizzazione completa dei numeri interi, devi calibrare o stimare l'intervallo, ovvero (min, max) di tutti i tensori a virgola mobile nel modello. A differenza della costante tensori come ponderazioni e bias, tensori variabili come input del modello, (output degli strati intermedi) e l'output del modello non calibrata, a meno che non eseguiamo alcuni cicli di inferenza. Di conseguenza, l'utente che ha completato richiede un set di dati rappresentativo per calibrarli. Questo set di dati può essere un insieme sottoinsieme (circa 100-500 campioni) dei dati di addestramento o convalida. Consulta la funzione representative_dataset() riportata di seguito.

A partire dalla versione TensorFlow 2.7, è possibile 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 sulle firme sull'approccio basato su elenco di tensori di input perché l'ordinamento dei tensori di input può possono essere facilmente capovolti.

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)

Al fine di quantificare completamente un modello, utilizza gli operatori in virgola mobile quando non hai un'implementazione di tipo intero (per garantire che la conversione avvenga senza problemi), utilizza 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 di LiteRT per Microcontrollori e Corallo Edge TPU.

Inoltre, per garantire la compatibilità con dispositivi che includono solo numeri interi (ad esempio, i dispositivi a 8 bit) microcontroller) e acceleratori (come la TPU Coral Edge), puoi la quantizzazione dei numeri interi completi per tutte le operazioni, compresi l'input e l'output, utilizzando 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
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

Puoi ridurre le dimensioni di un modello in virgola mobile quantificando le ponderazioni in float16, lo standard IEEE per i numeri in virgola mobile a 16 bit. Per attivare float16 quantizzazione delle ponderazioni, segui questi passaggi:

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à del loro dimensioni originali).
  • Causa una perdita minima di precisione.
  • Supporta alcuni delegati (ad esempio il delegato GPU) che possono operare direttamente sui dati float16, con un'esecuzione più rapida rispetto a float32 molto altro.

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 delle ponderazioni 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 a "solo numero intero" ma le attivazioni sono quantificate in base al loro intervallo a 16 bit, i pesi sono quantizzati in numeri interi a 8 bit e i bias vengono quantificati in numeri interi a 64 bit. Questo è detta "quantizzazione 16x8".

Il vantaggio principale di questa quantizzazione è che può migliorare l'accuratezza ma aumenta 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 la quantizzazione 16x8 non è supportata per alcuni operatori nel modello, il modello può comunque essere quantizzato, ma gli operatori non supportati vengono mantenuti in numero in virgola mobile. La Per consentire questa operazione, è 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 include:

  • super risoluzione,
  • 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 dell'implementazione del kernel ottimizzata.
  • Attualmente non è compatibile con la soluzione TFLite con accelerazione hardware esistente delegati.
di Gemini Advanced.

È disponibile 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 sono fornite per emittenti specifiche su Kaggle Modelli di Google. È importante controllare l'accuratezza del modello quantizzato per verificare che qualsiasi peggioramento dell'accuratezza rientri nei limiti accettabili. Esistono strumenti per valutare il modello LiteRT la precisione.

In alternativa, se il calo della precisione è troppo elevato, valuta la possibilità di utilizzare la quantizzazione consapevolezza formazione di Google. Tuttavia, questo processo richiede modifiche durante l'addestramento del modello per aggiungere nodi di quantizzazione, mentre le tecniche di quantizzazione post-addestramento utilizza un modello preaddestrato esistente.

Rappresentazione dei tensori quantizzati

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

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

La rappresentazione ha due parti principali:

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

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

Per una visione dettagliata del nostro schema di quantizzazione, consulta la quantizzazione del modello. Fornitori di hardware che vogliono collegarsi a TensorFlow Consigliamo all'interfaccia di delega di Lite di implementare lo schema di quantizzazione descritti qui.