Agregar metadatos a los modelos de TensorFlow Lite

Los metadatos de TensorFlow Lite proporcionan un estándar para las descripciones de modelos. Los metadatos son una fuente importante de conocimiento sobre lo que hace el modelo y su información de entrada/salida. Los metadatos se componen tanto de

Todos los modelos de imágenes publicados en TensorFlow Hub se han completado con metadatos.

Modelo con formato de metadatos

modelo_con_metadatos
Figura 1. Modelo TFLite con metadatos y archivos asociados.

Los metadatos del modelo se definen en metadata_schema.fbs , un archivo FlatBuffer . Como se muestra en la Figura 1, se almacena en el campo de metadatos del esquema del modelo TFLite , bajo el nombre "TFLITE_METADATA" . Algunos modelos pueden venir con archivos asociados, como archivos de etiquetas de clasificación . Estos archivos se concatenan al final del archivo del modelo original como un ZIP utilizando el modo "añadir" de ZipFile (modo 'a' ). TFLite Interpreter puede consumir el nuevo formato de archivo de la misma manera que antes. Consulte Empaquetar los archivos asociados para obtener más información.

Consulte las instrucciones a continuación sobre cómo completar, visualizar y leer metadatos.

Configurar las herramientas de metadatos

Antes de agregar metadatos a su modelo, necesitará configurar un entorno de programación Python para ejecutar TensorFlow. Hay una guía detallada sobre cómo configurar esto aquí .

Después de configurar el entorno de programación Python, necesitará instalar herramientas adicionales:

pip install tflite-support

Las herramientas de metadatos de TensorFlow Lite son compatibles con Python 3.

Agregar metadatos usando Flatbuffers Python API

Hay tres partes de los metadatos del modelo en el esquema :

  1. Información del modelo : descripción general del modelo, así como elementos como los términos de la licencia. Consulte ModelMetadatos .
  2. Información de entrada : descripción de las entradas y el procesamiento previo requerido, como la normalización. Consulte SubGraphMetadata.input_tensor_metadata .
  3. Información de salida : descripción de la salida y el posprocesamiento requerido, como la asignación a etiquetas. Consulte SubGraphMetadata.output_tensor_metadata .

Dado que TensorFlow Lite solo admite un subgrafo en este momento, el generador de código de TensorFlow Lite y la función de enlace ML de Android Studio usarán ModelMetadata.name y ModelMetadata.description , en lugar de SubGraphMetadata.name y SubGraphMetadata.description , al mostrar metadatos y generar código.

Tipos de entrada/salida admitidos

Los metadatos de TensorFlow Lite para entrada y salida no están diseñados teniendo en cuenta tipos de modelos específicos, sino tipos de entrada y salida. No importa lo que haga funcionalmente el modelo, siempre que los tipos de entrada y salida consten de lo siguiente o una combinación de lo siguiente, será compatible con los metadatos de TensorFlow Lite:

  • Característica: números que son enteros sin signo o flotantes32.
  • Imagen: los metadatos actualmente admiten imágenes RGB y en escala de grises.
  • Cuadro delimitador: cuadros delimitadores de forma rectangular. El esquema admite una variedad de esquemas de numeración .

Empaquetar los archivos asociados

Los modelos de TensorFlow Lite pueden venir con diferentes archivos asociados. Por ejemplo, los modelos de lenguaje natural suelen tener archivos de vocabulario que asignan fragmentos de palabras a ID de palabras; Los modelos de clasificación pueden tener archivos de etiquetas que indican categorías de objetos. Sin los archivos asociados (si los hay), un modelo no funcionará bien.

Los archivos asociados ahora se pueden agrupar con el modelo a través de la biblioteca de metadatos de Python. El nuevo modelo de TensorFlow Lite se convierte en un archivo zip que contiene tanto el modelo como los archivos asociados. Se puede descomprimir con herramientas zip comunes. Este nuevo formato de modelo sigue usando la misma extensión de archivo, .tflite . Es compatible con el marco TFLite y el intérprete existentes. Consulte Empaquetar metadatos y archivos asociados en el modelo para obtener más detalles.

La información del archivo asociado se puede registrar en los metadatos. Dependiendo del tipo de archivo y de dónde está adjunto el archivo (es decir, ModelMetadata , SubGraphMetadata y TensorMetadata ), el generador de código de Android TensorFlow Lite puede aplicar el procesamiento previo/posterior correspondiente automáticamente al objeto. Consulte la sección <Uso de Codegen> de cada tipo de archivo asociado en el esquema para obtener más detalles.

Parámetros de normalización y cuantificación.

La normalización es una técnica de preprocesamiento de datos común en el aprendizaje automático. El objetivo de la normalización es cambiar los valores a una escala común, sin distorsionar las diferencias en los rangos de valores.

La cuantificación de modelos es una técnica que permite representaciones de pesos con precisión reducida y, opcionalmente, activaciones tanto para el almacenamiento como para el cálculo.

En términos de preprocesamiento y posprocesamiento, la normalización y la cuantificación son dos pasos independientes. Aquí están los detalles.

