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 le 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 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, è memorizzato nel campo dei metadati dello schema del modello TFLite , sotto il nome "TFLITE_METADATA" . Alcuni modelli possono essere dotati di file associati, ad esempio file di etichetta 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 di file nello stesso modo di prima. Per ulteriori informazioni, vedere Comprimere i file associati .

Consulta le istruzioni seguenti 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 i metadati TensorFlow Lite supportano Python 3.

Aggiunta di metadati utilizzando l'API Python di Flatbuffers

Ci sono tre parti per i metadati del modello nello schema :

  1. Informazioni sul modello : descrizione generale del modello e articoli come i termini della licenza. Vedi ModelMetadata .
  2. Informazioni sull'input : descrizione degli input e della preelaborazione richiesta, ad esempio la normalizzazione. Vedere SubGraphMetadata.input_tensor_metadata .
  3. Informazioni sull'output: descrizione dell'output e della post-elaborazione richiesta, ad esempio la mappatura delle etichette. Vedere 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 di Android Studio ML utilizzeranno ModelMetadata.name e ModelMetadata.description , invece di 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 di TensorFlow Lite:

  • Funzionalità: numeri interi senza segno o float32.
  • Immagine: i metadati attualmente supportano le 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 .

Imballare i file associati

I modelli TensorFlow Lite possono essere forniti con diversi file associati. Ad esempio, i modelli in 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 etichetta che indicano le categorie di oggetti. Senza i file associati (se presenti), un modello non funzionerà bene.

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 del modello continua a utilizzare la stessa estensione di file, .tflite . È compatibile con il framework e l'interprete TFLite esistenti. Per maggiori dettagli, vedere 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 della posizione in cui il file è allegato (ad esempio ModelMetadata , SubGraphMetadata e TensorMetadata ), il generatore di codice Android TensorFlow Lite può applicare automaticamente la corrispondente elaborazione pre/post all'oggetto. Per ulteriori dettagli, vedere la sezione <Utilizzo del codice> 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 pre-elaborazione e post-elaborazione, la normalizzazione e la quantizzazione sono due fasi 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
- std: 127,5
Modello quantitativo :
- media: 127,5
- std: 127,5
Modello galleggiante :
- Punto zero: 0
- scala: 1.0
Modello quantitativo :
- Punto zero: 128,0
- scala:0.0078125f




Quando invocare?


Input : se i dati di input vengono normalizzati durante l'addestramento, i dati di input dell'inferenza devono essere normalizzati di conseguenza.
Output : i dati di output non verranno normalizzati in generale.
I modelli float non necessitano di quantizzazione.
Il modello quantizzato può richiedere o meno la quantizzazione in fase di pre/post elaborazione. Dipende dal tipo di dati dei tensori di input/output.
- tensori float: nessuna quantizzazione in pre/post elaborazione necessaria. Quant op e dequant op sono inseriti nel grafico del modello.
- tensori int8/uint8: necessitano di quantizzazione in pre/post elaborazione.


Formula


normalized_input = (input - media) / std
Quantizza per input :
q = f / scala + punto zero
Dequantizza per le uscite :
f = (q - Punto zero) * scala

Dove sono i parametri
Compilato dal creatore del modello e archiviato nei metadati del modello, come NormalizationOptions Riempito 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 il binding di Android Studio ML lo generano automaticamente nell'elaborazione dei dati?

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

Quando si elaborano i dati dell'immagine per i modelli uint8, la normalizzazione e la quantizzazione a volte vengono saltate. È possibile farlo quando i valori dei pixel sono compresi nell'intervallo [0, 255]. Ma in generale, dovresti sempre elaborare i dati in base ai parametri di normalizzazione e quantizzazione, quando applicabili.

TensorFlow Lite Task Library 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 compilare i metadati per diversi tipi di modelli qui:

Classificazione delle immagini

Scarica lo script qui , che popola 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 questa nello script. Il resto di questa guida evidenzierà alcune delle sezioni chiave nell'esempio di classificazione delle immagini per illustrare gli elementi chiave.

Immergiti nell'esempio di classificazione delle immagini

Informazioni sul modello

I metadati iniziano creando una nuova informazione 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 input/output

Questa sezione mostra come descrivere la firma di input e output del tuo modello. Questi metadati possono essere utilizzati da generatori di codice automatici 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()

Immissione di immagini

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]

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

Comprimi i metadati e i file associati nel modello

Una volta creati i metadati Flatbuffer, 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 quei file documentati nei metadati. In questo esempio, l'imballaggio del file dell'etichetta è obbligatorio.

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 usando 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 funzione di rilegatura di Android Studio ML .

Controllo delle versioni 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 vera compatibilità della versione.

Il numero di versione semantica

Lo schema dei metadati ha la versione in base al numero di versione semantico , ad esempio 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 .

L'identificazione del file Flatbuffers

Il versionamento semantico garantisce la compatibilità se si seguono le regole, ma non implica la vera incompatibilità. Quando si aumenta il numero PRINCIPALE, non significa necessariamente che la compatibilità con le versioni precedenti sia interrotta. Pertanto, utilizziamo l' identificatore di file Flatbuffers , file_identifier , per denotare la vera compatibilità dello schema di 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 la compatibilità con le versioni precedenti dello schema dei metadati deve essere interrotta per qualche motivo, il file_identifier aumenterà, ad esempio, da "M001" a "M002". File_identifier dovrebbe essere 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 i flatbuffer dei metadati per intero. La versione è effettivamente il numero di versione più grande tra le versioni di tutti i campi compilati 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 inseriti in un modello TFLite. Vedere l' estrattore di metadati per ulteriori informazioni su come viene utilizzata la versione minima necessaria del parser di metadati.

Leggi i metadati dai modelli

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

Leggi i metadati in Java

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

Puoi specificarlo nelle tue 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 il controllo delle versioni dei metadati .

Con gli identificatori di file corrispondenti, l'estrattore di metadati leggerà correttamente i metadati generati da tutti gli schemi passati e futuri grazie al meccanismo di compatibilità avanti e indietro di Flatbuffers. Tuttavia, i campi di schemi futuri non possono essere estratti da estrattori di metadati precedenti. La versione minima necessaria del parser dei metadati indica la versione minima del parser dei metadati in grado di leggere i flatbuffer dei metadati per intero. È 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 ha metadati invocando il metodo hasMetadata :

public boolean hasMetadata();

MetadataExtractor fornisce utili funzioni 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 dell'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;