La cuantización posterior al entrenamiento es una técnica de conversión que puede reducir el tamaño del modelo y, al mismo tiempo, mejora la latencia del acelerador de CPU y hardware, con poco en la exactitud del modelo. Puedes cuantizar un número de punto flotante ya entrenado modelo de TensorFlow cuando lo conviertes al formato LiteRT con la Convertidor de LiteRT.
Métodos de optimización
Existen varias opciones de cuantización posterior al entrenamiento entre las que puedes elegir. Este es un resumen de las opciones y los beneficios que proporcionan:
Técnica | Beneficios | Hardware |
---|---|---|
Rango dinámico cuantización | 4 veces más pequeño, 2 o 3 veces más rápido | CPU |
Número entero completo cuantización | 4 veces más pequeño, 3 veces más rápido | CPU, Edge TPU, Microcontroladores |
Cuantización de float16 | 2 veces más pequeño, GPU aceleración | CPU, GPU |
El siguiente árbol de decisión puede ayudar a determinar qué cuantización posterior al entrenamiento es el mejor para tu caso de uso:
Sin cuantización
Se recomienda comenzar la conversión a un modelo de TFLite sin cuantización punto. Esto generará un modelo de TFLite de número de punto flotante.
import tensorflow as tf converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir) tflite_quant_model = converter.convert()
Te recomendamos que lo hagas como un paso inicial para verificar que el Los operadores del modelo de TF son compatibles con TFLite y también se pueden usar como modelo de referencia para depurar errores de cuantización ingresados por el entrenamiento posterior y los métodos de cuantización. Por ejemplo, si un modelo de TFLite cuantizado produce resultados inesperados, si bien el modelo float de TFLite es exacto, podemos acotar el problema con errores introducidos por la versión cuantizada de los operadores de TFLite.
Cuantización de rango dinámico
La cuantización de rango dinámico proporciona un uso reducido de la memoria y un procesamiento más rápido. sin tener que proporcionar un conjunto de datos representativo para la calibración. Esta tipo de cuantización, cuantiza estáticamente solo los pesos del punto flotante a números enteros al momento de la conversión, lo que proporciona 8 bits de precisión:
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()
Para reducir aún más la latencia durante la inferencia, “rango dinámico” operadores cuantizan de forma dinámica las activaciones según su rango a 8 bits y realizan cálculos con ponderaciones de 8 bits y activaciones. Esta optimización proporciona latencias cercanas a las inferencias de punto fijo en su totalidad. Sin embargo, las salidas con punto flotante, por lo que la velocidad aumentada de las operaciones de rango dinámico es menor que un cálculo completo de punto fijo.
Cuantización completa de números enteros
Puedes obtener más mejoras en la latencia, reducciones en el uso máximo de memoria y compatibilidad con dispositivos de hardware o aceleradores que solo usan números enteros toda la matemática del modelo está cuantizada con números enteros.
Para una cuantización completa de números enteros, se necesita calibrar o estimar el rango,
es decir, (mín., máx.) de todos los tensores de punto flotante en el modelo. Diferenciar constante
tensores como pesos y sesgos, tensores variables como entrada del modelo,
activaciones (salidas de capas intermedias) y la salida del modelo no se pueden
a menos que ejecutemos algunos ciclos de inferencia. Como resultado, el conversor
requieren un conjunto de datos representativo para calibrarlas. Este conjunto de datos puede ser una pequeña
subconjunto (alrededor de 100-500 muestras) de los datos de entrenamiento o validación. Consulta
la función representative_dataset()
a continuación.
Desde la versión de TensorFlow 2.7, puedes especificar el conjunto de datos representativo a través de Una firma como el siguiente ejemplo:
def representative_dataset(): for data in dataset: yield { "image": data.image, "bias": data.bias, }
Si hay más de una firma en el modelo de TensorFlow dado, puedes Para especificar el conjunto de datos múltiple, especifica las claves de 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, }, )
Puedes generar el conjunto de datos representativo proporcionando una lista de tensores de entrada:
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 partir de la versión de TensorFlow 2.7, recomendamos usar el enfoque basado en firmas. sobre el enfoque basado en listas de tensores de entrada porque el ordenamiento de tensores de entrada puede pueden invertirse fácilmente.
Para realizar pruebas, puedes usar un conjunto de datos ficticio de la siguiente manera:
def representative_dataset(): for _ in range(100): data = np.random.rand(1, 244, 244, 3) yield [data.astype(np.float32)]
Número entero con resguardo de número de punto flotante (con entrada/salida de número de punto flotante predeterminada)
Para cuantizar por completo un número entero, pero use operadores flotantes cuando no cuentan con una implementación de números enteros (para garantizar que la conversión se realice sin problemas), usa sigue estos pasos:
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 números enteros
La creación de modelos solo de números enteros es un caso de uso común para LiteRT para Microcontroladores y Coral Edge TPU.
Además, para garantizar la compatibilidad con dispositivos que solo usan números enteros (como microcontroladores) y aceleradores (como Coral Edge TPU), puedes aplicar la cuantización completa de números enteros para todas las operaciones, incluidas la entrada y la salida, mediante sigue estos pasos:
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()
Cuantización de float16
Puedes reducir el tamaño de un modelo de punto flotante si cuantificas los pesos a float16, el estándar IEEE para números de punto flotante de 16 bits. Para habilitar float16 la cuantización de pesos, sigue estos pasos:
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()
Las ventajas de la cuantización de float16 son las siguientes:
- Reduce el tamaño del modelo hasta la mitad (ya que todos los pesos se convierten en la mitad de su tamaño original).
- provoca una pérdida mínima de exactitud.
- Admite algunos delegados (p.ej., el delegado de GPU) que pueden operar directamente sobre los datos de float16, lo que da como resultado una ejecución más rápida que la de float32 cálculos.
Las desventajas de la cuantización de float16 son las siguientes:
- No reduce la latencia tanto como una cuantización a una matemática de puntos fijos.
- De forma predeterminada, un modelo cuantizado de float16 “descuantizará” los valores de las ponderaciones a float32 cuando se ejecuta en la CPU. (Ten en cuenta que el delegado de GPU no realizará esta descuantización, ya que puede operar con datos float16).
Solo números enteros: activaciones de 16 bits con ponderaciones de 8 bits (experimental)
Este es un esquema de cuantización experimental. Es similar a "integer only". pero las activaciones se cuantifican en función de su rango de 16 bits, ponderaciones se cuantizan en un número entero de 8 bits y la inclinación en un número entero de 64 bits. Esta también se denomina "cuantización de 16 × 8".
La ventaja principal de esta cuantización es que puede mejorar la exactitud significativamente, pero solo aumentará levemente el tamaño del modelo.
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()
Si algunos operadores del modelo no admiten la cuantización de 16 × 8, el valor modelo aún se puede cuantificar, pero los operadores no admitidos se mantienen en número de punto flotante. El la siguiente opción debe agregarse a target_spec para permitir esto.
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()
Ejemplos de casos de uso en los que las mejoras en la precisión proporcionadas por este esquema de cuantización incluyen lo siguiente:
- alta resolución,
- para el procesamiento de señales de audio, como la cancelación de ruido y la conformación de haces
- quitar ruido de imagen,
- Reconstrucción HDR a partir de una sola imagen.
La desventaja de esta cuantización es la siguiente:
- En la actualidad, la inferencia es notablemente más lenta que los números enteros de 8 bits debido a la falta de una implementación optimizada del kernel.
- Actualmente, no es compatible con el TFLite existente acelerado por hardware. delegados.
Puede encontrarse un instructivo para este modo de cuantización aquí.
Precisión del modelo
Debido a que los pesos están cuantificados después del entrenamiento, podría haber una pérdida de exactitud, particularmente para redes más pequeñas. Los modelos completamente cuantizados previamente entrenados para redes específicas en Kaggle Modelos de Google Cloud. Es importante comprobar la exactitud del modelo cuantizado para comprobar que cualquier degradación en la exactitud se encuentre dentro de límites aceptables. Hay herramientas para evaluar el modelo LiteRT exactitud.
Por otro lado, si la disminución de exactitud es demasiado alta, considera usar la cuantización consciente entrenamiento de Google Cloud. Sin embargo, hacer esto requiere modificaciones durante el entrenamiento del modelo para agregar entre los nodos de cuantización, mientras que las técnicas página usan un modelo existente previamente entrenado.
Representación de tensores cuantificados
La cuantización de 8 bits se aproxima a los valores de punto flotante mediante los siguientes fórmula.
\[real\_value = (int8\_value - zero\_point) \times scale\]
La representación tiene dos partes principales:
Ponderaciones por eje (también conocida como por canal) o por tensor representadas por valores de dos int8 complementar valores en el rango [-127, 127] con un punto cero igual a 0.
Activaciones/entradas por tensor representadas por los valores del complemento de dos de int8 en el rango [-128, 127], con un punto cero en el rango [-128, 127].
Para obtener una vista detallada de nuestro esquema de cuantización, consulta nuestro esquema de cuantización. spec. Proveedores de hardware que quieren conectarse a TensorFlow Se recomienda implementar el esquema de cuantización en la interfaz de delegado de Lite. que se describe allí.