Расширения поставщика Neural Networks API (NNAPI), представленные в Android 10, представляют собой наборы операций и типов данных, определенных поставщиком. На устройствах с NN HAL 1.2 или выше драйверы могут предоставлять пользовательские аппаратно-ускоренные операции, поддерживая соответствующие расширения поставщика. Расширения поставщика не изменяют поведение существующих операций.
Расширения поставщика предоставляют более структурированную альтернативу операциям и типам данных OEM, которые были объявлены устаревшими в Android 10. Для получения дополнительной информации см. раздел Операции и типы данных OEM .
Список разрешенных расширений
Расширения поставщика могут использоваться только явно указанными приложениями Android и собственными двоичными файлами на разделах /product
, /vendor
, /odm
и /data
. Приложения и собственные двоичные файлы, расположенные на разделе /system
не могут использовать расширения поставщика.
Список приложений и двоичных файлов Android, которым разрешено использовать расширения поставщиков NNAPI, хранится в /vendor/etc/nnapi_extensions_app_allowlist
. Каждая строка файла содержит новую запись. Запись может быть собственным двоичным путем, начинающимся с косой черты (/), например, /data/foo
, или именем пакета приложения Android, например, com.foo.bar
.
Список разрешений реализуется из библиотеки NNAPI runtime shared. Эта библиотека защищает от случайного использования, но не от преднамеренного обхода приложением, напрямую использующим интерфейс HAL драйвера NNAPI.
Определение расширения поставщика
Поставщик создает и поддерживает файл заголовка с определением расширения. Полный пример определения расширения можно найти в example/fibonacci/FibonacciExtension.h
.
Каждое расширение должно иметь уникальное имя, начинающееся с обратного доменного имени поставщика.
const char EXAMPLE_EXTENSION_NAME[] = "com.example.my_extension";
Имя действует как пространство имен для операций и типов данных. NNAPI использует это имя для различения расширений поставщиков.
Операции и типы данных объявляются аналогично тому, как это делается в 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,
};
Операция расширения может использовать любой тип операнда, включая типы операндов non-extension и типы операндов из других расширений. При использовании типа операнда из другого расширения драйвер должен поддерживать другое расширение.
Расширения также могут объявлять пользовательские структуры для сопровождения операндов расширения.
/**
* Quantization parameters for {@link EXAMPLE_TENSOR}.
*/
typedef struct ExampleTensorParams {
double scale;
int64_t zeroPoint;
} ExampleTensorParams;
Используйте расширения в клиентах NNAPI
Файл runtime/include/NeuralNetworksExtensions.h
(C API) обеспечивает поддержку расширения времени выполнения. В этом разделе представлен обзор C API.
Чтобы проверить, поддерживает ли устройство расширение, используйте ANeuralNetworksDevice_getExtensionSupport
.
bool isExtensionSupported;
CHECK_EQ(ANeuralNetworksDevice_getExtensionSupport(device, EXAMPLE_EXTENSION_NAME,
&isExtensionSupported),
ANEURALNETWORKS_NO_ERROR);
if (isExtensionSupported) {
// The device supports the extension.
...
}
Чтобы построить модель с операндом расширения, используйте ANeuralNetworksModel_getExtensionOperandType
для получения типа операнда и вызовите 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);
При желании можно использовать ANeuralNetworksModel_setOperandExtensionData
для связывания дополнительных данных с операндом расширения.
ExampleTensorParams params{
.scale = 0.5,
.zeroPoint = 128,
};
CHECK_EQ(ANeuralNetworksModel_setOperandExtensionData(model, operandIndex, ¶ms, sizeof(params)),
ANEURALNETWORKS_NO_ERROR);
Чтобы построить модель с операцией расширения, используйте ANeuralNetworksModel_getExtensionOperationType
для получения типа операции и вызовите 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);
Добавить поддержку расширений в драйвер NNAPI
Драйверы сообщают о поддерживаемых расширениях через метод IDevice::getSupportedExtensions
. Возвращаемый список должен содержать запись, описывающую каждое поддерживаемое расширение.
Extension {
.name = EXAMPLE_EXTENSION_NAME,
.operandTypes = {
{
.type = EXAMPLE_SCALAR,
.isTensor = false,
.byteSize = 8,
},
{
.type = EXAMPLE_TENSOR,
.isTensor = true,
.byteSize = 8,
},
},
}
Из 32 бит, используемых для идентификации типов и операций, старшие биты Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX
представляют префикс расширения, а младшие биты Model::ExtensionTypeEncoding::LOW_BITS_TYPE
представляют тип или операцию расширения.
При обработке типа операции или операнда драйвер должен проверить префикс расширения. Если префикс расширения имеет ненулевое значение, тип операции или операнда является типом расширения. Если значение равно 0
, тип операции или операнда не является типом расширения.
Чтобы сопоставить префикс с именем расширения, найдите его в model.extensionNameToPrefix
. Сопоставление префикса с именем расширения является соответствием один к одному (биекцией) для данной модели. Различные значения префикса могут соответствовать одному и тому же имени расширения в различных моделях.
Драйвер должен проверять операции расширения и типы данных, поскольку среда выполнения NNAPI не может проверять отдельные операции расширения и типы данных.
Операнды расширения могут иметь связанные данные в operand.extraParams.extension
, которые среда выполнения обрабатывает как необработанный блок данных произвольного размера.
Операции OEM и типы данных
NNAPI имеет OEM-операцию и OEM-типы данных, позволяющие производителям устройств предоставлять пользовательские, специфичные для драйверов функции. Эти операции и типы данных используются только OEM-приложениями. Семантика OEM-операции и типов данных специфична для OEM и может измениться в любое время. OEM-операция и типы данных кодируются с помощью OperationType::OEM_OPERATION
, OperandType::OEM
и OperandType::TENSOR_OEM_BYTE
.
Расширения поставщика Neural Networks API (NNAPI), представленные в Android 10, представляют собой наборы операций и типов данных, определенных поставщиком. На устройствах с NN HAL 1.2 или выше драйверы могут предоставлять пользовательские аппаратно-ускоренные операции, поддерживая соответствующие расширения поставщика. Расширения поставщика не изменяют поведение существующих операций.
Расширения поставщика предоставляют более структурированную альтернативу операциям и типам данных OEM, которые были объявлены устаревшими в Android 10. Для получения дополнительной информации см. раздел Операции и типы данных OEM .
Список разрешенных расширений
Расширения поставщика могут использоваться только явно указанными приложениями Android и собственными двоичными файлами на разделах /product
, /vendor
, /odm
и /data
. Приложения и собственные двоичные файлы, расположенные на разделе /system
не могут использовать расширения поставщика.
Список приложений и двоичных файлов Android, которым разрешено использовать расширения поставщиков NNAPI, хранится в /vendor/etc/nnapi_extensions_app_allowlist
. Каждая строка файла содержит новую запись. Запись может быть собственным двоичным путем, начинающимся с косой черты (/), например, /data/foo
, или именем пакета приложения Android, например, com.foo.bar
.
Список разрешений реализуется из библиотеки NNAPI runtime shared. Эта библиотека защищает от случайного использования, но не от преднамеренного обхода приложением, напрямую использующим интерфейс HAL драйвера NNAPI.
Определение расширения поставщика
Поставщик создает и поддерживает файл заголовка с определением расширения. Полный пример определения расширения можно найти в example/fibonacci/FibonacciExtension.h
.
Каждое расширение должно иметь уникальное имя, начинающееся с обратного доменного имени поставщика.
const char EXAMPLE_EXTENSION_NAME[] = "com.example.my_extension";
Имя действует как пространство имен для операций и типов данных. NNAPI использует это имя для различения расширений поставщиков.
Операции и типы данных объявляются аналогично тому, как это делается в 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,
};
Операция расширения может использовать любой тип операнда, включая типы операндов non-extension и типы операндов из других расширений. При использовании типа операнда из другого расширения драйвер должен поддерживать другое расширение.
Расширения также могут объявлять пользовательские структуры для сопровождения операндов расширения.
/**
* Quantization parameters for {@link EXAMPLE_TENSOR}.
*/
typedef struct ExampleTensorParams {
double scale;
int64_t zeroPoint;
} ExampleTensorParams;
Используйте расширения в клиентах NNAPI
Файл runtime/include/NeuralNetworksExtensions.h
(C API) обеспечивает поддержку расширения времени выполнения. В этом разделе представлен обзор C API.
Чтобы проверить, поддерживает ли устройство расширение, используйте ANeuralNetworksDevice_getExtensionSupport
.
bool isExtensionSupported;
CHECK_EQ(ANeuralNetworksDevice_getExtensionSupport(device, EXAMPLE_EXTENSION_NAME,
&isExtensionSupported),
ANEURALNETWORKS_NO_ERROR);
if (isExtensionSupported) {
// The device supports the extension.
...
}
Чтобы построить модель с операндом расширения, используйте ANeuralNetworksModel_getExtensionOperandType
для получения типа операнда и вызовите 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);
При желании можно использовать ANeuralNetworksModel_setOperandExtensionData
для связывания дополнительных данных с операндом расширения.
ExampleTensorParams params{
.scale = 0.5,
.zeroPoint = 128,
};
CHECK_EQ(ANeuralNetworksModel_setOperandExtensionData(model, operandIndex, ¶ms, sizeof(params)),
ANEURALNETWORKS_NO_ERROR);
Чтобы построить модель с операцией расширения, используйте ANeuralNetworksModel_getExtensionOperationType
для получения типа операции и вызовите 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);
Добавить поддержку расширений в драйвер NNAPI
Драйверы сообщают о поддерживаемых расширениях через метод IDevice::getSupportedExtensions
. Возвращаемый список должен содержать запись, описывающую каждое поддерживаемое расширение.
Extension {
.name = EXAMPLE_EXTENSION_NAME,
.operandTypes = {
{
.type = EXAMPLE_SCALAR,
.isTensor = false,
.byteSize = 8,
},
{
.type = EXAMPLE_TENSOR,
.isTensor = true,
.byteSize = 8,
},
},
}
Из 32 бит, используемых для идентификации типов и операций, старшие биты Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX
представляют префикс расширения, а младшие биты Model::ExtensionTypeEncoding::LOW_BITS_TYPE
представляют тип или операцию расширения.
При обработке типа операции или операнда драйвер должен проверить префикс расширения. Если префикс расширения имеет ненулевое значение, тип операции или операнда является типом расширения. Если значение равно 0
, тип операции или операнда не является типом расширения.
Чтобы сопоставить префикс с именем расширения, найдите его в model.extensionNameToPrefix
. Сопоставление префикса с именем расширения является соответствием один к одному (биекцией) для данной модели. Различные значения префикса могут соответствовать одному и тому же имени расширения в различных моделях.
Драйвер должен проверять операции расширения и типы данных, поскольку среда выполнения NNAPI не может проверять отдельные операции расширения и типы данных.
Операнды расширения могут иметь связанные данные в operand.extraParams.extension
, которые среда выполнения обрабатывает как необработанный блок данных произвольного размера.
Операции OEM и типы данных
NNAPI имеет OEM-операцию и OEM-типы данных, позволяющие производителям устройств предоставлять пользовательские, специфичные для драйверов функции. Эти операции и типы данных используются только OEM-приложениями. Семантика OEM-операции и типов данных специфична для OEM и может измениться в любое время. OEM-операция и типы данных кодируются с помощью OperationType::OEM_OPERATION
, OperandType::OEM
и OperandType::TENSOR_OEM_BYTE
.