Como adicionar metadados aos modelos LiteRT

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

Todos os modelos de imagem publicados no Kaggle Os modelos foram preenchidos com metadados.

Modelo com formato de metadados

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

Os metadados do modelo são definidos em metadata_schema.fbs (em inglês), por FlatBuffer . Como mostrado na figura 1, ele é armazenado metadados campo do modelo TFLite esquema, abaixo do nome, "TFLITE_METADATA". Alguns modelos podem vir com arquivos associados, como o rótulo de classificação .tf. Esses arquivos são concatenados ao final do arquivo de modelo original como um arquivo usando o ZipFile "append" (modo 'a'). TFLite O intérprete pode consumir o novo formato de arquivo da mesma forma que antes. Consulte Pacote os arquivos associados para mais informações.

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

Configurar as ferramentas de metadados

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

Depois de configurar o ambiente de programação Python, instale outras ferramentas:

pip install tflite-support

As ferramentas de metadados da LiteRT são compatíveis com o Python 3.

Como adicionar metadados usando a API Flatbuffers Python

Os metadados do modelo se dividem em três partes esquema:

  1. Informações do modelo: descrição geral do modelo e dos itens como termos de licença. Consulte ModelMetadata.
    1. Informações de entrada: descrição das entradas e do pré-processamento necessárias, como a normalização. Consulte SubGraphMetadata.input_tensor_metadata.
      1. Informações de saída: descrição da saída e exige o pós-processamento, como o mapeamento para rótulos. Consulte SubGraphMetadata.output_tensor_metadata.

Como o LiteRT suporta somente um subgráfico neste momento, o Gerador de código LiteRT e o Android Studio ML Binding recurso vai usar ModelMetadata.name e ModelMetadata.description, em vez de SubGraphMetadata.name e SubGraphMetadata.description, ao exibir metadados e geração de códigos.

Tipos de entrada / saída compatíveis

Os metadados LiteRT para entrada e saída não são projetados com informações tipos de modelo em mente, mas sim tipos de entrada e saída. Não importa o que funcionalmente, desde que os tipos de entrada e saída consistam em dos itens a seguir ou uma combinação das opções abaixo, ela é aceita pelo TensorFlow Metadados do Lite:

  • Recurso: números que sejam números inteiros não assinados ou float32.
  • Imagem: no momento, os metadados são compatíveis com imagens RGB e escala de cinza.
  • Caixa delimitadora: caixas delimitadoras de forma retangular. O esquema oferece suporte a uma variedade de numeração esquemas.

Empacotar os arquivos associados

Os modelos LiteRT podem vir com diferentes arquivos associados. Por exemplo: os modelos de linguagem natural geralmente têm arquivos de vocabulário que mapeiam IDs os modelos de classificação podem ter arquivos identificadores que indicam as categorias de objetos. Um modelo não funciona bem sem os arquivos associados (se houver).

Os arquivos associados agora podem ser agrupados com o modelo por meio dos metadados biblioteca Python. O novo modelo LiteRT se torna um arquivo ZIP que contém o modelo e os arquivos associados. Ele pode ser descompactado com um CEP comum ferramentas de visualização. Esse novo formato de modelo continua usando a mesma extensão de arquivo, .tflite. Ela é compatível com o framework TFLite e o intérprete existentes. Consulte Metadados do pacote e arquivos associados no model para mais detalhes.

As informações dos arquivos associados podem ser gravadas nos metadados. Dependendo o tipo de arquivo e onde ele está anexado (por exemplo, ModelMetadata, SubGraphMetadata e TensorMetadata), o código LiteRT do Android gerador pode aplicar os critérios pré/pós-testes automaticamente ao objeto. Consulte a página <Uso do Codegen> seção de cada arquivo associado tipo no esquema para saber mais.

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

A normalização é uma técnica comum de pré-processamento de dados em machine learning. A o objetivo da normalização é alterar os valores para uma escala comum, sem diferenças que distorçam os intervalos de valores.

A quantização de modelo é uma técnica que reduz a precisão das representações de pesos e, opcionalmente, e ativações para armazenamento e computação.

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

Normalização Quantização.

