O Dia da Comunidade de ML é dia 9 de novembro! Junte-nos para atualização de TensorFlow, JAX, e mais Saiba mais

Processar dados de entrada e saída com a Biblioteca de Suporte TensorFlow Lite

Os desenvolvedores de aplicativos móveis normalmente interagem com objetos digitados, como bitmaps, ou primitivos, como inteiros. No entanto, o TensorFlow Lite Interpreter que executa o modelo de aprendizado de máquina no dispositivo usa tensores na forma de ByteBuffer, que pode ser difícil de depurar e manipular. A Biblioteca de Apoio Android TensorFlow Lite foi projetado para processo ajuda a entrada e saída de modelos TensorFlow Lite, e fazer o TensorFlow Lite intérprete mais fácil de usar.

Começando

Importar dependência do Gradle e outras configurações

Copie o .tflite arquivo de modelo para o diretório ativo do módulo Android onde o modelo será executado. Especificar que o arquivo não deve ser comprimido, e adicione a biblioteca TensorFlow Lite ao módulo build.gradle arquivo:

android {
    // Other settings

    // Specify tflite file should not be compressed for the app apk
    aaptOptions {
        noCompress "tflite"
    }

}

dependencies {
    // Other dependencies

    // Import tflite dependencies
    implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly-SNAPSHOT'
    // The GPU delegate library is optional. Depend on it as needed.
    implementation 'org.tensorflow:tensorflow-lite-gpu:0.0.0-nightly-SNAPSHOT'
    implementation 'org.tensorflow:tensorflow-lite-support:0.0.0-nightly-SNAPSHOT'
}

Explore a TensorFlow Lite Suporte Biblioteca AAR hospedado no MavenCentral para diferentes versões da biblioteca de suporte.

Manipulação e conversão de imagens básicas

A Biblioteca de Suporte do TensorFlow Lite tem um pacote de métodos básicos de manipulação de imagens, como cortar e redimensionar. Para usá-lo, criar um ImagePreprocessor e adicione as operações necessárias. Para converter a imagem para o formato tensor exigido pelo intérprete TensorFlow Lite, criar um TensorImage para ser usado como entrada:

import org.tensorflow.lite.support.image.ImageProcessor;
import org.tensorflow.lite.support.image.TensorImage;
import org.tensorflow.lite.support.image.ops.ResizeOp;

// Initialization code
// Create an ImageProcessor with all ops required. For more ops, please
// refer to the ImageProcessor Architecture section in this README.
ImageProcessor imageProcessor =
    new ImageProcessor.Builder()
        .add(new ResizeOp(224, 224, ResizeOp.ResizeMethod.BILINEAR))
        .build();

// Create a TensorImage object. This creates the tensor of the corresponding
// tensor type (uint8 in this case) that the TensorFlow Lite interpreter needs.
TensorImage tensorImage = new TensorImage(DataType.UINT8);

// Analysis code for every frame
// Preprocess the image
tensorImage.load(bitmap);
tensorImage = imageProcessor.process(tensorImage);

DataType de um tensor podem ser lidos através da biblioteca exractor metadados , bem como outras informações sobre o modelo.

Processamento básico de dados de áudio

A Biblioteca de Apoio Lite TensorFlow também define um TensorAudio classe envolvendo alguns dados de áudio básicos métodos de processamento. É principalmente utilizado em conjunto com AudioRecord e captura de amostras de dio em um tampão de anel.

import org.tensorflow.lite.support.audio.TensorAudio;

// Create an `AudioRecord` instance.
AudioRecord record = AudioRecord(...)

// Create a `TensorAudio` object from Android AudioFormat.
TensorAudio tensorAudio = new TensorAudio(record.getFormat(), size)

// Load all audio samples available in the AudioRecord without blocking.
tensorAudio.load(record)

// Get the `TensorBuffer` for inference.
TensorBuffer buffer = tensorAudio.getTensorBuffer()

Crie objetos de saída e execute o modelo

Antes de executar o modelo, precisamos criar os objetos container que irão armazenar o resultado:

import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;

// Create a container for the result and specify that this is a quantized model.
// Hence, the 'DataType' is defined as UINT8 (8-bit unsigned integer)
TensorBuffer probabilityBuffer =
    TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8);

Carregando o modelo e executando a inferência:

import org.tensorflow.lite.support.model.Model;

// Initialise the model
try{
    MappedByteBuffer tfliteModel
        = FileUtil.loadMappedFile(activity,
            "mobilenet_v1_1.0_224_quant.tflite");
    Interpreter tflite = new Interpreter(tfliteModel)
} catch (IOException e){
    Log.e("tfliteSupport", "Error reading model", e);
}

// Running inference
if(null != tflite) {
    tflite.run(tImage.getBuffer(), probabilityBuffer.getBuffer());
}

