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:
- Phân loại hình ảnh MobileNet v1 (224x224) (tải xuống mô hình nổi) (tải xuống mô hình lượng tử hóa)
(mô hình phân loại hình ảnh được thiết kế cho các ứng dụng thị giác dựa trên thiết bị di động và nhúng) - Phát hiện đối tượng SSD MobileNet v2 (tải xuống)
(mô hình phân loại hình ảnh phát hiện nhiều đối tượng có hộp giới hạn) - MobileNet v1(300x300) Phát hiện đối tượng Single Shot Detector (SSD) (tải xuống)
- PoseNet để ước tính tư thế (tải xuống)
(mô hình tầm nhìn ước tính tư thế của một người trong hình ảnh hoặc video)
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
.