La quantification post-entraînement est une technique de conversion permettant de réduire la taille du modèle tout en améliorant la latence du processeur et de l'accélérateur matériel, la dégradation de la justesse du modèle. Vous pouvez quantifier une valeur flottante déjà entraînée modèle TensorFlow lorsque vous le convertissez au format LiteRT à l'aide de la Convertisseur LiteRT :
Méthodes d'optimisation
Plusieurs options de quantification post-entraînement sont disponibles. Voici un tableau récapitulatif des choix et des avantages qu'ils offrent:
Technique | Avantages | Matériel |
---|---|---|
Plage dynamique quantification | 4 fois plus petit, 2x-3x plus rapide | Processeur |
Nombre entier quantification | 4x plus petit, 3x+ vitesse | CPU, Edge TPU, Microcontrôleurs |
Quantification Float16 | 2 fois plus petit, GPU accélération | Processeur, GPU |
L'arbre de décision suivant peut vous aider à déterminer quelle quantification post-entraînement la mieux adaptée à votre cas d'utilisation:
Aucune quantification
Nous vous recommandons de commencer par passer à un modèle TFLite sans quantification point d'accès. Un modèle TFLite avec float sera alors généré.
import tensorflow as tf converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir) tflite_quant_model = converter.convert()
Nous vous recommandons de commencer par vérifier que la configuration d'origine Les opérateurs du modèle TF sont compatibles avec TFLite et peuvent également être utilisés référence pour déboguer les erreurs de quantification introduites par les post-entraînements ultérieurs méthodes de quantification. Par exemple, si un modèle TFLite quantifié produit des résultats inattendus, alors que le modèle TFLite de float est précis, nous pouvons affiner le problème aux erreurs introduites par la version quantifiée des opérateurs TFLite.
Quantification de plage dynamique
La quantification dynamique permet de réduire l'utilisation de la mémoire et d'accélérer les calculs sans avoir à fournir un ensemble de données représentatif pour l'étalonnage. Ce type de quantification, ne quantifie statique que les pondérations à partir des valeurs à virgule flottante en nombre entier au moment de la conversion, ce qui donne 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()
Pour réduire davantage la latence lors de l'inférence, "dynamique" opérateurs quantifient dynamiquement les activations selon leur portée (jusqu'à 8 bits) et effectuent avec des pondérations et des activations de 8 bits. Cette optimisation permet des latences proches des inférences à point fixe entièrement fixes. Cependant, les résultats sont toujours stockées à l'aide de la virgule flottante, de sorte que l'augmentation de la vitesse des opérations de plage dynamique est plus faible qu'un calcul complet à point fixe.
Quantification complète
Vous pouvez encore améliorer la latence, réduire les pics d'utilisation de la mémoire et la compatibilité avec des périphériques matériels ou des accélérateurs utilisant uniquement des entiers en s'assurant toutes les opérations mathématiques du modèle sont quantifiées sous forme d'entiers.
Pour la quantification complète, vous devez calibrer ou estimer la plage.
Exemple : (min, max) de tous les Tensors à virgule flottante du modèle. À la différence d'une constante
les Tensors comme les pondérations et les biais, les Tensors variables comme l'entrée du modèle,
(sorties des couches intermédiaires) et la sortie du modèle ne peuvent pas
à moins d'exécuter quelques cycles d'inférence. Par conséquent, le convertisseur
nécessite un jeu de données
représentatif pour les calibrer. Ce jeu de données
peut être un petit
(environ 100 à 500 échantillons) de données d'entraînement ou de validation. Consultez
la fonction representative_dataset()
ci-dessous.
À partir de la version 2.7 de TensorFlow, vous pouvez spécifier l'ensemble de données représentatif via Une signature, comme dans l'exemple suivant:
def representative_dataset(): for data in dataset: yield { "image": data.image, "bias": data.bias, }
S'il y a plusieurs signatures dans le modèle TensorFlow donné, vous pouvez Spécifiez les différents ensembles de données en spécifiant les clés de signature:
def representative_dataset(): # Feed data set for the "encode" signature. for data in encode_signature_dataset: yield ( "encode", { "image": data.image, "bias": data.bias, } ) # Feed data set for the "decode" signature. for data in decode_signature_dataset: yield ( "decode", { "image": data.image, "hint": data.hint, }, )
Vous pouvez générer l'ensemble de données représentatif en fournissant une liste de Tensors d'entrée:
def representative_dataset(): for data in tf.data.Dataset.from_tensor_slices((images)).batch(1).take(100): yield [tf.dtypes.cast(data, tf.float32)]
Depuis la version 2.7 de TensorFlow, nous vous recommandons d'utiliser l'approche basée sur la signature sur l'approche basée sur une liste de Tensors d'entrée, car l'ordre des Tensors d'entrée peut qu'on peut facilement retourner.
À 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 création de remplacement de type float (utilisation de l'entrée/sortie de type float par défaut)
Pour quantifier un modèle sous forme d'entier complet, mais utiliser des opérateurs à virgule flottante lorsqu'ils n'utilisez pas de nombre entier (pour garantir le bon déroulement des conversions), utilisez 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
Créer des modèles ne comportant que des entiers est un cas d'utilisation courant de LiteRT pour Microcontrôleurs et Corail Edge TPU.
De plus, pour assurer la compatibilité avec les appareils utilisant uniquement des entiers (comme les disques 8 bits des microcontrôleurs) et des accélérateurs (tels que le TPU Coral Edge), vous pouvez appliquer une quantification complète des nombres entiers pour toutes les opérations, y compris les entrées et les sorties, en utilisant 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 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 ses pondérations à float16, la norme IEEE pour les nombres à virgule flottante 16 bits. Pour activer float16 des pondérations, 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 de moitié (puisque toutes les pondérations deviennent la moitié de la taille d'origine).
- Elle entraîne une perte de précision minimale.
- Il accepte certains délégués (comme le délégué de GPU) qui peuvent fonctionner directement sur les données float16, ce qui permet une exécution plus rapide que float32 des calculs.
Les inconvénients de la quantification float16 sont les suivants:
- Elle ne réduit pas la latence autant qu'une quantification sur des opérations mathématiques à point fixe.
- Par défaut, un modèle quantifié float16 "déquantifie" les valeurs des pondérations à float32 lorsqu’elle est exécutée sur le CPU. (Notez que le délégué de GPU n'effectue pas cette déquantification, car elle peut fonctionner sur des données float16.)
Entier uniquement: activations 16 bits avec des pondérations de 8 bits (expérimental)
Il s'agit d'un schéma de quantification expérimental. Il est similaire au "nombre entier uniquement" mais les activations sont quantifiées en fonction de leur plage de pondérations (16 bits) sont quantifiées en entier 8 bits et les biais sont quantifiées en entiers de 64 bits. Ce est encore appelée quantification 16x8.
Le principal avantage de cette quantification est qu'elle peut améliorer la précision de façon significative, mais n'augmentent 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 compatible avec certains opérateurs du modèle, peuvent toujours être quantifiées, mais les opérateurs non compatibles sont conservés dans une valeur flottante. La 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ù l'amélioration de la précision schéma de quantification incluent:
- haute résolution,
- le traitement du signal audio, comme la suppression du bruit et le beamforming,
- la suppression du bruit dans les images,
- Reconstitution HDR à partir d'une seule image.
L'inconvénient de cette quantification est le suivant:
- Actuellement, l'inférence est nettement plus lente qu'un nombre entier de 8 bits en raison de la l'absence d'implémentation optimisée du noyau.
- Actuellement, il est incompatible avec le TFLite avec accélération matérielle existante. délégués.
Un tutoriel sur ce mode de quantification est disponible cliquez ici.
Précision du modèle
Les pondérations étant quantifiées après l'entraînement, il peut y avoir une perte de justesse. en particulier pour les petits réseaux. Les modèles pré-entraînés entièrement quantifiés fournis pour des réseaux spécifiques sur Kaggle Modèles pour en savoir plus. Il est important de vérifier la justesse du modèle quantifié toute dégradation de la précision est dans des limites acceptables. Il existe des outils pour évaluer le modèle LiteRT précision.
Si la baisse de justesse est trop importante, envisagez d'utiliser la quantification. savoir formation pour en savoir plus. Toutefois, cela nécessite des modifications lors de l'entraînement du modèle pour ajouter les nœuds de quantification, tandis que les techniques de quantification post-entraînement utilisez un modèle pré-entraîné existant.
Représentation de Tensors quantifiés
La quantification sur 8 bits se rapproche des valeurs à virgule flottante à l'aide des éléments suivants : formule.
\[real\_value = (int8\_value - zero\_point) \times scale\]
La représentation comporte deux parties principales:
Pondérations par axe (ou canal) ou par Tensor représentées par des valeurs de type int8 2 valeurs complémentaires comprises dans la plage [-127, 127] avec un point zéro égal à 0.
Activations/entrées par Tensor représentées par les valeurs complémentaires de int8 2 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, consultez notre article sur la quantification. caractéristiques. Les fournisseurs de matériel souhaitant se connecter à TensorFlow Nous vous encourageons à utiliser l'interface déléguée de Lite pour implémenter le schéma de quantification. décrites ici.