Metadaten zu TensorFlow Lite-Modellen hinzufügen

TensorFlow Lite-Metadaten bieten einen Standard für Modellbeschreibungen. Die Metadaten sind eine wichtige Informationsquelle über das Verhalten des Modells und seine Eingabe-/Ausgabeinformationen. Die Metadaten umfassen sowohl

Alle auf Kaggle Models veröffentlichten Bildmodelle wurden mit Metadaten gefüllt.

Modell mit Metadatenformat

model_with_metadata
Abbildung 1. TFLite-Modell mit Metadaten und verknüpften Dateien.

Modellmetadaten werden in metadata_schema.fbs, einer FlatBuffer, definiert. Wie in Abbildung 1 gezeigt, wird er im Feld metadata des TFLite-Modellschemas unter dem Namen "TFLITE_METADATA" gespeichert. Einige Modelle enthalten möglicherweise verknüpfte Dateien, z. B. Dateien mit Klassifizierungslabels. Diese Dateien werden am Ende der ursprünglichen Modelldatei als ZIP-Datei im Modus"Anhängen" der ZipFile (Modus 'a') verkettet. TFLite Interpreter kann das neue Dateiformat wie zuvor verarbeiten. Weitere Informationen finden Sie unter Verknüpfte Dateien packen.

In der folgenden Anleitung erfahren Sie, wie Sie Metadaten füllen, visualisieren und lesen.

Metadatentools einrichten

Bevor Sie Ihrem Modell Metadaten hinzufügen, müssen Sie eine Python-Programmierumgebung zum Ausführen von TensorFlow einrichten. Eine ausführliche Anleitung zur Einrichtung finden Sie hier.

Nach der Einrichtung der Python-Programmierumgebung müssen Sie zusätzliche Tools installieren:

pip install tflite-support

Das Metadatentool von TensorFlow Lite unterstützt Python 3.

Metadaten mithilfe der Flatbuffers Python API hinzufügen

Die Modellmetadaten im Schema bestehen aus drei Teilen:

  1. Modellinformationen: Gesamtbeschreibung des Modells sowie Elemente wie Lizenzbedingungen. Siehe ModelMetadata.
    1. Eingabeinformationen: Beschreibung der erforderlichen Eingaben und der erforderlichen Vorverarbeitung wie Normalisierung. Siehe SubGraphMetadata.input_tensor_metadata.
      1. Ausgabeinformationen: Beschreibung der Ausgabe und der erforderlichen Nachbearbeitung, z. B. der Zuordnung zu Labels. Siehe SubGraphMetadata.output_tensor_metadata.

Da TensorFlow Lite derzeit nur einzelne Teilgrafiken unterstützt, verwenden der TensorFlow Lite-Codegenerator und das Binding-Feature für Android Studio ML beim Anzeigen von Metadaten und beim Generieren von Code ModelMetadata.name und ModelMetadata.description anstelle von SubGraphMetadata.name und SubGraphMetadata.description.

Unterstützte Eingabe-/Ausgabetypen

Die TensorFlow Lite-Metadaten für die Ein- und Ausgabe wurden nicht für bestimmte Modelltypen entwickelt, sondern für Ein- und Ausgabetypen. Es spielt keine Rolle, welche Funktion das Modell hat. Solange die Eingabe- und Ausgabetypen aus Folgendem oder einer Kombination davon bestehen, wird es von den TensorFlow Lite-Metadaten unterstützt:

  • Merkmal: Zahlen, die als Ganzzahlen ohne Vorzeichen oder als Gleitkommazahl (FLOAT32) formatiert sind.
  • Bild: Metadaten unterstützen derzeit RGB- und Graustufenbilder.
  • Begrenzungsrahmen - Begrenzungsrahmen in rechteckiger Form. Das Schema unterstützt eine Vielzahl von Nummerierungsschemas.

Verknüpfte Dateien packen

TensorFlow Lite-Modelle können verschiedene zugehörige Dateien enthalten. Zum Beispiel haben Natural Language Models in der Regel Vokabulardateien, in denen Wortteile Wort-IDs zugeordnet werden. Klassifizierungsmodelle können Labeldateien haben, die Objektkategorien angeben. Ohne verknüpfte Dateien (falls vorhanden) funktioniert ein Modell nicht gut.

