Réserve cette date! Google I / O revient du 18 au 20 mai S'inscrire maintenant
Cette page a été traduite par l'API Cloud Translation.
Switch to English

Quantification post-formation

La quantification post-entraînement est une technique de conversion qui peut réduire la taille du modèle tout en améliorant la latence du processeur et de l'accélérateur matériel, avec une faible dégradation de la précision du modèle. Vous pouvez quantifier un modèle TensorFlow flottant déjà entraîné lorsque vous le convertissez au format TensorFlow Lite à l'aide du convertisseur TensorFlow Lite .

Méthodes d'optimisation

Il existe plusieurs options de quantification post-formation parmi lesquelles choisir. Voici un tableau récapitulatif des choix et des avantages qu'ils procurent:

Technique Avantages Matériel
Quantification de la plage dynamique 4x plus petit, accélération 2x-3x CPU
Quantification entière entière 4x plus petit, 3x + accélération CPU, Edge TPU, microcontrôleurs
Quantification Float16 Accélération GPU 2x plus petite Processeur, GPU

L'arbre de décision suivant peut vous aider à déterminer la méthode de quantification post-entraînement la mieux adaptée à votre cas d'utilisation:

options d'optimisation post-formation

Quantification de la plage dynamique

La forme la plus simple de quantification post-entraînement ne quantifie statiquement que les poids de la virgule flottante à l'entier, qui a une précision de 8 bits:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_quant_model = converter.convert()

Lors de l'inférence, les poids sont convertis de 8 bits de précision en virgule flottante et calculés à l'aide de noyaux à virgule flottante. Cette conversion est effectuée une fois et mise en cache pour réduire la latence.

Pour améliorer encore la latence, les opérateurs de «plage dynamique» quantifient dynamiquement les activations en fonction de leur plage de 8 bits et effectuent des calculs avec des pondérations et activations de 8 bits. Cette optimisation fournit des latences proches de l'inférence en virgule fixe. Cependant, les sorties sont toujours stockées en virgule flottante de sorte que l'accélération avec les opérations de plage dynamique soit inférieure à un calcul en virgule fixe complet.

Quantification entière entière

Vous pouvez obtenir d'autres améliorations de la latence, des réductions de l'utilisation maximale de la mémoire et la compatibilité avec des périphériques matériels ou des accélérateurs de nombres entiers uniquement en vous assurant que toutes les mathématiques du modèle sont quantifiées en nombres entiers.

Pour une quantification entière, vous devez calibrer ou estimer la plage, c'est-à-dire (min, max) de tous les tenseurs à virgule flottante dans le modèle. Contrairement aux tenseurs constants tels que les poids et les biais, les tenseurs variables tels que l'entrée du modèle, les activations (sorties des couches intermédiaires) et la sortie du modèle ne peuvent pas être calibrés à moins d'exécuter quelques cycles d'inférence. En conséquence, le convertisseur a besoin d'un ensemble de données représentatif pour les étalonner. Cet ensemble de données peut être un petit sous-ensemble (environ 100 à 500 échantillons) des données d'apprentissage ou de validation. Reportez-vous à la fonction representative_dataset() ci-dessous.

def representative_dataset():
  for data in tf.data.Dataset.from_tensor_slices((images)).batch(1).take(100):
    yield [tf.dtypes.cast(data, tf.float32)]

À des fins de test, vous pouvez utiliser un ensemble de données factice comme suit:

def representative_dataset():
    for _ in range(100):
      data = np.random.rand(1, 244, 244, 3)
      yield [data.astype(np.float32)]
 

Entier avec repli flottant (en utilisant l'entrée / sortie flottante par défaut)

Afin de quantifier entièrement un modèle en entier, mais utilisez des opérateurs flottants lorsqu'ils n'ont pas d'implémentation d'entiers (pour garantir que la conversion se déroule sans heurts), procédez comme suit:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
tflite_quant_model = converter.convert()

Entier uniquement

La création de modèles de type entier uniquement est un cas d'utilisation courant de TensorFlow Lite for Microcontrollers et des TPU Coral Edge .

De plus, pour assurer la compatibilité avec les périphériques uniquement entiers (tels que les microcontrôleurs 8 bits) et les accélérateurs (tels que le Coral Edge TPU), vous pouvez appliquer la quantification complète des entiers pour toutes les opérations, y compris l'entrée et la sortie, en suivant les étapes suivantes:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8  # or tf.uint8
converter.inference_output_type = tf.int8  # or tf.uint8
tflite_quant_model = converter.convert()

Quantification Float16

Vous pouvez réduire la taille d'un modèle à virgule flottante en quantifiant les poids à float16, la norme IEEE pour les nombres à virgule flottante 16 bits. Pour activer la quantification float16 des poids, procédez comme suit:

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]
tflite_quant_model = converter.convert()

