Đại biểu TensorFlow Lite NNAPI

API mạng thần kinh Android (NNAPI) có sẵn trên tất cả các thiết bị Android chạy Android 8.1 (API cấp 27) trở lên. Nó cung cấp khả năng tăng tốc cho các mẫu TensorFlow Lite trên các thiết bị Android có bộ tăng tốc phần cứng được hỗ trợ bao gồm:

  • Bộ xử lý đồ họa (GPU)
  • Bộ xử lý tín hiệu số (DSP)
  • Bộ xử lý thần kinh (NPU)

Hiệu suất sẽ khác nhau tùy thuộc vào phần cứng cụ thể có sẵn trên thiết bị.

Trang này mô tả cách sử dụng ủy quyền NNAPI với Trình thông dịch TensorFlow Lite trong Java và Kotlin. Đối với API Android C, vui lòng tham khảo tài liệu về Bộ công cụ dành cho nhà phát triển Android gốc .

Đang thử đại biểu NNAPI trên mô hình của riêng bạn

Nhập lớp

Đại biểu NNAPI là một phần của trình thông dịch Android TensorFlow Lite, phát hành 1.14.0 trở lên. Bạn có thể nhập nó vào dự án của mình bằng cách thêm phần sau vào tệp lớp mô-đun của bạn:

dependencies {
   implementation 'org.tensorflow:tensorflow-lite:+'
}

Đang khởi tạo đại biểu NNAPI

Thêm mã để khởi tạo ủy nhiệm NNAPI trước khi bạn khởi tạo trình thông dịch TensorFlow Lite.

kotlin

import android.content.res.AssetManager
import org.tensorflow.lite.Interpreter
import org.tensorflow.lite.nnapi.NnApiDelegate
import java.io.FileInputStream
import java.io.IOException
import java.nio.MappedByteBuffer
import java.nio.channels.FileChannel
...

val options = Interpreter.Options()
var nnApiDelegate: NnApiDelegate? = null
// Initialize interpreter with NNAPI delegate for Android Pie or above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    nnApiDelegate = NnApiDelegate()
    options.addDelegate(nnApiDelegate)
}
val assetManager = assets

// Initialize TFLite interpreter
val tfLite: Interpreter
try {
    tfLite = Interpreter(loadModelFile(assetManager, "model.tflite"), options)
} catch (e: Exception) {
    throw RuntimeException(e)
}

// Run inference
// ...

// Unload delegate
tfLite.close()
nnApiDelegate?.close()

...

@Throws(IOException::class)
private fun loadModelFile(assetManager: AssetManager, modelFilename: String): MappedByteBuffer {
    val fileDescriptor = assetManager.openFd(modelFilename)
    val inputStream = FileInputStream(fileDescriptor.fileDescriptor)
    val fileChannel = inputStream.channel
    val startOffset = fileDescriptor.startOffset
    val declaredLength = fileDescriptor.declaredLength
    return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength)
}

...

java

import android.content.res.AssetManager;
import org.tensorflow.lite.Interpreter;
import org.tensorflow.lite.nnapi.NnApiDelegate;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
...

Interpreter.Options options = (new Interpreter.Options());
NnApiDelegate nnApiDelegate = null;
// Initialize interpreter with NNAPI delegate for Android Pie or above
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    nnApiDelegate = new NnApiDelegate();
    options.addDelegate(nnApiDelegate);
}

AssetManager assetManager = getAssets();
// Initialize TFLite interpreter
try {
    tfLite = new Interpreter(loadModelFile(assetManager, "model.tflite"), options);
} catch (Exception e) {
    throw new RuntimeException(e);
}

// Run inference
// ...

// Unload delegate
tfLite.close();
if(null != nnApiDelegate) {
    nnApiDelegate.close();
}

...

private MappedByteBuffer loadModelFile(AssetManager assetManager, String modelFilename) throws IOException {
    AssetFileDescriptor fileDescriptor = assetManager.openFd(modelFilename);
    FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
    FileChannel fileChannel = inputStream.getChannel();
    long startOffset = fileDescriptor.getStartOffset();
    long declaredLength = fileDescriptor.getDeclaredLength();
    return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
}

...

Thực hành tốt nhất

Kiểm tra hiệu suất trước khi triển khai