Um exemplo do do parâmetro imagem de entrada em MobileNet para dados flutuantes e modelos quantitativos, respectivamente.
Modelo de ponto flutuante:
- média: 127,5
- std: 127,5
Modelo quantitativo:
- média: 127,5
- std: 127,5
Modelo de ponto flutuante:
- zeroPoint: 0
- escala: 1,0
Modelo quantitativo:
- zeroPoint: 128,0
- scale:0.0078125f




Quando invocar?


Entradas: se entrada os dados são normalizados o treinamento, a entrada dados de necessidades de inferência para ser normalizado de acordo.
Saídas: output. os dados não serão normalizados em geral.
Os modelos flutuantes não precisam de quantização.
O modelo quantizado pode talvez não precisem quantização antes/depois processamento. Depende sobre o tipo de dados tensores de entrada/saída.
- tensores flutuantes: não quantização antes/depois processamento necessário. Quant op e dequant op são incorporada ao modelo gráfico.
- tensores int8/uint8: precisam de quantização pré/pós-processamento.


Fórmula


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

Onde estão os parâmetros
Preenchido pelo criador do modelo e armazenados no modelo metadados, conforme NormalizationOptions Preenchido automaticamente por conversor do TFLite armazenadas no modelo do tflite .
Como obter o parâmetros? Durante o API MetadataExtractor [2] Pelo TFLite API Tensor [1] ou através do API MetadataExtractor [2]
Flutuar e quantificar têm os mesmos valor? Sim, ponto flutuante e quant os modelos têm a mesma Normalização parâmetros Não, o modelo de flutuação não precisam de quantização.
O TFLite codifica ou Android Vinculação de ML do Studio gerar automaticamente no processamento de dados?
Sim

Sim

[1] A LiteRT Java API e a ferramenta LiteRT C++ API.
[2] A biblioteca de extratores de metadados

Ao processar dados de imagem para modelos uint8, a normalização e a quantização são pode ser ignorado. É possível fazer isso quando os valores de pixel estiverem no intervalo de [0, 255]. Mas, em geral, você deve sempre processar os dados de acordo com o normalização e quantização, quando aplicável.

Exemplos

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

Classificação de imagens

Fazer o download do script aqui , que preenche os metadados para mobilenet_v1_0.75_160_quantized.tflite. Execute o script desta forma:

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 preencher metadados de outros modelos de classificação de imagem, adicione as especificações do modelo. marcação "gostei" este no script. O restante deste guia destacará algumas das principais seções no exemplo de classificação de imagem para ilustrar os elementos-chave.

Análise detalhada do exemplo de classificação de imagens

Informações do modelo

Os metadados começam com a criação de 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

Nesta seção, mostramos como descrever a assinatura de entrada e saída do seu modelo. Esses metadados podem ser usados por geradores de código automáticos para criar pré e pós- o código de 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

A imagem é um tipo de entrada comum para machine learning. Metadados do LiteRT suporta 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 porque já é fornecido pela forma do tensor de entrada e pode ser inferidos 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 do rótulo

O identificador pode ser mapeado para um tensor de saída por meio 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]

Criar os Flatbuffers de metadados

O código a seguir combina as informações do modelo com as entradas e saídas informações:

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

Empacotar metadados e arquivos associados no modelo

Após a criação dos metadados Flatbuffers, os metadados e o arquivo de rótulo são gravado no arquivo TFLite usando o 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()

É possível empacotar quantos arquivos associados quiser no modelo load_associated_files: No entanto, é necessário empacotar pelo menos esses arquivos documentadas nos metadados. Neste exemplo, empacotar o arquivo de rótulo obrigatórios.

visualizar os metadados

Você pode usar o Netron para visualizar seus metadados, ou os metadados de um modelo LiteRT podem ser lidos em um arquivo 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)

O Android Studio também oferece suporte à exibição de metadados pela API Android Studio ML Vinculação .

Controle de versão de metadados

Os metadados esquema o controle de versão é baseado no número do controle de versão semântico, que rastreia as alterações do no arquivo de esquema e pela identificação do arquivo Flatbuffers, que indica o compatibilidade real de versão.

O número do controle de versão semântico

O esquema de metadados é controlado pelo controle de versão semântico número, como MAJOR.MINOR.PATCH. Ele rastreia as mudanças no esquema de acordo com as regras. aqui. Consulte a história da campos adicionado após a versão 1.0.0.

A identificação do arquivo Flatbuffers

