Metadaten zu TensorFlow Lite-Modellen hinzufügen

TensorFlow Lite-Metadaten bieten einen Standard für Modellbeschreibungen. Die Metadaten sind eine wichtige Wissensquelle darüber, was das Modell tut und welche Eingabe-/Ausgabeinformationen es enthält. Die Metadaten bestehen sowohl aus

Alle auf TensorFlow Hub 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-Datei, definiert. Wie in Abbildung 1 dargestellt, wird sie 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 im „append“-Modus (Modus 'a') der ZipFile-Datei mit dem Ende der ursprünglichen Modelldatei als ZIP-Datei verkettet. TFLite Interpreter kann das neue Dateiformat wie zuvor verarbeiten. Weitere Informationen finden Sie unter Zugehörige Dateien packen.

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

Metadatentools einrichten

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

Nachdem Sie die Python-Programmierumgebung eingerichtet haben, müssen Sie zusätzliche Tools installieren:

pip install tflite-support

Das TensorFlow Lite-Metadatentool unterstützt Python 3.

Metadaten mit der Flatbuffers Python API hinzufügen

Das Schema besteht aus drei Teilen der Modellmetadaten:

  1. Modellinformationen – Allgemeine Beschreibung des Modells sowie Elemente wie Lizenzbedingungen. Siehe ModelMetadata.
  2. Eingabeinformationen – Beschreibung der erforderlichen Eingaben und Vorverarbeitung, z. B. Normalisierung. Siehe SubGraphMetadata.input_tensor_metadata.
  3. Ausgabeinformationen – Beschreibung der Ausgabe und Nachverarbeitung, die erforderlich sind, z. B. die Zuordnung zu Labels. Siehe SubGraphMetadata.output_tensor_metadata.

Da TensorFlow Lite derzeit nur eine einzelne Teilgrafik unterstützt, verwenden der TensorFlow Lite-Codegenerator und das Android Studio ML-Binding-Feature ModelMetadata.name und ModelMetadata.description anstelle von SubGraphMetadata.name und SubGraphMetadata.description, um Metadaten anzuzeigen und Code zu generieren.

Unterstützte Ein-/Ausgabetypen

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

  • Funktion: Zahlen, die als Ganzzahlen oder Gleitkommazahl ohne Vorzeichen angegeben werden.
  • Bild: Metadaten unterstützen derzeit RGB- und Graustufenbilder.
  • Begrenzungsrahmen: Begrenzungsrahmen in rechteckiger Form. Das Schema unterstützt eine Vielzahl von Nummerierungsschemata.

Zugehörige Dateien packen

TensorFlow Lite-Modelle haben möglicherweise andere verknüpfte Dateien. Natural Language Models haben beispielsweise in der Regel Vokabulardateien, in denen Wortbestandteile Wort-IDs zugeordnet werden. Klassifizierungsmodelle können Labeldateien haben, die Objektkategorien angeben. Ohne die zugehörigen Dateien (falls vorhanden) funktioniert ein Modell nicht gut.

Die zugehörigen Dateien können jetzt über die Python-Metadatenbibliothek 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. Es kann mit gängigen Zip-Tools entpackt werden. Dieses neue Modellformat verwendet weiterhin dieselbe Dateiendung, .tflite. Er ist mit dem vorhandenen TFLite-Framework und dem vorhandenen Interpreter kompatibel. Weitere Informationen finden Sie unter Metadaten und verknüpfte Dateien in das Modell packen.

Die zugehörigen Dateiinformationen können in den Metadaten aufgezeichnet werden. Je nach Dateityp und dem Ort, an den die Datei angehängt wird (z.B. ModelMetadata, SubGraphMetadata und TensorMetadata), wendet der Android-Codegenerator von TensorFlow Lite möglicherweise automatisch die entsprechende Vor-/Nachverarbeitung auf das Objekt an. Weitere Informationen finden Sie im Abschnitt <Codegen-Nutzung> jedes verknüpften Dateityps im Schema.

Normalisierungs- und Quantisierungsparameter

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

Die Modellquantisierung ist ein Verfahren, das eine reduzierte Präzision von Gewichtungen und optional Aktivierungen sowohl für Speicherung als auch für 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 Eingabebildes in MobileNet für Gleitkomma- bzw. Quant-Modelle.
Gleitkommazahl:
- Mittelwert: 127,5
- std: 127,5
Quant-Modell:
- Mittelwert: 127,5
- std: 127,5
Gleitkommazahl:
– ZeroPoint: 0
– Skalierung: 1,0
Quant-Modell:
– ZeroPoint: 128,0
– scale:0.0078125f




