Aggiunta di metadati ai modelli TensorFlow Lite

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

Tutti i modelli di immagine pubblicati su Modelli Kaggle sono stati compilati con metadati.

Modello con formato metadati

model_with_metadata
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, viene archiviato nel campo metadata dello schema del modello TFLite, sotto il nome "TFLITE_METADATA". Alcuni modelli potrebbero essere forniti con file associati, ad esempio file delle etichette di classificazione. Questi file sono concatenati alla fine del file del modello originale come file ZIP utilizzando la modalità"append" ZipFile (modalità 'a'). TFLite Interpreter può utilizzare il nuovo formato file come prima. Per ulteriori informazioni, consulta la sezione Pacchettizzare i file associati.

Per informazioni su come compilare, visualizzare e leggere i metadati, consulta le istruzioni riportate di seguito.

Configurare gli strumenti per i metadati

Prima di aggiungere metadati al modello, devi configurare un ambiente di programmazione Python per eseguire TensorFlow. Qui puoi trovare una guida dettagliata per la configurazione.

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

pip install tflite-support

Lo strumento per i metadati TensorFlow Lite supporta Python 3.

Aggiunta di metadati utilizzando l'API Python Flatbuffers

I metadati del modello sono costituiti da tre parti nello schema:

  1. Informazioni sul modello: descrizione complessiva del modello e altri elementi come i termini di licenza. Vedi ModelMetadata.
    1. Informazioni di input: descrizione degli input e pre-elaborazione necessaria, come la normalizzazione. Vedi SubGraphMetadata.input_tensor_metadata.
      1. Informazioni di output: descrizione dell'output e della post-elaborazione richieste, come la mappatura alle etichette. Vedi SubGraphMetadata.output_tensor_metadata.

Poiché al momento TensorFlow Lite supporta un solo grafico secondario, il generatore di codice TensorFlow e la funzionalità Associazione ML di Android Studio utilizzeranno ModelMetadata.name e ModelMetadata.description, anziché SubGraphMetadata.name e SubGraphMetadata.description, per la visualizzazione dei metadati e la generazione del codice.

Tipi di input / output supportati

I metadati TensorFlow Lite per l'input e l'output non sono progettati per tipi di modelli specifici, ma piuttosto per tipi di input e output. Non è importante sapere quali funzionalità facciano il modello, purché i tipi di input e output siano costituiti dai seguenti elementi o da una combinazione dei seguenti, saranno supportati dai metadati TensorFlow Lite:

  • Funzione: numeri che sono numeri interi senza segno o float32.
  • Immagine: al momento, i metadati supportano le immagini RGB e in scala di grigi.
  • Riquadro di delimitazione: riquadri di delimitazione rettangolari. Lo schema supporta diversi schemi di numerazione.

Comprimere i file associati

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

Ora i file associati possono essere abbinati al modello tramite la libreria Python dei metadati. Il nuovo modello TensorFlow Lite diventa un file ZIP che contiene sia il modello sia i file associati. Può essere scompattato con i comuni strumenti per la zip. Questo nuovo formato di modello continua a utilizzare la stessa estensione di file, .tflite. È compatibile con il framework TFLite e la modalità Interprete esistenti. Per ulteriori dettagli, consulta Pacchettizzare i metadati e i file associati nel modello.

Le informazioni del file associate possono essere registrate nei metadati. A seconda del tipo di file e della posizione a cui è allegato il file (ad es. ModelMetadata, SubGraphMetadata e TensorMetadata), il generatore di codice Android TensorFlow Lite potrebbe applicare automaticamente la pre/post-elaborazione corrispondente all'oggetto. Per ulteriori dettagli, consulta la sezione <Utilizzo codegen> di ogni tipo di file associato nello schema.

Parametri di normalizzazione e quantizzazione

La normalizzazione è una tecnica di pre-elaborazione dei dati comune nel machine learning. L'obiettivo della normalizzazione è modificare i valori su una scala comune, senza distorcere le differenze negli intervalli di valori.

