¿Tengo una pregunta? Conéctese con la comunidad en el Foro de visita del foro de TensorFlow

Cuantización de enteros posterior al entrenamiento con activaciones int16

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

Descripción general

TensorFlow Lite ahora admite la conversión de activaciones a valores enteros de 16 bits y pesos a valores enteros de 8 bits durante la conversión del modelo de TensorFlow al formato de búfer plano de TensorFlow Lite. Nos referimos a este modo como el "modo de cuantificación 16x8". Este modo puede mejorar la precisión del modelo cuantificado de manera significativa, cuando las activaciones son sensibles a la cuantificación, mientras se logra una reducción de casi 3-4x en el tamaño del modelo. Además, este modelo totalmente cuantificado puede ser consumido por aceleradores de hardware de solo enteros.

Algunos ejemplos de modelos que se benefician de este modo de cuantificación posterior al entrenamiento incluyen:

  • súper resolución,
  • procesamiento de señales de audio, como cancelación de ruido y formación de haces,
  • eliminación de ruido en la imagen,
  • Reconstrucción HDR a partir de una sola imagen

En este tutorial, entrena un modelo MNIST desde cero, verifica su precisión en TensorFlow y luego convierte el modelo en un búfer plano de Tensorflow Lite usando este modo. Al final, verifica la precisión del modelo convertido y lo compara con el modelo float32 original. Tenga en cuenta que este ejemplo demuestra el uso de este modo y no muestra beneficios sobre otras técnicas de cuantificación disponibles en TensorFlow Lite.

Construye un modelo MNIST

Configuración

import logging
logging.getLogger("tensorflow").setLevel(logging.DEBUG)

import tensorflow as tf
from tensorflow import keras
import numpy as np
import pathlib

Compruebe que el modo de cuantificación 16x8 esté disponible

tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8
<OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8: 'EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8'>

Entrene y exporte el modelo

# Load MNIST dataset
mnist = keras.datasets.mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

# Normalize the input image so that each pixel value is between 0 to 1.
train_images = train_images / 255.0
test_images = test_images / 255.0

# Define the model architecture
model = keras.Sequential([
  keras.layers.InputLayer(input_shape=(28, 28)),
  keras.layers.Reshape(target_shape=(28, 28, 1)),
  keras.layers.Conv2D(filters=12, kernel_size=(3, 3), activation=tf.nn.relu),
  keras.layers.MaxPooling2D(pool_size=(2, 2)),
  keras.layers.Flatten(),
  keras.layers.Dense(10)
])

# Train the digit classification model
model.compile(optimizer='adam',
              loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
model.fit(
  train_images,
  train_labels,
  epochs=1,
  validation_data=(test_images, test_labels)
)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
1875/1875 [==============================] - 13s 2ms/step - loss: 0.2827 - accuracy: 0.9209 - val_loss: 0.1246 - val_accuracy: 0.9664
<tensorflow.python.keras.callbacks.History at 0x7fc6d432cd50>

Por ejemplo, entrenó el modelo solo durante una época, por lo que solo entrena con una precisión de ~ 96%.

Convertir a un modelo de TensorFlow Lite

Con Python TFLiteConverter , ahora puede convertir el modelo entrenado en un modelo de TensorFlow Lite.

Ahora, convierta el modelo usando TFliteConverter al formato float32 predeterminado:

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
INFO:tensorflow:Assets written to: /tmp/tmpsw317yw_/assets

Escríbalo en un archivo .tflite :

tflite_models_dir = pathlib.Path("/tmp/mnist_tflite_models/")
tflite_models_dir.mkdir(exist_ok=True, parents=True)
tflite_model_file = tflite_models_dir/"mnist_model.tflite"
tflite_model_file.write_bytes(tflite_model)
84552

En su lugar, para cuantificar el modelo al modo de cuantificación 16x8, primero configure el indicador de optimizations para usar optimizaciones predeterminadas. Luego, especifique que el modo de cuantificación 16x8 es la operación admitida requerida en la especificación de destino:

converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]

Como en el caso de la cuantificación posterior al entrenamiento de int8, es posible producir un modelo cuantificado completamente entero configurando las opciones del convertidor inference_input(output)_type en tf.int16.

Configure los datos de calibración:

