Aggiunta di metadati ai modelli TensorFlow Lite

I metadati di TensorFlow Lite forniscono uno standard per le descrizioni dei modelli. I metadati sono un'importante fonte di conoscenza su ciò che fa il modello e sulle sue informazioni di input/output. I metadati sono costituiti da entrambi

Tutti i modelli di immagine pubblicati su TensorFlow Hub sono stati popolati con metadati.

Modello con formato di metadati

modello_con_metadati
Figura 1. Modello TFLite con metadati e file associati.

I metadati del modello sono definiti in metadata_schema.fbs , un file FlatBuffer . Come mostrato nella Figura 1, è archiviato nel campo dei metadati dello schema del modello TFLite , sotto il nome "TFLITE_METADATA" . Alcuni modelli potrebbero essere dotati di file associati, come file di etichette di classificazione . Questi file vengono concatenati alla fine del file del modello originale come ZIP utilizzando la modalità "append" ZipFile (modalità 'a' ). TFLite Interpreter può utilizzare il nuovo formato file nello stesso modo di prima. Per ulteriori informazioni, vedere Comprimere i file associati .

Consulta le istruzioni di seguito su come popolare, visualizzare e leggere i metadati.

Configura gli strumenti per i metadati

Prima di aggiungere metadati al tuo modello, dovrai configurare un ambiente di programmazione Python per eseguire TensorFlow. C'è una guida dettagliata su come impostarlo qui .

Dopo aver configurato l'ambiente di programmazione Python, dovrai installare strumenti aggiuntivi:

pip install tflite-support

Gli strumenti per metadati TensorFlow Lite supportano Python 3.

Aggiunta di metadati utilizzando l'API Python Flatbuffers

Ci sono tre parti dei metadati del modello nello schema :

  1. Informazioni sul modello : descrizione generale del modello e elementi quali i termini di licenza. Vedere ModelMetadata .
  2. Informazioni sull'input : descrizione degli input e pre-elaborazione richiesta come la normalizzazione. Vedi SubGraphMetadata.input_tensor_metadata .
  3. Informazioni sull'output : descrizione dell'output e della post-elaborazione richiesta, come la mappatura sulle etichette. Vedi SubGraphMetadata.output_tensor_metadata .

Poiché TensorFlow Lite supporta solo un singolo sottografo a questo punto, il generatore di codice TensorFlow Lite e la funzione di associazione ML di Android Studio utilizzeranno ModelMetadata.name e ModelMetadata.description , anziché SubGraphMetadata.name e SubGraphMetadata.description , durante la visualizzazione dei metadati e la generazione del codice.

Tipi di input/output supportati

I metadati di TensorFlow Lite per input e output non sono progettati pensando a tipi di modello specifici ma piuttosto a tipi di input e output. Non importa cosa fa funzionalmente il modello, purché i tipi di input e output siano costituiti da quanto segue o da una combinazione di quanto segue, è supportato dai metadati TensorFlow Lite:

  • Caratteristica: numeri che sono interi senza segno o float32.
  • Immagine: i metadati attualmente supportano immagini RGB e in scala di grigi.
  • Riquadro di delimitazione: riquadri di delimitazione di forma rettangolare. Lo schema supporta una varietà di schemi di numerazione .

Comprimere i file associati

I modelli TensorFlow Lite possono essere dotati di diversi file associati. Ad esempio, i modelli del linguaggio naturale di solito hanno file di vocaboli che associano parti di parole a ID di parole; i modelli di classificazione possono avere file di etichette che indicano le categorie di oggetti. Senza i file associati (se presenti), un modello non funzionerà correttamente.

I file associati possono ora essere raggruppati con il modello tramite la libreria Python di metadati. Il nuovo modello TensorFlow Lite diventa un file zip che contiene sia il modello che i file associati. Può essere decompresso con i comuni strumenti zip. Questo nuovo formato di modello continua a utilizzare la stessa estensione di file, .tflite . È compatibile con il framework e l'interprete TFLite esistenti. Per ulteriori dettagli, consulta Comprimere i metadati e i file associati nel modello .

Le informazioni sul file associato possono essere registrate nei metadati. A seconda del tipo di file e del punto in cui è allegato (ad esempio ModelMetadata , SubGraphMetadata e TensorMetadata ), il generatore di codice Android TensorFlow Lite può applicare automaticamente la pre/post elaborazione corrispondente all'oggetto. Per ulteriori dettagli, vedere la sezione <Utilizzo codegen> di ciascun tipo di file associato nello schema.

Parametri di normalizzazione e quantizzazione

La normalizzazione è una tecnica comune di preelaborazione dei dati nell'apprendimento automatico. L'obiettivo della normalizzazione è modificare i valori su una scala comune, senza distorcere le differenze negli intervalli di valori.

La quantizzazione del modello è una tecnica che consente rappresentazioni di pesi con precisione ridotta e, facoltativamente, attivazioni sia per l'archiviazione che per il calcolo.

In termini di preelaborazione e postelaborazione, la normalizzazione e la quantizzazione sono due passaggi indipendenti. Ecco i dettagli.

