Pilotes d'API pour les réseaux de neurones

Cette page fournit une présentation de la façon d'implémenter un pilote API Neural Networks (NNAPI). Pour plus de détails, consultez la documentation trouvée dans les 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 plus d'informations sur l'API des réseaux de neurones, consultez API des réseaux de neurones .

Réseaux de neurones HAL

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 périphériques doivent être conformes au NN HAL. 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 représenté dans la figure 1.

Flux de réseaux de neurones

Figure 1. Flux des réseaux de neurones

Initialisation

Lors de l'initialisation, le framework interroge le pilote pour connaître ses capacités à l'aide de IDevice::getCapabilities_1_3 . La structure @1.3::Capabilities inclut tous les types de données et représente des performances non détendues à l’aide d’un vecteur.

Pour déterminer comment allouer les calculs aux appareils disponibles, le framework utilise les capacités permettant de 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 basés sur 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 de référence 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 pour les valeurs à virgule flottante de 32 bits et les modèles quantifiés MobileNet v1 et v2 sont recommandés pour les valeurs quantifiées de 8 bits. Pour plus d’informations, consultez Suite de tests Android Machine Learning .

Dans Android 9 et versions antérieures, la structure Capabilities inclut des informations sur les performances du pilote uniquement pour les tenseurs à virgule flottante et quantifiés et n'inclut pas les types de données scalaires.

Dans le cadre du processus d'initialisation, l'infrastructure peut demander plus d'informations à l'aide de IDevice::getType , IDevice::getVersionString , IDevice:getSupportedExtensions et IDevice::getNumberOfCacheFilesNeeded .

Entre les redémarrages du produit, l'infrastructure s'attend à ce que toutes les requêtes décrites dans cette section rapportent 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 demande d'une application. Dans Android 10, les applications peuvent découvrir et spécifier les appareils parmi lesquels le framework sélectionne. Pour plus d’informations, consultez Découverte et attribution de périphériques .

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 booléens 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. Par exemple:

  • Le pilote ne prend pas en charge le type de données.
  • Le pilote ne prend en charge que 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 7x7.
  • Le pilote a des contraintes de mémoire qui l'empêchent de gérer des graphiques ou des entrées volumineux.

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 plus d’informations, consultez 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 laps de temps important peut s'écouler entre la compilation du modèle et l'exécution des requêtes, des 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 succès, le pilote renvoie un handle @1.3::IPreparedModel . Si le pilote renvoie un code d'échec lors de la préparation de son sous-ensemble du modèle, le framework exécute l'intégralité du modèle sur le CPU.

Pour réduire le temps nécessaire à la compilation au démarrage d’une application, un pilote peut mettre en cache les artefacts de compilation. Pour plus d'informations, consultez Mise en cache de 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 execute_1_3 , de la executeFenced (voir Exécution clôturée ) ou exécutée à l'aide d'une exécution en rafale .

Les appels d'exécution synchrone améliorent les performances et réduisent la surcharge de thread par rapport aux appels asynchrones, car le contrôle n'est rendu au processus d'application qu'une fois l'exécution terminée. Cela signifie que le pilote n'a pas besoin d'un mécanisme distinct pour informer le processus d'application qu'une exécution est terminée.

Avec la méthode asynchrone execute_1_3 , le contrôle revient au processus d'application après le début de l'exécution et le pilote doit informer le framework lorsque l'exécution est terminée, à l'aide de @1.3::IExecutionCallback .

Le paramètre Request passé à la méthode d'exécution répertorie 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 des lignes principales, la première dimension itérant le plus lentement et ne comportant aucun remplissage à la fin d'une ligne. Pour plus d'informations sur les types d'opérandes, voir Opérandes .

Pour les pilotes NN HAL 1.2 ou version ultérieure, lorsqu'une requête est terminée, l'état de l'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 rangs inconnus. Lorsqu'au moins un opérande de sortie a une dimension ou un rang inconnu, 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 demande 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 se termine avec succès. Les opérandes internes peuvent avoir une ou plusieurs dimensions inconnues, mais ils doivent avoir un rang spécifié.

Pour les demandes des utilisateurs qui couvrent plusieurs pilotes, le framework est responsable de la réservation de la mémoire intermédiaire et du séquençage des 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 des requêtes en parallèle ou sérialiser les exécutions.

