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 soporta la conversión de activaciones para valores enteros de 16 bits y los pesos de 8-bit número entero valores durante la conversión de modelo de TensorFlow a formato tampón plana 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)
)
1875/1875 [==============================] - 6s 2ms/step - loss: 0.2797 - accuracy: 0.9224 - val_loss: 0.1224 - val_accuracy: 0.9641
<keras.callbacks.History at 0x7f6f19eff210>

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

Utilizando el pitón TFLiteConverter , ahora se puede convertir el modelo entrenado en un modelo TensorFlow Lite.

Ahora, convertir el modelo usando TFliteConverter en formato float32 por defecto:

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
2021-10-30 11:55:42.971843: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/tmpbriefkal/assets
2021-10-30 11:55:43.402148: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 11:55:43.402187: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.

Escribirlo a un .tflite archivo:

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)
84500

Para cuantificar lugar el modelo de 16x8 modo de cuantificación, establecido por primera vez la optimizations la bandera de optimizaciones uso por defecto. 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 int8 cuantificación post-formación, es posible producir un modelo totalmente número entero cuantificado mediante el establecimiento de opciones del convertidor inference_input(output)_type a 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/tmpfxn_2jql/assets
INFO:tensorflow:Assets written to: /tmp/tmpfxn_2jql/assets
2021-10-30 11:55:44.514461: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 11:55:44.514507: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.
24768

Nótese cómo el archivo resultante es aproximadamente 1/3 del tamaño.

ls -lh {tflite_models_dir}
total 136K
-rw-rw-r-- 1 kbuilder kbuilder 83K Oct 30 11:55 mnist_model.tflite
-rw-rw-r-- 1 kbuilder kbuilder 24K Oct 30 11:54 mnist_model_quant.tflite
-rw-rw-r-- 1 kbuilder kbuilder 25K Oct 30 11:55 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.9641

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.964

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

,

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

Descripción general

TensorFlow Lite ahora soporta la conversión de activaciones para valores enteros de 16 bits y los pesos de 8-bit número entero valores durante la conversión de modelo de TensorFlow a formato tampón plana 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)
)
1875/1875 [==============================] - 6s 2ms/step - loss: 0.2797 - accuracy: 0.9224 - val_loss: 0.1224 - val_accuracy: 0.9641
<keras.callbacks.History at 0x7f6f19eff210>

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

Utilizando el pitón TFLiteConverter , ahora se puede convertir el modelo entrenado en un modelo TensorFlow Lite.

Ahora, convertir el modelo usando TFliteConverter en formato float32 por defecto:

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
2021-10-30 11:55:42.971843: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/tmpbriefkal/assets
2021-10-30 11:55:43.402148: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 11:55:43.402187: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.

Escribirlo a un .tflite archivo:

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)
84500

Para cuantificar lugar el modelo de 16x8 modo de cuantificación, establecido por primera vez la optimizations la bandera de optimizaciones uso por defecto. 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 int8 cuantificación post-formación, es posible producir un modelo totalmente número entero cuantificado mediante el establecimiento de opciones del convertidor inference_input(output)_type a 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/tmpfxn_2jql/assets
INFO:tensorflow:Assets written to: /tmp/tmpfxn_2jql/assets
2021-10-30 11:55:44.514461: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:351] Ignored output_format.
2021-10-30 11:55:44.514507: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:354] Ignored drop_control_dependency.
24768

Nótese cómo el archivo resultante es aproximadamente 1/3 del tamaño.

ls -lh {tflite_models_dir}
total 136K
-rw-rw-r-- 1 kbuilder kbuilder 83K Oct 30 11:55 mnist_model.tflite
-rw-rw-r-- 1 kbuilder kbuilder 24K Oct 30 11:54 mnist_model_quant.tflite
-rw-rw-r-- 1 kbuilder kbuilder 25K Oct 30 11:55 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.9641

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.964

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