使用 LiteRT 支援資料庫處理輸入和輸出資料

行動應用程式開發人員通常會與輸入的物件互動,例如 點陣圖,或整數等基本功能不過,LRT 直譯器 執行裝置端機器學習模型的 API 使用張量,格式為 ByteBuffer,這可能難以偵錯及操控。 LiteRT Android 支援資料庫 旨在協助處理 LiteRT 模型的輸入和輸出內容 讓 LiteRT 直譯器更容易使用

開始使用

匯入 Gradle 依附元件和其他設定

.tflite 模型檔案複製到 Android 模組的資產目錄 以便訓練模型指定不要壓縮檔案,且 將 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,並 新增必要作業如要將圖片轉換為 Tensor 格式 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 的 TensorFlow 可讀取 metadata 擷取器程式庫 以及其他模型資訊

基本音訊資料處理

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 (很有可能)。

選用:將結果對應至標籤

開發人員也可以選擇將結果對應至標籤。請先複製文字 並在模組的資產目錄中顯示標籤。接著,載入標籤 改為使用下列程式碼:

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 支援資料庫包含:

  • 常見的資料類型 (浮點值、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,將結果量化為浮點值 介於 0 到 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);

張量的量化參數可透過 中繼資料擷取器程式庫