Wann soll aufgerufen werden?


Eingaben: Wenn Eingabedaten während des Trainings normalisiert werden, müssen die Inferenzeingabedaten entsprechend normalisiert werden.
Ausgaben: Die Ausgabedaten werden im Allgemeinen nicht normalisiert.
Float-Modelle benötigen keine Quantisierung.
Für ein quantisiertes Modell ist möglicherweise keine Quantisierung in der Vor-/Nachverarbeitung erforderlich. Dies hängt vom Datentyp der Eingabe-/Ausgabetensoren ab.
– Gleitkomma-Tensoren: keine Quantisierung in der Vor-/Nachverarbeitung erforderlich Quant- und Dequant-Vorgänge sind in die Modellgrafik verankert.
– int8/uint8-Tensoren: In der Vor-/Nachverarbeitung muss eine Quantisierung erfolgen.


Formel


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

Wo befinden sich die Parameter
Vom Modellersteller ausgefüllt und in Modellmetadaten als NormalizationOptions gespeichert Wird automatisch mit dem 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 Gleitkommazahl-Modell muss nicht quantisiert werden.
Erzeugt der TFLite-Codegenerator oder die Android Studio ML-Bindung ihn automatisch in der Datenverarbeitung?
Ja

Ja

[1] Die TensorFlow Lite Java API und die TensorFlow Lite C++ API.
[2] Die Metadaten-Extrahierer-Bibliothek

Bei der Verarbeitung von Bilddaten für uint8-Modelle werden 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 dazu, wie die Metadaten für verschiedene Modelltypen ausgefüllt werden sollten, finden Sie hier:

Bildklassifizierung

Laden Sie hier das Skript herunter, mit dem Metadaten in mobilenet_v1_0.75_160_quantized.tflite eingefügt werden. Führen Sie das Skript wie folgt 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 ausfüllen möchten, fügen Sie die Modellspezifikationen wie hier in das Skript ein. Im weiteren Verlauf dieses Leitfadens werden einige der wichtigsten Abschnitte aus dem Beispiel zur Bildklassifizierung hervorgehoben, um die wichtigsten Elemente zu veranschaulichen.

Beispiel für die Bildklassifizierung im Detail

Modellinformationen

Zuerst werden Metadaten erstellt:

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

Eingabe-/Ausgabeinformationen

In diesem Abschnitt erfahren Sie, wie Sie die Eingabe- und Ausgabesignatur Ihres Modells beschreiben. Diese Metadaten können von automatischen Codegeneratoren verwendet werden, um Code zur Vor- und Nachverarbeitung zu erstellen. So erstellen Sie Eingabe- oder Ausgabeinformationen zu einem Tensor:

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

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

Bildeingabe

„Bilder“ ist ein gängiger Eingabetyp für maschinelles Lernen. TensorFlow Lite-Metadaten unterstützen Informationen wie Farbraum und Vorverarbeitungsinformationen wie Normalisierung. Die Abmessung des Bildes muss nicht manuell angegeben werden, da sie 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

Ein Label kann einem Ausgabetensor über eine verknüpfte Datei mit TENSOR_AXIS_LABELS 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 Metadaten-Flatbuffer erstellt wurden, werden die Metadaten und die Labeldatei über die 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()

Über load_associated_files können Sie beliebig viele verknüpfte Dateien in das Modell packen. Es müssen jedoch zumindest die in den Metadaten dokumentierten Dateien gepackt werden. In diesem Beispiel ist das Packen der Labeldatei obligatorisch.

Metadaten visualisieren

Sie können Netron verwenden, um Ihre Metadaten zu visualisieren, oder Sie können die Metadaten aus einem TensorFlow Lite-Modell mit dem MetadataDisplayer 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 Funktion „Android Studio ML-Bindung“.

Versionsverwaltung für Metadaten

Das Metadatenschema wird sowohl über die semantische Versionsnummer, mit der die Änderungen der Schemadefinition verfolgt werden, als auch über die Identifikation der Flatbuffers-Datei versioniert, die die tatsächliche Versionskompatibilität angibt.

Die semantische Versionsnummer

