Extensions de fournisseur de l'API Neural Networks (NNAPI), introduites dans Android 10, sont d'opérations et de types de données définis par le fournisseur. Sur les appareils exécutant NN HAL 1.2 ou version ultérieure, les pilotes peuvent fournir des opérations personnalisées avec accélération matérielle la prise en charge des extensions des fournisseurs correspondants. Les extensions de fournisseur ne modifient pas le comportement des opérations existantes.
Les extensions de fournisseur offrent une alternative plus structurée aux opérations OEM et de données, qui ont été abandonnés dans Android 10. Pour en savoir plus, consultez Opération et types de données OEM.
Liste d'autorisation d'utilisation des extensions
Les extensions de fournisseur ne peuvent être utilisées que par les applications Android et les applications Android explicitement spécifiées
binaires natifs sur les partitions /product
, /vendor
, /odm
et /data
.
Les applications et les binaires natifs situés sur la partition /system
ne peuvent pas utiliser le fournisseur
.
La liste des applications et binaires Android autorisés à utiliser les extensions de fournisseur NNAPI est
stocké dans /vendor/etc/nnapi_extensions_app_allowlist
. Chaque ligne du fichier
contient une nouvelle entrée. Une entrée peut être un chemin binaire natif précédé de
une barre oblique (/), par exemple /data/foo
, ou le nom d'un package d'application Android, pour
Exemple : com.foo.bar
.
La liste d'autorisation est appliquée à partir de la bibliothèque partagée de l'environnement d'exécution NNAPI. Cette bibliothèque protège contre l'utilisation accidentelle, mais pas contre le contournement délibéré une application directement à l'aide de l'interface HAL du pilote NNAPI.
Définition de l'extension du fournisseur
Le fournisseur crée et gère un fichier d'en-tête avec la définition de l'extension. A
un exemple complet de définition d'extension se trouve dans
example/fibonacci/FibonacciExtension.h
Chaque extension doit avoir un nom unique qui commence par le nom de domaine inversé du fournisseur.
const char EXAMPLE_EXTENSION_NAME[] = "com.example.my_extension";
Le nom sert d'espace de noms pour les opérations et les types de données. La NNAPI utilise cette pour distinguer les extensions de fournisseur.
Les opérations et les types de données sont déclarés d'une manière semblable à celles
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,
};
Une opération d'extension peut utiliser n'importe quel type d'opérande, y compris les opérandes sans extension et les types d'opérandes d'autres extensions. Lorsque vous utilisez un type d'opérande une autre extension, le pilote doit être compatible avec l'autre extension.
Les extensions peuvent également déclarer des structures personnalisées pour accompagner les opérandes d'extension.
/**
* Quantization parameters for {@link EXAMPLE_TENSOR}.
*/
typedef struct ExampleTensorParams {
double scale;
int64_t zeroPoint;
} ExampleTensorParams;
Utiliser des extensions dans les clients NNAPI
La
runtime/include/NeuralNetworksExtensions.h
(API C) prend en charge l'extension d'exécution. Cette section fournit
de l'API C.
Pour vérifier si un appareil est compatible avec une extension, utilisez
ANeuralNetworksDevice_getExtensionSupport
bool isExtensionSupported;
CHECK_EQ(ANeuralNetworksDevice_getExtensionSupport(device, EXAMPLE_EXTENSION_NAME,
&isExtensionSupported),
ANEURALNETWORKS_NO_ERROR);
if (isExtensionSupported) {
// The device supports the extension.
...
}
Pour créer un modèle avec un opérande d'extension, utilisez
ANeuralNetworksModel_getExtensionOperandType
pour obtenir le type d'opérande et appeler
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);
Vous pouvez également utiliser
ANeuralNetworksModel_setOperandExtensionData
pour associer des données supplémentaires à un opérande d'extension.
ExampleTensorParams params{
.scale = 0.5,
.zeroPoint = 128,
};
CHECK_EQ(ANeuralNetworksModel_setOperandExtensionData(model, operandIndex, ¶ms, sizeof(params)),
ANEURALNETWORKS_NO_ERROR);
Pour créer un modèle avec une opération d'extension, utilisez
ANeuralNetworksModel_getExtensionOperationType
pour obtenir le type d'opération et appeler
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);
Ajouter la prise en charge des extensions à un pilote NNAPI
Les pilotes signalent les extensions compatibles via la
IDevice::getSupportedExtensions
. La liste renvoyée doit contenir une entrée décrivant chaque élément compatible
.
Extension {
.name = EXAMPLE_EXTENSION_NAME,
.operandTypes = {
{
.type = EXAMPLE_SCALAR,
.isTensor = false,
.byteSize = 8,
},
{
.type = EXAMPLE_TENSOR,
.isTensor = true,
.byteSize = 8,
},
},
}
Sur les 32 bits utilisés pour identifier les types et les opérations, le haut
Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX
bits est l'extension
préfixe et la valeur
Model::ExtensionTypeEncoding::LOW_BITS_TYPE
bits représentent le type ou l'opération
de l'extension.
Lors du traitement d'une opération ou d'un type d'opérande, le pilote doit vérifier l'extension
. Si le préfixe d'extension a une valeur non nulle, l'opération ou l'opérande
type est un type d'extension. Si la valeur est 0
, le type d'opération ou d'opérande
n'est pas un type d'extension.
Pour mapper le préfixe à un nom d'extension, recherchez-le dans
model.extensionNameToPrefix
Le mappage entre le préfixe et le nom de l'extension est une correspondance
(bijection) pour un modèle donné. Différentes valeurs de préfixe peuvent correspondre au
le même nom d'extension dans différents modèles.
Le pilote doit valider les opérations d'extension et les types de données, car la NNAPI l'environnement d'exécution ne peut pas valider des opérations d'extension spécifiques et des types de données spécifiques.
Les opérandes d'extension peuvent
avoir des données associées dans
operand.extraParams.extension
que l'environnement d'exécution traite comme un blob de données brutes de taille arbitraire.
Opération et types de données OEM
NNAPI dispose d'une opération OEM et de types de données OEM
aux fabricants de périphériques de fournir
des fonctionnalités personnalisées et spécifiques au pilote. Ces
et les types de données ne sont utilisés
que par les applications OEM. La sémantique des produits OEM
et les types de données sont spécifiques aux OEM et peuvent changer à tout moment. L'OEM
et les types de données sont encodés à l'aide de OperationType::OEM_OPERATION
,
OperandType::OEM
et OperandType::TENSOR_OEM_BYTE
.