Adicionar metadados aos modelos do TensorFlow Lite

Os metadados do TensorFlow Lite fornecem um padrão para descrições de modelos. Os metadados são uma importante fonte de conhecimento sobre o que o modelo faz e suas informações de entrada / saída. Os metadados consistem em ambos

Todos os modelos de imagem publicadas em TensorFlow Lite hospedado modelos e TensorFlow Hub foram preenchidos com metadados.

Modelo com formato de metadados

model_with_metadata
Figura 1. Modelo TFLite com metadados e arquivos associados.

Metadados modelo é definido em metadata_schema.fbs , um FlatBuffer arquivo. Como mostrado na Figura 1, ela é armazenada no metadados campo do esquema modelo TFLite , sob o nome, "TFLITE_METADATA" . Alguns modelos podem vir com arquivos associados, tais como arquivos de etiquetas de classificação . Esses arquivos são concatenados para o final do arquivo do modelo original como um ZIP usando o ZipFile modo "anexar" ( 'a' mode). O TFLite Interpreter pode consumir o novo formato de arquivo da mesma maneira que antes. Veja Pacote os arquivos associados para mais informações.

Veja as instruções abaixo sobre como preencher, visualizar e ler metadados.

Configure as ferramentas de metadados

Antes de adicionar metadados ao seu modelo, você precisará de uma configuração de ambiente de programação Python para executar o TensorFlow. Há um guia detalhado sobre como configurar isso aqui .

Após configurar o ambiente de programação Python, você precisará instalar ferramentas adicionais:

pip install tflite-support

As ferramentas de metadados TensorFlow Lite são compatíveis com Python 3.

Adicionando metadados usando Flatbuffers Python API

Há três partes para os metadados do modelo no esquema :

  1. Informações Model - descrição geral do modelo, bem como itens como termos de licença. Veja ModelMetadata .
  2. Informações de entrada - Descrição das entradas e pré-processamento necessário, tais como a normalização. Veja SubGraphMetadata.input_tensor_metadata .
  3. Informações de saída - Descrição do produto e pós-processamento necessária, como mapeamento de etiquetas. Veja SubGraphMetadata.output_tensor_metadata .

Desde TensorFlow Lite suporta apenas única subgráfico neste momento, o gerador de código TensorFlow Lite eo recurso Encadernação Android Estúdio ML usará ModelMetadata.name e ModelMetadata.description , em vez de SubGraphMetadata.name e SubGraphMetadata.description , ao exibir metadados e gerar código.

Tipos de entrada / saída suportados

Os metadados do TensorFlow Lite para entrada e saída não são projetados com tipos de modelo específicos em mente, mas sim tipos de entrada e saída. Não importa o que o modelo faz funcionalmente, contanto que os tipos de entrada e saída consistam no seguinte ou uma combinação do seguinte, ele é compatível com os metadados do TensorFlow Lite:

  • Feature - Números que são inteiros sem sinal ou float32.
  • Imagem - Os metadados atualmente suportam imagens RGB e em tons de cinza.
  • Caixa delimitadora - Caixas delimitadoras de forma retangular. O esquema suporta uma variedade de esquemas de numeração .

Empacote os arquivos associados

Os modelos do TensorFlow Lite podem vir com diferentes arquivos associados. Por exemplo, os modelos de linguagem natural geralmente têm arquivos de vocabulário que mapeiam pedaços de palavras para IDs de palavras; modelos de classificação podem ter arquivos de rótulo que indicam categorias de objeto. Sem os arquivos associados (se houver), um modelo não funcionará bem.

Os arquivos associados agora podem ser agrupados com o modelo por meio da biblioteca Python de metadados. O novo modelo do TensorFlow Lite se torna um arquivo zip que contém o modelo e os arquivos associados. Ele pode ser descompactado com ferramentas zip comuns. Este novo formato modelo continua usando a mesma extensão de arquivo, .tflite . É compatível com a estrutura TFLite e o Interpreter existentes. Ver metadados Pack e arquivos associados para o modelo para mais detalhes.

As informações do arquivo associado podem ser registradas nos metadados. Dependendo do tipo de ficheiro e onde o ficheiro está ligado a (isto é, ModelMetadata , SubGraphMetadata , e TensorMetadata ), o gerador de código TensorFlow Lite Android pode aplicar o processamento de pré / pós correspondente automaticamente para o objecto. Veja o <uso Codegen> seção de cada tipo de arquivo associado no esquema para obter mais detalhes.

Parâmetros de normalização e quantização

A normalização é uma técnica comum de pré-processamento de dados no aprendizado de máquina. O objetivo da normalização é alterar os valores para uma escala comum, sem distorcer as diferenças nas faixas de valores.

Modelo de quantização é uma técnica que permite a precisão representações reduzidas de pesos e, opcionalmente, as activações, tanto para o armazenamento e computação.

Em termos de pré-processamento e pós-processamento, normalização e quantização são duas etapas independentes. Aqui estão os detalhes.