Die zugehörigen Dateien können jetzt über die Metadaten-Python-Bibliothek mit dem Modell gebündelt werden. Das neue TensorFlow Lite-Modell wird zu einer ZIP-Datei, die sowohl das Modell als auch die zugehörigen Dateien enthält. Sie kann mit gängigen Zip-Tools entpackt werden. Das neue Modellformat hat weiterhin dieselbe Dateiendung – .tflite. Er ist mit dem vorhandenen TFLite-Framework und dem Interpreter kompatibel. Weitere Informationen finden Sie unter Metadaten und zugehörige Dateien in das Modell packen.

Die zugehörigen Dateiinformationen können in den Metadaten aufgezeichnet werden. Je nach Dateityp und dem Anhang der Datei (ModelMetadata, SubGraphMetadata und TensorMetadata) kann der Android-Codegenerator von TensorFlow Lite eine entsprechende Vor-/Nachverarbeitung automatisch auf das Objekt anwenden. Weitere Informationen finden Sie im Abschnitt zur <Codegen-Nutzung> der einzelnen Verknüpfungsdateitypen im Schema.

Normalisierungs- und Quantisierungsparameter

Die Normalisierung ist eine gängige Methode der Datenvorverarbeitung im maschinellen Lernen. Das Ziel der Normalisierung besteht darin, die Werte auf eine gemeinsame Skala zu ändern, ohne die Unterschiede in den Wertebereichen zu verzerren.

Die Modellquantisierung ist ein Verfahren, das die Darstellung von Gewichtungen mit geringerer Genauigkeit und optional auch Aktivierungen für Speicherung und Berechnung ermöglicht.

In Bezug auf die Vorverarbeitung und Nachverarbeitung sind Normalisierung und Quantisierung zwei unabhängige Schritte. Ausführliche Informationen zum Problem:

Normalisierung Quantisierung

Beispiel für die Parameterwerte des Eingabebilds in MobileNet für Gleitkomma- bzw. Quant-Modelle.
Gleitkommamodell:
- Mittelwert: 127,5
- std: 127,5
Quant-Modell:
- Mittelwert: 127,5
- std: 127,5
Gleitkommamodell:
– nullPoint: 0
– Skalierung: 1.0
Quant-Modell:
– nullPoint: 128.0
– Skalierung:0.0078125f




Wann wird aufgerufen?


Eingaben: Wenn Eingabedaten während des Trainings normalisiert werden, müssen die Inferenzdaten entsprechend normalisiert werden.
Ausgaben: Ausgabedaten werden im Allgemeinen nicht normalisiert.
Gleitkommamodelle erfordern keine Quantisierung.
Ein quantisiertes Modell muss bei der Vor-/Nachverarbeitung möglicherweise quantisiert werden. Dies hängt vom Datentyp der Eingabe-/Ausgabetensoren ab.
: Float-Tensoren: Keine Quantisierung bei der Vor-/Nachverarbeitung erforderlich. Quantenoptik- und Dequantungsoperationen sind in den Modellgraphen eingebunden.
– Int8/uint8-Tensoren: Quantisierung bei der Vor-/Nachverarbeitung erforderlich.


Formel


normalized_input = (input – mean) / std
Für Eingaben quantisieren:
q = f / scale + zeroPoint
Dequantisieren für Ausgaben:
f = (q – nullPoint) * Skalierung

Wo befinden sich die Parameter
Wird vom Modellersteller ausgefüllt und in den Modellmetadaten gespeichert, als NormalizationOptions Wird automatisch vom TFLite-Konverter ausgefüllt und in der tflite-Modelldatei gespeichert.
Wie erhalte ich die Parameter? Über die MetadataExtractor API[2] Über die TFLite Tensor API [1] oder über die MetadataExtractor API[2]
Haben Gleitkomma- und Quant-Modelle denselben Wert? Ja, Gleitkomma- und Quant-Modelle haben dieselben Normalisierungsparameter. Nein, das Float-Modell erfordert keine Quantisierung.
Wird der TFLite Code-Generator oder die Android Studio-ML-Bindung bei der Datenverarbeitung automatisch generiert?
Ja

Ja

[1] Die TensorFlow Lite Java API und die TensorFlow Lite C++ API.
[2] Metadatenextraktorbibliothek

Bei der Verarbeitung von Bilddaten für uint8-Modelle werden die Normalisierung und Quantisierung manchmal übersprungen. Dies ist kein Problem, wenn die Pixelwerte im Bereich von [0, 255] liegen. Im Allgemeinen sollten Sie die Daten jedoch immer gemäß den Normalisierungs- und Quantisierungsparametern verarbeiten, sofern zutreffend.

Beispiele

Beispiele zum Auffüllen der Metadaten für verschiedene Modelltypen finden Sie hier:

Bildklassifizierung

Laden Sie hier das Skript herunter, das Metadaten in mobilenet_v1_0.75_160_quantized.tflite auffüllt. Führen Sie das Skript so aus:

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

Wenn Sie Metadaten für andere Bildklassifizierungsmodelle einfügen möchten, fügen Sie dem Skript Modellspezifikationen wie diese hier hinzu. Im weiteren Verlauf dieses Leitfadens werden einige der wichtigsten Abschnitte des Beispiels zur Bildklassifizierung hervorgehoben, um die wichtigsten Elemente zu veranschaulichen.

Beispiel für die Bildklassifizierung im Detail

Modellinformationen

Metadaten beginnen damit, dass neue Modellinformationen erstellt werden:

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.")

Ein-/Ausgabeinformationen

In diesem Abschnitt erfahren Sie, wie Sie die Ein- und Ausgabesignatur Ihres Modells beschreiben. Diese Metadaten können von automatischen Codegeneratoren verwendet werden, um Vor- und Nachbearbeitungscode zu erstellen. So erstellen Sie Eingabe- oder Ausgabeinformationen für einen Tensor:

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

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

Bildeingabe

Bilder sind ein gängiger Eingabetyp für maschinelles Lernen. TensorFlow Lite-Metadaten unterstützen Informationen wie den Farbraum und Informationen zur Vorverarbeitung wie die Normalisierung. Die Abmessung des Bildes muss nicht manuell angegeben werden, da es bereits durch die Form des Eingabetensors bereitgestellt wird und automatisch abgeleitet werden kann.

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

Labelausgabe

Das Label kann mithilfe von TENSOR_AXIS_LABELS über eine verknüpfte Datei einem Ausgabetensor zugeordnet werden.

# 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]

Metadaten-Flatbuffer erstellen

Der folgende Code kombiniert die Modellinformationen mit den Ein- und Ausgabeinformationen:

# 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()

Metadaten und zugehörige Dateien in das Modell packen

Nachdem die Flatbuffers für Metadaten erstellt wurden, werden die Metadaten und die Labeldatei mit der Methode populate in die TFLite-Datei geschrieben:

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()

Mit load_associated_files können Sie beliebig viele verknüpfte Dateien in das Modell packen. Es ist jedoch erforderlich, mindestens die in den Metadaten dokumentierten Dateien zu packen. In diesem Beispiel muss die Labeldatei gepackt werden.

Metadaten visualisieren

Sie können Netron verwenden, um Ihre Metadaten zu visualisieren, oder die Metadaten mit dem MetadataDisplayer aus einem TensorFlow Lite-Modell in ein JSON-Format lesen:

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 unterstützt auch die Anzeige von Metadaten über die Bindungsfunktion in Android Studio ML.

Versionsverwaltung für Metadaten

Das Metadatenschema wird sowohl durch die semantische Versionsnummer, die die Änderungen der Schlüsseldatei verfolgt, als auch durch die Flatbuffer-Dateiidentifikation versioniert, die die tatsächliche Versionskompatibilität angibt.

Semantische Versionsnummer

Das Metadatenschema wird nach der semantischen Versionierungsnummer versioniert, z. B. MAJOR.MINOR.PATCH. Er verfolgt Schemaänderungen gemäß den hier aufgeführten Regeln. Sehen Sie sich den Verlauf der Felder an, die nach Version 1.0.0 hinzugefügt wurden.

Identifizierung der Flatbuffers-Datei

Die semantische Versionsverwaltung garantiert die Kompatibilität, wenn die Regeln eingehalten werden. Sie impliziert jedoch nicht die tatsächliche Inkompatibilität. Wenn die MAJOR-Nummer angehoben wird, bedeutet dies nicht unbedingt, dass die Abwärtskompatibilität beeinträchtigt ist. Daher verwenden wir die Flatbuffer-Dateiidentifikation file_identifier, um die tatsächliche Kompatibilität des Metadatenschemas anzugeben. Die Dateikennung ist genau 4 Zeichen lang. Sie ist auf ein bestimmtes Metadatenschema festgelegt und kann von den Nutzern nicht geändert werden. Wenn die Abwärtskompatibilität des Metadatenschemas unterbrochen werden muss, steigt die Datei-ID (file_identifier) beispielsweise von „M001“ in „M002“. Es wird erwartet, dass „file_identifier“ viel seltener geändert wird als „metadata_version“.

Die mindestens erforderliche Version des Metadatenparsers