Hiệu suất thời gian chạy có thể thay đổi đáng kể do kiến ​​trúc mô hình, kích thước, hoạt động, tính khả dụng của phần cứng và việc sử dụng phần cứng thời gian chạy. Ví dụ: nếu một ứng dụng sử dụng nhiều GPU để hiển thị thì khả năng tăng tốc NNAPI có thể không cải thiện hiệu suất do tranh chấp tài nguyên. Chúng tôi khuyên bạn nên chạy thử nghiệm hiệu suất đơn giản bằng trình ghi nhật ký gỡ lỗi để đo thời gian suy luận. Chạy thử nghiệm trên một số điện thoại có chipset khác nhau (nhà sản xuất hoặc kiểu máy của cùng một nhà sản xuất) đại diện cho cơ sở người dùng của bạn trước khi bật NNAPI trong sản xuất.

Đối với các nhà phát triển nâng cao, TensorFlow Lite cũng cung cấp công cụ đo điểm chuẩn mô hình cho Android .

Tạo danh sách loại trừ thiết bị

Trong quá trình sản xuất, có thể có trường hợp NNAPI không hoạt động như mong đợi. Chúng tôi khuyên các nhà phát triển nên duy trì danh sách các thiết bị không nên sử dụng khả năng tăng tốc NNAPI kết hợp với các kiểu máy cụ thể. Bạn có thể tạo danh sách này dựa trên giá trị của "ro.board.platform" mà bạn có thể truy xuất bằng đoạn mã sau:

String boardPlatform = "";

try {
    Process sysProcess =
        new ProcessBuilder("/system/bin/getprop", "ro.board.platform").
        redirectErrorStream(true).start();

    BufferedReader reader = new BufferedReader
        (new InputStreamReader(sysProcess.getInputStream()));
    String currentLine = null;

    while ((currentLine=reader.readLine()) != null){
        boardPlatform = line;
    }
    sysProcess.destroy();
} catch (IOException e) {}

Log.d("Board Platform", boardPlatform);

Đối với các nhà phát triển nâng cao, hãy cân nhắc việc duy trì danh sách này thông qua hệ thống cấu hình từ xa. Nhóm TensorFlow đang tích cực nghiên cứu các cách đơn giản hóa và tự động hóa việc khám phá cũng như áp dụng cấu hình NNAPI tối ưu.

Lượng tử hóa

Lượng tử hóa làm giảm kích thước mô hình bằng cách sử dụng số nguyên 8 bit hoặc số float 16 bit thay vì số float 32 bit để tính toán. Kích thước mô hình số nguyên 8 bit là một phần tư của phiên bản float 32 bit; Số float 16 bit có kích thước bằng một nửa. Lượng tử hóa có thể cải thiện hiệu suất đáng kể mặc dù quá trình này có thể đánh đổi một số độ chính xác của mô hình.

Có nhiều loại kỹ thuật lượng tử hóa sau đào tạo, tuy nhiên, để được hỗ trợ và tăng tốc tối đa trên phần cứng hiện tại, chúng tôi khuyên bạn nên lượng tử hóa số nguyên đầy đủ . Cách tiếp cận này chuyển đổi cả trọng số và các phép toán thành số nguyên. Quá trình lượng tử hóa này yêu cầu một tập dữ liệu đại diện để hoạt động.

Sử dụng các mô hình và hoạt động được hỗ trợ

Nếu đại biểu NNAPI không hỗ trợ một số hoạt động hoặc kết hợp tham số trong mô hình thì khung chỉ chạy các phần được hỗ trợ của biểu đồ trên bộ tăng tốc. Phần còn lại chạy trên CPU, dẫn đến việc thực thi phân tách. Do chi phí đồng bộ hóa CPU/bộ tăng tốc cao, điều này có thể dẫn đến hiệu suất chậm hơn so với việc chỉ thực hiện toàn bộ mạng trên CPU.

NNAPI hoạt động tốt nhất khi các mô hình chỉ sử dụng các hoạt động được hỗ trợ . Các mô hình sau được biết là tương thích với NNAPI:

Khả năng tăng tốc NNAPI cũng không được hỗ trợ khi mô hình chứa các đầu ra có kích thước động. Trong trường hợp này, bạn sẽ nhận được cảnh báo như:

ERROR: Attempting to use a delegate that only supports static-sized tensors \
with a graph that has dynamic-sized tensors.

Cho phép triển khai CPU NNAPI

Một biểu đồ không thể được xử lý hoàn toàn bằng máy gia tốc có thể quay trở lại việc triển khai CPU NNAPI. Tuy nhiên, vì tính năng này thường kém hiệu quả hơn trình thông dịch TensorFlow nên tùy chọn này bị tắt theo mặc định trong ủy nhiệm NNAPI cho Android 10 (API cấp 29) trở lên. Để ghi đè hành vi này, hãy đặt setUseNnapiCpu thành true trong đối tượng NnApiDelegate.Options .