Ispezione degli errori di quantizzazione con il debugger di quantizzazione

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza la fonte su GitHub Scarica taccuino Vedi il modello del mozzo TF

Sebbene la quantizzazione di numeri interi completi fornisca dimensioni e latenza del modello migliorate, il modello quantizzato non funzionerà sempre come previsto. Di solito ci si aspetta che la qualità del modello (es. accuratezza, mappa, WER) sia leggermente inferiore al modello float originale. Tuttavia, ci sono casi in cui la qualità del modello può andare al di sotto delle tue aspettative o generare risultati completamente errati.

Quando si verifica questo problema, è difficile e doloroso individuare la causa principale dell'errore di quantizzazione ed è ancora più difficile correggere l'errore di quantizzazione. Per facilitare questo processo di ispezione modello, debugger quantizzazione può essere utilizzato per identificare i livelli problematici, e quantizzazione selettiva può lasciare quegli strati problematici galleggiante in modo che la precisione modello può essere recuperato a costo di ridotta beneficiare quantizzazione.

Debugger di quantizzazione

Il debugger di quantizzazione consente di eseguire l'analisi metrica della qualità della quantizzazione nel modello esistente. Il debugger di quantizzazione può automatizzare i processi per l'esecuzione del modello con un set di dati di debug e raccogliere le metriche di qualità della quantizzazione per ciascun tensore.

Prerequisiti

Se hai già una pipeline per quantizzare un modello, hai tutti i pezzi necessari per eseguire il debugger di quantizzazione!

  • Modello da quantizzare
  • Set di dati rappresentativo

Oltre al modello e ai dati, dovrai utilizzare un framework di elaborazione dati (ad es. Panda, Fogli Google) per analizzare i risultati esportati.

Impostare

Questa sezione prepara le librerie, il modello MobileNet v3 e il set di dati di prova di 100 immagini.

# Quantization debugger is available from TensorFlow 2.7.0
pip uninstall -y tensorflow
pip install tf-nightly
pip install tensorflow_datasets --upgrade  # imagenet_v2 needs latest checksum
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import tensorflow as tf
import tensorflow_datasets as tfds
import tensorflow_hub as hub

Boilerplates e aiutanti

2021-10-30 11:57:45.262002: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/tmp_3ry7zon/assets
INFO:tensorflow:Assets written to: /tmp/tmp_3ry7zon/assets
2021-10-30 11:57:52.134354: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 11:57:52.134407: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
test_ds = ds.map(lambda data: (data['image'], data['label'] + 1)).batch(16)
loss, acc = model.evaluate(test_ds)
print(f'Top-5 accuracy (float): {acc * 100:.2f}%')
7/7 [==============================] - 6s 33ms/step - loss: 88.6092 - sparse_top_k_categorical_accuracy: 11.7143
Top-5 accuracy (float): 1171.43%
eval_tflite(quantized_model, ds)
Top-5 accuracy (quantized): 51.00%

Possiamo vedere che il modello originale ha un'accuratezza dei primi 5 molto più alta per il nostro piccolo set di dati, mentre il modello quantizzato ha una significativa perdita di precisione.

Passaggio 1. Preparazione del debugger

Il modo più semplice per utilizzare il debugger quantizzazione è quello di fornire tf.lite.TFLiteConverter che è stato utilizzato per quantizzare il modello.

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset(ds)

# my_debug_dataset should have the same format as my_representative_dataset
debugger = tf.lite.experimental.QuantizationDebugger(
    converter=converter, debug_dataset=representative_dataset(ds))
INFO:tensorflow:Assets written to: /tmp/tmpoa_5gejn/assets
INFO:tensorflow:Assets written to: /tmp/tmpoa_5gejn/assets
2021-10-30 11:58:34.006052: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 11:58:34.006103: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0

Passaggio 2. Eseguire il debugger e ottenere i risultati

