extensiones de proveedores de la API de Neural Networks (NNAPI), introducidas en Android 10 son colecciones de operaciones y tipos de datos definidos por el proveedor. En dispositivos que ejecutan NN HAL 1.2 o versiones posteriores, los controladores pueden proporcionar operaciones personalizadas con aceleración de hardware mediante admiten las extensiones de proveedores correspondientes. Las extensiones de proveedor no modifican el de las operaciones existentes.
Las extensiones de proveedores ofrecen una alternativa más estructurada a la operación del OEM y que dejaron de estar disponibles en Android 10. Para obtener más información, consulta Operación del OEM y tipos de datos.
Lista de entidades permitidas para el uso de extensiones
Las extensiones de proveedores solo se pueden usar en apps de Android especificadas explícitamente
objetos binarios nativos en las particiones /product
, /vendor
, /odm
y /data
Las apps y los objetos binarios nativos ubicados en la partición /system
no pueden usar el proveedor
extensiones.
Se incluye una lista de archivos binarios y apps para Android que pueden usar extensiones de proveedores de la NNAPI:
almacenado en /vendor/etc/nnapi_extensions_app_allowlist
. Cada línea del archivo
contiene una entrada nueva. Una entrada puede ser una ruta binaria nativa que tiene el prefijo
una barra (/), por ejemplo, /data/foo
, o el nombre de un paquete de apps para Android, para
Por ejemplo, com.foo.bar
.
La lista de entidades permitidas se aplica desde la biblioteca compartida del tiempo de ejecución de la NNAPI. Esta biblioteca brinda protección contra el uso accidental, pero no contra la elusión deliberada por una app directamente con la interfaz de HAL del controlador de NNAPI
Definición de extensión de proveedor
El proveedor crea y mantiene un archivo de encabezado con la definición de la extensión. R
Puedes encontrar un ejemplo completo de la definición de una extensión en
example/fibonacci/FibonacciExtension.h
Cada extensión debe tener un nombre único que comience con el nombre de dominio inverso del proveedor.
const char EXAMPLE_EXTENSION_NAME[] = "com.example.my_extension";
El nombre actúa como un espacio de nombres para operaciones y tipos de datos. La NNAPI usa para distinguir entre extensiones de proveedores.
Las operaciones y los tipos de datos se declaran de manera similar a los de
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,
};
Una operación de extensión puede usar cualquier tipo de operando, incluido un operando sin extensión y los tipos de operando de otras extensiones. Cuando se usa un tipo de operando de otra extensión, el controlador debe ser compatible con la otra extensión.
Las extensiones también pueden declarar estructuras personalizadas para acompañar a los operandos de extensión.
/**
* Quantization parameters for {@link EXAMPLE_TENSOR}.
*/
typedef struct ExampleTensorParams {
double scale;
int64_t zeroPoint;
} ExampleTensorParams;
Cómo usar extensiones en clientes de la NNAPI
El
runtime/include/NeuralNetworksExtensions.h
(C API) proporciona compatibilidad con extensiones del entorno de ejecución. En esta sección, se proporciona un
descripción general de la API de C.
Para comprobar si un dispositivo admite una extensión, usa
ANeuralNetworksDevice_getExtensionSupport
bool isExtensionSupported;
CHECK_EQ(ANeuralNetworksDevice_getExtensionSupport(device, EXAMPLE_EXTENSION_NAME,
&isExtensionSupported),
ANEURALNETWORKS_NO_ERROR);
if (isExtensionSupported) {
// The device supports the extension.
...
}
Para crear un modelo con un operando de extensión, usa
ANeuralNetworksModel_getExtensionOperandType
para obtener el tipo de operando y llamar
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);
De manera opcional, usa
ANeuralNetworksModel_setOperandExtensionData
para asociar datos adicionales con un operando de extensión.
ExampleTensorParams params{
.scale = 0.5,
.zeroPoint = 128,
};
CHECK_EQ(ANeuralNetworksModel_setOperandExtensionData(model, operandIndex, ¶ms, sizeof(params)),
ANEURALNETWORKS_NO_ERROR);
Para crear un modelo con una operación de extensión, usa
ANeuralNetworksModel_getExtensionOperationType
para obtener el tipo de operación y llamar
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);
Cómo agregar compatibilidad con extensiones a un controlador de NNAPI
Los controladores informan las extensiones admitidas a través de la
IDevice::getSupportedExtensions
. La lista que se muestra debe contener una entrada que describa cada una de las opciones
.
Extension {
.name = EXAMPLE_EXTENSION_NAME,
.operandTypes = {
{
.type = EXAMPLE_SCALAR,
.isTensor = false,
.byteSize = 8,
},
{
.type = EXAMPLE_TENSOR,
.isTensor = true,
.byteSize = 8,
},
},
}
De los 32 bits que se usan para identificar tipos y operaciones, la alta
Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX
bits es la extensión
prefijo y el valor
Model::ExtensionTypeEncoding::LOW_BITS_TYPE
bits representa el tipo o la operación
de la extensión.
Cuando controla una operación o un tipo de operando, el controlador debe verificar la extensión
. Si el prefijo de la extensión tiene un valor distinto de cero, la operación o el operando
es un tipo de extensión. Si el valor es 0
, la operación o el tipo de operando
no es un tipo de extensión.
Para asignar el prefijo al nombre de una extensión, búscalo en
model.extensionNameToPrefix
La asignación del prefijo al nombre de la extensión es una correspondencia de uno a uno
(biyección) para un modelo determinado. Diferentes valores de prefijo pueden corresponder al
el mismo nombre de extensión en distintos modelos.
El controlador debe validar las operaciones de extensión y los tipos de datos porque la NNAPI no puede validar operaciones de extensión ni tipos de datos particulares.
Los operandos de extensión pueden tener datos asociados en
operand.extraParams.extension
:
que el tiempo de ejecución trata como un BLOB de datos sin procesar de tamaño arbitrario.
Operación del OEM y tipos de datos
La NNAPI tiene una operación de OEM y tipos de datos de OEM que permiten
y fabricantes de dispositivos para brindar funcionalidades
personalizadas específicas de controladores. Estos
las operaciones y los tipos de datos solo los usan las aplicaciones del OEM. Semántica de OEM
las operaciones y los tipos de datos son específicos de OEM y pueden cambiar en cualquier momento. El OEM
operación y los tipos de datos se codifican con OperationType::OEM_OPERATION
,
OperandType::OEM
y OperandType::TENSOR_OEM_BYTE
.