RSVP pour votre événement TensorFlow Everywhere local dès aujourd'hui!
Cette page a été traduite par l'API Cloud Translation.
Switch to English

Quantification d'entiers post-entraînement avec activations int16

Voir sur TensorFlow.org Exécuter dans Google Colab Afficher la source sur GitHub Télécharger le carnet

Aperçu

TensorFlow Lite prend désormais en charge la conversion des activations en valeurs entières 16 bits et des pondérations en valeurs entières 8 bits lors de la conversion de modèle de TensorFlow au format de tampon plat de TensorFlow Lite. Nous appelons ce mode le "mode de quantification 16x8". Ce mode peut améliorer considérablement la précision du modèle quantifié, lorsque les activations sont sensibles à la quantification, tout en permettant une réduction de presque 3 à 4 fois la taille du modèle. De plus, ce modèle entièrement quantifié peut être utilisé par des accélérateurs matériels uniquement entiers.

Voici quelques exemples de modèles qui bénéficient de ce mode de quantification post-formation:

  • super-résolution,
  • traitement du signal audio tel que la suppression du bruit et la formation de faisceaux,
  • suppression du bruit d'image,
  • Reconstruction HDR à partir d'une seule image

Dans ce didacticiel, vous entraînez un modèle MNIST à partir de zéro, vérifiez sa précision dans TensorFlow, puis convertissez le modèle en tampon plat Tensorflow Lite à l'aide de ce mode. À la fin, vous vérifiez la précision du modèle converti et comparez-le au modèle float32 d'origine. Notez que cet exemple illustre l'utilisation de ce mode et ne présente aucun avantage par rapport aux autres techniques de quantification disponibles dans TensorFlow Lite.

Construire un modèle MNIST

Installer

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

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

Vérifiez que le mode de quantification 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'>

Former et exporter le modèle

# 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 [==============================] - 4s 2ms/step - loss: 0.2762 - accuracy: 0.9227 - val_loss: 0.1264 - val_accuracy: 0.9623

<tensorflow.python.keras.callbacks.History at 0x7ff30d818d68>

Pour l'exemple, vous avez entraîné le modèle pour une seule époque, de sorte qu'il ne s'entraîne qu'avec une précision d'environ 96%.

Conversion en modèle TensorFlow Lite

À l'aide de Python TFLiteConverter , vous pouvez désormais convertir le modèle entraîné en modèle TensorFlow Lite.

Maintenant, convertissez le modèle à l'aide de TFliteConverter au format float32 par défaut:

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
INFO:tensorflow:Assets written to: /tmp/tmp9n8j08tn/assets

Écrivez-le dans un fichier .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)
84452

Pour quantifier à la place le modèle en mode de quantification 16x8, définissez d'abord l'indicateur d' optimizations pour utiliser les optimisations par défaut. Spécifiez ensuite que le mode de quantification 16x8 est l'opération prise en charge requise dans la spécification cible:

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

Comme dans le cas de la quantification post-apprentissage int8, il est possible de produire un modèle quantifié entièrement entier en définissant les options du convertisseur inference_input(output)_type sur tf.int16.

Définissez les données d'étalonnage:

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

Enfin, convertissez le modèle comme d'habitude. Notez que par défaut, le modèle converti utilisera toujours les entrées et les sorties flottantes pour faciliter l'invocation.

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/tmpx5tq2f5a/assets

INFO:tensorflow:Assets written to: /tmp/tmpx5tq2f5a/assets

24720

Notez que le fichier résultant a environ 1/3 la taille.

ls -lh {tflite_models_dir}
total 112K
-rw-rw-r-- 1 kbuilder kbuilder 83K Nov 24 12:14 mnist_model.tflite
-rw-rw-r-- 1 kbuilder kbuilder 25K Nov 24 12:14 mnist_model_quant_16x8.tflite

Exécutez les modèles TensorFlow Lite

Exécutez le modèle TensorFlow Lite à l'aide de l'interpréteur Python TensorFlow Lite.

Chargez le modèle dans les interpréteurs

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

Testez les modèles sur une image

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

Évaluer les modèles

# 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.9623

Répétez l'évaluation sur le modèle quantifié 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.9622

Dans cet exemple, vous avez quantifié un modèle en 16x8 sans différence de précision, mais avec une taille réduite 3x.