Path: blob/master/site/pt-br/lite/guide/inference.md
25118 views
Inferência com o TensorFlow Lite
O termo inferência refere-se ao processo de executar um modelo do TensdorFlow Lite em um dispositivo para fazer previsões com base nos dados de entrada. Para fazer a inferência de um modelo do TensorFlow Lite, você precisa executá-lo por meio de um interpretador. O interpretador do TensorFlow Lite é leve, rápido e usa uma ordenação estática de grafos e um alocador personalizado (menos dinâmico) de memória para garantir uma latência mínima de carga, inicialização e execução.
Esta página descreve como acessar o interpretador do TensorFlow Lite e fazer inferência usando o C++, Java e Python, além de incluir links para outros recursos para cada plataforma com suporte.
[TOC]
Conceitos importantes
Tipicamente, a inferência com o TensorFlow Lite segue estas etapas:
Carregamento do modelo
Você precisa adicionar o modelo
.tflite
à memória, que contém o grafo de execução do modelo.Transformação dos dados
Geralmente, os dados de entrada brutos do modelo não coincidem com o formato de dados de entrada esperado por ele. Por exemplo: talvez você precise redimensionar uma imagem ou alterar o formato da imagem para que fique compatível com o modelo.
Execução da inferência
Esta etapa envolve o uso da API do TensorFlow Lite para executar o modelo, além de envolver algumas etapas como compilar o interpretador e alocar tensores, conforme descrito nas próximas seções.
Interpretação da saída
Ao receber os resultados de inferência do modelo, você precisa interpretar os tensores de uma forma que faça sentido e seja útil para sua aplicação.
Por exemplo, talvez um modelo retorne somente uma lista de probabilidades. Cabe a você mapeá-las para categorias relevantes e apresentar os resultados ao usuário final.
Plataformas com suporte
São fornecidas APIs de inferência do TensorFlow para a maioria das plataformas comuns de dispositivos móveis/embarcadas, como Android, iOS e Linux, em diversas linguagens de programação.
Na maioria dos casos, o design da API reflete a preferência por desempenho em vez de facilidade de uso. O TensorFlow Lite foi criado para fazer uma inferência rápida em dispositivos pequenos, então não é surpresa nenhuma que as APIs tentem evitar cópias desnecessárias apenas por questões de conveniência. De maneira similar, a consistência com as APIs do TensorFlow não era um objetivo explícito, e deve-se esperar algumas variações entre as linguagens.
Dentre todas as bibliotecas, a API do TensorFlow Lite permite carregar modelos, alimentar entradas e buscar saídas de inferência.
Plataforma Android
No Android, a inferência com o TensorFlow Lite pode ser realizada usando APIs do Java ou C++. As APIs do Java são convenientes e podem ser usadas diretamente nas classes de Activity do Android. As APIs do C++ oferecem mais flexibilidade e velocidade, mas podem exigir a programação de encapsuladores JNI para mover dados entre as camadas do Java e do C++.
Confira detalhes sobre o uso do C++ e do Java abaixo ou confira um tutorial e exemplo de código no Guia de início rápido para Android.
Gerador de código do encapsulador Android para o TensorFlow Lite
Observação: o gerador de código do encapsulador para o TensorFlow Lite está em fase experimental (beta) e, no momento, só tem suporte ao Android.
Para o modelo do TensorFlow Lite aprimorado com metadados, os desenvolvedores podem usar o gerador de código do encapsulador Android para o TensorFlow Lite para criar o código do encapsulador específico para a plataforma. O código do encapsulador remove a necessidade de interagir diretamente com o ByteBuffer
no Android. Em vez disso, os desenvolvedores podem interagir com o modelo do TensorFlow Lite usando objetos tipados, como Bitmap
e Rect
. Confira mais informações em Gerador de código do encapsulador Android para o TensorFlow Lite.
Plataforma iOS
No iOS, o TensorFlow Lite está disponível com bibliotecas nativas do iOS no Swift e no Objective-C. Além disso, você pode usar a API do C diretamente em código do Objective-C.
Confira detalhes sobre o uso do Swift, do Objective-C e da API do C abaixo ou confira um tutorial e exemplo de código no Guia rápido para iOS.
Plataforma Linux
Em plataformas Linux (incluindo Raspberry Pi), você pode executar inferência usando as APIs do TensorFlow Lite disponíveis no C++ e no Python, conforme exibido nas seções abaixo.
Como executar um modelo
Para executar um modelo do TensorFlow Lite, é preciso seguir algumas etapas:
Carregue o modelo na memória.
Compile um
Interpreter
com base em um modelo existente.Defina os valores dos tensores de entrada (opcionalmente, redimensione os tensores de entrada se os tamanhos predefinidos não forem desejáveis).
Invoque a inferência.
Leia os valores dos tensores de saída.
As próximas seções descrevem como essas etapas podem ser feitas em cada linguagem.
Carregue e execute um modelo no Java
Plataforma: Android
A API do Java para executar inferência com o TensorFlow Lite foi criada principalmente para uso com o Android, então ela está disponível como uma dependência de biblioteca do Android: org.tensorflow:tensorflow-lite
.
No Java, você usará a classe Interpreter
para carregar um modelo e fazer a inferência. Em diversos casos, essa poderá ser a única API que você precisará utilizar.
Você pode inicializar um Interpreter
usando um arquivo .tflite
:
Ou com um MappedByteBuffer
:
Nos dois casos, você precisa fornecer um modelo válido do TensorFlow Lite, ou então a API vai gerar a exceção IllegalArgumentException
. Se você utilizar MappedByteBuffer
para inicializar um Interpreter
, ele precisará permanecer inalterado durante todo o ciclo de vida do Interpreter
.
A melhor forma de executar a inferência em um modelo é usando assinaturas, disponíveis para modelos convertidos a partir do Tensorflow 2.5.
O método runSignature
recebe três argumentos:
Inputs (entradas): faz o mapeamento de entradas do nome de entradas na assinatura para um objeto de entrada.
Outputs (saídas): faz o mapeamento de saídas do nome de saída na assinatura para os dados de saída.
Signature Name (nome da assinatura) [opcional]: nome da assinatura (pode ser deixado em branco se o modelo tiver uma única assinatura).
Outra forma de executar a inferência quando o modelo não tiver assinaturas definidas: basta chamar Interpreter.run()
. Por exemplo:
O método run()
recebe somente uma entrada e retorna somente uma saída. Portanto, se o seu modelo tiver diversas entradas ou diversas saídas, use:
Neste caso, cada entrada em inputs
corresponde a um tensor de entrada, e map_of_indices_to_outputs
mapeia índices de tensores de saída para os dados de saída correspondentes.
Nos dois casos, os índices dos tensores correspondem aos valores que você forneceu ao TensorFlow Lite Converter (conversor do TF Lite) ao criar o modelo. É importante salientar que a ordem dos tensores em input
precisa coincidir com a ordem fornecida para o conversor do TensorFlow Lite.
A classe Interpreter
também conta com funções convenientes para obter o índice de qualquer entrada ou saída do modelo usando um nome de operação:
Se opName
não for uma operação válida no modelo, é gerada a exceção IllegalArgumentException
.
Também é importante salientar que o Interpreter
é proprietário de recursos. Para evitar vazamento de memória, os recursos precisam ser liberados após o uso da seguinte forma:
Confira um exemplo de projeto com Java no exemplo de classificação de imagens no Android.
Tipos de dados permitidos (no Java)
Para usar o TensorFlow Lite, os tipos de dados dos tensores de entrada e saída precisam ser um dos tipos primitivos abaixo:
float
int
long
byte
Também há suporte aos tipos String
, mas eles são codificados de forma diferente do que os tipos primitivos. Especificamente, o formato de um tensor String determina o número e a organização das strings no tensor, em que cada elemento é um string de tamanho variável. Nesse sentido, o tamanho (byte) do tensor não pode ser computado somente a partir do formato e do tipo e, consequentemente, as strings não podem ser fornecidas como um único argumento simples ByteBuffer
. Confira alguns exemplos nesta página.
Se forem usados outros tipos de dados, incluindo tipos boxed, como Integer
e Float
, será gerada a exceção IllegalArgumentException
.
Entradas
Cada entrada deve ser um array ou um array multidimensional dos tipos primitivos permitidos, ou um ByteBuffer
bruto do tamanho adequado. Se a entrada for um array ou um array multidimensional, o tensor de entrada associado será redimensionado implicitamente para as dimensões do array no momento da inferência. Se a entrada for um ByteBuffer, o chamador deverá primeiro redimensionar manualmente o tensor de entrada associado (via Interpreter.resizeInput()
) antes de executar a inferência.
Ao usar ByteBuffer
, é melhor usar buffers de byte diretos, pois assim o Interpreter
poderá evitar cópias desnecessárias. Se o ByteBuffer
for um buffer de byte direto, sua ordem deve ser ByteOrder.nativeOrder()
. Após ser usado para inferência do modelo, ele deve permanecer inalterado até a conclusão da inferência.
Saídas
Cada saída deve ser um array ou um array multidimensional dos tipos primitivos permitidos, ou um ByteBuffer do tamanho adequado. Alguns modelos têm saídas dinâmicas, em que o formato dos tensores de saída pode variar, dependendo da entrada. Não há uma única forma direta de tratar esse problema com a API atual de inferência do Java, mas extensões futuras deverão permitir isso.
Carregue e execute um modelo no Swift
Plataforma: iOS
A API do Swift está disponível no pod TensorFlowLiteSwift
do CocoaPods.
Primeiro, você precisa importar o módulo TensorFlowLite
.
Carregue e execute um modelo no Objective-C
Plataforma: iOS
A API do Objective-C está disponível no pod TensorFlowLiteObjC
do CocoaPods.
Primeiro, você precisa importar o módulo TensorFlowLite
.
Como usar a API do C em código do Objective-C
Atualmente, a API do Objective-C não tem suporte a delegados. Para usar delegados em código do Objective-C, você precisa chamar diretamente a API do C subjacente.
Carregue e execute um modelo no C++
Plataformas: Android, iOS e Linux
Observação: a API do C++ no iOS está disponível somente ao usar o Bazel.
No C++, o modelo é armazenado na classe FlatBufferModel
. Ele encapsula um modelo do TensorFlow Lite, e você pode compilá-lo de diferentes formas, dependendo de onde o modelo é armazenado:
Observação: se o TensorFlow Lite detectar a presença da NNAPI do Android, vai tentar automaticamente usar a memória compartilhada para armazenar o FlatBufferModel
.
Agora que você tem o modelo como um objeto FlatBufferModel
, pode executá-lo com um Interpreter
. Um único FlatBufferModel
pode ser usado simultaneamente por mais de um Interpreter
.
Atenção: o objeto FlatBufferModel
precisa permanecer válido até todas as instâncias do Interpreter
que o utilizem serem destruídas.
As partes importantes da API do Interpreter
são exibidas no trecho de código abaixo. Deve-se observar que:
Os tensores são representados por inteiros para evitar comparações entre strings (e qualquer dependência fixa nas bibliotecas de strings).
Um interpretador não pode ser acessado em threads simultâneos.
A alocação de memória para os tensores de entrada e saída precisa ser acionada chamando
AllocateTensors()
logo após o redimensionamento dos tensores.
Veja o uso mais simples do TensorFlow Lite com C++:
Confira mais códigos de exemplo em minimal.cc
e label_image.cc
.
Carregue e execute um modelo no Python
Plataforma: Linux
A API do Python para executar inferência é fornecida no módulo tf.lite
. Basicamente, você só precisa do tf.lite.Interpreter
para carregar um modelo e executar a inferência.
O exemplo abaixo mostra como usar o interpretador do Python para carregar um arquivo .tflite
e executar a inferência com dados de entrada aleatórios:
Este exemplo é recomendado se você estiver convertendo um SavedModel com uma SignatureDef definida. Disponível a partir do TensorFlow 2.5.
Outro exemplo se o modelo não tiver SignatureDefs definidas.
Como alternativa para carregar o modelo como um arquivo .tflite
pré-convertido, você pode combinar seu código com a API do Python do conversor do TensorFlow Lite (tf.lite.TFLiteConverter
), permitindo converter seu modelo do Keras para o formato do TensorFlow Lite e depois executar a inferência:
Confira mais exemplos de código do Python em label_image.py
.
Dica: execute help(tf.lite.Interpreter)
no terminal do Python para ver a documentação detalhada sobre o interpretador.
Execute a inferência com um modelo de formato dinâmico
Se você deseja executar um modelo com formato de entrada dinâmico, redimensione o formato da entrada antes de executar a inferência. Caso contrário, o formato None
em modelos do Tensorflow será substituído pelo padrão 1
nos modelos do TF Lite.
Os exemplos abaixo mostram como redimensionar o formato da entrada antes de executar a inferência em diferentes linguagens. Todos os exemplos pressupõem que o formato da entrada é definido como [1/None, 10]
e precisa ser redimensionado para [3, 10]
.
Exemplo no C++:
Exemplo no Python:
Operações permitidas
O TensorFlow Lite tem suporte a um subconjunto das operações do TensorFlow, com algumas limitações. Veja a lista completa de operações e limitações na página de operações do TF Lite.