O controle de versões semântico garante a compatibilidade se seguir as regras, mas não implica a verdadeira incompatibilidade. Ao encontrar o número MAJOR, não significa necessariamente que a compatibilidade com versões anteriores não está funcionando. Portanto, use o arquivo Flatbuffers identificação, file_identifier, para denotar a compatibilidade real do esquema de metadados. O identificador do arquivo é exatamente 4 caracteres. for fixa em um determinado esquema de metadados e não e está sujeita a alterações pelos usuários. Se a compatibilidade com versões anteriores do esquema de metadados precisar ser corrompido, o campo file_identifier aparecerá, por exemplo, de "M001" para "M002". Espera-se que o valor de "file_identifier" seja bem menor frequentemente que a metadata_version.

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

O analisador de metadados mínimo necessário versão é a versão mínima do analisador de metadados (o código gerado por Flatbuffers) que pode ler os Flatbuffers de metadados por completo. Efetivamente, a versão é maior número de versão entre as versões de todos os campos preenchidos e o menor versão compatível indicada pelo identificador do arquivo. O mínimo versão necessária do analisador de metadados é preenchida automaticamente pelo MetadataPopulator quando os metadados são preenchidos em um modelo do TFLite. Consulte a extrator de metadados para mais informações sobre como é usada a versão mínima necessária do analisador de metadados.

Ler os metadados dos modelos

A biblioteca Metadata Extractor é uma ferramenta conveniente para ler os metadados e arquivos associados a partir de um modelo em diferentes plataformas (consulte a documentação Java versão e a linguagem C++ versão). Você pode criar sua própria ferramenta de extração de metadados em outros idiomas usando o Flatbuffers.

Ler os metadados em Java

Para usar a biblioteca Metadata Extractor em seu app Android, recomendamos o uso de AAR de metadados da LiteRT hospedada em MavenCentral. Ele contém a classe MetadataExtractor e a classe FlatBuffers Java vinculações para os metadados esquema e o modelo esquema.

É possível especificar isso nas dependências build.gradle da seguinte maneira:

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

Para usar os snapshots noturnos, confira se você adicionou o snapshot do Sonatype repositório.

É possível inicializar um objeto MetadataExtractor com um ByteBuffer que aponta ao modelo:

public MetadataExtractor(ByteBuffer buffer);

O ByteBuffer precisa permanecer inalterado durante todo o ciclo de vida do objeto MetadataExtractor. A inicialização pode falhar se o arquivo Flatbuffers identificador dos metadados do modelo não corresponde ao identificador do analisador de metadados. Consulte controle de versão de metadados para mais informações.

Se houver identificadores de arquivo correspondentes, o extrator de metadados fará a leitura metadados gerados por todos os esquemas passados e futuros devido ao efeito mecanismo de compatibilidade com versões anteriores e posteriores. No entanto, os campos de dados futuros esquemas não podem ser extraídos por extratores de metadados mais antigos. O mínimo necessário versão do analisador dos metadados indica a versão mínima do analisador de metadados que pode ler os metadados Flatbuffers na totalidade. Você pode usar o método a seguir para verificar se o mínimo que a condição necessária da versão do analisador seja atendida:

public final boolean isMinimumParserVersionSatisfied();

É permitido transmitir um modelo sem metadados. No entanto, invocar métodos que uma leitura de metadados causará erros de tempo de execução. É possível verificar se um modelo tem metadados invocando o método hasMetadata:

public boolean hasMetadata();

O MetadataExtractor fornece funções convenientes para você receber tensores de entrada/saída' metadados. 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 modelo LiteRT esquema suporta vários subgráficos, o TFLite Interpreter atualmente oferece suporte apenas a um um único subgráfico. Portanto, MetadataExtractor omite o índice do subgráfico como uma entrada em seus métodos.

Ler os arquivos associados dos modelos

O modelo LiteRT com metadados e arquivos associados é essencialmente uma zip que pode ser descompactado com ferramentas zip comuns para obter os arquivos associados. Por exemplo, descompactar mobilenet_v1_0.75_160_quantized e extraia o arquivo do rótulo no modelo da seguinte maneira:

$ 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 pela biblioteca Metadata Extractor.

Em Java, transmita o nome do arquivo ao MetadataExtractor.getAssociatedFile :

public InputStream getAssociatedFile(String fileName);

Da mesma forma, em C++, isso pode ser feito com o método, ModelMetadataExtractor::GetAssociatedFile:

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