Os metadados do TensorFlow Lite fornecem um padrão para descrições de modelos. Os metadados são uma fonte importante de conhecimento sobre o que o modelo faz e as informações de entrada / saída. Os metadados consistem em
- partes legíveis por humanos, que transmitem a prática recomendada ao usar o modelo, e
- partes legíveis por máquina que podem ser aproveitadas por geradores de código, como o gerador de código do TensorFlow Lite para Android e o recurso de vinculação de ML do Android Studio.
Todos os modelos de imagem publicados no Kaggle Models foram preenchidos com metadados.
Modelo com formato de metadados
Os metadados do modelo são definidos em
metadata_schema.fbs,
um
arquivo
FlatBuffer. Conforme mostrado na Figura 1, ele é armazenado no campo de
metadados
do esquema do modelo
TFLite,
abaixo do nome "TFLITE_METADATA"
. Alguns modelos podem vir com arquivos associados, como arquivos de rótulo de classificação.
Esses arquivos são concatenados ao final do arquivo de modelo original como um ZIP usando o modo"append" (modo 'a'
) do ZipFile. O intérprete do TFLite
pode consumir o novo formato de arquivo da mesma maneira que antes. Consulte Compactar
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 modelo, configure um 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 outras ferramentas:
pip install tflite-support
As ferramentas de metadados do TensorFlow Lite são compatíveis com o Python 3.
Como adicionar metadados usando a API Flatbuffers Python
Os metadados do modelo têm três partes no esquema:
- Informações do modelo: descrição geral do modelo, bem como itens
como termos de licença. Consulte ModelMetadata.
- Informações de entrada: descrição das entradas e do pré-processamento
necessários, como a normalização. Consulte SubGraphMetadata.input_tensor_metadata.
- Informações de saída: descrição da saída e do pós-processamento necessários, como mapeamento para rótulos. Consulte SubGraphMetadata.output_tensor_metadata.
- Informações de entrada: descrição das entradas e do pré-processamento
necessários, como a normalização. Consulte SubGraphMetadata.input_tensor_metadata.
Como o TensorFlow Lite oferece suporte apenas a um único subgráfico neste momento, o
gerador de código do TensorFlow Lite
e o recurso de vinculação de ML
do Android Studio
usarão 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 compatíveis
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 com tipos de entrada e saída. Não importa o funcionalidade do modelo, desde que os tipos de entrada e saída consistam no seguinte ou em uma combinação dos itens abaixo, ele é compatível com os metadados do TensorFlow 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 é compatível com diversos esquemas de numeração.
Empacotar 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 associam palavras a IDs. Os modelos de classificação podem ter arquivos de rótulos que indicam 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 da biblioteca de metadados do Python. 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. Esse novo formato de modelo continua usando a mesma extensão de arquivo, .tflite
. Ele
é compatível com o framework e o interpretador do TFLite. Consulte Empacotar metadados e arquivos associados no modelo para saber mais.
As informações dos arquivos associados podem ser gravadas nos metadados. Dependendo do
tipo de arquivo e de onde ele está anexado (ou seja, ModelMetadata
, SubGraphMetadata
e TensorMetadata
), o gerador de código do TensorFlow Lite para Android pode aplicar automaticamente o pré/pós-processamento
correspondente ao objeto. Consulte a seção <Uso do Codegen> de cada tipo de arquivo associado 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. O objetivo da normalização é mudar os valores para uma escala comum, sem distorcer as diferenças nos intervalos de valores.
A quantização de modelo é uma técnica que permite reduzir representações de precisão de pesos e, opcionalmente, ativações para armazenamento e computação.
Em termos de pré e pós-processamento, a normalização e a quantização são duas etapas independentes. Veja os detalhes abaixo:
Normalização | Quantização. | |
---|---|---|
Um exemplo dos valores de parâmetro da imagem de entrada no MobileNet para modelos flutuantes e quantos, respectivamente. |
Modelo flutuante: - média: 127,5 - std: 127,5 Modelo quantitativo: - média: 127,5 - std: 127,5 |
Modelo flutuante: - zeroPoint: 0 - escala: 1,0 Modelo quantitativo: - zeroPoint: 128,0 - escalonamento:0.0078125f |
Quando invocar? |
Entradas: se os dados de entrada estiverem normalizados no treinamento, os dados de entrada de inferência precisarão ser normalizados adequadamente. Saídas: os dados de saída não serão normalizados em geral. |
Os modelos flutuantes não precisam de quantização. O modelo quantizado pode ou não precisar da quantização no pré/pós-processamento. Isso depende do tipo de dados dos tensores de entrada/saída. - tensores flutuantes: não é necessária a quantização no pré/pós processamento. As operações quantitativas e dequantas são integradas ao gráfico de modelo. - tensores int8/uint8: precisam de quantização no pré/pós-processamento. |
Fórmula |
normalized_input = (entrada - média) / std |
Quantizar para entradas:
q = f / scale + zeroPoint Desquantizar para saídas: f = (q - zeroPoint) * escalar |
Onde estão os parâmetros |
Preenchido pelo criador do modelo e armazenado em metadados dele, como NormalizationOptions . |
Preenchido automaticamente pelo conversor do TFLite e armazenado no arquivo de modelo do tflite. |
Como conseguir os parâmetros? | Pela
API MetadataExtractor
[2]
|
Pela API TFLite
Tensor [1] ou
pela
API MetadataExtractor
[2] |
Os modelos flutuantes e quânticos compartilham o mesmo valor? | Sim, os modelos flutuantes e quant têm os mesmos parâmetros de normalização | Não, o modelo flutuante não precisa de quantização. |
O gerador do TFLite Code ou a vinculação de ML do Android Studio o geram automaticamente no processamento de dados? | Sim |
Sim |
[1] A API
Java do TensorFlow Lite
e a API do
TensorFlow Lite para C++.
[2] A biblioteca de extratores de metadados
Ao processar dados de imagem para modelos uint8, a normalização e a quantização às vezes são ignoradas. Não há problema em fazer isso quando os valores de pixel estão no intervalo 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.
Exemplos
Veja exemplos de como os metadados devem ser preenchidos em diferentes tipos de modelos aqui:
Classificação de imagens
Faça 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 ao script as especificações de modelo como estas (link em inglês). O restante deste guia destacará algumas das principais seções no exemplo de classificação de imagem para ilustrar os elementos principais.
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 automáticos de código para criar códigos 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
A imagem é um tipo de entrada comum para machine learning. 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, porque ela 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 do rótulo
O rótulo 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 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()
Empacotar metadados e arquivos associados no modelo
Depois que os Flatbuffers de metadados são criados, os metadados e o arquivo de rótulo são
gravados 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 usando
load_associated_files
. No entanto, é necessário empacotar pelo menos os arquivos
documentados nos metadados. Neste exemplo, o empacotamento do arquivo de rótulos é obrigatório.
visualizar os metadados
É possível usar o Netron para visualizar seus
metadados ou ler os metadados de um modelo do 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)
O Android Studio também oferece suporte à exibição de metadados com o recurso de vinculação de ML do Android Studio.
Controle de versão de metadados
O esquema de metadados tem controle de versão pelo número do controle de versão semântico, que rastreia as mudanças do arquivo de esquema, e pela identificação do arquivo Flatbuffers, que indica a compatibilidade da versão verdadeira.
O número do controle de versão semântico
A versão do esquema de metadados é controlada pelo número de controle de versão semântico, como MAJOR.MINOR.PATCH. Ele rastreia as alterações no esquema de acordo com as regras aqui.
Consulte o histórico de campos adicionados 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. Aumentar o número MAJOR não significa necessariamente que a compatibilidade com versões anteriores está corrompida. Portanto, usamos a identificação de arquivo Flatbuffers, file_identifier, para indicar a verdadeira compatibilidade do esquema de metadados. O identificador do arquivo tem exatamente quatro caracteres. Ele é fixo em um determinado esquema de metadados e não está sujeito a alterações por parte dos usuários. Se a compatibilidade com versões anteriores do esquema de metadados precisar 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 o metadata_version.
A versão mínima necessária do analisador de metadados
A versão mínima necessária do analisador
de metadados
é a versão mínima do analisador de metadados (o código gerado por Flatbuffers) que
pode ler os Flatbuffers de 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
necessária do analisador de metadados é preenchida automaticamente pelo
MetadataPopulator
quando os metadados são preenchidos em um modelo do TFLite. Consulte o
extrator de metadados para mais informações sobre como
a versão mínima necessária do analisador de metadados é usada.
Ler os metadados dos modelos
A biblioteca Metadata Extractor é uma ferramenta conveniente para ler os metadados e os arquivos associados de um modelo em diferentes plataformas. Consulte a versão do Java e a versão C++. Você pode criar sua própria ferramenta de extração de metadados em outros idiomas usando a biblioteca Flatbuffers.
Ler os metadados em Java
Para usar a biblioteca de extrator de metadados no seu app Android, recomendamos usar
o AAR de metadados do TensorFlow Lite hospedado no
MavenCentral.
Ele contém a classe MetadataExtractor
, bem como as vinculações Java do FlatBuffers para o esquema de metadados e o esquema do modelo.
É possível especificar isso nas dependências build.gradle
da seguinte maneira:
dependencies {
implementation 'org.tensorflow:tensorflow-lite-metadata:0.1.0'
}
Para usar snapshots noturnos, verifique se você adicionou o repositório de snapshots Sonatype.
É possível inicializar um objeto MetadataExtractor
com um ByteBuffer
que aponte
para o modelo:
public MetadataExtractor(ByteBuffer buffer);
O ByteBuffer
precisa permanecer inalterado durante toda a vida útil do
objeto MetadataExtractor
. A inicialização pode falhar se o identificador do arquivo Flatbuffers
dos metadados do modelo não corresponder ao identificador do analisador de metadados. Consulte Controle de versão de metadados para mais informações.
Com identificadores de arquivo correspondentes, o extrator de metadados vai ler os metadados gerados de todos os esquemas passados e futuros devido ao mecanismo de compatibilidade com versões anteriores e encaminhamento dos Flatbuffers. No entanto, os campos de esquemas futuros não podem ser extraídos por extratores de metadados mais antigos. A versão mínima necessária do analisador dos metadados indica a versão mínima do analisador de metadados que pode ler os Flatbuffers de metadados na íntegra. Use o método abaixo para verificar se a condição mínima necessária de versão do analisador foi atendida:
public final boolean isMinimumParserVersionSatisfied();
É permitido transmitir um modelo sem metadados. No entanto, invocar métodos que
leem metadados causará erros de ambiente de execução. Verifique se um modelo tem metadados invocando o método hasMetadata
:
public boolean hasMetadata();
MetadataExtractor
fornece funções convenientes para você receber os 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);
O esquema do modelo
do TensorFlow Lite
oferece suporte a vários subgráficos, mas o TFLite Interpreter atualmente aceita apenas um
único subgráfico. Portanto, MetadataExtractor
omite o índice do subgráfico como um argumento
de entrada nos métodos.
Ler os arquivos associados dos modelos
O modelo do TensorFlow Lite com metadados e arquivos associados é essencialmente um arquivo ZIP que pode ser descompactado com ferramentas ZIP comuns para receber os arquivos associados. Por exemplo, você pode descompactar mobilenet_v1_0.75_160_quantized e extrair o arquivo de 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 para o método
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;