Normalización Cuantización

Un ejemplo de los valores de los parámetros de la imagen de entrada en MobileNet para modelos flotantes y cuantitativos, respectivamente.
Modelo de flotador :
- media: 127,5
- estándar: 127,5
Modelo cuantitativo :
- media: 127,5
- estándar: 127,5
Modelo de flotador :
- punto cero: 0
- escala: 1.0
Modelo cuantitativo :
- Punto cero: 128,0
- escala: 0,0078125f




¿Cuándo invocar?


Entradas : si los datos de entrada se normalizan durante el entrenamiento, los datos de entrada de inferencia deben normalizarse en consecuencia.
Salidas : los datos de salida no se normalizarán en general.
Los modelos flotantes no necesitan cuantificación.
El modelo cuantificado puede necesitar o no cuantificación en el procesamiento previo o posterior. Depende del tipo de datos de los tensores de entrada/salida.
- tensores flotantes: no se necesita cuantificación en el pre/post procesamiento. Las operaciones cuantitativas y decuantitativas se integran en el gráfico del modelo.
- Tensores int8/uint8: necesitan cuantificación en pre/post procesamiento.


Fórmula


entrada_normalizada = (entrada - media) / std
Cuantizar para entradas :
q = f / escala + punto cero
Descuantificar para salidas :
f = (q - punto cero) * escala

donde estan los parametros
Rellenado por el creador del modelo y almacenado en los metadatos del modelo, como NormalizationOptions Se rellena automáticamente mediante el convertidor TFLite y se almacena en un archivo de modelo tflite.
¿Cómo obtener los parámetros? A través de la API MetadataExtractor [2] A través de la API TFLite Tensor [1] o mediante la API MetadataExtractor [2]
¿Los modelos flotante y cuantitativo comparten el mismo valor? Sí, los modelos flotante y cuantitativo tienen los mismos parámetros de normalización. No, el modelo flotante no necesita cuantificación.
¿El generador de código TFLite o el enlace Android Studio ML lo generan automáticamente en el procesamiento de datos?

[1] API Java de TensorFlow Lite y API C++ de TensorFlow Lite .
[2] La biblioteca extractora de metadatos

Al procesar datos de imágenes para modelos uint8, a veces se omiten la normalización y la cuantificación. Está bien hacerlo cuando los valores de píxeles están en el rango de [0, 255]. Pero, en general, siempre debe procesar los datos de acuerdo con los parámetros de normalización y cuantificación cuando corresponda.

La biblioteca de tareas de TensorFlow Lite puede manejar la normalización por usted si configura NormalizationOptions en los metadatos. El procesamiento de cuantificación y descuantización siempre está encapsulado.

Ejemplos

Puede encontrar ejemplos sobre cómo se deben completar los metadatos para diferentes tipos de modelos aquí:

Clasificación de imágenes

Descargue el script aquí , que completa los metadatos en mobilenet_v1_0.75_160_quantized.tflite . Ejecute el script de esta manera:

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

Para completar metadatos para otros modelos de clasificación de imágenes, agregue especificaciones de modelo como esta en el script. El resto de esta guía resaltará algunas de las secciones clave del ejemplo de clasificación de imágenes para ilustrar los elementos clave.

Profundice en el ejemplo de clasificación de imágenes

Información del modelo

Los metadatos comienzan con la creación de una nueva información de modelo:

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

Información de entrada/salida

Esta sección le muestra cómo describir la firma de entrada y salida de su modelo. Estos metadatos pueden ser utilizados por generadores automáticos de código para crear código de procesamiento previo y posterior. Para crear información de entrada o salida sobre un tensor:

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

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

Entrada de imagen

La imagen es un tipo de entrada común para el aprendizaje automático. Los metadatos de TensorFlow Lite admiten información como el espacio de color e información de preprocesamiento como la normalización. La dimensión de la imagen no requiere especificación manual ya que ya la proporciona la forma del tensor de entrada y se puede inferir automáticamente.

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

Salida de etiqueta

La etiqueta se puede asignar a un tensor de salida a través de un archivo asociado usando 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]

Crear los Flatbuffers de metadatos

El siguiente código combina la información del modelo con la información de entrada y salida:

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

Empaquetar metadatos y archivos asociados en el modelo

Una vez que se crean los metadatos Flatbuffers, los metadatos y el archivo de etiqueta se escriben en el archivo TFLite mediante el método 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()

Puede empaquetar tantos archivos asociados como desee en el modelo a través de load_associated_files . Sin embargo, es necesario empaquetar al menos aquellos archivos documentados en los metadatos. En este ejemplo, es obligatorio empaquetar el archivo de etiquetas.

Visualizar los metadatos

Puede usar Netron para visualizar sus metadatos, o puede leer los metadatos de un modelo de TensorFlow Lite en 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 también admite la visualización de metadatos a través de la función Android Studio ML Binding .

Control de versiones de metadatos

El esquema de metadatos está versionado tanto por el número de versión semántica, que rastrea los cambios del archivo de esquema, como por la identificación del archivo Flatbuffers, que indica la verdadera compatibilidad de la versión.