Quando si chiama QuantizationDebugger.run() , il debugger registrerà differenze tra tensori galleggiante e tensori quantizzati per la stessa posizione op, ed elaborarli con determinate metriche.

debugger.run()

Le metriche elaborati possono essere raggiunti con QuantizationDebugger.layer_statistics , oppure possono essere scaricati in un file di testo in formato CSV con QuantizationDebugger.layer_statistics_dump() .

RESULTS_FILE = '/tmp/debugger_results.csv'
with open(RESULTS_FILE, 'w') as f:
  debugger.layer_statistics_dump(f)
head /tmp/debugger_results.csv

Per ogni riga della discarica, il nome e l'indice op viene prima, seguito da parametri di quantizzazione e metriche di errore (comprese le metriche di errore definito dall'utente , se presente). Il file CSV risultante può essere utilizzato per selezionare livelli problematici con metriche di errore di quantizzazione di grandi dimensioni.

Con i panda o altre librerie di elaborazione dati, possiamo ispezionare metriche di errore dettagliate per livello.

layer_stats = pd.read_csv(RESULTS_FILE)
layer_stats.head()

Passaggio 3. Analisi dei dati

Ci sono vari modi per analizzare il risultato. Innanzitutto, aggiungiamo alcune metriche utili derivate dagli output del debugger. ( scale indica il fattore di scala di quantizzazione per ogni tensore.)

  • Intervallo ( 256 / scale )
  • RMSE / scala ( sqrt(mean_squared_error) / scale )

Il RMSE / scale è vicino a 1 / sqrt(12) (~ 0,289) quando quantizzato distribuzione è simile alla distribuzione galleggiante originale, indicando un buon modello quantizzato. Maggiore è il valore, è più probabile che il livello non venga quantizzato bene.

layer_stats['range'] = 255.0 * layer_stats['scale']
layer_stats['rmse/scale'] = layer_stats.apply(
    lambda row: np.sqrt(row['mean_squared_error']) / row['scale'], axis=1)
layer_stats[['op_name', 'range', 'rmse/scale']].head()
plt.figure(figsize=(15, 5))
ax1 = plt.subplot(121)
ax1.bar(np.arange(len(layer_stats)), layer_stats['range'])
ax1.set_ylabel('range')
ax2 = plt.subplot(122)
ax2.bar(np.arange(len(layer_stats)), layer_stats['rmse/scale'])
ax2.set_ylabel('rmse/scale')
plt.show()

png

Ci sono molti strati con ampi intervalli, e alcuni strati che hanno alta RMSE/scale valori. Prendiamo i livelli con metriche di errore elevate.

layer_stats[layer_stats['rmse/scale'] > 0.7][[
    'op_name', 'range', 'rmse/scale', 'tensor_name'
]]

Con questi livelli, puoi provare la quantizzazione selettiva per vedere se la quantizzazione di quei livelli migliora la qualità del modello.

suspected_layers = list(
    layer_stats[layer_stats['rmse/scale'] > 0.7]['tensor_name'])

Oltre a questi, saltare la quantizzazione per i primi livelli aiuta anche a migliorare la qualità del modello quantizzato.

suspected_layers.extend(list(layer_stats[:5]['tensor_name']))

Quantizzazione selettiva

La quantizzazione selettiva salta la quantizzazione per alcuni nodi, in modo che il calcolo possa avvenire nel dominio a virgola mobile originale. Quando i livelli corretti vengono saltati, possiamo aspettarci un recupero della qualità del modello a scapito di una maggiore latenza e dimensioni del modello.

Tuttavia, se stai pianificando di eseguire modelli quantizzati su acceleratori di soli interi (ad es. Hexagon DSP, EdgeTPU), la quantizzazione selettiva causerebbe la frammentazione del modello e comporterebbe una latenza di inferenza più lenta principalmente causata dal costo di trasferimento dei dati tra CPU e quegli acceleratori . Per evitare questo, si può considerare l'esecuzione di quantizzazione di formazione a conoscenza di tenere tutti gli strati in intero, preservando l'accuratezza del modello.