Acessando o resultado

Promotores pode aceder a saída directamente através probabilityBuffer.getFloatArray() . Se o modelo produzir uma saída quantizada, lembre-se de converter o resultado. Para o modelo quantizado MobileNet, o desenvolvedor precisa dividir cada valor de saída por 255 para obter a probabilidade que varia de 0 (menos provável) a 1 (mais provável) para cada categoria.

Opcional: mapeamento de resultados para rótulos

Os desenvolvedores também podem, opcionalmente, mapear os resultados para rótulos. Primeiro, copie o arquivo de texto contendo rótulos para o diretório de ativos do módulo. Em seguida, carregue o arquivo de etiqueta usando o seguinte código:

import org.tensorflow.lite.support.common.FileUtil;

final String ASSOCIATED_AXIS_LABELS = "labels.txt";
List<String> associatedAxisLabels = null;

try {
    associatedAxisLabels = FileUtil.loadLabels(this, ASSOCIATED_AXIS_LABELS);
} catch (IOException e) {
    Log.e("tfliteSupport", "Error reading label file", e);
}

O snippet a seguir demonstra como associar as probabilidades aos rótulos de categoria:

import org.tensorflow.lite.support.common.TensorProcessor;
import org.tensorflow.lite.support.label.TensorLabel;

// Post-processor which dequantize the result
TensorProcessor probabilityProcessor =
    new TensorProcessor.Builder().add(new NormalizeOp(0, 255)).build();

if (null != associatedAxisLabels) {
    // Map of labels and their corresponding probability
    TensorLabel labels = new TensorLabel(associatedAxisLabels,
        probabilityProcessor.process(probabilityBuffer));

    // Create a map to access the result based on label
    Map<String, Float> floatMap = labels.getMapWithFloatValue();
}

Cobertura de caso de uso atual

A versão atual da Biblioteca de Suporte TensorFlow Lite abrange:

  • tipos de dados comuns (float, uint8, imagens, áudio e array desses objetos) como entradas e saídas de modelos tflite.
  • operações básicas de imagem (cortar imagem, redimensionar e girar).
  • normalização e quantização
  • utilitários de arquivo

As versões futuras irão melhorar o suporte para aplicativos relacionados a texto.

Arquitetura ImageProcessor

O design do ImageProcessor permitiu que as operações de manipulação de imagem a ser definida para a recepção e optimizado durante o processo de criação. O ImageProcessor atualmente suporta três operações básicas de pré-processamento:

int width = bitmap.getWidth();
int height = bitmap.getHeight();

int size = height > width ? width : height;

ImageProcessor imageProcessor =
    new ImageProcessor.Builder()
        // Center crop the image to the largest square possible
        .add(new ResizeWithCropOrPadOp(size, size))
        // Resize using Bilinear or Nearest neighbour
        .add(new ResizeOp(224, 224, ResizeOp.ResizeMethod.BILINEAR));
        // Rotation counter-clockwise in 90 degree increments
        .add(new Rot90Op(rotateDegrees / 90))
        .add(new NormalizeOp(127.5, 127.5))
        .add(new QuantizeOp(128.0, 1/128.0))
        .build();

Veja mais detalhes aqui sobre a normalização e quantização.

O objetivo eventual da biblioteca de suporte é apoiar todos os tf.image transformações. Isso significa que a transformação será a mesma do TensorFlow e a implementação será independente do sistema operacional.

Os desenvolvedores também podem criar processadores personalizados. É importante, nesses casos, estar alinhado com o processo de treinamento - ou seja, o mesmo pré-processamento deve ser aplicado ao treinamento e à inferência para aumentar a reprodutibilidade.

Quantização

Ao iniciar objetos de entrada ou de saída, como TensorImage ou TensorBuffer você precisa especificar seus tipos para ser DataType.UINT8 ou DataType.FLOAT32 .

TensorImage tensorImage = new TensorImage(DataType.UINT8);
TensorBuffer probabilityBuffer =
    TensorBuffer.createFixedSize(new int[]{1, 1001}, DataType.UINT8);

O TensorProcessor pode ser utilizado para quantificar tensores de entrada ou de saída dequantize tensores. Por exemplo, quando o processamento de uma saída quantizada TensorBuffer , o programador pode utilizar DequantizeOp para dequantize o resultado de uma probabilidade de ponto flutuante entre 0 e 1:

import org.tensorflow.lite.support.common.TensorProcessor;

// Post-processor which dequantize the result
TensorProcessor probabilityProcessor =
    new TensorProcessor.Builder().add(new DequantizeOp(0, 1/255.0)).build();
TensorBuffer dequantizedBuffer = probabilityProcessor.process(probabilityBuffer);

Os parâmetros de quantização de um tensor podem ser lidos através da biblioteca de metadados exractor .