![]() | ![]() | ![]() | ![]() |
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)
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)
É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.