使用 LiteRT 支持库处理输入和输出数据

移动应用开发者通常会与类型化对象交互,例如 位图或整数等基元。然而,LiteRT 解释器 运行设备端机器学习模型的 API 使用如下形式的张量: ByteBuffer,可能难以调试和操纵。通过 LiteRT Android 支持库 旨在帮助处理 LiteRT 模型的输入和输出,以及 使 LiteRT 解释器更易于使用。

使用入门

导入 Gradle 依赖项和其他设置

.tflite 模型文件复制到 Android 模块的 assets 目录中 将运行模型的位置。指定不应压缩该文件,并且 将 LiteRT 库添加到模块的 build.gradle 文件中:

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 'com.google.ai.edge.litert:litert-gpu:0.0.0-nightly-SNAPSHOT'
    implementation 'com.google.ai.edge.litert:litert-support:0.0.0-nightly-SNAPSHOT'
}

探索 由 MavenCentral 托管的 LiteRT 支持库 AAR 不同版本的支持库。

基本图片操作和转换

LiteRT 支持库具有一套基本图像处理功能 例如剪裁和调整大小。如需使用它,请创建一个 ImagePreprocessor 并 添加所需的操作将图片转换为张量格式 根据 LiteRT 解释器的要求,创建一个要使用的 TensorImage 作为输入:

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 LiteRT interpreter needs.
TensorImage tensorImage = new TensorImage(DataType.UINT8);

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

张量的 DataType 可通过 元数据提取器库 以及其他模型信息。

基本音频数据处理

LiteRT 支持库还定义了封装 TensorAudio 的类。 一些基本的音频数据处理方法。它主要与以下参数搭配使用: AudioRecord 并在环形缓冲区中捕获音频样本。

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

创建输出对象并运行模型

在运行模型之前,我们需要创建容器对象, 存储结果:

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

加载模型并运行推理:

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

访问结果

开发者可以直接通过 probabilityBuffer.getFloatArray()。如果模型生成量化输出, 请务必转换结果。对于 MobileNet 量化模型,开发者 需要将每个输出值除以 255, 每个类别 0(可能性最低)到 1(可能性极大)。

可选:将结果映射到标签

开发者还可以选择将结果映射到标签。首先,复制 包含标签的 .file 文件放入模块的资产目录中。接下来,加载标签 文件:

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

以下代码段展示了如何将概率 类别标签:

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

当前用例覆盖率

LiteRT 支持库的当前版本包括:

  • 常见数据类型(float、uint8、图片、音频和这些对象的数组) 作为 tflite 模型的输入和输出。
  • 基本图片操作(剪裁图片、调整大小和旋转)。
  • 归一化和量化
  • 文件实用程序

未来版本将改进对文本相关应用的支持。

ImageProcessor 架构

ImageProcessor 的设计让图片操纵操作能够 可以预先定义并在构建流程中进行优化。ImageProcessor 目前支持三种基本的预处理操作,如 以下代码段中的三条注释:

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

查看更多详情 此处了解 归一化和量化。

支持库的最终目标是支持 tf.image 转换。这意味着转换将与 TensorFlow 相同, 而且实施将独立于操作系统。

开发者也可以创建自定义处理器。请务必注意 与训练过程保持一致,也就是说, 预处理应当应用于训练和推理,以提高 可重现性。

量化

启动输入或输出对象(例如 TensorImageTensorBuffer)时 则需要将其类型指定为 DataType.UINT8DataType.FLOAT32

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

TensorProcessor 可用于量化输入张量或去量化输出 张量。例如,在处理量化输出 TensorBuffer 时, 开发者可以使用 DequantizeOp 将结果反量化为浮点数 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);

张量的量化参数可通过 元数据提取器库