El número de versiones semánticas

El esquema de metadatos está versionado por el número de versión semántica , como MAJOR.MINOR.PATCH. Realiza un seguimiento de los cambios de esquema de acuerdo con las reglas aquí . Vea el historial de campos agregados después de la versión 1.0.0 .

La identificación del archivo Flatbuffers

El versionado semántico garantiza la compatibilidad si se siguen las reglas, pero no implica la verdadera incompatibilidad. Aumentar el número PRINCIPAL no significa necesariamente que se haya roto la compatibilidad con versiones anteriores. Por lo tanto, utilizamos la identificación de archivo de Flatbuffers , file_identifier , para indicar la verdadera compatibilidad del esquema de metadatos. El identificador del archivo tiene exactamente 4 caracteres. Está fijado a un determinado esquema de metadatos y no está sujeto a cambios por parte de los usuarios. Si por algún motivo es necesario romper la compatibilidad con versiones anteriores del esquema de metadatos, el identificador de archivo aumentará, por ejemplo, de "M001" a "M002". Se espera que File_identifier se cambie con mucha menos frecuencia que metadata_version.

La versión mínima necesaria del analizador de metadatos

La versión mínima necesaria del analizador de metadatos es la versión mínima del analizador de metadatos (el código generado por Flatbuffers) que puede leer los metadatos de Flatbuffers en su totalidad. La versión es efectivamente el número de versión más grande entre las versiones de todos los campos completados y la versión compatible más pequeña indicada por el identificador del archivo. MetadataPopulator completa automáticamente la versión mínima necesaria del analizador de metadatos cuando los metadatos se completan en un modelo TFLite. Consulte el extractor de metadatos para obtener más información sobre cómo se utiliza la versión mínima necesaria del analizador de metadatos.

Leer los metadatos de los modelos.

La biblioteca Metadata Extractor es una herramienta conveniente para leer los metadatos y los archivos asociados de modelos en diferentes plataformas (consulte la versión Java y la versión C++ ). Puede crear su propia herramienta de extracción de metadatos en otros idiomas utilizando la biblioteca Flatbuffers.

Leer los metadatos en Java

Para usar la biblioteca Metadata Extractor en su aplicación de Android, le recomendamos usar TensorFlow Lite Metadata AAR alojado en MavenCentral . Contiene la clase MetadataExtractor , así como los enlaces Java FlatBuffers para el esquema de metadatos y el esquema del modelo .

Puede especificar esto en sus dependencias build.gradle de la siguiente manera:

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

Para utilizar instantáneas nocturnas, asegúrese de haber agregado el repositorio de instantáneas de Sonatype .

Puede inicializar un objeto MetadataExtractor con un ByteBuffer que apunte al modelo:

public MetadataExtractor(ByteBuffer buffer);

El ByteBuffer debe permanecer sin cambios durante toda la vida útil del objeto MetadataExtractor . La inicialización puede fallar si el identificador del archivo Flatbuffers de los metadatos del modelo no coincide con el del analizador de metadatos. Consulte versiones de metadatos para obtener más información.

Con identificadores de archivos coincidentes, el extractor de metadatos leerá con éxito los metadatos generados a partir de todos los esquemas pasados ​​y futuros debido al mecanismo de compatibilidad hacia adelante y hacia atrás de Flatbuffers. Sin embargo, los extractores de metadatos más antiguos no pueden extraer campos de esquemas futuros. La versión mínima necesaria del analizador de metadatos indica la versión mínima del analizador de metadatos que puede leer los Flatbuffers de metadatos en su totalidad. Puede utilizar el siguiente método para verificar si se cumple la condición de versión mínima necesaria del analizador:

public final boolean isMinimumParserVersionSatisfied();

Se permite pasar un modelo sin metadatos. Sin embargo, invocar métodos que leen los metadatos provocará errores de tiempo de ejecución. Puedes comprobar si un modelo tiene metadatos invocando el método hasMetadata :

public boolean hasMetadata();

MetadataExtractor proporciona funciones convenientes para obtener los metadatos de los tensores de entrada/salida. Por ejemplo,

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

Aunque el esquema del modelo TensorFlow Lite admite múltiples subgrafos, TFLite Interpreter actualmente solo admite un único subgrafo. Por lo tanto, MetadataExtractor omite el índice de subgrafo como argumento de entrada en sus métodos.

Leer los archivos asociados de los modelos.

El modelo TensorFlow Lite con metadatos y archivos asociados es esencialmente un archivo zip que se puede descomprimir con herramientas zip comunes para obtener los archivos asociados. Por ejemplo, puede descomprimir mobilenet_v1_0.75_160_quantized y extraer el archivo de etiqueta en el modelo de la siguiente manera:

$ 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

También puede leer archivos asociados a través de la biblioteca Metadata Extractor.

En Java, pase el nombre del archivo al método MetadataExtractor.getAssociatedFile :

public InputStream getAssociatedFile(String fileName);

De manera similar, en C++, esto se puede hacer con el método ModelMetadataExtractor::GetAssociatedFile :

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