Ayuda a proteger la Gran Barrera de Coral con TensorFlow en Kaggle Únete Challenge

Procesar datos de entrada y salida con la biblioteca de compatibilidad de TensorFlow Lite

Los desarrolladores de aplicaciones móviles suelen interactuar con objetos escritos como mapas de bits o primitivas como números enteros. Sin embargo, la API de intérprete de TensorFlow Lite que ejecuta el modelo de aprendizaje automático en el dispositivo usa tensores en forma de ByteBuffer, que pueden ser difíciles de depurar y manipular. La biblioteca de soporte Android TensorFlow Lite está diseñado para proceso de ayuda la entrada y salida de los modelos TensorFlow Lite, y hacer que el TensorFlow Lite intérprete más fácil de usar.

Empezando

Importar dependencia de Gradle y otras configuraciones

Copiar el .tflite archivo del modelo para el directorio activo del módulo de Android en la que se ejecuta el modelo. Especifica que el archivo no se debe comprimir, y añadir la biblioteca TensorFlow Lite para el módulo de build.gradle archivo:

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'
}

Explorar la TensorFlow Lite Soporte Biblioteca AAR alojado en MavenCentral para diferentes versiones de la biblioteca de soporte.

Conversión y manipulación básica de imágenes

La biblioteca de compatibilidad de TensorFlow Lite tiene un conjunto de métodos básicos de manipulación de imágenes, como recortar y cambiar el tamaño. Para usarlo, crear una ImagePreprocessor y añadir las operaciones requeridas. Para convertir la imagen en el formato requerido por tensor de la intérprete TensorFlow Lite, crear un TensorImage para ser utilizado como entrada:

import org.tensorflow.lite.DataType;
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 un tensor se puede leer a través de la biblioteca de exractor metadatos , así como otra información del modelo.

Procesamiento básico de datos de audio

La biblioteca de soporte Lite TensorFlow también define un TensorAudio clase envolver algunos datos de audio básicas de procesamiento de métodos. Se utiliza sobre todo junto con AudioRecord y capturas de muestras de audio en una memoria cíclica.

import android.media.AudioRecord;
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()

Crea objetos de salida y ejecuta el modelo.

Antes de ejecutar el modelo, necesitamos crear los objetos contenedores que almacenarán el resultado:

import org.tensorflow.lite.DataType;
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);

Cargando el modelo y ejecutando inferencia:

import java.nio.MappedByteBuffer;
import org.tensorflow.lite.InterpreterFactory;
import org.tensorflow.lite.InterpreterApi;

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

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

Accediendo al resultado

Los desarrolladores pueden acceder a la salida directamente a través de probabilityBuffer.getFloatArray() . Si el modelo produce una salida cuantificada, recuerde convertir el resultado. Para el modelo cuantificado de MobileNet, el desarrollador debe dividir cada valor de salida por 255 para obtener la probabilidad que va desde 0 (menos probable) a 1 (más probable) para cada categoría.

Opcional: asignación de resultados a etiquetas

Los desarrolladores también pueden, opcionalmente, asignar los resultados a las etiquetas. Primero, copie el archivo de texto que contiene las etiquetas en el directorio de activos del módulo. A continuación, cargue el archivo de etiqueta con el siguiente 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);
}

El siguiente fragmento muestra cómo asociar las probabilidades con etiquetas de categoría:

import java.util.Map;
import org.tensorflow.lite.support.common.TensorProcessor;
import org.tensorflow.lite.support.common.ops.NormalizeOp;
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 casos de uso actual

La versión actual de la biblioteca de compatibilidad de TensorFlow Lite cubre:

  • tipos de datos comunes (float, uint8, imágenes, audio y matriz de estos objetos) como entradas y salidas de modelos tflite.
  • operaciones de imagen básicas (recortar imagen, cambiar el tamaño y rotar).
  • normalización y cuantificación
  • utilidades de archivo

Las versiones futuras mejorarán el soporte para aplicaciones relacionadas con texto.

Arquitectura del procesador de imágenes

El diseño de la ImageProcessor permitió que las operaciones de manipulación de la imagen para ser definidas por adelantado y optimizado durante el proceso de construcción. El ImageProcessor es compatible actualmente con tres operaciones básicas de procesamiento previo, como se describe en los tres comentarios en el siguiente fragmento de código:

import org.tensorflow.lite.support.common.ops.NormalizeOp;
import org.tensorflow.lite.support.common.ops.QuantizeOp;
import org.tensorflow.lite.support.image.ops.ResizeOp;
import org.tensorflow.lite.support.image.ops.ResizeWithCropOrPadOp;
import org.tensorflow.lite.support.image.ops.Rot90Op;

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

Vea más detalles aquí sobre la normalización y la cuantificación.

El objetivo final de la biblioteca de soporte es apoyar a todos los tf.image transformaciones. Esto significa que la transformación será la misma que TensorFlow y la implementación será independiente del sistema operativo.

Los desarrolladores también pueden crear procesadores personalizados. En estos casos, es importante estar alineado con el proceso de capacitación, es decir, se debe aplicar el mismo procesamiento previo tanto al entrenamiento como a la inferencia para aumentar la reproducibilidad.

Cuantización

Cuando se inicia la entrada o salida de objetos tales como TensorImage o TensorBuffer necesita especificar su tipo a ser DataType.UINT8 o DataType.FLOAT32 .

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

El TensorProcessor se puede utilizar para cuantificar los tensores de entrada o descuantificar tensores de salida. Por ejemplo, cuando se procesa una salida cuantificada TensorBuffer , el desarrollador puede utilizar DequantizeOp para descuantificar el resultado a una probabilidad de coma flotante entre 0 y 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);

Los parámetros de cuantificación de un tensor se pueden leer a través de la biblioteca de metadatos exractor .