Các phần mở rộng của nhà cung cấp Neural Networks API (NNAPI) được ra mắt trong Android 10 là tập hợp các thao tác và loại dữ liệu do nhà cung cấp xác định. Trên các thiết bị chạy NN HAL 1.2 trở lên, trình điều khiển có thể cung cấp các thao tác tuỳ chỉnh có tăng tốc phần cứng bằng cách hỗ trợ các phần mở rộng tương ứng của nhà cung cấp. Các phần mở rộng của nhà cung cấp không sửa đổi hành vi của các thao tác hiện có.
Các phần mở rộng của nhà cung cấp cung cấp một giải pháp thay thế có cấu trúc hơn cho các thao tác và loại dữ liệu OEM (không dùng nữa trong Android 10). Để biết thêm thông tin, hãy xem bài viết Thao tác và loại dữ liệu OEM.
Danh sách cho phép sử dụng phần mở rộng
Các phần mở rộng của nhà cung cấp chỉ có thể được sử dụng bởi các ứng dụng Android và tệp nhị phân gốc được chỉ định rõ ràng trên các phân vùng /product, /vendor, /odm và /data.
Các ứng dụng và tệp nhị phân gốc nằm trên phân vùng /system không thể sử dụng các phần mở rộng của nhà cung cấp.
Danh sách các ứng dụng và tệp nhị phân Android được phép sử dụng các phần mở rộng của nhà cung cấp NNAPI được lưu trữ trong /vendor/etc/nnapi_extensions_app_allowlist. Mỗi dòng của tệp chứa một mục mới. Một mục có thể là đường dẫn nhị phân gốc có tiền tố là dấu gạch chéo (/), ví dụ: /data/foo hoặc tên của gói ứng dụng Android, ví dụ: com.foo.bar.
Danh sách cho phép được thực thi từ thư viện dùng chung thời gian chạy NNAPI. Thư viện này bảo vệ khỏi việc sử dụng vô tình nhưng không bảo vệ khỏi việc cố ý lách luật bằng cách sử dụng trực tiếp giao diện HAL trình điều khiển NNAPI.
Định nghĩa phần mở rộng của nhà cung cấp
Nhà cung cấp tạo và duy trì tệp tiêu đề có định nghĩa phần mở rộng. Bạn có thể xem ví dụ hoàn chỉnh về định nghĩa phần mở rộng trong
example/fibonacci/FibonacciExtension.h.
Mỗi phần mở rộng phải có một tên riêng biệt bắt đầu bằng tên miền đảo ngược của nhà cung cấp.
const char EXAMPLE_EXTENSION_NAME[] = "com.example.my_extension";
Tên này đóng vai trò là không gian tên cho các thao tác và loại dữ liệu. NNAPI sử dụng tên này để phân biệt giữa các phần mở rộng của nhà cung cấp.
Các thao tác và loại dữ liệu được khai báo theo cách tương tự như trong
runtime/include/NeuralNetworks.h.
enum {
/**
* A custom scalar type.
*/
EXAMPLE_SCALAR = 0,
/**
* A custom tensor type.
*
* Attached to this tensor is {@link ExampleTensorParams}.
*/
EXAMPLE_TENSOR = 1,
};
enum {
/**
* Computes example function.
*
* Inputs:
* * 0: A scalar of {@link EXAMPLE_SCALAR}.
*
* Outputs:
* * 0: A tensor of {@link EXAMPLE_TENSOR}.
*/
EXAMPLE_FUNCTION = 0,
};
Một thao tác phần mở rộng có thể sử dụng bất kỳ loại toán hạng nào, bao gồm cả các loại toán hạng không phải phần mở rộng và các loại toán hạng từ các phần mở rộng khác. Khi sử dụng loại toán hạng từ một phần mở rộng khác, trình điều khiển phải hỗ trợ phần mở rộng khác.
Các phần mở rộng cũng có thể khai báo các cấu trúc tuỳ chỉnh để đi kèm với các toán hạng phần mở rộng.
/**
* Quantization parameters for {@link EXAMPLE_TENSOR}.
*/
typedef struct ExampleTensorParams {
double scale;
int64_t zeroPoint;
} ExampleTensorParams;
Sử dụng các phần mở rộng trong ứng dụng NNAPI
Tệp
runtime/include/NeuralNetworksExtensions.h
(C API) cung cấp tính năng hỗ trợ phần mở rộng thời gian chạy. Phần này cung cấp thông tin tổng quan về C API.
Để kiểm tra xem thiết bị có hỗ trợ phần mở rộng hay không, hãy sử dụng
ANeuralNetworksDevice_getExtensionSupport.
bool isExtensionSupported;
CHECK_EQ(ANeuralNetworksDevice_getExtensionSupport(device, EXAMPLE_EXTENSION_NAME,
&isExtensionSupported),
ANEURALNETWORKS_NO_ERROR);
if (isExtensionSupported) {
// The device supports the extension.
...
}
Để tạo mô hình có toán hạng phần mở rộng, hãy sử dụng
ANeuralNetworksModel_getExtensionOperandType
để lấy loại toán hạng và gọi
ANeuralNetworksModel_addOperand.
int32_t type;
CHECK_EQ(ANeuralNetworksModel_getExtensionOperandType(model, EXAMPLE_EXTENSION_NAME, EXAMPLE_TENSOR, &type),
ANEURALNETWORKS_NO_ERROR);
ANeuralNetworksOperandType operandType{
.type = type,
.dimensionCount = dimensionCount,
.dimensions = dimensions,
};
CHECK_EQ(ANeuralNetworksModel_addOperand(model, &operandType), ANEURALNETWORKS_NO_ERROR);
Bạn có thể sử dụng
ANeuralNetworksModel_setOperandExtensionData
để liên kết dữ liệu bổ sung với toán hạng phần mở rộng.
ExampleTensorParams params{
.scale = 0.5,
.zeroPoint = 128,
};
CHECK_EQ(ANeuralNetworksModel_setOperandExtensionData(model, operandIndex, ¶ms, sizeof(params)),
ANEURALNETWORKS_NO_ERROR);
Để tạo mô hình có thao tác phần mở rộng, hãy sử dụng
ANeuralNetworksModel_getExtensionOperationType
để lấy loại thao tác và gọi
ANeuralNetworksModel_addOperation.
ANeuralNetworksOperationType type;
CHECK_EQ(ANeuralNetworksModel_getExtensionOperationType(model, EXAMPLE_EXTENSION_NAME, EXAMPLE_FUNCTION,
&type),
ANEURALNETWORKS_NO_ERROR);
CHECK_EQ(ANeuralNetworksModel_addOperation(model, type, inputCount, inputs, outputCount, outputs),
ANEURALNETWORKS_NO_ERROR);
Thêm tính năng hỗ trợ phần mở rộng vào trình điều khiển NNAPI
Trình điều khiển báo cáo các phần mở rộng được hỗ trợ thông qua
IDevice::getSupportedExtensions
phương thức. Danh sách trả về phải chứa một mục mô tả từng phần mở rộng được hỗ trợ.
Extension {
.name = EXAMPLE_EXTENSION_NAME,
.operandTypes = {
{
.type = EXAMPLE_SCALAR,
.isTensor = false,
.byteSize = 8,
},
{
.type = EXAMPLE_TENSOR,
.isTensor = true,
.byteSize = 8,
},
},
}
Trong số 32 bit được dùng để xác định các loại và thao tác, các bit cao
Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX
là _tiền tố_ phần mở rộng và các bit thấp
Model::ExtensionTypeEncoding::LOW_BITS_TYPE
biểu thị loại hoặc thao tác
của phần mở rộng.
Khi xử lý một thao tác hoặc loại toán hạng, trình điều khiển phải kiểm tra tiền tố phần mở rộng. Nếu tiền tố phần mở rộng có giá trị khác 0, thì thao tác hoặc loại toán hạng là loại phần mở rộng. Nếu giá trị là 0, thì thao tác hoặc loại toán hạng không phải là loại phần mở rộng.
Để liên kết tiền tố với tên phần mở rộng, hãy tra cứu trong
model.extensionNameToPrefix.
Việc liên kết từ tiền tố đến tên phần mở rộng là mối tương ứng một-một (song ánh) cho một mô hình nhất định. Các giá trị tiền tố khác nhau có thể tương ứng với cùng một tên phần mở rộng trong các mô hình khác nhau.
Trình điều khiển phải xác thực các thao tác và loại dữ liệu phần mở rộng vì thời gian chạy NNAPI không thể xác thực các thao tác và loại dữ liệu phần mở rộng cụ thể.
Các toán hạng phần mở rộng có thể có dữ liệu được liên kết trong
operand.extraParams.extension,
mà thời gian chạy coi là một blob dữ liệu thô có kích thước tuỳ ý.
Thao tác và loại dữ liệu OEM
NNAPI có thao tác OEM và các loại dữ liệu OEM để cho phép nhà sản xuất thiết bị cung cấp chức năng tuỳ chỉnh dành riêng cho trình điều khiển. Các thao tác và loại dữ liệu này chỉ được ứng dụng OEM sử dụng. Ngữ nghĩa của các thao tác và loại dữ liệu OEM dành riêng cho OEM và có thể thay đổi bất cứ lúc nào. Các thao tác và loại dữ liệu OEM được mã hoá bằng OperationType::OEM_OPERATION, OperandType::OEM và OperandType::TENSOR_OEM_BYTE.