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 float16 post-entraînement

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 poids en valeurs à virgule flottante 16 bits lors de la conversion du modèle de TensorFlow au format de tampon plat de TensorFlow Lite. Cela se traduit par une réduction de 2x 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 en virgule flottante traditionnelle. 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 fonctionner 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 tampon plat Tensorflow Lite avec quantification float16. Enfin, vérifiez la précision 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
tf.float16
tf.float16

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 [==============================] - 15s 2ms/step - loss: 0.5048 - accuracy: 0.8596 - val_loss: 0.1465 - val_accuracy: 0.9598

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

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.

TFLiteConverter maintenant le modèle à l'aide du TFLiteConverter :

converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
INFO:tensorflow:Assets written to: /tmp/tmphrlr_scf/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)
84488

Pour quantifier à la place le modèle en float16 lors de l'exportation, définissez d'abord l'indicateur d' optimizations pour utiliser les optimisations par défaut. Spécifiez ensuite 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 les 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/tmpexbkmgd6/assets

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

44320

Notez que le fichier résultant fait environ la 1/2 la taille.

ls -lh {tflite_models_dir}
total 128K
-rw-rw-r-- 1 kbuilder kbuilder 83K Dec 17 20:21 mnist_model.tflite
-rw-rw-r-- 1 kbuilder kbuilder 44K Dec 17 20:21 mnist_model_quant_f16.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_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.9598

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

Dans cet exemple, vous avez quantifié un modèle sur 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 la structure TfLiteGPUDelegateOptions dans votre application et de définir precision_loss_allowed sur 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 peut être trouvée ici