Inspección de errores de cuantificación con el depurador de cuantificación

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno Ver modelo TF Hub

Aunque la cuantificación de enteros completos proporciona un tamaño de modelo y una latencia mejorados, el modelo cuantificado no siempre funcionará como se esperaba. Por lo general, se espera que la calidad del modelo (por ejemplo, precisión, mAP, WER) sea ligeramente inferior a la del modelo flotante original. Sin embargo, hay casos en los que la calidad del modelo puede estar por debajo de sus expectativas o generar resultados completamente incorrectos.

Cuando ocurre este problema, es complicado y doloroso detectar la causa raíz del error de cuantificación, y es aún más difícil corregir el error de cuantificación. Para ayudar en este proceso de inspección de modelo, depurador de cuantificación se puede utilizar para identificar capas problemáticos, y de cuantificación selectiva puede dejar esas capas problemáticos en flotador de modo que la exactitud del modelo se puede recuperar a costa de beneficio reducido de cuantificación.

Depurador de cuantificación

El depurador de cuantificación permite realizar análisis métricos de calidad de cuantificación en el modelo existente. El depurador de cuantificación puede automatizar los procesos para ejecutar el modelo con un conjunto de datos de depuración y recopilar métricas de calidad de cuantificación para cada tensor.

Prerrequisitos

Si ya tiene una tubería para cuantificar un modelo, ¡tiene todas las piezas necesarias para ejecutar el depurador de cuantificación!

  • Modelo para cuantificar
  • Conjunto de datos representativo

Además del modelo y los datos, deberá utilizar un marco de procesamiento de datos (por ejemplo, pandas, Hojas de cálculo de Google) para analizar los resultados exportados.

Configuración

Esta sección prepara bibliotecas, el modelo MobileNet v3 y el conjunto de datos de prueba de 100 imágenes.

# 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

Planchas de calderas y ayudantes

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%

Podemos ver que el modelo original tiene una precisión de los 5 primeros para nuestro pequeño conjunto de datos, mientras que el modelo cuantificado tiene una pérdida de precisión significativa.

Paso 1. Preparación del depurador

La manera más fácil de utilizar el depurador de cuantificación es proporcionar tf.lite.TFLiteConverter que usted ha estado utilizando para cuantificar el modelo.

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

Paso 2. Ejecutar el depurador y obtener los resultados

Cuando se llama a QuantizationDebugger.run() , el depurador registrará diferencias entre los tensores y tensores de flotación cuantificados para la misma ubicación op, y procesarlos con métricas dadas.

debugger.run()

Las métricas procesadas se puede acceder con QuantizationDebugger.layer_statistics , o pueden ser descargados a un archivo de texto en 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

Para cada fila en el vertedero, el nombre op y el índice viene primero, seguido de parámetros de cuantificación y las métricas de error (incluyendo métricas de error definidos por el usuario , si lo hay). El archivo CSV resultante se puede utilizar para seleccionar capas problemáticas con grandes métricas de error de cuantificación.

Con pandas u otras bibliotecas de procesamiento de datos, podemos inspeccionar métricas de error detalladas por capa.

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

Paso 3. Análisis de datos

Hay varias formas de analizar el resultado. Primero, agreguemos algunas métricas útiles derivadas de los resultados del depurador. ( scale significa que el factor de escala de cuantificación para cada tensor.)

  • Rango ( 256 / scale )
  • RMSE / escala ( sqrt(mean_squared_error) / scale )

El RMSE / scale está cerca de 1 / sqrt(12) (~ 0.289) cuando la distribución cuantificada es similar a la distribución de flotador original, lo que indica un modelo cuantizado bueno. Cuanto mayor sea el valor, es más probable que la capa no se cuantifique bien.

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

Hay muchas capas con amplios intervalos, y algunas capas que tienen alta RMSE/scale valores. Consigamos las capas con métricas de alto error.

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

Con estas capas, puede probar la cuantificación selectiva para ver si no cuantificar esas capas mejora la calidad del modelo.

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