Le framework peut demander à un conducteur 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 Cleanup ) 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 bégaiement de la première image), 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 affectent négativement la santé du système lorsqu'elles sont effectuées tôt, telles que la réservation de tampons temporaires volumineux ou l'augmentation de la fréquence d'horloge d'un périphérique. Les pilotes capables de préparer uniquement un nombre limité de modèles simultanés devront peut-être effectuer leur initialisation lors de la première exécution.

Sous Android 10 ou version ultérieure, dans les cas où 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 de rafale d'exécution pour communiquer entre les processus de l'application et du pilote. Pour plus d'informations, consultez Exécutions en rafale et files d'attente de messages rapides .

Pour améliorer les performances de plusieurs exécutions successives, le pilote peut conserver des tampons temporaires ou augmenter la fréquence d'horloge. La création d'un thread de surveillance est recommandée pour libérer des ressources si aucune nouvelle demande n'est créée après une période de temps déterminée.

Forme de sortie

Pour les requêtes pour lesquelles un ou plusieurs opérandes de sortie n'ont pas toutes les dimensions 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 plus d’informations sur les dimensions, consultez OutputShape .

Si une exécution échoue en raison d'un tampon de sortie sous-dimensionné, le pilote doit indiquer quels opérandes de sortie ont une taille de tampon insuffisante dans la liste des formes de sortie et doit rapporter autant d'informations dimensionnelles que possible, en utilisant zéro pour les dimensions inconnues.

Horaire

Sous Android 10, une application peut demander le temps d'exécution si l'application a spécifié un seul appareil à utiliser pendant le processus de compilation. Pour plus de détails, consultez MeasureTiming et Device Discovery and Assignment . 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 performance résultant de la mesure de la durée d'exécution.

Le pilote signale 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 soit disponible.

Lorsqu'il n'a pas été demandé au pilote de mesurer la durée d'exécution ou lorsqu'il y a une erreur d'exécution, le pilote doit signaler les durées sous la forme UINT64_MAX . Même lorsqu'il a été demandé au pilote de mesurer la durée d'exécution, il peut à la place signaler UINT64_MAX pour le temps sur le périphérique, le temps dans le pilote, ou les deux. Lorsque le pilote signale 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 le périphérique.

Exécution clôturée

Dans Android 11, NNAPI permet aux exécutions d'attendre une liste de handles sync_fence et éventuellement de renvoyer un objet sync_fence , qui est signalé lorsque l'exécution est terminée. Cela réduit les frais généraux pour les modèles de petites séquences et les cas d’utilisation de streaming. L'exécution clôturée permet également une interopérabilité plus efficace avec d'autres composants qui peuvent signaler ou attendre sync_fence . Pour plus d'informations sur sync_fence , voir Structure de synchronisation .

Dans une exécution isolée, le framework appelle la méthode IPreparedModel::executeFenced pour lancer une exécution asynchrone isolée sur un modèle préparé avec un vecteur de clôtures de synchronisation à attendre. Si la tâche asynchrone est terminée avant le retour de l'appel, un handle vide peut être renvoyé pour sync_fence . Un objet IFencedExecutionCallback doit également être renvoyé pour permettre à l’infrastructure d’interroger les informations sur l’état et la durée de l’erreur.

Une fois l'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 le moment executeFenced est appelé et le moment executeFenced signale le syncFence renvoyé.
  • timingFenced : durée à partir du moment où toutes les clôtures de synchronisation attendues par l'exécution sont signalées jusqu'au moment où executeFenced signale le syncFence renvoyé.

Flux de contrôle

Pour les appareils exécutant Android 11 ou version ultérieure, NNAPI comprend 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 de manière répétée ( WHILE ). Pour plus d’informations sur la façon de mettre en œuvre cela, consultez Flux de contrôle .

Qualité de service

Dans Android 11, le NNAPI inclut une qualité de service (QoS) améliorée en permettant à une application d'indiquer les priorités relatives de ses modèles, le temps maximum attendu pour la préparation d'un modèle et le temps maximum attendu pour une exécution. à compléter. Pour plus d'informations, voir Qualité de service .

Nettoyer

Lorsqu'une application a fini d'utiliser un modèle préparé, le framework publie 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 moment 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 utilisé par le client, il ne doit contenir aucune référence à l'objet IPreparedModel une fois que l'objet IPreparedeModel a été renvoyé via IPreparedModelCallback::notify_1_3 .