Opzione del debugger quantizzazione accetta denylisted_nodes e denylisted_ops opzioni per saltare quantizzazione per i layer specifici, o tutte le istanze di ops specifici. Usando suspected_layers abbiamo preparato dal passaggio precedente, possiamo usare debugger quantizzazione per ottenere un modello selettivamente quantizzato.

debug_options = tf.lite.experimental.QuantizationDebugOptions(
    denylisted_nodes=suspected_layers)
debugger = tf.lite.experimental.QuantizationDebugger(
    converter=converter,
    debug_dataset=representative_dataset(ds),
    debug_options=debug_options)
INFO:tensorflow:Assets written to: /tmp/tmpqqc57uli/assets
INFO:tensorflow:Assets written to: /tmp/tmpqqc57uli/assets
2021-10-30 11:59:13.603355: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 11:59:13.603400: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
selective_quantized_model = debugger.get_nondebug_quantized_model()
eval_tflite(selective_quantized_model, ds)
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
Top-5 accuracy (quantized): 64.00%

La precisione è ancora inferiore rispetto al modello float originale, ma abbiamo un notevole miglioramento rispetto all'intero modello quantizzato saltando la quantizzazione per circa 10 livelli su 111 livelli.

Puoi anche provare a non quantizzare tutte le operazioni nella stessa classe. Ad esempio, per saltare quantizzazione per tutti i ops medi, è possibile passare MEAN a denylisted_ops .

debug_options = tf.lite.experimental.QuantizationDebugOptions(
    denylisted_ops=['MEAN'])
debugger = tf.lite.experimental.QuantizationDebugger(
    converter=converter,
    debug_dataset=representative_dataset(ds),
    debug_options=debug_options)
INFO:tensorflow:Assets written to: /tmp/tmpxltlornb/assets
INFO:tensorflow:Assets written to: /tmp/tmpxltlornb/assets
2021-10-30 11:59:44.677473: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 11:59:44.677519: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
selective_quantized_model = debugger.get_nondebug_quantized_model()
eval_tflite(selective_quantized_model, ds)
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
Top-5 accuracy (quantized): 54.00%

Con queste tecniche, siamo in grado di migliorare la precisione del modello MobileNet V3 quantizzato. Successivamente esploreremo tecniche avanzate per migliorare ulteriormente la precisione del modello.

Usi avanzati

Con le seguenti funzionalità, puoi personalizzare ulteriormente la tua pipeline di debug.

Metriche personalizzate

Per impostazione predefinita, il debugger di quantizzazione emette cinque metriche per ciascuna differenza float-quant: dimensione del tensore, deviazione standard, errore medio, errore assoluto massimo ed errore quadratico medio. Puoi aggiungere più metriche personalizzate passandole alle opzioni. Per ogni metrica, il risultato dovrebbe essere un singolo valore float e la metrica risultante sarà una media delle metriche di tutti gli esempi.

  • layer_debug_metrics : calcola metrico basato su diff per ciascuna uscita OP del galleggiante e uscite op quantizzati.
  • layer_direct_compare_metrics : piuttosto che ottenere solo diff, questo calcolerà metrica basata su galleggiante crudo e tensori quantizzati, ei suoi parametri di quantizzazione (scala, punto zero)
  • model_debug_metrics : utilizzate solo quando float_model_(path|content) è passato al debugger. Oltre alle metriche di livello operativo, l'output del livello finale viene confrontato con l'output di riferimento del modello float originale.
debug_options = tf.lite.experimental.QuantizationDebugOptions(
    layer_debug_metrics={
        'mean_abs_error': (lambda diff: np.mean(np.abs(diff)))
    },
    layer_direct_compare_metrics={
        'correlation':
            lambda f, q, s, zp: (np.corrcoef(f.flatten(),
                                             (q.flatten() - zp) / s)[0, 1])
    },
    model_debug_metrics={
        'argmax_accuracy': (lambda f, q: np.mean(np.argmax(f) == np.argmax(q)))
    })

