Quantification float16 post-entraînement

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

Aperçu

Tensorflow Lite supporte maintenant le poids de conversion de valeurs à virgule flottante de 16 bits lors de la conversion du modèle de tensorflow au format tampon plat de tensorflow Lite. Cela se traduit par une réduction de 2 fois de la taille du modèle. Certains matériels, comme les GPU, peuvent calculer nativement dans cette arithmétique à précision réduite, réalisant une accélération par rapport à l'exécution traditionnelle en virgule flottante. Le délégué GPU Tensorflow Lite peut être configuré pour s'exécuter de cette manière. Cependant, un modèle converti en poids float16 peut toujours s'exécuter sur le processeur sans modification supplémentaire : les poids float16 sont suréchantillonnés en float32 avant la première inférence. Cela permet une réduction significative de la taille du modèle en échange d'un impact minimal sur la latence et la précision.

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 un flatbuffer Tensorflow Lite avec quantification float16. Enfin, vérifiez l'exactitude du modèle converti et comparez-le au modèle float32 d'origine.

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

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
11501568/11490434 [==============================] - 0s 0us/step
1875/1875 [==============================] - 13s 2ms/step - loss: 0.2655 - accuracy: 0.9244 - val_loss: 0.1237 - val_accuracy: 0.9654
<keras.callbacks.History at 0x7f3f8428e6d0>

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

Convertir en un modèle TensorFlow Lite

En utilisant Python TFLiteConverter , vous pouvez convertir le modèle formé dans un modèle tensorflow Lite.

Maintenant charger le modèle en utilisant la TFLiteConverter :

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
2021-12-14 12:18:07.073783: 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/tmpm1s3vkrd/assets
2021-12-14 12:18:07.876066: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-12-14 12:18:07.876112: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
WARNING:absl:Buffer deduplication procedure will be skipped when flatbuffer library is not properly loaded

Écrivez-un .tflite fichier:

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

Pour le modèle à la place quantifie à float16 à l' exportation, d' abord définir les optimizations drapeau à l' utilisation des optimisations par défaut. Ensuite, spécifiez que float16 est le type pris en charge sur la plate-forme cible :

converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]

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

tflite_fp16_model = converter.convert()
tflite_model_fp16_file = tflite_models_dir/"mnist_model_quant_f16.tflite"
tflite_model_fp16_file.write_bytes(tflite_fp16_model)
INFO:tensorflow:Assets written to: /tmp/tmpvjt9l68i/assets
INFO:tensorflow:Assets written to: /tmp/tmpvjt9l68i/assets
2021-12-14 12:18:08.810262: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:363] Ignored output_format.
2021-12-14 12:18:08.810303: W tensorflow/compiler/mlir/lite/python/tf_tfl_flatbuffer_helpers.cc:366] Ignored drop_control_dependency.
WARNING:absl:Buffer deduplication procedure will be skipped when flatbuffer library is not properly loaded
44384

Notez comment le fichier obtenu est d' environ 1/2 de la taille.

ls -lh {tflite_models_dir}
total 128K
-rw-rw-r-- 1 kbuilder kbuilder 83K Dec 14 12:18 mnist_model.tflite
-rw-rw-r-- 1 kbuilder kbuilder 44K Dec 14 12:18 mnist_model_quant_f16.tflite

Exécuter les modèles TensorFlow Lite

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

Charger le modèle dans les interpréteurs

interpreter = tf.lite.Interpreter(model_path=str(tflite_model_file))
interpreter.allocate_tensors()
interpreter_fp16 = tf.lite.Interpreter(model_path=str(tflite_model_fp16_file))
interpreter_fp16.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_fp16.get_input_details()[0]["index"]
output_index = interpreter_fp16.get_output_details()[0]["index"]

interpreter_fp16.set_tensor(input_index, test_image)
interpreter_fp16.invoke()
predictions = interpreter_fp16.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.9654

Répétez l'évaluation sur le modèle quantifié float16 pour obtenir :

# NOTE: Colab runs on server CPUs. At the time of writing this, TensorFlow Lite
# doesn't have super optimized server CPU kernels. For this reason this may be
# slower than the above float interpreter. But for mobile CPUs, considerable
# speedup can be observed.
print(evaluate_model(interpreter_fp16))
0.9654

Dans cet exemple, vous avez quantifié un modèle à float16 sans différence de précision.

Il est également possible d'évaluer le modèle quantifié fp16 sur le GPU. Pour effectuer toutes les opérations arithmétiques avec les valeurs de précision réduites, assurez - vous de créer les TfLiteGPUDelegateOptions struct dans votre application et ensemble precision_loss_allowed à 1 , comme ceci:

//Prepare GPU delegate.
const TfLiteGpuDelegateOptions options = {
  .metadata = NULL,
  .compile_options = {
    .precision_loss_allowed = 1,  // FP16
    .preferred_gl_object_type = TFLITE_GL_OBJECT_TYPE_FASTEST,
    .dynamic_batch_enabled = 0,   // Not fully functional yet
  },
};

Une documentation détaillée sur le délégué GPU TFLite et comment l'utiliser dans votre application se trouve ici