Cette page explique comment implémenter un pilote d'API Neural Networks (NNAPI). Pour en savoir plus, consultez la documentation des fichiers de définition HAL dans hardware/interfaces/neuralnetworks
.
Un exemple d'implémentation de pilote se trouve dans frameworks/ml/nn/driver/sample
.
Pour en savoir plus sur l'API Neural Networks, consultez la page API Neural Networks.
HAL des réseaux de neurones
Le HAL des réseaux de neurones (NN) définit une abstraction des différents appareils, tels que les unités de traitement graphique (GPU) et les processeurs de signaux numériques (DSP), qui se trouvent dans un produit (par exemple, un téléphone ou une tablette). Les pilotes de ces appareils doivent être conformes à la HAL NN. L'interface est spécifiée dans les fichiers de définition HAL dans hardware/interfaces/neuralnetworks
.
Le flux général de l'interface entre le framework et un pilote est illustré dans la figure 1.
Figure 1 : Flux des réseaux de neurones
Initialisation
Lors de l'initialisation, le framework interroge le pilote sur ses fonctionnalités à l'aide de IDevice::getCapabilities_1_3
.
La structure @1.3::Capabilities
inclut tous les types de données et représente les performances non relâchées à l'aide d'un vecteur.
Pour déterminer comment allouer des calculs aux appareils disponibles, le framework utilise les fonctionnalités pour comprendre à quelle vitesse et avec quelle efficacité énergétique chaque pilote peut effectuer une exécution. Pour fournir ces informations, le pilote doit fournir des chiffres de performances standardisés en fonction de l'exécution de charges de travail de référence.
Pour déterminer les valeurs que le pilote renvoie en réponse à IDevice::getCapabilities_1_3
, utilisez l'application d'analyse comparative NNAPI pour mesurer les performances des types de données correspondants. Les modèles MobileNet v1 et v2, asr_float
et tts_float
sont recommandés pour mesurer les performances des valeurs à virgule flottante 32 bits, et les modèles MobileNet v1 et v2 quantifiés sont recommandés pour les valeurs quantifiées 8 bits. Pour en savoir plus, consultez la Suite de tests de machine learning Android.
Sous Android 9 et versions antérieures, la structure Capabilities
n'inclut des informations sur les performances du pilote que pour les tenseurs à virgule flottante et quantiques, et n'inclut pas les types de données scalaires.
Lors du processus d'initialisation, le framework peut interroger d'autres informations à l'aide de IDevice::getType
, IDevice::getVersionString
, IDevice:getSupportedExtensions
et IDevice::getNumberOfCacheFilesNeeded
.
Entre les redémarrages du produit, le framework s'attend à ce que toutes les requêtes décrites dans cette section renvoient toujours les mêmes valeurs pour un pilote donné. Sinon, une application utilisant ce pilote peut présenter des performances réduites ou un comportement incorrect.
Compilation
Le framework détermine les appareils à utiliser lorsqu'il reçoit une requête d'une application. Sous Android 10, les applications peuvent découvrir et spécifier les appareils parmi lesquels le framework fait son choix. Pour en savoir plus, consultez la section Découverte et attribution des appareils.
Au moment de la compilation du modèle, le framework envoie le modèle à chaque pilote candidat en appelant IDevice::getSupportedOperations_1_3
.
Chaque pilote renvoie un tableau de valeurs booléennes indiquant quelles opérations du modèle sont prises en charge. Un pilote peut déterminer qu'il ne peut pas prendre en charge une opération donnée pour plusieurs raisons. Exemple :
- Le pilote n'est pas compatible avec le type de données.
- Le pilote n'est compatible qu'avec les opérations avec des paramètres d'entrée spécifiques. Par exemple, un pilote peut prendre en charge les opérations de convolution 3x3 et 5x5, mais pas les opérations de convolution 7x7.
- Le pilote présente des contraintes de mémoire qui l'empêchent de gérer de grands graphiques ou entrées.
Lors de la compilation, les opérandes d'entrée, de sortie et internes du modèle, comme décrit dans OperandLifeTime
, peuvent avoir des dimensions ou un rang inconnus. Pour en savoir plus, consultez la section Forme de sortie.
Le framework demande à chaque pilote sélectionné de se préparer à exécuter un sous-ensemble du modèle en appelant IDevice::prepareModel_1_3
.
Chaque pilote compile ensuite son sous-ensemble. Par exemple, un pilote peut générer du code ou créer une copie réorganisée des poids. Étant donné qu'un temps important peut s'écouler entre la compilation du modèle et l'exécution des requêtes, les ressources telles que de grandes parties de la mémoire de l'appareil ne doivent pas être attribuées lors de la compilation.
En cas de réussite, le pilote renvoie un gestionnaire @1.3::IPreparedModel
. Si le pilote renvoie un code d'erreur lors de la préparation de son sous-ensemble du modèle, le framework exécute l'ensemble du modèle sur le processeur.
Pour réduire le temps de compilation au démarrage d'une application, un pilote peut mettre en cache les artefacts de compilation. Pour en savoir plus, consultez la section Mise en cache de la compilation.
Exécution
Lorsqu'une application demande au framework d'exécuter une requête, le framework appelle la méthode HAL IPreparedModel::executeSynchronously_1_3
par défaut pour effectuer une exécution synchrone sur un modèle préparé.
Une requête peut également être exécutée de manière asynchrone à l'aide de la méthode execute_1_3
, de la méthode executeFenced
(voir Exécution avec barrière) ou à l'aide d'une exécution par rafales.
Les appels d'exécution synchrones améliorent les performances et réduisent les coûts liés aux threads par rapport aux appels asynchrones, car le contrôle n'est redonné au processus de l'application qu'après l'exécution. Cela signifie que le pilote n'a pas besoin d'un mécanisme distinct pour informer le processus de l'application qu'une exécution est terminée.
Avec la méthode execute_1_3
asynchrone, le contrôle revient au processus de l'application une fois l'exécution lancée, et le pilote doit informer le framework lorsque l'exécution est terminée, à l'aide de @1.3::IExecutionCallback
.
Le paramètre Request
transmis à la méthode d'exécution liste les opérandes d'entrée et de sortie utilisés pour l'exécution. La mémoire qui stocke les données d'opérande doit utiliser l'ordre de ligne, la première dimension itérant le plus lentement et ne comportant aucun remplissage à la fin de chaque ligne. Pour en savoir plus sur les types d'opérandes, consultez la section Opérandes.
Pour les pilotes NN HAL 1.2 ou version ultérieure, lorsqu'une requête est terminée, l'état d'erreur, la forme de sortie et les informations de synchronisation sont renvoyés au framework. Lors de l'exécution, les opérandes de sortie ou internes du modèle peuvent avoir une ou plusieurs dimensions ou un rang inconnus. Lorsqu'au moins un opérande de sortie a une dimension ou un rang inconnus, le pilote doit renvoyer des informations de sortie de taille dynamique.
Pour les pilotes avec NN HAL 1.1 ou version antérieure, seul l'état d'erreur est renvoyé lorsqu'une requête est terminée. Les dimensions des opérandes d'entrée et de sortie doivent être entièrement spécifiées pour que l'exécution aboutisse. Les opérandes internes peuvent avoir une ou plusieurs dimensions inconnues, mais elles doivent avoir un rang spécifié.
Pour les requêtes utilisateur qui couvrent plusieurs pilotes, le framework est chargé de réserver de la mémoire intermédiaire et de séquencer les appels à chaque pilote.
Plusieurs requêtes peuvent être lancées en parallèle sur le même @1.3::IPreparedModel
.
Le pilote peut exécuter les requêtes en parallèle ou sérialiser les exécutions.
Le framework peut demander à un pilote de conserver plusieurs modèles préparés. Par exemple, préparez le modèle m1
, préparez m2
, exécutez la requête r1
sur m1
, exécutez r2
sur m2
, exécutez r3
sur m1
, exécutez r4
sur m2
, libérez (décrit dans la section Nettoyage) m1
et libérez m2
.
Pour éviter une première exécution lente qui pourrait entraîner une mauvaise expérience utilisateur (par exemple, un premier frame stutter), le pilote doit effectuer la plupart des initialisations lors de la phase de compilation. L'initialisation lors de la première exécution doit être limitée aux actions qui ont un impact négatif sur l'état du système lorsqu'elles sont effectuées tôt, telles que la réservation de grands tampons temporaires ou l'augmentation de la fréquence d'horloge d'un appareil. Les pilotes qui ne peuvent préparer qu'un nombre limité de modèles simultanés peuvent devoir effectuer leur initialisation lors de la première exécution.
Sous Android 10 ou version ultérieure, lorsque plusieurs exécutions avec le même modèle préparé sont exécutées en succession rapide, le client peut choisir d'utiliser un objet d'exécution groupée pour communiquer entre les processus d'application et de pilote. Pour en savoir plus, consultez la section Exécutions par rafales et files de messages rapides.
Pour améliorer les performances de plusieurs exécutions à la suite, le pilote peut conserver des tampons temporaires ou augmenter les fréquences d'horloge. Il est recommandé de créer un thread de surveillance pour libérer des ressources si aucune nouvelle requête n'est créée au bout d'un certain temps.
Forme de sortie
Pour les requêtes pour lesquelles une ou plusieurs dimensions d'un ou de plusieurs opérandes de sortie ne sont pas spécifiées, le pilote doit fournir une liste de formes de sortie contenant les informations de dimension pour chaque opérande de sortie après l'exécution. Pour en savoir plus sur les dimensions, consultez OutputShape
.
Si une exécution échoue en raison d'un tampon de sortie de taille insuffisante, le pilote doit indiquer les opérandes de sortie dont la taille de tampon est insuffisante dans la liste des formes de sortie et doit fournir autant d'informations dimensionnelles que possible, en utilisant zéro pour les dimensions inconnues.
Durée
Dans Android 10, une application peut demander le temps d'exécution si elle a spécifié un seul appareil à utiliser lors du processus de compilation. Pour en savoir plus, consultez MeasureTiming
et Détection et attribution d'appareils.
Dans ce cas, un pilote NN HAL 1.2 doit mesurer la durée d'exécution ou signaler UINT64_MAX
(pour indiquer que la durée n'est pas disponible) lors de l'exécution d'une requête. Le pilote doit minimiser toute pénalité de performances résultant de la mesure de la durée d'exécution.
Le pilote indique les durées suivantes en microsecondes dans la structure Timing
:
- Temps d'exécution sur l'appareil:n'inclut pas le temps d'exécution dans le pilote, qui s'exécute sur le processeur hôte.
- Temps d'exécution dans le pilote:inclut le temps d'exécution sur l'appareil.
Ces durées doivent inclure le moment où l'exécution est suspendue, par exemple lorsque l'exécution a été préemptée par d'autres tâches ou lorsqu'elle attend qu'une ressource devienne disponible.
Lorsque le pilote n'a pas été invité à mesurer la durée d'exécution ou en cas d'erreur d'exécution, il doit indiquer les durées sous la forme UINT64_MAX
. Même si le pilote a été invité à mesurer la durée d'exécution, il peut plutôt signaler UINT64_MAX
pour l'heure sur l'appareil, l'heure dans le pilote ou les deux. Lorsque le pilote indique les deux durées sous la forme d'une valeur autre que UINT64_MAX
, le temps d'exécution dans le pilote doit être égal ou supérieur au temps sur l'appareil.
Exécution cloisonnée
Dans Android 11, NNAPI permet aux exécutions d'attendre une liste de poignées sync_fence
et de renvoyer éventuellement un objet sync_fence
, qui est signalé lorsque l'exécution est terminée. Cela réduit les frais généraux pour les petits modèles de séquence et les cas d'utilisation de streaming. L'exécution cloisonnée permet également une interopérabilité plus efficace avec d'autres composants pouvant signaler ou attendre sync_fence
. Pour en savoir plus sur sync_fence
, consultez la section Framework de synchronisation.
Dans une exécution clôturée, le framework appelle la méthode IPreparedModel::executeFenced
pour lancer une exécution asynchrone clôturée sur un modèle préparé avec un vecteur de barrières de synchronisation à attendre. Si la tâche asynchrone est terminée avant le retour de l'appel, un gestionnaire vide peut être renvoyé pour sync_fence
. Un objet IFencedExecutionCallback
doit également être renvoyé pour permettre au framework d'interroger l'état et la durée des erreurs.
Une fois une exécution terminée, les deux valeurs de synchronisation suivantes mesurant la durée de l'exécution peuvent être interrogées via IFencedExecutionCallback::getExecutionInfo
.
timingLaunched
: durée entre l'appel deexecuteFenced
et le signalement de l'syncFence
renvoyé parexecuteFenced
.timingFenced
: durée écoulée entre le moment où tous les barrières de synchronisation que l'exécution attend sont signalées et le moment oùexecuteFenced
signale lesyncFence
renvoyé.
Flux de contrôle
Pour les appareils équipés d'Android 11 ou version ultérieure, la NNAPI inclut deux opérations de flux de contrôle, IF
et WHILE
, qui prennent d'autres modèles comme arguments et les exécutent de manière conditionnelle (IF
) ou répétée (WHILE
). Pour en savoir plus sur l'implémentation, consultez la section Flux de contrôle.
Qualité de service
Dans Android 11, NNAPI offre une meilleure qualité de service (QoS) en permettant à une application d'indiquer les priorités relatives de ses modèles, le temps maximal attendu pour préparer un modèle et la durée maximale de temps attendue pour qu'une exécution soit terminée. Pour en savoir plus, consultez la section Qualité de service.
Effectuer un nettoyage
Lorsqu'une application a terminé d'utiliser un modèle préparé, le framework libère sa référence à l'objet @1.3::IPreparedModel
. Lorsque l'objet IPreparedModel
n'est plus référencé, il est automatiquement détruit dans le service de pilote qui l'a créé. Les ressources spécifiques au modèle peuvent être récupérées à ce stade dans l'implémentation du destructeur par le pilote. Si le service de pilote souhaite que l'objet IPreparedModel
soit automatiquement détruit lorsqu'il n'est plus nécessaire par le client, il ne doit pas contenir de références à l'objet IPreparedModel
une fois que l'objet IPreparedeModel
a été renvoyé via IPreparedModelCallback::notify_1_3
.
Utilisation du processeur
Les pilotes doivent utiliser le processeur pour configurer les calculs. Les pilotes ne doivent pas utiliser le processeur pour effectuer des calculs de graphiques, car cela interfère avec la capacité du framework à allouer correctement le travail. Le pilote doit signaler les parties qu'il ne peut pas gérer au framework et laisser le framework gérer le reste.
Le framework fournit une implémentation de processeur pour toutes les opérations NNAPI, à l'exception des opérations définies par le fournisseur. Pour en savoir plus, consultez la section Extensions du fournisseur.
Les opérations introduites dans Android 10 (niveau d'API 29) ne disposent que d'une implémentation de CPU de référence pour vérifier que les tests CTS et VTS sont corrects. Les implémentations optimisées incluses dans les frameworks de machine learning mobile sont privilégiées par rapport à l'implémentation du processeur NNAPI.
Fonctions utilitaires
Le codebase NNAPI inclut des fonctions utilitaires pouvant être utilisées par les services de pilotes.
Le fichier frameworks/ml/nn/common/include/Utils.h
contient diverses fonctions utilitaires, telles que celles utilisées pour la journalisation et la conversion entre différentes versions de HAL NN.
VLogging:
VLOG
est une macro de wrapper autour deLOG
d'Android qui n'enregistre le message que si la balise appropriée est définie dans la propriétédebug.nn.vlog
.initVLogMask()
doit être appelé avant tout appel àVLOG
. La macroVLOG_IS_ON
peut être utilisée pour vérifier siVLOG
est actuellement activé, ce qui permet d'ignorer le code de journalisation complexe s'il n'est pas nécessaire. La valeur de la propriété doit correspondre à l'un des éléments suivants:- Chaîne vide, indiquant qu'aucune journalisation ne doit être effectuée.
- Le jeton
1
ouall
, qui indique que toutes les journalisations doivent être effectuées. - Liste de balises, délimitées par des espaces, des virgules ou des deux-points, indiquant la journalisation à effectuer. Les tags sont
compilation
,cpuexe
,driver
,execution
,manager
etmodel
.
compliantWithV1_*
: renvoietrue
si un objet HAL NN peut être converti au même type d'une autre version HAL sans perdre d'informations. Par exemple, l'appel decompliantWithV1_0
sur unV1_2::Model
renvoiefalse
si le modèle inclut des types d'opérations introduits dans NN HAL 1.1 ou NN HAL 1.2.convertToV1_*
: convertit un objet HAL de NN d'une version à une autre. Un avertissement est consigné si la conversion entraîne une perte d'informations (c'est-à-dire si la nouvelle version du type ne peut pas représenter complètement la valeur).Fonctionnalités: les fonctions
nonExtensionOperandPerformance
etupdate
peuvent être utilisées pour créer le champCapabilities::operandPerformance
.Interrogation des propriétés des types:
isExtensionOperandType
,isExtensionOperationType
,nonExtensionSizeOfData
,nonExtensionOperandSizeOfData
,nonExtensionOperandTypeIsScalar
ettensorHasUnspecifiedDimensions
.
Le fichier frameworks/ml/nn/common/include/ValidateHal.h
contient des fonctions utilitaires permettant de vérifier qu'un objet HAL de NN est valide conformément aux spécifications de sa version HAL.
validate*
: renvoietrue
si l'objet HAL de NN est valide conformément aux spécifications de sa version HAL. Les types d'OEM et les types d'extensions ne sont pas validés. Par exemple,validateModel
renvoiefalse
si le modèle contient une opération qui fait référence à un indice d'opérande qui n'existe pas ou à une opération qui n'est pas compatible avec cette version de HAL.
Le fichier frameworks/ml/nn/common/include/Tracing.h
contient des macros permettant de simplifier l'ajout d'informations de systrace au code des réseaux de neurones.
Pour obtenir un exemple, consultez les invocations de macro NNTRACE_*
dans l'exemple de pilote.
Le fichier frameworks/ml/nn/common/include/GraphDump.h
contient une fonction utilitaire permettant de vider le contenu d'un Model
sous forme graphique à des fins de débogage.
graphDump
: écrit une représentation du modèle au format Graphviz (.dot
) dans le flux spécifié (le cas échéant) ou dans le logcat (si aucun flux n'est fourni).
Validation
Pour tester votre implémentation de NNAPI, utilisez les tests VTS et CTS inclus dans le framework Android. VTS exécute vos pilotes directement (sans utiliser le framework), tandis que CTS les exécute indirectement via le framework. Ils testent chaque méthode d'API et vérifient que toutes les opérations compatibles avec les pilotes fonctionnent correctement et fournissent des résultats qui répondent aux exigences de précision.
Les exigences de précision dans CTS et VTS pour NNAPI sont les suivantes:
Virgule flottante:abs(attendu - réel) <= atol + rtol * abs(attendu) ; où:
- Pour fp32, atol = 1e-5f, rtol = 5.0f * 1.1920928955078125e-7
- Pour fp16, atol = rtol = 5,0f * 0,0009765625f
Quantifié:décalage d'un (sauf pour
mobilenet_quantized
, qui est décalé de trois)Valeur booléenne:correspondance exacte
Une des méthodes de test de NNAPI par CTS consiste à générer des graphiques pseudo-aléatoires fixes utilisés pour tester et comparer les résultats d'exécution de chaque pilote avec l'implémentation de référence NNAPI. Pour les pilotes avec NN HAL 1.2 ou version ultérieure, si les résultats ne répondent pas aux critères de précision, CTS signale une erreur et génère un fichier de spécifications pour le modèle défaillant sous /data/local/tmp
à des fins de débogage.
Pour en savoir plus sur les critères de précision, consultez TestRandomGraph.cpp
et TestHarness.h
.
Test de fuzz
L'objectif des tests aléatoires est de détecter les plantages, les assertions, les violations de mémoire ou les comportements indéfinis généraux dans le code testé en raison de facteurs tels que des entrées inattendues. Pour les tests de fuzzing NNAPI, Android utilise des tests basés sur libFuzzer, qui sont efficaces pour le fuzzing, car ils utilisent la couverture des lignes des cas de test précédents pour générer de nouvelles entrées aléatoires. Par exemple, libFuzzer privilégie les scénarios de test qui s'exécutent sur de nouvelles lignes de code. Cela réduit considérablement le temps nécessaire aux tests pour trouver le code problématique.
Pour effectuer des tests aléatoires afin de valider l'implémentation de votre pilote, modifiez frameworks/ml/nn/runtime/test/android_fuzzing/DriverFuzzTest.cpp
dans l'utilitaire de test libneuralnetworks_driver_fuzzer
disponible dans AOSP afin d'inclure votre code de pilote. Pour en savoir plus sur les tests aléatoires NNAPI, consultez frameworks/ml/nn/runtime/test/android_fuzzing/README.md
.
Sécurité
Étant donné que les processus d'application communiquent directement avec le processus d'un pilote, les pilotes doivent valider les arguments des appels qu'ils reçoivent. Cette validation est effectuée par VTS. Le code de validation se trouve dans frameworks/ml/nn/common/include/ValidateHal.h
.
Les pilotes doivent également s'assurer que les applications ne peuvent pas interférer avec d'autres applications lorsqu'elles utilisent le même appareil.
Android Machine Learning Test Suite
La suite de tests de machine learning Android (MLTS) est un benchmark NNAPI inclus dans CTS et VTS pour valider l'exactitude de modèles réels sur les appareils du fournisseur. Elle évalue la latence et la justesse, et compare les résultats des pilotes à ceux obtenus avec TF Lite exécuté sur le processeur, pour le même modèle et les mêmes ensembles de données. Cela garantit que la précision d'un pilote n'est pas inférieure à l'implémentation de référence du processeur.
Les développeurs de la plate-forme Android utilisent également les MLTS pour évaluer la latence et la justesse des pilotes.
L'analyse comparative de NNAPI se trouve dans deux projets d'AOSP:
platform/test/mlts/benchmark
(application de référence)platform/test/mlts/models
(modèles et ensembles de données)
Modèles et ensembles de données
L'analyse comparative de NNAPI utilise les modèles et ensembles de données suivants.
- MobileNetV1 à virgule flottante et u8 quantifiés dans différentes tailles, exécutés sur un petit sous-ensemble (1 500 images) d'Open Images Dataset V4.
- MobileNetV2 à virgule flottante et u8 quantifiés dans différentes tailles, exécutés sur un petit sous-ensemble (1 500 images) d'Open Images Dataset V4.
- Modèle acoustique basé sur la mémoire à court terme (LSTM) pour la synthèse vocale, exécuté sur un petit sous-ensemble de l'ensemble CMU Arctic.
- Modèle acoustique basé sur LSTM pour la reconnaissance vocale automatique, exécuté sur un petit sous-ensemble de l'ensemble de données LibriSpeech.
Pour en savoir plus, consultez platform/test/mlts/models
.
Test de stress
La suite de tests Android Machine Learning inclut une série de tests de plantage pour valider la résilience des pilotes dans des conditions d'utilisation intensive ou dans des cas particuliers de comportement des clients.
Tous les tests de plantage offrent les fonctionnalités suivantes:
- Détection d'arrêt:si le client NNAPI se bloque pendant un test, le test échoue avec le code d'erreur
HANG
et la suite de tests passe au test suivant. - Détection des plantages du client NNAPI:les tests survivent aux plantages du client et échouent avec le code d'erreur
CRASH
. - Détection de plantage du pilote:les tests peuvent détecter un plantage du pilote qui entraîne une défaillance sur un appel NNAPI. Notez qu'il peut y avoir des plantages dans les processus de pilote qui ne provoquent pas de défaillance NNAPI et ne provoquent pas l'échec du test. Pour couvrir ce type de défaillance, nous vous recommandons d'exécuter la commande
tail
sur le journal système pour rechercher les erreurs ou les plantages liés aux pilotes. - Ciblage de tous les accélérateurs disponibles:les tests sont exécutés sur tous les pilotes disponibles.
Quatre résultats sont possibles pour tous les tests de collision:
SUCCESS
: l'exécution s'est terminée sans erreur.FAILURE
: l'exécution a échoué. Généralement causée par une défaillance lors du test d'un modèle, ce qui indique que le pilote n'a pas réussi à compiler ou à exécuter le modèle.HANG
: le processus de test ne répond plus.CRASH
: le processus de test a planté.
Pour en savoir plus sur les tests de stress et obtenir la liste complète des tests de plantage, consultez platform/test/mlts/benchmark/README.txt
.
Utiliser MLTS
Pour utiliser le MLTS:
- Connectez un appareil cible à votre poste de travail et assurez-vous qu'il est accessible via adb.
Exportez la variable d'environnement
ANDROID_SERIAL
de l'appareil cible si plusieurs appareils sont connectés. cd
dans le répertoire source Android de premier niveau.source build/envsetup.sh lunch aosp_arm-userdebug # Or aosp_arm64-userdebug if available. ./test/mlts/benchmark/build_and_run_benchmark.sh
À la fin d'une analyse comparative, les résultats sont présentés sous la forme d'une page HTML et transmis à
xdg-open
.
Pour en savoir plus, consultez platform/test/mlts/benchmark/README.txt
.
Versions du HAL des réseaux de neurones
Cette section décrit les modifications apportées aux versions Android et HAL de réseaux de neurones.
Android 11
Android 11 introduit NN HAL 1.3, qui inclut les modifications notables suivantes.
- Compatibilité avec la quantification 8 bits signée dans NNAPI. Ajoute le type d'opérande
TENSOR_QUANT8_ASYMM_SIGNED
. Les pilotes avec NN HAL 1.3 qui prennent en charge les opérations avec une quantification non signée doivent également prendre en charge les variantes signées de ces opérations. Lorsque vous exécutez des versions signées et non signées de la plupart des opérations quantifiées, les pilotes doivent produire les mêmes résultats jusqu'à un décalage de 128. Il existe cinq exceptions à cette exigence:CAST
,HASHTABLE_LOOKUP
,LSH_PROJECTION
,PAD_V2
etQUANTIZED_16BIT_LSTM
. L'opérationQUANTIZED_16BIT_LSTM
n'est pas compatible avec les opérandes signés, et les quatre autres opérations sont compatibles avec la quantification signée, mais ne nécessitent pas que les résultats soient identiques. - Prise en charge des exécutions clôturées où le framework appelle la méthode
IPreparedModel::executeFenced
pour lancer une exécution asynchrone clôturée sur un modèle préparé avec un vecteur de barrières de synchronisation à attendre. Pour en savoir plus, consultez la section Exécution cloisonnée. - Prise en charge du flux de contrôle. Ajoute les opérations
IF
etWHILE
, qui prennent d'autres modèles comme arguments et les exécutent de manière conditionnelle (IF
) ou répétée (WHILE
). Pour en savoir plus, consultez la section Flux de contrôle. - Amélioration de la qualité de service (QoS), car les applications peuvent indiquer les priorités relatives de leurs modèles, le temps maximal attendu pour la préparation d'un modèle et la durée maximale attendue pour l'exécution. Pour en savoir plus, consultez la section Qualité de service.
- Compatibilité avec les domaines de mémoire qui fournissent des interfaces d'allocation pour les tampons gérés par le pilote. Cela permet de transmettre les mémoires natives de l'appareil lors des exécutions, ce qui supprime la copie et la transformation inutiles des données entre les exécutions consécutives sur le même pilote. Pour en savoir plus, consultez la section Domaines de mémoire.
Android 10
Android 10 introduit NN HAL 1.2, qui inclut les modifications notables suivantes.
- La struct
Capabilities
inclut tous les types de données, y compris les types de données scalaires, et représente les performances non relâchées à l'aide d'un vecteur plutôt que de champs nommés. - Les méthodes
getVersionString
etgetType
permettent au framework de récupérer le type d'appareil (DeviceType
) et les informations de version. Consultez la section Détection et attribution d'appareils. - La méthode
executeSynchronously
est appelée par défaut pour effectuer une exécution de manière synchrone. La méthodeexecute_1_2
indique au framework d'effectuer une exécution de manière asynchrone. Voir Exécution. - Le paramètre
MeasureTiming
pourexecuteSynchronously
,execute_1_2
et l'exécution par rafales indique si le pilote doit mesurer la durée d'exécution. Les résultats sont indiqués dans la structureTiming
. Voir la section Calendrier. - Prise en charge des exécutions pour lesquelles une ou plusieurs des opérandes de sortie ont une dimension ou un rang inconnus. Consultez Forme de sortie.
- Prise en charge des extensions du fournisseur, qui sont des collections d'opérations et de types de données définis par le fournisseur. Le pilote signale les extensions compatibles via la méthode
IDevice::getSupportedExtensions
. Consultez la section Extensions du fournisseur. - Possibilité pour un objet de rafales de contrôler un ensemble d'exécutions de rafales à l'aide de files d'attente de messages rapides (FMQ) pour communiquer entre les processus d'application et de pilote, ce qui réduit la latence. Consultez la section Exécutions intensives et files d'attente de messages rapides.
- Prise en charge d'AHardwareBuffer pour permettre au pilote d'effectuer des exécutions sans copier de données. Consultez la section AHardwareBuffer.
- Amélioration de la prise en charge de la mise en cache des artefacts de compilation afin de réduire le temps de compilation au démarrage d'une application. Consultez la section Mise en cache de la compilation.
Android 10 introduit les types et opérations d'opérandes suivants.
-
ANEURALNETWORKS_BOOL
ANEURALNETWORKS_FLOAT16
ANEURALNETWORKS_TENSOR_BOOL8
ANEURALNETWORKS_TENSOR_FLOAT16
ANEURALNETWORKS_TENSOR_QUANT16_ASYMM
ANEURALNETWORKS_TENSOR_QUANT16_SYMM
ANEURALNETWORKS_TENSOR_QUANT8_SYMM
ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL
-
ANEURALNETWORKS_ABS
ANEURALNETWORKS_ARGMAX
ANEURALNETWORKS_ARGMIN
ANEURALNETWORKS_AXIS_ALIGNED_BBOX_TRANSFORM
ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_LSTM
ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_RNN
ANEURALNETWORKS_BOX_WITH_NMS_LIMIT
ANEURALNETWORKS_CAST
ANEURALNETWORKS_CHANNEL_SHUFFLE
ANEURALNETWORKS_DETECTION_POSTPROCESSING
ANEURALNETWORKS_EQUAL
ANEURALNETWORKS_EXP
ANEURALNETWORKS_EXPAND_DIMS
ANEURALNETWORKS_GATHER
ANEURALNETWORKS_GENERATE_PROPOSALS
ANEURALNETWORKS_GREATER
ANEURALNETWORKS_GREATER_EQUAL
ANEURALNETWORKS_GROUPED_CONV_2D
ANEURALNETWORKS_HEATMAP_MAX_KEYPOINT
ANEURALNETWORKS_INSTANCE_NORMALIZATION
ANEURALNETWORKS_LESS
ANEURALNETWORKS_LESS_EQUAL
ANEURALNETWORKS_LOG
ANEURALNETWORKS_LOGICAL_AND
ANEURALNETWORKS_LOGICAL_NOT
ANEURALNETWORKS_LOGICAL_OR
ANEURALNETWORKS_LOG_SOFTMAX
ANEURALNETWORKS_MAXIMUM
ANEURALNETWORKS_MINIMUM
ANEURALNETWORKS_NEG
ANEURALNETWORKS_NOT_EQUAL
ANEURALNETWORKS_PAD_V2
ANEURALNETWORKS_POW
ANEURALNETWORKS_PRELU
ANEURALNETWORKS_QUANTIZE
ANEURALNETWORKS_QUANTIZED_16BIT_LSTM
ANEURALNETWORKS_RANDOM_MULTINOMIAL
ANEURALNETWORKS_REDUCE_ALL
ANEURALNETWORKS_REDUCE_ANY
ANEURALNETWORKS_REDUCE_MAX
ANEURALNETWORKS_REDUCE_MIN
ANEURALNETWORKS_REDUCE_PROD
ANEURALNETWORKS_REDUCE_SUM
ANEURALNETWORKS_RESIZE_NEAREST_NEIGHBOR
ANEURALNETWORKS_ROI_ALIGN
ANEURALNETWORKS_ROI_POOLING
ANEURALNETWORKS_RSQRT
ANEURALNETWORKS_SELECT
ANEURALNETWORKS_SIN
ANEURALNETWORKS_SLICE
ANEURALNETWORKS_SPLIT
ANEURALNETWORKS_SQRT
ANEURALNETWORKS_TILE
ANEURALNETWORKS_TOPK_V2
ANEURALNETWORKS_TRANSPOSE_CONV_2D
ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_LSTM
ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_RNN
Android 10 apporte des mises à jour de nombreuses opérations existantes. Les mises à jour concernent principalement les éléments suivants:
- Prise en charge de la mise en page de mémoire NCHW
- Compatibilité avec les tenseurs de rang différent de 4 dans les opérations de softmax et de normalisation
- Prise en charge des convolutions dilatées
- Compatibilité avec les entrées avec quantification mixte dans
ANEURALNETWORKS_CONCATENATION
La liste ci-dessous présente les opérations modifiées dans Android 10. Pour en savoir plus sur les modifications, consultez OperationCode dans la documentation de référence de NNAPI.
ANEURALNETWORKS_ADD
ANEURALNETWORKS_AVERAGE_POOL_2D
ANEURALNETWORKS_BATCH_TO_SPACE_ND
ANEURALNETWORKS_CONCATENATION
ANEURALNETWORKS_CONV_2D
ANEURALNETWORKS_DEPTHWISE_CONV_2D
ANEURALNETWORKS_DEPTH_TO_SPACE
ANEURALNETWORKS_DEQUANTIZE
ANEURALNETWORKS_DIV
ANEURALNETWORKS_FLOOR
ANEURALNETWORKS_FULLY_CONNECTED
ANEURALNETWORKS_L2_NORMALIZATION
ANEURALNETWORKS_L2_POOL_2D
ANEURALNETWORKS_LOCAL_RESPONSE_NORMALIZATION
ANEURALNETWORKS_LOGISTIC
ANEURALNETWORKS_LSH_PROJECTION
ANEURALNETWORKS_LSTM
ANEURALNETWORKS_MAX_POOL_2D
ANEURALNETWORKS_MEAN
ANEURALNETWORKS_MUL
ANEURALNETWORKS_PAD
ANEURALNETWORKS_RELU
ANEURALNETWORKS_RELU1
ANEURALNETWORKS_RELU6
ANEURALNETWORKS_RESHAPE
ANEURALNETWORKS_RESIZE_BILINEAR
ANEURALNETWORKS_RNN
ANEURALNETWORKS_ROI_ALIGN
ANEURALNETWORKS_SOFTMAX
ANEURALNETWORKS_SPACE_TO_BATCH_ND
ANEURALNETWORKS_SPACE_TO_DEPTH
ANEURALNETWORKS_SQUEEZE
ANEURALNETWORKS_STRIDED_SLICE
ANEURALNETWORKS_SUB
ANEURALNETWORKS_SVDF
ANEURALNETWORKS_TANH
ANEURALNETWORKS_TRANSPOSE
Android 9
NN HAL 1.1 est introduit dans Android 9 et inclut les modifications notables suivantes.
IDevice::prepareModel_1_1
inclut un paramètreExecutionPreference
. Un pilote peut l'utiliser pour ajuster sa préparation, sachant que l'application préfère préserver la batterie ou qu'elle exécutera le modèle dans des appels successifs rapides.- Neuf nouvelles opérations ont été ajoutées:
BATCH_TO_SPACE_ND
,DIV
,MEAN
,PAD
,SPACE_TO_BATCH_ND
,SQUEEZE
,STRIDED_SLICE
,SUB
etTRANSPOSE
. - Une application peut spécifier que les calculs à virgule flottante 32 bits peuvent être exécutés à l'aide de la plage et/ou de la précision à virgule flottante 16 bits en définissant
Model.relaxComputationFloat32toFloat16
surtrue
. La structureCapabilities
contient le champ supplémentairerelaxedFloat32toFloat16Performance
afin que le pilote puisse signaler ses performances d'exécution simplifiée au framework.
Android 8.1
La version initiale du HAL des réseaux de neurones (1.0) a été publiée dans Android 8.1. Pour en savoir plus, consultez /neuralnetworks/1.0/
.