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 importante fuente de conocimiento sobre lo que hace el modelo y su información de entrada/salida. Los metadatos consisten en ambos

Todos los modelos de imágenes publicados en TensorFlow Hub se han rellenado 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 , con 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 mediante el modo "anexar" 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 de Python para ejecutar TensorFlow. Hay una guía detallada sobre cómo configurar esto aquí .

Después de configurar el entorno de programación de Python, deberá 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 en 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 ModelMetadata .
  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 solo subgráfico en este momento, el generador de código de TensorFlow Lite y la función de vinculación de 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 qué función tenga el modelo, siempre que los tipos de entrada y salida sean los siguientes o una combinación de los siguientes, es compatible con los metadatos de TensorFlow Lite:

  • Característica: números que son enteros sin signo o float32.
  • 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 partes de palabras a identificadores 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 existente y el intérprete. 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. Según el tipo de archivo y dónde se adjunte el archivo (es decir, SubGraphMetadata ModelMetadata TensorMetadata ), el generador de código de Android TensorFlow Lite puede aplicar el procesamiento previo o 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 común de preprocesamiento de datos 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 de 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 parámetro de la imagen de entrada en MobileNet para modelos flotantes y cuánticos, 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 en 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 o no necesitar cuantificación en el procesamiento previo o posterior. Depende del tipo de datos de los tensores de entrada/salida.
- tensores flotantes: no se necesita cuantización en el procesamiento previo/posterior. Quant op y dequant op se integran en el gráfico del modelo.
- Tensores int8/uint8: necesitan cuantificación en pre/postprocesamiento.


Fórmula


entrada_normalizada = (entrada - media) / std
Cuantificar 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 Llenado automáticamente por el convertidor TFLite y almacenado en el archivo del modelo tflite.
¿Cómo obtener los parámetros? A través de la API de MetadataExtractor [2] A través de la API TFLite Tensor [1] o a través de la API MetadataExtractor [2]
¿Los modelos flotantes y cuantitativos comparten el mismo valor? Sí, los modelos de flotación y cuantificación 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] La API de Java de TensorFlow Lite y la API de C++ de TensorFlow Lite.
[2] La biblioteca extractora de metadatos

Cuando se procesan datos de imagen para modelos uint8, a veces se omiten la normalización y la cuantificación. Está bien hacerlo cuando los valores de píxel 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 gestionar la normalización por ti si configuras NormalizationOptions en los metadatos. El procesamiento de cuantificación y descuantificació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 las especificaciones del modelo como esta en la secuencia de comandos. El resto de esta guía destacará algunas de las secciones clave en el ejemplo de clasificación de imágenes para ilustrar los elementos clave.

Sumérgete en el ejemplo de clasificación de imágenes

Información del modelo

Los metadatos comienzan creando una nueva información del 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 de código automáticos 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 y la información de preprocesamiento, como la normalización. La dimensión de la imagen no requiere especificación manual ya que la forma del tensor de entrada ya la proporciona 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 etiquetas

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 Flatbuffers de metadatos, los metadatos y el archivo de etiqueta se escriben en el archivo populate a través del método de llenado:

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 load_associated_files . Sin embargo, se requiere empaquetar al menos aquellos archivos documentados en los metadatos. En este ejemplo, es obligatorio empaquetar el archivo de etiquetas.

Visualiza los metadatos

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

Versionado de metadatos

El esquema de metadatos está versionado tanto por el número de versión Semantic, 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 versión semántica

El esquema de metadatos está versionado por el número de versión semántica , como MAYOR.MENOR.PARCHE. 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. Cuando aumenta el número PRINCIPAL, no significa necesariamente que la compatibilidad con versiones anteriores esté rota. Por lo tanto, usamos la identificación del archivo 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 la compatibilidad con versiones anteriores del esquema de metadatos debe romperse por algún motivo, 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 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 rellenados y la versión compatible más pequeña indicada por el identificador de archivo. La versión mínima necesaria del analizador de metadatos se completa automáticamente con MetadataPopulator 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 de Java y la versión de 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 del extractor de metadatos en su aplicación de Android, recomendamos usar el AAR de metadatos de TensorFlow Lite alojado en MavenCentral . Contiene la clase MetadataExtractor , así como los enlaces Java de 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 usar 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 control de versiones de metadatos para obtener más información.

Con los identificadores de archivo 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 los metadatos indica la versión mínima del analizador de metadatos que puede leer los Flatbuffers de metadatos en su totalidad. Puede usar el siguiente método para verificar si se cumple la condición mínima necesaria de la versión del analizador:

public final boolean isMinimumParserVersionSatisfied();

Se permite pasar un modelo sin metadatos. Sin embargo, la invocación de métodos que leen los metadatos provocará errores de tiempo de ejecución. Puede verificar 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 varios subgráficos, TFLite Interpreter actualmente solo admite un único subgráfico. Por lo tanto, MetadataExtractor omite el índice de subgráfico 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;