Das Metadatenschema wird mit der semantischen Versionsnummer versioniert, z. B. MAJOR.MINOR.PATCH. Schemaänderungen werden gemäß den hier aufgeführten Regeln verfolgt. Weitere Informationen finden Sie im Verlauf von Feldern, die nach Version 1.0.0 hinzugefügt wurden.

Identifizierung der Flatbuffers-Datei

Die semantische Versionsverwaltung garantiert die Kompatibilität, wenn die Regeln befolgt werden, deutet jedoch nicht auf eine tatsächliche Inkompatibilität hin. Eine Erhöhung der MAJOR-Nummer bedeutet nicht unbedingt, dass die Abwärtskompatibilität unterbrochen ist. Daher verwenden wir die Flatbuffers-Dateiidentifikation, file_identifier, um die tatsächliche Kompatibilität des Metadatenschemas anzugeben. Die Dateikennung ist genau 4 Zeichen lang. Sie ist an ein bestimmtes Metadatenschema gebunden und kann sich nicht von Nutzern ändern. Wenn die Abwärtskompatibilität des Metadatenschemas aus irgendeinem Grund unterbrochen werden muss, erhöht sich „file_identifier“, z. B. von „M001“ zu „M002“. „File_identifier“ wird voraussichtlich viel seltener geändert als „metadata_version“.

Die mindestens erforderliche Version des Metadaten-Parsers

Die Mindestversion für den Metadaten-Parser ist die Mindestversion des Metadaten-Parsers (der von den Flatbuffers generierten Code), die die Metadaten-Flatbuffer vollständig lesen kann. Die Version ist praktisch die größte Versionsnummer unter den Versionen aller ausgefüllten Felder und die kleinste kompatible Version, die in der Datei-ID angegeben ist. Die mindestens erforderliche Version des Metadatenparsers wird automatisch durch MetadataPopulator eingefügt, wenn die Metadaten in ein TFLite-Modell eingefügt werden. Weitere Informationen zur Verwendung der mindestens erforderlichen Metadaten-Parserversion finden Sie im 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 ein eigenes Metadaten-Extrahierertool in anderen Sprachen erstellen.

Metadaten in Java lesen

Wenn Sie die Metadata Extractor-Bibliothek in Ihrer Android-App verwenden möchten, empfehlen wir die Verwendung von TensorFlow Lite Metadata AAR, die in MavenCentral gehostet werden. Es enthält die Klasse MetadataExtractor sowie die FlatBuffers-Java-Bindungen für das Metadatenschema und das Modellschema.

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

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

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

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

public MetadataExtractor(ByteBuffer buffer);

Das 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 ID des Metadaten-Parsers übereinstimmt. Weitere Informationen finden Sie unter Metadatenversionsverwaltung.

Mit übereinstimmenden Datei-IDs liest der Metadaten-Extrahierer aufgrund des Vorwärts- und Abwärtskompatibilitätsmechanismus der Flatbuffers erfolgreich Metadaten, die aus allen vergangenen und zukünftigen Schemas generiert wurden. 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-Flatpuffer vollständig lesen kann. Mit der folgenden Methode können Sie prüfen, ob die mindestens erforderliche Bedingung der Parserversion erfüllt ist:

public final boolean isMinimumParserVersionSatisfied();

Die Übergabe eines Modells ohne Metadaten ist zulässig. Methoden, die aus den Metadaten lesen, verursachen jedoch Laufzeitfehler. Mit der Methode hasMetadata können Sie prüfen, ob ein Modell Metadaten hat:

public boolean hasMetadata();

MetadataExtractor bietet praktische Funktionen zum Abrufen der Metadaten der Eingabe-/Ausgabetensoren. 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 Teilgrafiken unterstützt, unterstützt der TFLite-Interpreter derzeit nur eine einzelne Teilgrafik. Daher lässt MetadataExtractor den Untergrafikindex als Eingabeargument in seinen Methoden weg.

Zugehörige Dateien aus Modellen lesen

Das TensorFlow Lite-Modell mit Metadaten und den zugehörigen Dateien ist im Wesentlichen eine ZIP-Datei, die mit gängigen ZIP-Tools entpackt werden kann, um die zugehörigen Dateien abzurufen. Sie können beispielsweise 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 ähnlich mit der Methode ModelMetadataExtractor::GetAssociatedFile erfolgen:

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