mnist_train, _ = tf.keras.datasets.mnist.load_data()
images = tf.cast(mnist_train[0], tf.float32) / 255.0
mnist_ds = tf.data.Dataset.from_tensor_slices((images)).batch(1)
def representative_data_gen():
  for input_value in mnist_ds.take(100):
    # Model has only one input so each data point has one element.
    yield [input_value]
converter.representative_dataset = representative_data_gen

Finalmente, convierta el modelo como de costumbre. Tenga en cuenta que, de forma predeterminada, el modelo convertido seguirá utilizando entradas y salidas flotantes para la conveniencia de la invocación.

tflite_16x8_model = converter.convert()
tflite_model_16x8_file = tflite_models_dir/"mnist_model_quant_16x8.tflite"
tflite_model_16x8_file.write_bytes(tflite_16x8_model)
INFO:tensorflow:Assets written to: /tmp/tmpaq8qqppx/assets
INFO:tensorflow:Assets written to: /tmp/tmpaq8qqppx/assets
24832

Tenga en cuenta que el archivo resultante tiene aproximadamente 1/3 del tamaño.

ls -lh {tflite_models_dir}
total 112K
-rw-rw-r-- 1 kbuilder kbuilder 83K May 15 11:12 mnist_model.tflite
-rw-rw-r-- 1 kbuilder kbuilder 25K May 15 11:12 mnist_model_quant_16x8.tflite

Ejecute los modelos de TensorFlow Lite

Ejecute el modelo de TensorFlow Lite con el intérprete de Python TensorFlow Lite.

Cargue el modelo en los intérpretes

interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))
interpreter.allocate_tensors()
interpreter_16x8 = tf.lite.Interpreter(model_path=str(tflite_model_16x8_file))
interpreter_16x8.allocate_tensors()

Pruebe los modelos en una imagen

test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)

input_index = interpreter.get_input_details()[0]["index"]
output_index = interpreter.get_output_details()[0]["index"]

interpreter.set_tensor(input_index, test_image)
interpreter.invoke()
predictions = interpreter.get_tensor(output_index)
import matplotlib.pylab as plt

plt.imshow(test_images[0])
template = "True:{true}, predicted:{predict}"
_ = plt.title(template.format(true= str(test_labels[0]),
                              predict=str(np.argmax(predictions[0]))))
plt.grid(False)

png

test_image = np.expand_dims(test_images[0], axis=0).astype(np.float32)

input_index = interpreter_16x8.get_input_details()[0]["index"]
output_index = interpreter_16x8.get_output_details()[0]["index"]

interpreter_16x8.set_tensor(input_index, test_image)
interpreter_16x8.invoke()
predictions = interpreter_16x8.get_tensor(output_index)
plt.imshow(test_images[0])
template = "True:{true}, predicted:{predict}"
_ = plt.title(template.format(true= str(test_labels[0]),
                              predict=str(np.argmax(predictions[0]))))
plt.grid(False)

png

Evaluar los modelos

# A helper function to evaluate the TF Lite model using "test" dataset.
def evaluate_model(interpreter):
  input_index = interpreter.get_input_details()[0]["index"]
  output_index = interpreter.get_output_details()[0]["index"]

  # Run predictions on every image in the "test" dataset.
  prediction_digits = []
  for test_image in test_images:
    # Pre-processing: add batch dimension and convert to float32 to match with
    # the model's input data format.
    test_image = np.expand_dims(test_image, axis=0).astype(np.float32)
    interpreter.set_tensor(input_index, test_image)

    # Run inference.
    interpreter.invoke()

    # Post-processing: remove batch dimension and find the digit with highest
    # probability.
    output = interpreter.tensor(output_index)
    digit = np.argmax(output()[0])
    prediction_digits.append(digit)

  # Compare prediction results with ground truth labels to calculate accuracy.
  accurate_count = 0
  for index in range(len(prediction_digits)):
    if prediction_digits[index] == test_labels[index]:
      accurate_count += 1
  accuracy = accurate_count * 1.0 / len(prediction_digits)

  return accuracy
print(evaluate_model(interpreter))
0.9664

Repita la evaluación en el modelo cuantificado 16x8:

# NOTE: This quantization mode is an experimental post-training mode,
# it does not have any optimized kernels implementations or
# specialized machine learning hardware accelerators. Therefore,
# it could be slower than the float interpreter.
print(evaluate_model(interpreter_16x8))
0.9662

En este ejemplo, ha cuantificado un modelo a 16x8 sin diferencia en la precisión, pero con el tamaño reducido 3x.