Ajouter des métadonnées aux modèles TensorFlow Lite

Les métadonnées TensorFlow Lite fournissent une norme pour les descriptions de modèles. Les métadonnées sont une importante source de connaissances sur les actions du modèle et sur ses informations d'entrée et de sortie. Les métadonnées comprennent à la fois

Tous les modèles d'images publiés sur les modèles Kaggle ont été remplis de métadonnées.

Modèle avec format de métadonnées

model_with_metadata
Figure 1. Modèle TFLite avec les métadonnées et les fichiers associés.

Les métadonnées du modèle sont définies dans metadata_schema.fbs, un fichier FlatBuffer. Comme le montre la figure 1, il est stocké dans le champ metadata (métadonnées) du schéma de modèle TFLite, sous le nom "TFLITE_METADATA". Certains modèles peuvent être associés à des fichiers, tels que des fichiers d'étiquettes de classification. Ces fichiers sont concaténés à la fin du fichier de modèle d'origine en tant que fichier ZIP à l'aide du mode "append" (mode 'a') de ZipFile. L'interpréteur TFLite peut utiliser le nouveau format de fichier de la même manière qu'auparavant. Pour en savoir plus, consultez la section Empaqueter les fichiers associés.

Consultez les instructions ci-dessous pour découvrir comment renseigner, visualiser et lire les métadonnées.

Configurer les outils de métadonnées

Avant d'ajouter des métadonnées à votre modèle, vous devez configurer un environnement de programmation Python pour exécuter TensorFlow. Vous trouverez un guide détaillé sur la façon de procéder sur cette page.

Après avoir configuré l'environnement de programmation Python, vous devez installer des outils supplémentaires:

pip install tflite-support

Les outils de métadonnées TensorFlow Lite sont compatibles avec Python 3.

Ajouter des métadonnées à l'aide de l'API Python Flatbuffers

Les métadonnées de modèle se composent de trois parties dans le schéma:

  1. Informations sur le modèle : description générale du modèle et éléments tels que les conditions de licence. Consultez ModelMetadata.
    1. Informations d'entrée : description des entrées et du prétraitement requis, tels que la normalisation. Consultez SubGraphMetadata.input_tensor_metadata.
      1. Informations de sortie : description des résultats et du post-traitement requis, par exemple leur mappage sur les étiquettes. Consultez SubGraphMetadata.output_tensor_metadata.

TensorFlow Lite n'acceptant qu'un seul sous-graphe pour le moment, le générateur de code TensorFlow Lite et la fonctionnalité de liaison ML d'Android Studio utiliseront ModelMetadata.name et ModelMetadata.description, au lieu de SubGraphMetadata.name et SubGraphMetadata.description, pour afficher les métadonnées et générer du code.

Types d'entrées / sorties compatibles

Les métadonnées TensorFlow Lite pour les entrées et les sorties ne sont pas conçues pour des types de modèles spécifiques, mais pour des types d'entrée et de sortie. Peu importe la fonction fonctionnelle du modèle. Tant que les types d'entrée et de sortie se composent des éléments suivants ou d'une combinaison des éléments suivants, ils sont compatibles avec les métadonnées TensorFlow Lite:

  • Fonctionnalité - Nombres qui sont des entiers non signés ou des valeurs float32.
  • Image : les métadonnées sont actuellement compatibles avec les images RVB et en niveaux de gris.
  • Cadre de délimitation : cadres de délimitation de forme rectangulaire. Le schéma est compatible avec différents schémas de numérotation.

Empaqueter les fichiers associés