Normalização Quantização

Um exemplo dos valores dos parâmetros da imagem de entrada no MobileNet para modelos float e quant, respectivamente.
Modelo float:
- média: 127,5
- std: 127,5
Modelo Quant:
- média: 127,5
- std: 127,5
Modelo float:
- zero ponto: 0
- escala: 1,0
Modelo Quant:
- zeroPoint: 128,0
- escala: 0,0078125f




Quando invocar?


Entradas: Se os dados de entrada é normalizado em treinamento, os dados de entrada de necessidades de inferência a ser normalizada em conformidade.
Saídas: dados de saída não será normalizado em geral.
Se modelos flutuador não precisa de quantização.
Modelo Quantized pode ou não pode precisar de quantização em pré processamento / post. Depende do tipo de dados dos tensores de entrada / saída.
- tensores flutuantes: não é necessária quantização no pré / pós-processamento. Quant op e dequant op são incorporados ao gráfico do modelo.
- tensores int8 / uint8: precisam de quantização no pré / pós processamento.


Fórmula


normalized_input = (entrada - média) / std
Quantize para entradas:
q = f / escala + ponto zero
Dequantize para saídas:
f = (q - zero ponto) * escala

Onde estão os parâmetros
Preenchida por modelo criador e armazenado em metadados modelo, como NormalizationOptions Preenchido automaticamente pelo conversor TFLite e armazenado no arquivo de modelo tflite.
Como obter os parâmetros? Através da MetadataExtractor API [2] Através da TFLite Tensor API [1] ou através do MetadataExtractor API [2]
Os modelos float e quant compartilham o mesmo valor? Sim, os modelos float e quant têm os mesmos parâmetros de normalização Não, o modelo float não precisa de quantização.
O gerador de código TFLite ou a associação do Android Studio ML o gera automaticamente no processamento de dados?
sim

sim

[1] O TensorFlow Lite Java API ea API TensorFlow Lite C ++ .
[2] A biblioteca extractor de metadados

Ao processar dados de imagem para modelos uint8, a normalização e a quantização às vezes são ignoradas. É bom fazer isso quando os valores de pixel estão na faixa de [0, 255]. Mas, em geral, você deve sempre processar os dados de acordo com os parâmetros de normalização e quantização quando aplicável.

Biblioteca de Tarefas Lite TensorFlow pode lidar com a normalização para você, se você configurar NormalizationOptions em metadados. O processamento de quantização e desquantização é sempre encapsulado.

Exemplos

Você pode encontrar exemplos de como os metadados devem ser preenchidos para diferentes tipos de modelos aqui:

Classificação de imagem

Baixe o roteiro aqui , que preenche metadados para mobilenet_v1_0.75_160_quantized.tflite . Execute o script assim:

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 metadados populate para outros modelos de classificação de imagens, adicionar as especificações modelo como este para o script. O restante deste guia destacará algumas das seções principais no exemplo de classificação de imagens para ilustrar os elementos principais.

Mergulhe no exemplo de classificação de imagens

Informação do modelo

Os metadados começam criando uma nova informação 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.")

Informações de entrada / saída

Esta seção mostra como descrever a assinatura de entrada e saída do seu modelo. Esses metadados podem ser usados ​​por geradores automáticos de código para criar código de pré e pós-processamento. Para criar informações de entrada ou saída sobre um tensor:

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

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

Entrada de imagem

Imagem é um tipo de entrada comum para aprendizado de máquina. Os metadados do TensorFlow Lite oferecem suporte a informações como espaço de cores e informações de pré-processamento, como normalização. A dimensão da imagem não requer especificação manual, pois já é fornecida pela forma do tensor de entrada e pode ser inferida 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

Saída de etiqueta

Etiqueta pode ser mapeado para um tensor de saída através de um arquivo associado 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]

Crie os metadados Flatbuffers

O código a seguir combina as informações do modelo com as informações de entrada e saída:

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

Pacote de metadados e arquivos associados no modelo

Uma vez que os Flatbuffers metadados é criado, os metadados e o arquivo de etiqueta são escritos para o arquivo TFLite através do populate método:

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

Você pode embalar tantos arquivos associados como você quer no modelo através load_associated_files . No entanto, é necessário compactar pelo menos os arquivos documentados nos metadados. Neste exemplo, embalar o arquivo de etiqueta é obrigatório.

Visualize os metadados

Você pode usar Netron para visualizar seus metadados, ou você pode ler os metadados de um modelo TensorFlow Lite em um formato JSON usando o 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)

Estúdio Android também suporta a exibição de metadados através do recurso Encadernação Android Estúdio ML .

Controle de versão de metadados

O esquema de metadados é versionadas tanto pelo número de versão semântica, que acompanha as mudanças do arquivo de esquema, e pela identificação de arquivo Flatbuffers, o que indica a verdadeira compatibilidade de versão.