l'utilisation du processeur

Les pilotes sont censés utiliser le processeur pour configurer les calculs. Les pilotes ne doivent pas utiliser le processeur pour effectuer des calculs graphiques, car cela interfère avec la capacité du framework à répartir 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 CPU pour toutes les opérations NNAPI, à l'exception des opérations définies par le fournisseur. Pour plus d'informations, consultez Extensions de fournisseur .

Les opérations introduites dans Android 10 (API niveau 29) n'ont qu'une implémentation 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 d'apprentissage automatique mobile sont préférées à l'implémentation du processeur NNAPI.

Fonctions utilitaires

La base de code NNAPI comprend des fonctions utilitaires qui peuvent ê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 NN HAL.

  • VLogging : VLOG est une macro wrapper autour LOG ​​d'Android qui enregistre le message uniquement si la balise appropriée est définie dans la propriété debug.nn.vlog . initVLogMask() doit être appelé avant tout appel à VLOG . La macro VLOG_IS_ON peut être utilisée pour vérifier si VLOG est actuellement activé, permettant ainsi d'ignorer le code de journalisation compliqué s'il n'est pas nécessaire. La valeur du bien doit être l'une des suivantes :

    • Une chaîne vide, indiquant qu'aucune journalisation ne doit être effectuée.
    • Le jeton 1 ou all , indiquant que toute la journalisation doit être effectuée.
    • Une liste de balises, délimitées par des espaces, des virgules ou des deux-points, indiquant quelle journalisation doit être effectuée. Les balises sont compilation , cpuexe , driver , execution , manager et model .
  • compliantWithV1_* : renvoie true si un objet NN HAL peut être converti au même type d'une version HAL différente sans perdre d'informations. Par exemple, l'appel compliantWithV1_0 sur un V1_2::Model renvoie false si le modèle inclut des types d'opération introduits dans NN HAL 1.1 ou NN HAL 1.2.

  • convertToV1_* : Convertit un objet NN HAL d'une version à une autre. Un avertissement est enregistré si la conversion entraîne une perte d'informations (c'est-à-dire si la nouvelle version du type ne peut pas représenter entièrement la valeur).

  • Capabilities : les fonctions nonExtensionOperandPerformance et update peuvent être utilisées pour aider à créer le champ Capabilities::operandPerformance .

  • Interrogation des propriétés des types : isExtensionOperandType , isExtensionOperationType , nonExtensionSizeOfData , nonExtensionOperandSizeOfData , nonExtensionOperandTypeIsScalar , tensorHasUnspecifiedDimensions .

Le fichier frameworks/ml/nn/common/include/ValidateHal.h contient des fonctions utilitaires permettant de valider qu'un objet NN HAL est valide selon la spécification de sa version HAL.

  • validate* : renvoie true si l'objet NN HAL est valide selon la spécification de sa version HAL. Les types OEM et les types d’extension ne sont pas validés. Par exemple, validateModel renvoie false si le modèle contient une opération qui fait référence à un index d'opérande qui n'existe pas ou une opération qui n'est pas prise en charge dans cette version de HAL.

Le fichier frameworks/ml/nn/common/include/Tracing.h contient des macros pour simplifier l'ajout d'informations de traçage système au code des réseaux de neurones. Pour obtenir un exemple, consultez les appels 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é (si fourni) ou dans le logcat (si aucun flux n'est fourni).

Validation

Pour tester votre implémentation du NNAPI, utilisez les tests VTS et CTS inclus dans le framework Android. VTS exerce vos pilotes directement (sans utiliser le framework), tandis que CTS les exerce indirectement via le framework. Ceux-ci testent chaque méthode API et vérifient que toutes les opérations prises en charge par 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 le 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é : un par un (sauf pour mobilenet_quantized , qui est un par trois)

  • Booléen : correspondance exacte

Une façon dont CTS teste NNAPI 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 supérieur, si les résultats ne répondent pas aux critères de précision, CTS signale une erreur et sauvegarde un fichier de spécification pour le modèle défaillant sous /data/local/tmp pour le débogage. Pour plus de détails sur les critères de précision, consultez TestRandomGraph.cpp et TestHarness.h .

Test de flou

Le but des tests fuzz est de détecter les plantages, les assertions, les violations de mémoire ou un comportement général non défini dans le code testé en raison de facteurs tels que des entrées inattendues. Pour les tests de fuzz NNAPI, Android utilise des tests basés sur libFuzzer , qui sont efficaces pour le fuzz car ils utilisent la couverture de lignes des cas de test précédents pour générer de nouvelles entrées aléatoires. Par exemple, libFuzzer privilégie les cas 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 fuzz 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 trouvé dans AOSP pour inclure le code de votre pilote. Pour plus d'informations sur les tests fuzz 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, celui-ci doit valider les arguments des appels qu'il reçoit. Cette validation est vérifiée par VTS. Le code de validation se trouve dans frameworks/ml/nn/common/include/ValidateHal.h .

Les conducteurs doivent également s'assurer que les applications ne peuvent pas interférer avec d'autres applications lorsqu'elles utilisent le même appareil.

Suite de tests d'apprentissage automatique Android

L'Android Machine Learning Test Suite (MLTS) est un benchmark NNAPI inclus dans CTS et VTS pour valider l'exactitude des modèles réels sur les appareils des fournisseurs. Le benchmark évalue la latence et la précision, et compare les résultats des pilotes avec les résultats de l'utilisation de 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 pire que l'implémentation de référence du CPU.

Les développeurs de plateformes Android utilisent également MLTS pour évaluer la latence et la précision des pilotes.

Le benchmark NNAPI se retrouve dans deux projets en AOSP :

Modèles et ensembles de données

Le benchmark NNAPI utilise les modèles et ensembles de données suivants.

  • MobileNetV1 float et u8 quantifiés dans différentes tailles, exécutés sur un petit sous-ensemble (1 500 images) de l'Open Images Dataset v4.
  • MobileNetV2 float et u8 quantifiés dans différentes tailles, exécutés sur un petit sous-ensemble (1 500 images) de l'Open Images Dataset v4.
  • Modèle acoustique basé sur la mémoire à long 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 plus d'informations, consultez platform/test/mlts/models .

Tests de résistance

La suite de tests Android Machine Learning comprend une série de crash tests pour valider la résilience des pilotes dans des conditions d'utilisation intensive ou dans des cas particuliers de comportement des clients.

Tous les crash tests offrent les fonctionnalités suivantes :

  • Détection de blocage : si le client NNAPI se bloque pendant un test, le test échoue avec le motif d'échec HANG et la suite de tests passe au test suivant.
  • Détection de crash du client NNAPI : les tests survivent aux crashs du client et les tests échouent avec la raison de l'échec CRASH .
  • Détection de crash de pilote : les tests peuvent détecter un crash de pilote qui provoque un échec lors d'un appel NNAPI. Notez qu'il peut y avoir des plantages dans les processus du pilote qui ne provoquent pas d'échec NNAPI et n'entraînent pas l'échec du test. Pour couvrir ce type d'échec, il est recommandé d'exécuter la commande tail sur le journal système pour les erreurs ou les plantages liés au pilote.
  • Ciblage de tous les accélérateurs disponibles : les tests sont exécutés sur tous les pilotes disponibles.

Tous les crash tests ont les quatre résultats possibles suivants :

  • SUCCESS : Exécution terminée sans erreur.
  • FAILURE : L'exécution a échoué. Généralement provoqué par un échec lors du test d'un modèle, indiquant 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 s'est écrasé.

Pour plus d'informations sur les tests de résistance et une liste complète des crash tests, consultez platform/test/mlts/benchmark/README.txt .

Utiliser MLTS

Pour utiliser le MLTS :

  1. 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.
  2. cd dans le répertoire source Android de niveau supérieur.

    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 exécution de benchmark, les résultats sont présentés sous forme de page HTML et transmis à xdg-open .

Pour plus d'informations, consultez platform/test/mlts/benchmark/README.txt .

Versions HAL des réseaux de neurones

Cette section décrit les modifications introduites dans les versions Android et Neural Networks HAL.

Android 11

Android 11 introduit NN HAL 1.3, qui inclut les changements notables suivants.

  • Prise en charge de la quantification signée 8 bits 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 quantification non signée doivent également prendre en charge les variantes signées de ces opérations. Lors de l'exécution de 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 et QUANTIZED_16BIT_LSTM . L'opération QUANTIZED_16BIT_LSTM ne prend pas en charge les opérandes signés et les quatre autres opérations prennent en charge la quantification signée mais n'exigent pas que les résultats soient identiques.
  • Prise en charge des exécutions isolées où le framework appelle la méthode IPreparedModel::executeFenced pour lancer une exécution asynchrone isolée sur un modèle préparé avec un vecteur de clôtures de synchronisation à attendre. Pour plus d'informations, voir Exécution clôturée .
  • Prise en charge du flux de contrôle. Ajoute les opérations IF et WHILE , qui prennent d'autres modèles comme arguments et les exécutent de manière conditionnelle ( IF ) ou de manière répétée ( WHILE ). Pour plus d’informations, consultez Flux de contrôle .
  • Qualité de service (QoS) améliorée, car les applications peuvent indiquer les priorités relatives de leurs modèles, le temps maximum attendu pour la préparation d'un modèle et le temps maximum attendu pour qu'une exécution soit terminée. Pour plus d'informations, voir Qualité de service .
  • Prise en charge des 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 du périphérique entre les exécutions, supprimant ainsi la copie et la transformation inutiles des données entre des exécutions consécutives sur le même pilote. Pour plus d’informations, consultez Domaines de mémoire .

Android 10

Android 10 introduit NN HAL 1.2, qui inclut les changements notables suivants.

  • La structure Capabilities inclut tous les types de données, y compris les types de données scalaires, et représente des performances non détendues en utilisant un vecteur plutôt que des champs nommés.
  • Les méthodes getVersionString et getType permettent au framework de récupérer le type de périphérique ( DeviceType ) et les informations de version. Voir Découverte et attribution de périphériques .
  • La executeSynchronously est appelée par défaut pour effectuer une exécution de manière synchrone. La méthode execute_1_2 indique au framework d'effectuer une exécution de manière asynchrone. Voir Exécution .
  • Le paramètre MeasureTiming pour executeSynchronously , execute_1_2 et exécution en rafale spécifie si le pilote doit mesurer la durée d'exécution. Les résultats sont rapportés dans la structure Timing . Voir Calendrier .
  • Prise en charge des exécutions dans lesquelles un ou plusieurs opérandes de sortie ont une dimension ou un rang inconnu. Voir Forme de sortie .
  • Prise en charge des extensions de fournisseur, qui sont des ensembles d'opérations et de types de données définis par le fournisseur. Le pilote signale les extensions prises en charge via la méthode IDevice::getSupportedExtensions . Voir Extensions de fournisseur .
  • Possibilité pour un objet en rafale de contrôler un ensemble d'exécutions en rafale à l'aide de files d'attente de messages rapides (FMQ) pour communiquer entre les processus d'application et de pilote, réduisant ainsi la latence. Voir Exécutions en rafale 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. Voir AHardwareBuffer .
  • Prise en charge améliorée de la mise en cache des artefacts de compilation afin de réduire le temps utilisé pour la compilation au démarrage d'une application. Voir Mise en cache de compilation .

Android 10 introduit les types d'opérandes et d'opérations suivants.

  • Types d'opérandes

    • 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
  • Opérations

    • 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 introduit des mises à jour pour de nombreuses opérations existantes. Les mises à jour concernent principalement les éléments suivants :

  • Prise en charge de la disposition de la mémoire NCHW
  • Prise en charge des tenseurs de rang différent de 4 dans les opérations softmax et de normalisation
  • Prise en charge des circonvolutions dilatées
  • Prise en charge des entrées avec quantification mixte dans ANEURALNETWORKS_CONCATENATION

La liste ci-dessous présente les opérations modifiées dans Android 10. Pour plus de détails sur les modifications, consultez OperationCode dans la documentation de référence 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ètre ExecutionPreference . Un conducteur peut l'utiliser pour ajuster sa préparation, sachant que l'application préfère économiser la batterie ou exécutera le modèle lors d'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 , TRANSPOSE .
  • Une application peut spécifier que les calculs flottants 32 bits peuvent être exécutés en utilisant une plage flottante et/ou une précision de 16 bits en définissant Model.relaxComputationFloat32toFloat16 sur true . La structure Capabilities a le champ supplémentaire relaxedFloat32toFloat16Performance afin que le pilote puisse signaler ses performances détendues au framework.

Android 8.1

Le premier réseau de neurones HAL (1.0) a été publié sous Android 8.1. Pour plus d’informations, consultez /neuralnetworks/1.0/ .