La quantizzazione dei modelli è una tecnica che consente rappresentazioni con precisione ridotta dei pesi 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 passaggi indipendenti. Di seguito sono riportati i dettagli:

Normalizzazione Quantizzazione

Un esempio dei valori dei parametri dell'immagine di input in MobileNet per i modelli mobili e quantitativi, rispettivamente.
Modello in virgola mobile:
- media: 127,5
- std: 127,5
Modello Quant:
- media: 127,5
- std: 127,5
Modello in virgola mobile:
- zeroPoint: 0
- scala: 1.0
Modello Quaant:
- zeroPoint: 128.0
- scala:0.0078125f




Quando richiamare?


Input: se i dati di input vengono normalizzati durante l'addestramento, devono essere normalizzati di conseguenza.
Output: i dati di output non verranno normalizzati in generale.
I modelli in virgola mobile non richiedono la quantizzazione.
Il modello quantizzato potrebbe o non richiedere la quantizzazione nella pre/post-elaborazione. Dipende dal tipo di dati dei tensori di input/output.
- tensori fluttuanti: non è necessaria nessuna quantizzazione in fase di pre/post-elaborazione. Le operazioni Quant e dequant op sono integrate nel grafico del modello.
- tensori int8/uint8: necessità di quantizzazione in pre/post-elaborazione.


Formula


normalized_input = (input - media) / std
Quantifica per gli input:
q = f / scala + zeroPoint
Dequantizza per le uscite:
f = (q - zeroPoint) * scala

Dove si trovano i parametri
Compilato dal creatore del modello e archiviato nei metadati del modello, come NormalizationOptions Compilato automaticamente dal convertitore TFLite e archiviato in un file di modello tflite.
Come si ottengono i parametri? Tramite l'API MetadataExtractor [2] Tramite l'API TFLite Tensor [1] o tramite l'API MetadataExtractor [2]
I modelli "float" e quantitativi hanno lo stesso valore? Sì, i modelli in virgola mobile e quantitativi hanno gli stessi parametri di normalizzazione No, il modello in virgola mobile non richiede la quantizzazione.
Il generatore di codice TFLite o l'associazione di Android Studio ML generano automaticamente questi elementi nell'elaborazione dei dati?

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

Durante l'elaborazione dei dati immagine per i modelli uint8, la normalizzazione e la quantizzazione a volte vengono ignorate. Puoi farlo se i valori dei pixel sono compresi nell'intervallo [0, 255]. In generale, però, dovresti sempre elaborare i dati in base ai parametri di normalizzazione e quantizzazione, se applicabili.

Esempi

Puoi trovare esempi su come compilare i metadati per diversi tipi di modelli qui:

Classificazione di immagini

Scarica lo script qui , che compila i metadati in mobilenet_v1_0.75_160_quantized.tflite. Esegui lo script come segue:

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 compilare i metadati per altri modelli di classificazione delle immagini, aggiungi le specifiche del modello come questa nello script. Il resto di questa guida evidenzia alcune delle sezioni principali nell'esempio di classificazione delle immagini per illustrare gli elementi chiave.

Approfondimento sull'esempio di classificazione delle immagini

Informazioni sul modello

Per prima cosa, i metadati creano 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 di output del modello. Questi metadati possono essere utilizzati da 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()

Input immagine

Immagine è un tipo di input comune per il machine learning. I metadati TensorFlow Lite supportano informazioni come lo spazio colore e le informazioni di pre-elaborazione come la normalizzazione. La dimensione dell'immagine non richiede una specifica manuale in quanto è 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

Output etichetta

L'etichetta può essere mappata a 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 Flatbuffers per i metadati

Il seguente codice combina le informazioni del 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()

Pacchettizzare i metadati e i file associati nel modello

Una volta creati i Flatbuffers dei metadati, i file dei metadati e delle etichette 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 pacchettizzare tutti i file associati che vuoi nel modello tramite load_associated_files. Tuttavia, è necessario comprimere almeno i file documentati nei metadati. In questo esempio, la pacchettizzazione del file di etichetta è obbligatoria.

Visualizza i metadati

Puoi utilizzare Netron per visualizzare i metadati oppure 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.