Les avantages de la quantification float16 sont les suivants:

  • Il réduit la taille du modèle jusqu'à la moitié (puisque tous les poids deviennent la moitié de leur taille d'origine).
  • Cela entraîne une perte de précision minimale.
  • Il prend en charge certains délégués (par exemple le délégué GPU) qui peuvent opérer directement sur les données float16, ce qui se traduit par une exécution plus rapide que les calculs float32.

Les inconvénients de la quantification float16 sont les suivants:

  • Il ne réduit pas autant la latence qu'une quantification en maths en virgule fixe.
  • Par défaut, un modèle quantifié float16 "déquantifiera" les valeurs de poids en float32 lorsqu'il est exécuté sur le CPU. (Notez que le délégué GPU n'effectuera pas cette déquantification, car il peut fonctionner sur des données float16.)

Entier uniquement: activations 16 bits avec pondérations 8 bits (expérimental)

Il s'agit d'un schéma de quantification expérimental. Il est similaire au schéma "entier uniquement", mais les activations sont quantifiées en fonction de leur plage de 16 bits, les poids sont quantifiés en entier de 8 bits et le biais est quantifié en entier de 64 bits. Ceci est également appelé quantification 16x8.

Le principal avantage de cette quantification est qu'elle peut améliorer la précision de manière significative, mais n'augmente que légèrement la taille du modèle.

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]
tflite_quant_model = converter.convert()

Si la quantification 16x8 n'est pas prise en charge pour certains opérateurs du modèle, le modèle peut toujours être quantifié, mais les opérateurs non pris en charge sont conservés dans float. L'option suivante doit être ajoutée à target_spec pour permettre cela.

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8,
tf.lite.OpsSet.TFLITE_BUILTINS]
tflite_quant_model = converter.convert()

Exemples de cas d'utilisation où les améliorations de précision fournies par ce schéma de quantification incluent: * super-résolution, * traitement du signal audio tel que la suppression du bruit et la formation de faisceau, * la suppression du bruit d'image, * la reconstruction HDR à partir d'une seule image.

L'inconvénient de cette quantification est:

  • Actuellement, l'inférence est nettement plus lente qu'un entier complet de 8 bits en raison du manque d'implémentation optimisée du noyau.
  • Actuellement, il est incompatible avec les délégués TFLite accélérés par matériel existants.

Un tutoriel pour ce mode de quantification peut être trouvé ici .

Précision du modèle

Puisque les poids sont quantifiés après l'entraînement, il pourrait y avoir une perte de précision, en particulier pour les petits réseaux. Des modèles entièrement quantifiés pré-entraînés sont fournis pour des réseaux spécifiques dans le référentiel de modèles TensorFlow Lite . Il est important de vérifier l'exactitude du modèle quantifié pour vérifier que toute dégradation de l'exactitude se situe dans des limites acceptables. Il existe des outils pour évaluer la précision du modèle TensorFlow Lite .

Sinon, si la baisse de précision est trop élevée, envisagez d'utiliser un entraînement prenant en charge la quantification . Cependant, cela nécessite des modifications pendant l'entraînement du modèle pour ajouter de faux nœuds de quantification, alors que les techniques de quantification post-entraînement de cette page utilisent un modèle pré-entraîné existant.

Représentation pour les tenseurs quantifiés

La quantification 8 bits se rapproche des valeurs en virgule flottante en utilisant la formule suivante.

$$real\_value = (int8\_value - zero\_point) \times scale$$

La représentation comprend deux parties principales:

  • Poids par axe (alias par canal) ou par tenseur représentés par des valeurs de complément à deux int8 dans la plage [-127, 127] avec un point zéro égal à 0.

  • Activations / entrées par tenseur représentées par des valeurs de complément à deux int8 dans la plage [-128, 127], avec un point zéro dans la plage [-128, 127].

Pour une vue détaillée de notre schéma de quantification, veuillez consulter nos spécifications de quantification . Les fournisseurs de matériel qui souhaitent se connecter à l'interface déléguée de TensorFlow Lite sont encouragés à mettre en œuvre le schéma de quantification décrit ici.