Die mindestens erforderliche Version des Metadatenparsers ist die Mindestversion des Metadatenparsers (der von Flatbuffers generierte Code), der die Metadaten-Flatbuffer vollständig lesen kann. Die Version ist im Grunde die größte Versionsnummer unter den Versionen aller ausgefüllten Felder und die kleinste kompatible Version, die durch die Datei-ID angegeben ist. Die mindestens erforderliche Version des Metadatenparsers wird automatisch von MetadataPopulator eingefügt, wenn die Metadaten in ein TFLite-Modell eingefügt werden. Weitere Informationen zur Verwendung der mindestens erforderlichen Version des Metadatenparsers finden Sie unter Metadatenextraktor.

Metadaten aus Modellen lesen

Die Metadata Extractor-Bibliothek ist ein praktisches Tool, um die Metadaten und die zugehörigen Dateien aus einem Modell auf verschiedenen Plattformen zu lesen (siehe Java-Version und C++-Version). Mit der Flatbuffers-Bibliothek können Sie Ihr eigenes Metadatenextraktor in anderen Sprachen erstellen.

Metadaten in Java lesen

Zur Verwendung der Metadata Extractor-Bibliothek in Ihrer Android-App empfehlen wir die Verwendung des AAR für TensorFlow Lite-Metadaten, das in MavenCentral gehostet wird. Sie enthält die Klasse MetadataExtractor sowie die FlatBuffers-Java-Bindungen für das Metadatenschema und das Modellschema.

Sie können dies so in Ihren build.gradle-Abhängigkeiten angeben:

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

Wenn Sie nächtliche Snapshots verwenden möchten, müssen Sie das Sonatype-Snapshot-Repository hinzugefügt haben.

Sie können ein MetadataExtractor-Objekt mit einer ByteBuffer initialisieren, die auf das Modell verweist:

public MetadataExtractor(ByteBuffer buffer);

ByteBuffer darf für die gesamte Lebensdauer des MetadataExtractor-Objekts unverändert bleiben. Die Initialisierung kann fehlschlagen, wenn die Flatbuffers-Datei-ID der Modellmetadaten nicht mit der des Metadatenparsers übereinstimmt. Weitere Informationen finden Sie unter Versionsverwaltung für Metadaten.

Mit übereinstimmenden Dateikennungen liest der Metadatenextraktor Metadaten, die aufgrund des Vorwärts- und Abwärtskompatibilitätsmechanismus der Flatbuffers aus allen vergangenen und zukünftigen Schemas generiert wurden, erfolgreich. Felder aus zukünftigen Schemas können jedoch nicht von älteren Metadatenextraktoren extrahiert werden. Die mindestens erforderliche Parserversion der Metadaten gibt die Mindestversion des Metadatenparsers an, die die Metadaten-Flatbuffer vollständig lesen kann. Mit der folgenden Methode können Sie prüfen, ob die mindestens erforderliche Bedingung für die Parserversion erfüllt ist:

public final boolean isMinimumParserVersionSatisfied();

Die Übergabe eines Modells ohne Metadaten ist zulässig. Das Aufrufen von Methoden, die aus den Metadaten lesen, führt jedoch zu Laufzeitfehlern. Mit der Methode hasMetadata können Sie prüfen, ob ein Modell Metadaten hat:

public boolean hasMetadata();

MetadataExtractor bietet praktische Funktionen, mit denen Sie die Metadaten der Eingabe-/Ausgabetensoren abrufen können. Beispiel:

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);

Obwohl das TensorFlow Lite-Modellschema mehrere Teildiagramme unterstützt, unterstützt der TFLite-Interpreter derzeit nur einen einzelnen Teildiagramm. Daher lässt MetadataExtractor den Teilgraphenindex als Eingabeargument in seinen Methoden weg.

Verknüpfte Dateien aus Modellen lesen

Das TensorFlow Lite-Modell mit Metadaten und zugehörigen Dateien ist im Wesentlichen eine ZIP-Datei, die mit gängigen ZIP-Tools entpackt werden kann, um die zugehörigen Dateien abzurufen. Beispielsweise können Sie mobilenet_v1_0.75_160_quantized entpacken und die Labeldatei im Modell so extrahieren:

$ 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

Sie können verknüpfte Dateien auch über die Metadata Extractor-Bibliothek lesen.

Übergeben Sie in Java den Dateinamen an die Methode MetadataExtractor.getAssociatedFile:

public InputStream getAssociatedFile(String fileName);

In C++ kann dies in ähnlicher Weise mit der Methode ModelMetadataExtractor::GetAssociatedFile erreicht werden:

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