Controllo delle versioni dei metadati

Per lo schema dei metadati viene eseguito il controllo delle versioni sia in base al numero di controllo delle versioni semantico, che tiene traccia delle modifiche del file di schema, sia tramite l'identificazione del file Flatbuffers, che indica la compatibilità reale della versione.

Il numero di controllo delle versioni semantico

Il controllo delle versioni dello schema dei metadati viene eseguito in base al numero di controllo delle versioni semantico, ad esempio MAJOR.MINOR.PATCH. Monitora le modifiche allo schema in base alle regole qui. Consulta la cronologia dei campi aggiunti dopo la versione 1.0.0.

Identificazione del file Flatbuffers

Il controllo delle versioni semantico garantisce la compatibilità se si rispettano le regole, ma non implica la vera incompatibilità. Quando passi al numero MAJOR, non significa che la compatibilità con le versioni precedenti sia interrotta. Pertanto, utilizziamo l'identificazione del file Flatbuffers, file_identifier, per indicare la vera compatibilità dello schema dei metadati. L'identificatore del file contiene 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, file_identifier salirà, ad esempio, da "M001" a "M002". Si prevede che File_identifier verrà modificato molto meno frequentemente rispetto a metadata_version.

Versione minima necessaria dell'analizzatore sintattico dei metadati

La versione minima necessaria dell'analizzatore sintattico di metadati è la versione minima dell'analizzatore sintattico di metadati (il codice generato da Flatbuffers) in grado di leggere per intero i Flatbuffer di metadati. 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 dell'analizzatore sintattico di metadati viene compilata automaticamente dall'MetadataPopulator quando i metadati vengono inseriti in un modello TFLite. Consulta l'estrattore di metadati per ulteriori informazioni su come viene utilizzata la versione minima necessaria dell'analizzatore sintattico di metadati.

Leggi i metadati dai modelli

La libreria Metadata Extractor è un pratico strumento per leggere i metadati e i file associati da un modello su diverse piattaforme (vedi la versione Java e la versione C++). Puoi creare il tuo strumento di estrazione di metadati in altri linguaggi utilizzando la libreria Flatbuffers.

Leggi i metadati in Java

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

Puoi specificare questa opzione 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 snapshot Sonatype.

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

public MetadataExtractor(ByteBuffer buffer);

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 dell'analizzatore sintattico dei metadati. Per ulteriori informazioni, consulta la sezione sul 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 a causa del meccanismo di compatibilità in avanti e alle versioni precedenti dei Flatbuffer. Tuttavia, i campi di schemi futuri non possono essere estratti da estrattori di metadati meno recenti. La versione minima necessaria dell'analizzatore sintattico dei metadati indica la versione minima dell'analizzatore sintattico dei metadati in grado di leggere per intero i Flatbuffer dei metadati. Puoi utilizzare il seguente metodo per verificare se è soddisfatta la condizione minima necessaria per la versione dell'analizzatore sintattico:

public final boolean isMinimumParserVersionSatisfied();

È consentito il passaggio in un modello senza metadati. Tuttavia, il richiamo di metodi che leggono i metadati causerà errori di runtime. Puoi verificare se un modello ha metadati richiamando il metodo hasMetadata:

public boolean hasMetadata();

MetadataExtractor offre pratiche funzioni per ottenere i metadati dei tensori di input/output. Ad 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);

Anche se lo schema del modello TensorFlow supporta più sottografi, TFLite Interpreter supporta al momento solo un singolo grafico secondario. Di conseguenza, nei propri metodi MetadataExtractor omette l'indice del sottografo come argomento di input.

Leggere i file associati dai modelli

Il modello TensorFlow Lite con metadati e file associati è essenzialmente un file ZIP che può essere scomposto con i comuni strumenti di compressione per ottenere i file associati. Ad esempio, puoi decomprimere mobilenet_v1_0.75_160_quantized ed estrarre il file di etichette 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);

Analogamente, in C++, questa operazione può essere eseguita utilizzando il metodo ModelMetadataExtractor::GetAssociatedFile:

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