Normalizzazione Quantizzazione

Un esempio dei valori dei parametri dell'immagine di input in MobileNet rispettivamente per i modelli float e quant.
Modello galleggiante :
- media: 127,5
- standard: 127,5
Modello quantitativo :
- media: 127,5
- standard: 127,5
Modello galleggiante :
-zeroPunto: 0
- scala: 1.0
Modello quantitativo :
-zeroPunto: 128.0
- scala: 0,0078125f




Quando invocare?


Input : se i dati di input vengono normalizzati nell'addestramento, i dati di input dell'inferenza devono essere normalizzati di conseguenza.
Uscite : i dati di uscita non verranno normalizzati in generale.
I modelli float non necessitano di quantizzazione.
Il modello quantizzato può richiedere o meno la quantizzazione nella pre/post elaborazione. Dipende dal tipo di dati dei tensori di input/output.
- tensori float: non è necessaria alcuna quantizzazione in pre/post elaborazione. Quant op e dequant op vengono integrati nel grafico del modello.
- Tensori int8/uint8: necessitano di quantizzazione in pre/post elaborazione.


Formula


normalized_input = (input - media) / std
Quantizzazione per gli input :
q = f / scala + punto zero
Dequantizza per gli output :
f = (q - Puntozero) * scala

Dove sono i parametri?
Compilato dal creatore del modello e archiviato nei metadati del modello, come NormalizationOptions Compilato automaticamente dal convertitore TFLite e archiviato nel file modello tflite.
Come ottenere i parametri? Attraverso l'API MetadataExtractor [2] Tramite l'API TFLite Tensor [1] o tramite l'API MetadataExtractor [2]
I modelli float e quant condividono lo stesso valore? Sì, i modelli float e quant hanno gli stessi parametri di normalizzazione No, il modello float non necessita di quantizzazione.
Il generatore di codice TFLite o l'associazione Android Studio ML lo generano automaticamente durante l'elaborazione dei dati?

[1] L' API Java di TensorFlow Lite e l' API C++ di TensorFlow Lite .
[2] La libreria di estrazione dei metadati

Durante l'elaborazione dei dati di immagine per i modelli uint8, la normalizzazione e la quantizzazione a volte vengono saltate. Va bene farlo quando i valori dei pixel sono compresi nell'intervallo [0, 255]. Ma in generale, dovresti sempre elaborare i dati secondo i parametri di normalizzazione e quantizzazione, quando applicabili.

La libreria attività TensorFlow Lite può gestire la normalizzazione per te se imposti NormalizationOptions nei metadati. L'elaborazione di quantizzazione e dequantizzazione è sempre incapsulata.

Esempi

Puoi trovare esempi su come devono essere popolati i metadati per diversi tipi di modelli qui:

Classificazione delle immagini

Scarica qui lo script, che inserisce i metadati in mobilenet_v1_0.75_160_quantized.tflite . Esegui lo script in questo modo:

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

Per popolare i metadati per altri modelli di classificazione delle immagini, aggiungi le specifiche del modello come queste nello script. Il resto di questa guida metterà in evidenza alcune delle sezioni chiave nell'esempio di classificazione delle immagini per illustrare gli elementi chiave.

Approfondisci l'esempio di classificazione delle immagini

Informazioni sul modello

I metadati iniziano creando nuove informazioni sul modello:

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

Informazioni di ingresso/uscita

Questa sezione mostra come descrivere la firma di input e output del tuo modello. Questi metadati possono essere utilizzati dai generatori automatici di codice per creare codice di pre e post elaborazione. Per creare informazioni di input o output su un tensore:

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

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

Ingresso immagine

L'immagine è un tipo di input comune per l'apprendimento automatico. I metadati di TensorFlow Lite supportano informazioni come lo spazio colore e informazioni di pre-elaborazione come la normalizzazione. La dimensione dell'immagine non richiede specificazione manuale poiché è già fornita dalla forma del tensore di input e può essere dedotta automaticamente.

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

Uscita etichetta

L'etichetta può essere mappata su un tensore di output tramite un file associato utilizzando 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]

Creare i flatbuffer dei metadati

Il codice seguente combina le informazioni sul modello con le informazioni di input e output:

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

Inserisci i metadati e i file associati nel modello

Una volta creati i Flatbuffer dei metadati, i metadati e il file di etichetta vengono scritti nel file TFLite tramite il metodo 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()

Puoi comprimere tutti i file associati che desideri nel modello tramite load_associated_files . Tuttavia, è necessario comprimere almeno i file documentati nei metadati. In questo esempio, la compressione del file di etichette è obbligatoria.

Visualizza i metadati

Puoi utilizzare Netron per visualizzare i tuoi metadati oppure puoi leggere i metadati da un modello TensorFlow Lite in un formato json utilizzando 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 supporta anche la visualizzazione dei metadati tramite la funzionalità di associazione ML di Android Studio .

Versionamento dei metadati

Lo schema dei metadati è versionato sia dal numero di versione semantico, che tiene traccia delle modifiche del file di schema, sia dall'identificazione del file Flatbuffers, che indica la reale compatibilità della versione.