O número de versão semântica

O esquema de metadados é versionadas pelo número de versão semântica , como MAJOR.MINOR.PATCH. Ele controla as alterações do esquema de acordo com as regras aqui . Veja a história de campos adicionados após a versão 1.0.0 .

A identificação do arquivo Flatbuffers

O versionamento semântico garante a compatibilidade se seguir as regras, mas não implica na verdadeira incompatibilidade. Ao aumentar o número PRINCIPAL, isso não significa necessariamente que a compatibilidade com versões anteriores foi interrompida. Por isso, usamos a identificação do ficheiro Flatbuffers , file_identifier , para denotar a verdadeira compatibilidade do esquema de metadados. O identificador do arquivo tem exatamente 4 caracteres. Ele é fixado em um determinado esquema de metadados e não está sujeito a alterações pelos usuários. Se a compatibilidade com versões anteriores do esquema de metadados tiver que ser quebrada por algum motivo, o file_identifier aumentará, por exemplo, de “M001” para “M002”. Espera-se que o File_identifier seja alterado com muito menos frequência do que metadata_version.

A versão mínima necessária do analisador de metadados

A versão mínima analisador metadados necessários é a versão mínima do analisador de metadados (os Flatbuffers código gerado) que pode ler os Flatbuffers metadados na íntegra. A versão é efetivamente o maior número de versão entre as versões de todos os campos preenchidos e a menor versão compatível indicada pelo identificador de arquivo. A versão mínima analisador metadados necessários é preenchido automaticamente pelo MetadataPopulator quando os metadados é preenchida em um modelo TFLite. Veja o extrator de metadados para mais informações sobre como a versão mínima necessária analisador de metadados é usado.

Leia os metadados dos modelos

A biblioteca Metadados Extractor é uma ferramenta conveniente para ler os metadados e arquivos associados a partir de um modelos em diferentes plataformas (ver a versão Java ea versão C ++ ). Você pode construir sua própria ferramenta de extração de metadados em outras linguagens usando a biblioteca Flatbuffers.

Leia os metadados em Java

Para usar a biblioteca Metadados Extractor em seu aplicativo Android, recomendamos o uso do TensorFlow Lite Metadados AAR hospedado no MavenCentral . Ele contém o MetadataExtractor classe, bem como as ligações FlatBuffers Java para o esquema de metadados e o esquema do modelo .

Você pode especificar isso em suas build.gradle dependências da seguinte forma:

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

Para usar snapshots noturnos, certifique-se que você adicionou repositório Sonatype instantâneo .

Você pode inicializar um MetadataExtractor objeto com um ByteBuffer que aponta para o modelo:

public MetadataExtractor(ByteBuffer buffer);

O ByteBuffer deve permanecer inalterada durante toda a vida útil do MetadataExtractor objeto. A inicialização pode falhar se o identificador de arquivo Flatbuffers dos metadados do modelo não corresponder ao do analisador de metadados. Ver metadados de versão para obter mais informações.

Com identificadores de arquivo correspondentes, o extrator de metadados lerá com êxito os metadados gerados de todos os esquemas anteriores e futuros devido ao mecanismo de compatibilidade com versões anteriores e posteriores do Flatbuffers. No entanto, os campos de esquemas futuros não podem ser extraídos por extratores de metadados mais antigos. A versão analisador mínimo necessário dos metadados indica a versão mínima do analisador de metadados que pode ler os Flatbuffers metadados na íntegra. Você pode usar o seguinte método para verificar se a condição de versão mínima necessária do analisador é atendida:

public final boolean isMinimumParserVersionSatisfied();

É permitido passar um modelo sem metadados. No entanto, invocar métodos que leem os metadados causará erros de tempo de execução. Você pode verificar se um modelo tem metadados invocando o hasMetadata método:

public boolean hasMetadata();

MetadataExtractor fornece funções convenientes para você obter metadados dos tensores de entrada / saída. Por exemplo,

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

Embora o esquema do modelo TensorFlow Lite suporta múltiplos subgraphs, o TFLite Interpreter atualmente suporta apenas um único subgráfico. Portanto, MetadataExtractor omite índice subgráfico como um argumento de entrada nos seus métodos.

Leia os arquivos associados dos modelos

O modelo TensorFlow Lite com metadados e arquivos associados é essencialmente um arquivo zip que pode ser descompactado com ferramentas zip comuns para obter os arquivos associados. Por exemplo, você pode descompactar mobilenet_v1_0.75_160_quantized e extrair o arquivo de etiqueta no modelo da seguinte forma:

$ 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

Você também pode ler arquivos associados por meio da biblioteca Extrator de Metadados.

Em Java, passar o nome do arquivo para o MetadataExtractor.getAssociatedFile método:

public InputStream getAssociatedFile(String fileName);

Do mesmo modo, em C ++, isso pode ser feito com o método, ModelMetadataExtractor::GetAssociatedFile :

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