Además de estos, omitir la cuantificación para las primeras capas también ayuda a mejorar la calidad del modelo cuantificado.

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

Cuantización selectiva

La cuantificación selectiva omite la cuantificación para algunos nodos, por lo que el cálculo puede ocurrir en el dominio de punto flotante original. Cuando se omiten las capas correctas, podemos esperar cierta recuperación de la calidad del modelo a costa de una mayor latencia y tamaño del modelo.

Sin embargo, si planea ejecutar modelos cuantificados en aceleradores de solo enteros (por ejemplo, Hexagon DSP, EdgeTPU), la cuantificación selectiva causaría la fragmentación del modelo y daría como resultado una latencia de inferencia más lenta causada principalmente por el costo de transferencia de datos entre la CPU y esos aceleradores . Para evitar esto, se puede considerar que ejecuta la cuantificación de formación conscientes de mantener todas las capas en el número entero preservando al mismo tiempo la exactitud del modelo.

Opción de cuantificación del depurador acepta denylisted_nodes y denylisted_ops opciones para saltar de cuantificación para capas específicas, o todas las instancias de operaciones específicas. Usando suspected_layers hemos preparado en el paso anterior, podemos utilizar depurador de cuantificación para obtener un modelo cuantificado de forma selectiva.

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 precisión es aún menor en comparación con el modelo flotante original, pero tenemos una mejora notable de todo el modelo cuantificado al omitir la cuantificación para ~ 10 capas de 111 capas.

También puede intentar no cuantificar todas las operaciones en la misma clase. Por ejemplo, para saltar de cuantificación para todas las operaciones medias, puede pasar 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 estas técnicas, podemos mejorar la precisión cuantificada del modelo MobileNet V3. A continuación, exploraremos técnicas avanzadas para mejorar aún más la precisión del modelo.

Usos avanzados

Con las siguientes características, puede personalizar aún más su canal de depuración.

Métricas personalizadas

De forma predeterminada, el depurador de cuantificación emite cinco métricas para cada diferencia de cuantificación flotante: tamaño del tensor, desviación estándar, error medio, error absoluto máximo y error cuadrático medio. Puede agregar más métricas personalizadas pasándolas a opciones. Para cada métrica, el resultado debe ser un único valor flotante y la métrica resultante será un promedio de las métricas de todos los ejemplos.

  • layer_debug_metrics : Cálculo de métrica basada en diferencias para cada una de las salidas op flotador y salidas op cuantificados.
  • layer_direct_compare_metrics : en lugar de obtener solamente diff, este calculará métrica basada en flotado bruto y tensores cuantificados, y sus parámetros de cuantificación (escala, punto cero)
  • model_debug_metrics : sólo se utilizan cuando float_model_(path|content) se pasa al depurador. Además de las métricas de nivel de operación, la salida de la capa final se compara con la salida de referencia del modelo flotante original.
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()

El resultado de model_debug_metrics puede verse por separado de debugger.model_statistics .

debugger.model_statistics
{'argmax_accuracy': 0.36}

Uso de la API mlir_quantize (interna) para acceder a funciones detalladas

from tensorflow.lite.python import convert

Modo de verificación de modelo completo

El comportamiento predeterminado para la generación del modelo de depuración es la verificación por capa. En este modo, la entrada para el par de operaciones de flotación y cuantización proviene de la misma fuente (operación cuantificada anterior). Otro modo es la verificación de modelo completo, donde los modelos de flotación y cuantización están separados. Este modo sería útil para observar cómo se propaga el error por el modelo. Para habilitar, enable_whole_model_verify=True a convert.mlir_quantize al generar el modelo de depuración 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

Cuantificación selectiva de un modelo ya calibrado

Puede llamar directamente convert.mlir_quantize para obtener el modelo cuantificado selectiva de modelo ya calibrado. Esto sería particularmente útil cuando desee calibrar el modelo una vez y experimentar con varias combinaciones de denylist.

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%