Il numero di versione semantica

Lo schema dei metadati ha una versione in base al numero di versione semantica , come MAJOR.MINOR.PATCH. Tiene traccia delle modifiche allo schema in base alle regole qui . Visualizza la cronologia dei campi aggiunti dopo la versione 1.0.0 .

Identificazione del file Flatbuffers

Il versioning semantico garantisce la compatibilità se si seguono le regole, ma non implica la vera incompatibilità. Quando si aumenta il numero MAJOR, ciò non significa necessariamente che la compatibilità con le versioni precedenti sia interrotta. Pertanto, utilizziamo l' identificazione del file Flatbuffers , file_identifier , per denotare la vera compatibilità dello schema dei metadati. L'identificatore del file è lungo esattamente 4 caratteri. È fissato a un determinato schema di metadati e non è soggetto a modifiche da parte degli utenti. Se per qualche motivo la compatibilità con le versioni precedenti dello schema dei metadati deve essere interrotta, il file_identifier aumenterà, ad esempio, da "M001" a "M002". Si prevede che File_identifier venga modificato molto meno frequentemente rispetto a metadata_version.

La versione minima necessaria del parser dei metadati

La versione minima necessaria del parser dei metadati è la versione minima del parser dei metadati (il codice generato dai Flatbuffer) in grado di leggere completamente i Flatbuffer dei metadati. La versione è effettivamente il numero di versione più grande tra le versioni di tutti i campi popolati e la versione compatibile più piccola indicata dall'identificatore del file. La versione minima necessaria del parser dei metadati viene popolata automaticamente da MetadataPopulator quando i metadati vengono popolati in un modello TFLite. Consulta l' estrattore di metadati per ulteriori informazioni su come viene utilizzata la versione minima necessaria del parser di metadati.

Leggere i metadati dai modelli

La libreria Metadata Extractor è uno strumento utile per leggere i metadati e i file associati da modelli su diverse piattaforme (vedere la versione Java e la versione C++ ). Puoi creare il tuo strumento di estrazione di metadati in altre lingue utilizzando la libreria Flatbuffers.

Leggere i metadati in Java

Per utilizzare la libreria Metadata Extractor nella tua app Android, ti consigliamo di utilizzare l' AAR metadati TensorFlow Lite ospitato su MavenCentral . Contiene la classe MetadataExtractor , nonché i collegamenti Java FlatBuffers per lo schema dei metadati e lo schema del modello .

Puoi specificarlo nelle dipendenze build.gradle come segue:

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

Per utilizzare gli snapshot notturni, assicurati di aver aggiunto il repository di snapshot Sonatype .

Puoi inizializzare un oggetto MetadataExtractor con un ByteBuffer che punta al modello:

public MetadataExtractor(ByteBuffer buffer);

Il ByteBuffer deve rimanere invariato per l'intera durata dell'oggetto MetadataExtractor . L'inizializzazione potrebbe non riuscire se l'identificatore del file Flatbuffers dei metadati del modello non corrisponde a quello del parser dei metadati. Per ulteriori informazioni, vedere controllo delle versioni dei metadati .

Con gli identificatori di file corrispondenti, l'estrattore di metadati leggerà con successo i metadati generati da tutti gli schemi passati e futuri grazie al meccanismo di compatibilità con le versioni successive e successive dei Flatbuffer. Tuttavia, i campi degli schemi futuri non possono essere estratti dai vecchi estrattori di metadati. La versione minima necessaria del parser dei metadati indica la versione minima del parser dei metadati in grado di leggere completamente i Flatbuffer dei metadati. È possibile utilizzare il metodo seguente per verificare se è soddisfatta la condizione minima necessaria della versione del parser:

public final boolean isMinimumParserVersionSatisfied();

È consentito il passaggio di un modello senza metadati. Tuttavia, il richiamo di metodi che leggono dai metadati causerà errori di runtime. Puoi verificare se un modello dispone di metadati invocando il metodo hasMetadata :

public boolean hasMetadata();

MetadataExtractor fornisce funzioni utili per ottenere i metadati dei tensori di input/output. Per esempio,

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

Sebbene lo schema del modello TensorFlow Lite supporti più sottografi, l'interprete TFLite attualmente supporta solo un singolo sottografo. Pertanto, MetadataExtractor omette l'indice del sottografo come argomento di input nei suoi metodi.

Leggere i file associati dai modelli

Il modello TensorFlow Lite con metadati e file associati è essenzialmente un file zip che può essere decompresso con strumenti zip comuni per ottenere i file associati. Ad esempio, puoi decomprimere mobilenet_v1_0.75_160_quantized ed estrarre il file etichetta nel modello come segue:

$ 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

Puoi anche leggere i file associati tramite la libreria Metadata Extractor.

In Java, passa il nome del file nel metodo MetadataExtractor.getAssociatedFile :

public InputStream getAssociatedFile(String fileName);

Allo stesso modo, in C++, questo può essere fatto con il metodo ModelMetadataExtractor::GetAssociatedFile :

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