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

Nhà phát triển ứng dụng dành cho thiết bị di động thường tương tác với các đối tượng đã nhập như bitmap hoặc các dữ liệu nguyên gốc 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 tensor ở dạng ByteBuffer. Đây là thành phần có thể khó gỡ lỗi và thao tác. Thư viện hỗ trợ Android của TensorFlow Lite được thiết kế nhằm giúp xử lý dữ liệu đầ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 chế độ cài đặt khác

Sao chép tệp mô hình .tflite vào thư mục tài sản của mô-đun Android nơi mô hình sẽ chạy. Chỉ định rằng tệp 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 cho 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 thức thao tác hình ảnh cơ bản như cắt và đổi kích thước. Để sử dụng công cụ này, hãy tạo một ImagePreprocessor và thêm các thao tác bắt buộc. Để 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 một TensorImage để dùng làm dữ liệu đầ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);

Bạn có thể đọc DataType của tensor thông qua thư viện trình trích xuất siêu dữ liệu cũng như các thông tin khác về mô hình.

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

Thư viện hỗ trợ TensorFlow Lite cũng xác định một lớp TensorAudio gói một số phương thức xử lý dữ liệu âm thanh cơ bản. API này chủ yếu được dùng cùng với AudioRecord và ghi lại các mẫu âm thanh trong vùng đệ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 vùng chứa 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 dự đoá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ả

Nhà phát triển có thể truy cập kết quả trực tiếp thông qua probabilityBuffer.getFloatArray(). Nếu mô hình tạo ra một đầu ra lượng tử hoá, hãy nhớ chuyển đổi kết quả. Đối với mô hình lượng tử hoá MobileNet, nhà phát triển cần chia từng 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.

Không bắt buộc: Ánh xạ kết quả tới các nhãn

Nhà phát triển cũng có thể tuỳ ý ánh xạ kết quả đến nhãn. Trước tiên, hãy sao chép tệp văn bản chứa nhãn vào thư mục tài sản của mô-đun. Tiếp theo, hãy 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 minh hoạ cách liên kết 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 nội dung sau:

  • 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 mô hình tflite.
  • các thao tác cơ bản đối với hình ảnh (cắt hình ảnh, đổi kích thước và xoay).
  • chuẩn hoá và lượng tử hoá
  • phần mềm tiện ích tệp

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

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

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

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 thông tin chi tiết tại đây về quá trình chuẩn hoá và lượng tử hoá.

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

Nhà phát triển cũng có thể tạo trình xử lý tuỳ chỉnh. Trong những trường hợp này, điều quan trọng là phải điều chỉnh cho phù hợp với quá trình huấn luyện – tức là quy trình tiền xử lý tương tự phải được áp dụng cho cả quá trình huấn luyện và dự đoán để tăng khả năng tái sản xuất.

Lượng tử hoá

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 kiểu của các đối tượng đó là DataType.UINT8 hoặc DataType.FLOAT32.

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

Bạn có thể dùng TensorProcessor để lượng hoá tensor đầu vào hoặc huỷ định lượng tensor đầu ra. Ví dụ: khi xử lý một đầu ra lượng tử hoá TensorBuffer, nhà phát triển có thể sử dụng DequantizeOp để loại bỏ 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);

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