Les modèles TensorFlow Lite peuvent être associés à différents fichiers. Par exemple, les modèles de langage naturel comportent généralement des fichiers de vocabulaire qui mappent des éléments de mot à des ID de mots. Les modèles de classification peuvent comporter des fichiers d'étiquettes qui indiquent des catégories d'objets. Sans les fichiers associés (s'il y en a), un modèle ne fonctionnera pas correctement.

Les fichiers associés peuvent désormais être regroupés avec le modèle via la bibliothèque de métadonnées Python. Le nouveau modèle TensorFlow Lite devient un fichier ZIP contenant à la fois le modèle et les fichiers associés. Vous pouvez le décompresser à l'aide des outils ZIP courants. Ce nouveau format de modèle continue à utiliser la même extension de fichier, .tflite. Il est compatible avec le framework et l'interpréteur TFLite existants. Pour en savoir plus, consultez la section Empaqueter les métadonnées et les fichiers associés dans le modèle.

Les informations du fichier associé peuvent être enregistrées dans les métadonnées. En fonction du type de fichier et de l'emplacement auquel il est associé (par exemple, ModelMetadata, SubGraphMetadata et TensorMetadata), le générateur de code Android TensorFlow Lite peut appliquer automatiquement le prétraitement/post-traitement correspondant à l'objet. Consultez la section <Codegen usage> de chaque type de fichier associé dans le schéma pour en savoir plus.

Paramètres de normalisation et de quantification

La normalisation est une technique courante de prétraitement des données dans le machine learning. L'objectif de la normalisation est de définir les valeurs sur une échelle commune, sans distorsion des différences au niveau des plages de valeurs.

La quantification de modèle est une technique qui permet de réduire la précision des représentations des pondérations et, éventuellement, d'activer les fonctionnalités de stockage et de calcul.

En termes de prétraitement et de post-traitement, la normalisation et la quantification sont deux étapes indépendantes. Voici les informations détaillées relatives à cet incident.

Normalization Quantification

Exemple de valeurs de paramètre de l'image d'entrée dans MobileNet pour les modèles float et quantitatifs, respectivement.
Modèle à virgule flottante:
- moyenne: 127,5
- std: 127,5
Modèle de quantit:
- moyenne: 127,5
- std: 127,5
Modèle à virgule flottante:
- zeroPoint: 0
- scale: 1.0
Modèle de quantification:
- zeroPoint: 128.0
- scale:0.0078125f




Quand appeler ?


Entrées: si les données d'entrée sont normalisées lors de l'entraînement, les données d'entrée d'inférence doivent être normalisées en conséquence.
Sorties: les données de sortie ne sont généralement pas normalisées.
Les modèles à virgule flottante n'ont pas besoin d'être quantifiés.
Le modèle quantifié peut nécessiter ou non une quantification lors du pré/post-traitement. Cela dépend du type de données des Tensors d'entrée/de sortie.
: Tensors à virgule flottante : aucune quantification en pré/post-traitement nécessaire. Les opérations quantiques et de quantification sont intégrées au graphe du modèle.
- Tensors int8/uint8 : une quantification est nécessaire en pré/post-traitement.


Formule


normalized_input = (entrée - moyenne) / std
Quantifier les entrées :
q = f / scale + zeroPoint
Déquantifier les résultats:
f = (q - zeroPoint) * scale

Où sont les paramètres
Rempli par le créateur du modèle et stocké dans les métadonnées du modèle, en tant que NormalizationOptions. Rempli automatiquement par le convertisseur TFLite et stocké dans le fichier de modèle tflite.
Comment récupérer les paramètres ? Via l'API MetadataExtractor[2] Via l'API Tensor TFLite[1] ou l'API MetadataExtractor[2]
Les modèles flottants et quantitatifs partagent-ils la même valeur ? Oui, les modèles de valeurs flottantes et quantitatives ont les mêmes paramètres de normalisation Non, le modèle flottant n'a pas besoin d'une quantification.
Le générateur de code TFLite ou la liaison ML d'Android Studio les génèrent-ils automatiquement lors du traitement des données ?
Oui

Oui

[1] L'API Java TensorFlow Lite et l'API TensorFlow Lite C++.
[2] La bibliothèque d'extracteurs de métadonnées

Lors du traitement des données d'image pour les modèles uint8, la normalisation et la quantification sont parfois ignorées. Cela ne pose aucun problème lorsque les valeurs en pixels sont comprises dans la plage [0, 255]. Mais en général, vous devez toujours traiter les données en fonction des paramètres de normalisation et de quantification, le cas échéant.

Exemples

Vous trouverez ci-dessous des exemples illustrant comment renseigner les métadonnées pour différents types de modèles:

Classification d'images

Téléchargez le script sur cette page, qui renseigne les métadonnées dans mobilenet_v1_0.75_160_quantized.tflite. Exécutez le script comme suit:

python ./metadata_writer_for_image_classifier.py \
    --model_file=./model_without_metadata/mobilenet_v1_0.75_160_quantized.tflite \
    --label_file=./model_without_metadata/labels.txt \
    --export_directory=model_with_metadata

Pour renseigner les métadonnées d'autres modèles de classification d'images, ajoutez les spécifications du modèle comme celle-ci dans le script. Le reste de ce guide met en évidence certaines des sections clés de l'exemple de classification d'images pour illustrer les éléments clés.

Présentation détaillée de l'exemple de classification d'images

Informations relatives au modèle

Les métadonnées commencent par créer les informations du modèle:

from tflite_support import flatbuffers
from tflite_support import metadata as _metadata
from tflite_support import metadata_schema_py_generated as _metadata_fb

""" ... """
"""Creates the metadata for an image classifier."""

# Creates model info.
model_meta = _metadata_fb.ModelMetadataT()
model_meta.name = "MobileNetV1 image classifier"
model_meta.description = ("Identify the most prominent object in the "
                          "image from a set of 1,001 categories such as "
                          "trees, animals, food, vehicles, person etc.")
model_meta.version = "v1"
model_meta.author = "TensorFlow"
model_meta.license = ("Apache License. Version 2.0 "
                      "http://www.apache.org/licenses/LICENSE-2.0.")

Informations d'entrée / de sortie

Cette section vous explique comment décrire la signature d'entrée et de sortie de votre modèle. Ces métadonnées peuvent être utilisées par les générateurs de code automatiques pour créer du code de prétraitement et de post-traitement. Pour créer des informations d'entrée ou de sortie concernant un Tensor, procédez comme suit:

# Creates input info.
input_meta = _metadata_fb.TensorMetadataT()

# Creates output info.
output_meta = _metadata_fb.TensorMetadataT()

Saisie d'image

L'image est un type d'entrée courant pour le machine learning. Les métadonnées TensorFlow Lite sont compatibles avec des informations telles que l'espace colorimétrique et des informations de prétraitement telles que la normalisation. La dimension de l'image ne nécessite pas de spécification manuelle, car elle est déjà fournie par la forme du Tensor d'entrée et peut être déduite automatiquement.

input_meta.name = "image"
input_meta.description = (
    "Input image to be classified. The expected image is {0} x {1}, with "
    "three channels (red, blue, and green) per pixel. Each value in the "
    "tensor is a single byte between 0 and 255.".format(160, 160))
input_meta.content = _metadata_fb.ContentT()
input_meta.content.contentProperties = _metadata_fb.ImagePropertiesT()
input_meta.content.contentProperties.colorSpace = (
    _metadata_fb.ColorSpaceType.RGB)
input_meta.content.contentPropertiesType = (
    _metadata_fb.ContentProperties.ImageProperties)
input_normalization = _metadata_fb.ProcessUnitT()
input_normalization.optionsType = (
    _metadata_fb.ProcessUnitOptions.NormalizationOptions)
input_normalization.options = _metadata_fb.NormalizationOptionsT()
input_normalization.options.mean = [127.5]
input_normalization.options.std = [127.5]
input_meta.processUnits = [input_normalization]
input_stats = _metadata_fb.StatsT()
input_stats.max = [255]
input_stats.min = [0]
input_meta.stats = input_stats

Sortie d'étiquette

L'étiquette peut être mappée à un Tensor de sortie via un fichier associé à l'aide de TENSOR_AXIS_LABELS.

# Creates output info.
output_meta = _metadata_fb.TensorMetadataT()
output_meta.name = "probability"
output_meta.description = "Probabilities of the 1001 labels respectively."
output_meta.content = _metadata_fb.ContentT()
output_meta.content.content_properties = _metadata_fb.FeaturePropertiesT()
output_meta.content.contentPropertiesType = (
    _metadata_fb.ContentProperties.FeatureProperties)
output_stats = _metadata_fb.StatsT()
output_stats.max = [1.0]
output_stats.min = [0.0]
output_meta.stats = output_stats
label_file = _metadata_fb.AssociatedFileT()
label_file.name = os.path.basename("your_path_to_label_file")
label_file.description = "Labels for objects that the model can recognize."
label_file.type = _metadata_fb.AssociatedFileType.TENSOR_AXIS_LABELS
output_meta.associatedFiles = [label_file]

Créer les Flatbuffers de métadonnées

Le code suivant combine les informations du modèle avec les informations d'entrée et de sortie:

# Creates subgraph info.
subgraph = _metadata_fb.SubGraphMetadataT()
subgraph.inputTensorMetadata = [input_meta]
subgraph.outputTensorMetadata = [output_meta]
model_meta.subgraphMetadata = [subgraph]

b = flatbuffers.Builder(0)
b.Finish(
    model_meta.Pack(b),
    _metadata.MetadataPopulator.METADATA_FILE_IDENTIFIER)
metadata_buf = b.Output()

Empaqueter les métadonnées et les fichiers associés dans le modèle

Une fois les Flatbuffers de métadonnées créés, les métadonnées et le fichier d'étiquettes sont écrits dans le fichier TFLite via la méthode populate:

populator = _metadata.MetadataPopulator.with_model_file(model_file)
populator.load_metadata_buffer(metadata_buf)
populator.load_associated_files(["your_path_to_label_file"])
populator.populate()

Vous pouvez empaqueter autant de fichiers associés que vous le souhaitez dans le modèle via load_associated_files. Toutefois, il est nécessaire d'empaqueter au moins les fichiers documentés dans les métadonnées. Dans cet exemple, l'empaquetage du fichier d'étiquettes est obligatoire.

Visualiser les métadonnées

Vous pouvez utiliser Netron pour visualiser vos métadonnées, ou lire les métadonnées d'un modèle TensorFlow Lite au format JSON à l'aide de MetadataDisplayer:

displayer = _metadata.MetadataDisplayer.with_model_file(export_model_path)
export_json_file = os.path.join(FLAGS.export_directory,
                                os.path.splitext(model_basename)[0] + ".json")
json_file = displayer.get_metadata_json()
# Optional: write out the metadata as a json file
with open(export_json_file, "w") as f:
  f.write(json_file)

Android Studio est également compatible avec l'affichage des métadonnées via la fonctionnalité de liaison ML d'Android Studio.

Gestion des versions des métadonnées

Les versions du schéma de métadonnées sont basées à la fois sur le numéro de gestion sémantique des versions, qui suit les modifications apportées au fichier de schéma, et sur l'identification du fichier Flatbuffers, qui indique la véritable compatibilité de la version.

Numéro de gestion sémantique des versions

La version du schéma de métadonnées est basée sur le numéro de gestion sémantique des versions, tel que MAJOR.MINOR.PATCH. Il suit les modifications de schéma conformément aux règles définies ici. Consultez l'historique des champs ajouté après la version 1.0.0.

Identification du fichier Flatbuffers

La gestion sémantique des versions garantit la compatibilité en respectant les règles, mais elle n'implique pas la véritable incompatibilité. Lorsque vous augmentez le nombre MAJEUR, cela ne signifie pas nécessairement que la rétrocompatibilité est rompue. Par conséquent, nous utilisons l'identification du fichier Flatbuffers, file_identifier, pour indiquer la véritable compatibilité du schéma de métadonnées. L'identifiant de fichier comporte exactement 4 caractères. Il est fixé à un certain schéma de métadonnées et n'est pas susceptible d'être modifié par les utilisateurs. Si la rétrocompatibilité du schéma de métadonnées doit être rompue pour une raison quelconque, l'élément file_identifier passera, par exemple, de "M001" à "M002". File_identifier devrait être modifié beaucoup moins souvent que "metadata_version".

Version minimale de l'analyseur de métadonnées nécessaire

La version minimale de l'analyseur de métadonnées nécessaire est la version minimale de l'analyseur de métadonnées (le code généré par Flatbuffers) pouvant lire les Flatbuffers de métadonnées dans leur intégralité. Il s'agit en effet du numéro de version le plus grand parmi les versions de tous les champs renseignés et de la plus petite version compatible indiquée par l'identifiant de fichier. La version minimale de l'analyseur de métadonnées est automatiquement renseignée par MetadataPopulator lorsque les métadonnées sont renseignées dans un modèle TFLite. Consultez la page sur l'extracteur de métadonnées pour en savoir plus sur l'utilisation de la version minimale de l'analyseur de métadonnées nécessaire.

Lire les métadonnées à partir des modèles

La bibliothèque d'extraction de métadonnées est un outil pratique pour lire les métadonnées et les fichiers associés à partir d'un modèle sur différentes plates-formes (voir la version de Java et la version C++). Vous pouvez créer votre propre outil d'extraction de métadonnées dans d'autres langages à l'aide de la bibliothèque Flatbuffers.

Lire les métadonnées en Java

Pour utiliser la bibliothèque d'extraction de métadonnées dans votre application Android, nous vous recommandons d'utiliser l'AAR de métadonnées TensorFlow Lite hébergée dans MavenCentral. Il contient la classe MetadataExtractor, ainsi que les liaisons Java FlatBuffers pour le schéma de métadonnées et le schéma de modèle.

Vous pouvez le spécifier dans vos dépendances build.gradle comme suit:

dependencies {
    implementation 'org.tensorflow:tensorflow-lite-metadata:0.1.0'
}

Pour utiliser des instantanés nocturnes, assurez-vous d'avoir ajouté le dépôt d'instantanés Sonatype.

Vous pouvez initialiser un objet MetadataExtractor avec un ByteBuffer qui pointe vers le modèle:

public MetadataExtractor(ByteBuffer buffer);

Le ByteBuffer doit rester inchangé pendant toute la durée de vie de l'objet MetadataExtractor. L'initialisation peut échouer si l'identifiant de fichier Flatbuffers des métadonnées du modèle ne correspond pas à celui de l'analyseur de métadonnées. Pour en savoir plus, consultez la section Gestion des versions des métadonnées.

Avec les identifiants de fichiers correspondants, l'extracteur de métadonnées lit avec succès les métadonnées générées à partir de tous les schémas passés et futurs en raison des mises en avant et du mécanisme de rétrocompatibilité des Flatbuffers. Toutefois, les champs des futurs schémas ne peuvent pas être extraits par les extracteurs de métadonnées plus anciens. La version minimale de l'analyseur nécessaire indique la version minimale de l'analyseur de métadonnées capable de lire les Flatbuffers de métadonnées dans leur intégralité. Vous pouvez utiliser la méthode suivante pour vérifier si la condition minimale nécessaire de la version de l'analyseur est remplie:

public final boolean isMinimumParserVersionSatisfied();

La transmission d'un modèle sans métadonnées est autorisée. Toutefois, appeler des méthodes qui lisent les métadonnées provoquera des erreurs d'exécution. Vous pouvez vérifier si un modèle possède des métadonnées en appelant la méthode hasMetadata:

public boolean hasMetadata();

MetadataExtractor fournit des fonctions pratiques pour obtenir les métadonnées des Tensors d'entrée/de sortie. Par exemple :

public int getInputTensorCount();
public TensorMetadata getInputTensorMetadata(int inputIndex);
public QuantizationParams getInputTensorQuantizationParams(int inputIndex);
public int[] getInputTensorShape(int inputIndex);
public int getoutputTensorCount();
public TensorMetadata getoutputTensorMetadata(int inputIndex);
public QuantizationParams getoutputTensorQuantizationParams(int inputIndex);
public int[] getoutputTensorShape(int inputIndex);

Bien que le schéma de modèle TensorFlow Lite accepte plusieurs sous-graphiques, l'interpréteur TFLite n'accepte actuellement qu'un seul sous-graphique. Par conséquent, MetadataExtractor omet l'index du sous-graphique comme argument d'entrée dans ses méthodes.

Lire les fichiers associés à partir des modèles

Le modèle TensorFlow Lite avec les métadonnées et les fichiers associés est essentiellement un fichier ZIP qui peut être décompressé à l'aide d'outils ZIP courants pour obtenir les fichiers associés. Par exemple, vous pouvez décompresser mobilenet_v1_0.75_160_quantized et extraire le fichier d'étiquettes du modèle comme suit:

$ unzip mobilenet_v1_0.75_160_quantized_1_metadata_1.tflite
Archive:  mobilenet_v1_0.75_160_quantized_1_metadata_1.tflite
 extracting: labels.txt

Vous pouvez également lire les fichiers associés via la bibliothèque d'extracteurs de métadonnées.

En Java, transmettez le nom du fichier à la méthode MetadataExtractor.getAssociatedFile:

public InputStream getAssociatedFile(String fileName);

De même, en C++, vous pouvez effectuer cette opération à l'aide de la méthode ModelMetadataExtractor::GetAssociatedFile:

tflite::support::StatusOr<absl::string_view> GetAssociatedFile(
      const std::string& filename) const;