debugger = tf.lite.experimental.QuantizationDebugger(
    converter=converter,
    debug_dataset=representative_dataset(ds),
    debug_options=debug_options)
INFO:tensorflow:Assets written to: /tmp/tmpm7cb9qcd/assets
INFO:tensorflow:Assets written to: /tmp/tmpm7cb9qcd/assets
2021-10-30 12:00:18.502193: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 12:00:18.502238: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
INFO:tensorflow:Assets written to: /tmp/tmpzkg3ny_8/assets
INFO:tensorflow:Assets written to: /tmp/tmpzkg3ny_8/assets
2021-10-30 12:00:28.401195: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 12:00:28.401241: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
debugger.run()
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/numpy/lib/function_base.py:2691: RuntimeWarning: invalid value encountered in true_divide
  c /= stddev[:, None]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/numpy/lib/function_base.py:2692: RuntimeWarning: invalid value encountered in true_divide
  c /= stddev[None, :]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/lite/tools/optimize/debugging/python/debugger.py:382: RuntimeWarning: Mean of empty slice
  metrics[metric_name] = np.nanmean(metrics[metric_name])
CUSTOM_RESULTS_FILE = '/tmp/debugger_results.csv'
with open(CUSTOM_RESULTS_FILE, 'w') as f:
  debugger.layer_statistics_dump(f)

custom_layer_stats = pd.read_csv(CUSTOM_RESULTS_FILE)
custom_layer_stats[['op_name', 'mean_abs_error', 'correlation']].tail()

Il risultato di model_debug_metrics può essere visto separatamente dal debugger.model_statistics .

debugger.model_statistics
{'argmax_accuracy': 0.36}

Utilizzo dell'API mlir_quantize (interna) per accedere a funzionalità approfondite

from tensorflow.lite.python import convert

Modalità di verifica dell'intero modello

Il comportamento predefinito per la generazione del modello di debug è la verifica per livello. In questa modalità, l'input per la coppia di operazioni float e quantize proviene dalla stessa sorgente (precedente operazione quantizzata). Un'altra modalità è la verifica dell'intero modello, in cui i modelli float e quantize sono separati. Questa modalità sarebbe utile per osservare come l'errore viene propagato lungo il modello. Per attivare, enable_whole_model_verify=True per convert.mlir_quantize durante la generazione del modello di debug manualmente.

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.representative_dataset = representative_dataset(ds)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter._experimental_calibrate_only = True
calibrated_model = converter.convert()
INFO:tensorflow:Assets written to: /tmp/tmp2oa0sp06/assets
INFO:tensorflow:Assets written to: /tmp/tmp2oa0sp06/assets
2021-10-30 12:01:33.233118: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-10-30 12:01:33.233171: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
# Note that enable_numeric_verify and enable_whole_model_verify are set.
quantized_model = convert.mlir_quantize(
    calibrated_model,
    enable_numeric_verify=True,
    enable_whole_model_verify=True)
debugger = tf.lite.experimental.QuantizationDebugger(
    quant_debug_model_content=quantized_model,
    debug_dataset=representative_dataset(ds))
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0

Quantizzazione selettiva da un modello già calibrato

È possibile chiamare direttamente convert.mlir_quantize per ottenere il modello quantizzato selettivo dal modello già calibrato. Ciò sarebbe particolarmente utile quando si desidera calibrare il modello una volta e sperimentare varie combinazioni di elenchi di negazione.

selective_quantized_model = convert.mlir_quantize(
    calibrated_model, denylisted_nodes=suspected_layers)
eval_tflite(selective_quantized_model, ds)
fully_quantize: 0, inference_type: 6, input_inference_type: 0, output_inference_type: 0
Top-5 accuracy (quantized): 64.00%