Xử lý dữ liệu đầu vào và đầu ra với Thư viện hỗ trợ TensorFlow Lite

Các nhà phát triển ứng dụng di động thường tương tác với các đối tượng được nhập như ảnh bitmap hoặc các đối tượng nguyên thủy như số nguyên. Tuy nhiên, API trình thông dịch TensorFlow Lite chạy mô hình học máy trên thiết bị sử dụng các tensor ở dạng ByteBuffer, có thể khó gỡ lỗi và thao tác. Thư viện hỗ trợ Android TensorFlow Lite được thiết kế để giúp xử lý đầu vào và đầu ra của các mô hình TensorFlow Lite, đồng thời giúp trình thông dịch TensorFlow Lite dễ sử dụng hơn.

Bắt đầu

Nhập phần phụ thuộc Gradle và các cài đặt khác

Sao chép tệp mô hình .tflite vào thư mục nội dung của mô-đun Android nơi mô hình sẽ được chạy. Chỉ định rằng tệp sẽ không được nén và thêm thư viện TensorFlow Lite vào tệp build.gradle của mô-đun:

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

Khám phá Thư viện hỗ trợ TensorFlow Lite AAR được lưu trữ tại MavenCentral để biết các phiên bản khác nhau của Thư viện hỗ trợ.

Thao tác và chuyển đổi hình ảnh cơ bản

Thư viện hỗ trợ TensorFlow Lite có một bộ phương pháp xử lý hình ảnh cơ bản như cắt và thay đổi kích thước. Để sử dụng nó, hãy tạo ImagePreprocessor và thêm các thao tác cần thiết. Để chuyển đổi hình ảnh sang định dạng tensor theo yêu cầu của trình thông dịch TensorFlow Lite, hãy tạo TensorImage để sử dụng làm đầu vào:

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 của tensor có thể được đọc thông qua thư viện trích xuất siêu dữ liệu cũng như các thông tin mô hình khác.

Xử lý dữ liệu âm thanh cơ bản

Thư viện hỗ trợ TensorFlow Lite cũng định nghĩa lớp TensorAudio bao gồm một số phương thức xử lý dữ liệu âm thanh cơ bản. Nó chủ yếu được sử dụng cùng với AudioRecord và ghi lại các mẫu âm thanh trong bộ đệm vòng.

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

Tạo đối tượng đầu ra và chạy mô hình

Trước khi chạy mô hình, chúng ta cần tạo các đối tượng container sẽ lưu trữ kết quả:

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

Đang tải mô hình và chạy suy luận:

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

Truy cập kết quả

Các nhà phát triển có thể truy cập trực tiếp vào kết quả đầu ra thông qua probabilityBuffer.getFloatArray() . Nếu mô hình tạo ra đầu ra lượng tử hóa, hãy nhớ chuyển đổi kết quả. Đối với mô hình lượng tử hóa MobileNet, nhà phát triển cần chia mỗi giá trị đầu ra cho 255 để có được xác suất nằm trong khoảng từ 0 (ít có khả năng nhất) đến 1 (rất có thể) cho mỗi danh mục.

Tùy chọn: Ánh xạ kết quả tới nhãn

Nhà phát triển cũng có thể tùy ý ánh xạ kết quả vào nhãn. Đầu tiên, sao chép tệp văn bản chứa nhãn vào thư mục nội dung của mô-đun. Tiếp theo, tải tệp nhãn bằng mã sau:

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ạn mã sau đây trình bày cách liên kết các xác suất với nhãn danh mục:

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

Phạm vi sử dụng hiện tại

Phiên bản hiện tại của Thư viện hỗ trợ TensorFlow Lite bao gồm:

  • các kiểu dữ liệu phổ biến (float, uint8, hình ảnh, âm thanh và mảng của các đối tượng này) làm đầu vào và đầu ra của các mô hình tflite.
  • các thao tác hình ảnh cơ bản (cắt ảnh, thay đổi kích thước và xoay).
  • chuẩn hóa và lượng tử hóa
  • tiện ích tập tin

Các phiên bản trong tương lai sẽ cải thiện khả năng hỗ trợ cho các ứng dụng liên quan đến văn bản.

Kiến trúc xử lý hình ảnh

Thiết kế của ImageProcessor cho phép xác định trước các thao tác xử lý hình ảnh và tối ưu hóa trong quá trình xây dựng. ImageProcessor hiện hỗ trợ ba thao tác tiền xử lý cơ bản, như được mô tả trong ba nhận xét trong đoạn mã bên dưới:

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

Xem thêm chi tiết tại đây về chuẩn hóa và lượng tử hóa.

Mục tiêu cuối cùng của thư viện hỗ trợ là hỗ trợ tất cả các phép biến đổi tf.image . Điều này có nghĩa là quá trình chuyển đổi sẽ giống như TensorFlow và việc triển khai sẽ độc lập với hệ điều hành.

Các nhà phát triển cũng được hoan nghênh tạo ra các bộ xử lý tùy chỉnh. Điều quan trọng trong những trường hợp này là phải phù hợp với quy trình đào tạo - tức là nên áp dụng cùng một quy trình tiền xử lý cho cả đào tạo và suy luận để tăng khả năng tái tạo.

Lượng tử hóa

Khi khởi tạo các đối tượng đầu vào hoặc đầu ra như TensorImage hoặc TensorBuffer , bạn cần chỉ định loại của chúng là DataType.UINT8 hoặc DataType.FLOAT32 .

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

TensorProcessor có thể được sử dụng để lượng tử hóa các tenxơ đầu vào hoặc khử lượng tử các tenxơ đầu ra. Ví dụ: khi xử lý đầu ra được lượng tử hóa TensorBuffer , nhà phát triển có thể sử dụng DequantizeOp để khử lượng tử kết quả thành xác suất dấu phẩy động trong khoảng từ 0 đến 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);

Các tham số lượng tử hóa của tensor có thể được đọc thông qua thư viện trích xuất siêu dữ liệu .