Driver API delle reti neurali

Questa pagina fornisce una panoramica su come implementare un driver NNAPI (Neural Networks API). Per ulteriori dettagli, consultare la documentazione disponibile nei file di definizione HAL in hardware/interfaces/neuralnetworks . Un'implementazione di driver di esempio è in frameworks/ml/nn/driver/sample .

Per ulteriori informazioni sull'API Neural Networks, consulta API Neural Networks .

Reti neurali HAL

L'HAL delle reti neurali (NN) definisce un'astrazione dei vari dispositivi , come unità di elaborazione grafica (GPU) e processori di segnali digitali (DSP), che si trovano in un prodotto (ad esempio, un telefono o un tablet). I driver per questi dispositivi devono essere conformi a NN HAL. L'interfaccia è specificata nei file di definizione HAL in hardware/interfaces/neuralnetworks .

Il flusso generale dell'interfaccia tra il framework e un driver è illustrato nella Figura 1.

Flusso delle reti neurali

Figura 1. Flusso delle reti neurali

Inizializzazione

Al momento dell'inizializzazione, il framework interroga il driver per le sue capacità utilizzando IDevice::getCapabilities_1_3 . La struttura @1.3::Capabilities include tutti i tipi di dati e rappresenta prestazioni non rilassate utilizzando un vettore.

Per determinare come allocare i calcoli ai dispositivi disponibili, il framework utilizza le capacità per comprendere con quanta rapidità ed efficienza energetica ciascun driver può eseguire un'esecuzione. Per fornire queste informazioni, il conducente deve fornire numeri di prestazioni standardizzati basati sull'esecuzione dei carichi di lavoro di riferimento.

Per determinare i valori che il driver restituisce in risposta a IDevice::getCapabilities_1_3 , utilizza l'app benchmark NNAPI per misurare le prestazioni per i tipi di dati corrispondenti. I modelli MobileNet v1 e v2, asr_float e tts_float sono consigliati per misurare le prestazioni per valori in virgola mobile a 32 bit e i modelli quantizzati MobileNet v1 e v2 sono consigliati per valori quantizzati a 8 bit. Per ulteriori informazioni, consulta Suite di test di Android Machine Learning .

In Android 9 e versioni precedenti, la struttura Capabilities include informazioni sulle prestazioni del driver solo per tensori a virgola mobile e quantizzati e non include tipi di dati scalari.

Come parte del processo di inizializzazione, il framework può richiedere ulteriori informazioni, utilizzando IDevice::getType , IDevice::getVersionString , IDevice:getSupportedExtensions e IDevice::getNumberOfCacheFilesNeeded .

Tra i riavvii del prodotto, il framework prevede che tutte le query descritte in questa sezione riportino sempre gli stessi valori per un determinato driver. In caso contrario, un'app che utilizza quel driver potrebbe presentare prestazioni ridotte o comportamenti errati.

Compilazione

Il framework determina quali dispositivi utilizzare quando riceve una richiesta da un'app. In Android 10, le app possono rilevare e specificare i dispositivi da cui preleva il framework. Per ulteriori informazioni, consulta Rilevamento e assegnazione dei dispositivi .

Al momento della compilazione del modello, il framework invia il modello a ciascun driver candidato chiamando IDevice::getSupportedOperations_1_3 . Ogni driver restituisce un array di valori booleani che indicano quali operazioni del modello sono supportate. Un conducente può determinare che non può supportare una determinata operazione per una serie di motivi. Per esempio:

  • Il driver non supporta il tipo di dati.
  • Il driver supporta solo operazioni con parametri di input specifici. Ad esempio, un driver potrebbe supportare le operazioni di convoluzione 3x3 e 5x5, ma non 7x7.
  • Il driver ha vincoli di memoria che gli impediscono di gestire grafici o input di grandi dimensioni.

Durante la compilazione, gli operandi di input, output e interni del modello, come descritto in OperandLifeTime , possono avere dimensioni o rango sconosciuti. Per ulteriori informazioni, consulta Forma di output .

Il framework indica a ciascun driver selezionato di prepararsi a eseguire un sottoinsieme del modello chiamando IDevice::prepareModel_1_3 . Ciascun driver compila quindi il proprio sottoinsieme. Ad esempio, un conducente potrebbe generare codice o creare una copia riordinata dei pesi. Poiché può trascorrere una notevole quantità di tempo tra la compilazione del modello e l'esecuzione delle richieste, durante la compilazione non devono essere assegnate risorse come grandi porzioni di memoria del dispositivo.

In caso di successo, il driver restituisce un handle @1.3::IPreparedModel . Se il driver restituisce un codice di errore durante la preparazione del sottoinsieme del modello, il framework esegue l'intero modello sulla CPU.

Per ridurre il tempo utilizzato per la compilazione all'avvio di un'app, un driver può memorizzare nella cache gli artefatti di compilazione. Per ulteriori informazioni, vedere Caching della compilazione .

Esecuzione

Quando un'app chiede al framework di eseguire una richiesta, il framework chiama il metodo HAL IPreparedModel::executeSynchronously_1_3 per impostazione predefinita per eseguire un'esecuzione sincrona su un modello preparato. Una richiesta può anche essere eseguita in modo asincrono utilizzando il execute_1_3 , il executeFenced (vedere Esecuzione recintata ) o eseguita utilizzando un'esecuzione burst .

Le chiamate di esecuzione sincrone migliorano le prestazioni e riducono il sovraccarico del threading rispetto alle chiamate asincrone perché il controllo viene restituito al processo dell'app solo al termine dell'esecuzione. Ciò significa che il driver non necessita di un meccanismo separato per notificare al processo dell'app il completamento di un'esecuzione.

Con il execute_1_3 asincrono, il controllo ritorna al processo dell'app dopo l'avvio dell'esecuzione e il driver deve notificare al framework il completamento dell'esecuzione, utilizzando @1.3::IExecutionCallback .

Il parametro Request passato al metodo di esecuzione elenca gli operandi di input e output utilizzati per l'esecuzione. La memoria che memorizza i dati dell'operando deve utilizzare l'ordine principale delle righe con la prima dimensione che esegue l'iterazione più lenta e non deve avere riempimento alla fine di alcuna riga. Per ulteriori informazioni sui tipi di operandi, vedere Operandi .

Per i driver NN HAL 1.2 o versioni successive, quando una richiesta viene completata, lo stato dell'errore, la forma dell'output e le informazioni sulla tempistica vengono restituiti al framework. Durante l'esecuzione, gli operandi di output o interni del modello possono avere una o più dimensioni sconosciute o rango sconosciuto. Quando almeno un operando di output ha una dimensione o un rango sconosciuto, il driver deve restituire informazioni di output di dimensioni dinamiche.

Per i driver con NN HAL 1.1 o versione precedente, al completamento della richiesta viene restituito solo lo stato di errore. Le dimensioni per gli operandi di input e output devono essere specificate completamente affinché l'esecuzione venga completata correttamente. Gli operandi interni possono avere una o più dimensioni sconosciute, ma devono avere un rango specifico.

Per le richieste degli utenti che si estendono su più driver, il framework è responsabile della riservazione della memoria intermedia e della sequenziazione delle chiamate a ciascun driver.

È possibile avviare più richieste in parallelo sullo stesso @1.3::IPreparedModel . Il driver può eseguire richieste in parallelo o serializzare le esecuzioni.

Il quadro può chiedere a un conducente di conservare più di un modello preparato. Ad esempio, prepara il modello m1 , prepara m2 , esegui la richiesta r1 su m1 , esegui r2 su m2 , esegui r3 su m1 , esegui r4 su m2 , rilascia (descritto in Cleanup ) m1 e rilascia m2 .

Per evitare una prima esecuzione lenta che potrebbe comportare un'esperienza utente scadente (ad esempio, uno stuttering del primo frame), il driver dovrebbe eseguire la maggior parte delle inizializzazioni nella fase di compilazione. L'inizializzazione alla prima esecuzione dovrebbe essere limitata alle azioni che influiscono negativamente sulla salute del sistema se eseguite in anticipo, come riservare buffer temporanei di grandi dimensioni o aumentare la frequenza di clock di un dispositivo. I driver che possono preparare solo un numero limitato di modelli simultanei potrebbero dover eseguire l'inizializzazione alla prima esecuzione.

In Android 10 o versioni successive, nei casi in cui vengono eseguite più esecuzioni con lo stesso modello preparato in rapida successione, il client può scegliere di utilizzare un oggetto burst di esecuzione per comunicare tra i processi dell'app e del driver. Per ulteriori informazioni, consulta Esecuzioni burst e code di messaggi veloci .

Per migliorare le prestazioni per più esecuzioni in rapida successione, il driver può mantenere buffer temporanei o aumentare la frequenza di clock. Si consiglia di creare un thread di watchdog per rilasciare risorse se non vengono create nuove richieste dopo un periodo di tempo fisso.

Forma di uscita

Per le richieste in cui per uno o più operandi di output non sono specificate tutte le dimensioni, il driver deve fornire un elenco di forme di output contenenti le informazioni sulle dimensioni per ogni operando di output dopo l'esecuzione. Per ulteriori informazioni sulle dimensioni, vedere OutputShape .

Se un'esecuzione fallisce a causa di un buffer di output sottodimensionato, il driver deve indicare quali operandi di output hanno una dimensione del buffer insufficiente nell'elenco delle forme di output e deve riportare quante più informazioni dimensionali possibile, utilizzando zero per le dimensioni sconosciute.

Tempistica

In Android 10 un'app può richiedere il tempo di esecuzione se ha specificato un singolo dispositivo da utilizzare durante il processo di compilazione. Per i dettagli, consulta MeasureTiming e rilevamento e assegnazione del dispositivo . In questo caso, un driver NN HAL 1.2 deve misurare la durata dell'esecuzione o segnalare UINT64_MAX (per indicare che la durata non è disponibile) durante l'esecuzione di una richiesta. Il conducente dovrebbe ridurre al minimo qualsiasi penalizzazione delle prestazioni derivante dalla misurazione della durata dell'esecuzione.

Il conducente riporta nella struttura Timing le seguenti durate in microsecondi:

  • Tempo di esecuzione sul dispositivo: non include il tempo di esecuzione nel driver, che viene eseguito sul processore host.
  • Tempo di esecuzione nel driver: include il tempo di esecuzione sul dispositivo.

Queste durate devono includere il tempo in cui l'esecuzione viene sospesa, ad esempio, quando l'esecuzione è stata anticipata da altre attività o quando è in attesa che una risorsa diventi disponibile.

Quando al driver non è stato chiesto di misurare la durata dell'esecuzione o quando si verifica un errore di esecuzione, il driver deve segnalare le durate come UINT64_MAX . Anche quando al driver è stato chiesto di misurare la durata dell'esecuzione, può invece segnalare UINT64_MAX per il tempo sul dispositivo, il tempo nel driver o entrambi. Quando il driver segnala entrambe le durate come un valore diverso da UINT64_MAX , il tempo di esecuzione nel driver deve essere uguale o superiore al tempo sul dispositivo.

Esecuzione recintata

In Android 11, NNAPI consente alle esecuzioni di attendere un elenco di handle sync_fence e facoltativamente restituire un oggetto sync_fence , che viene segnalato al completamento dell'esecuzione. Ciò riduce il sovraccarico per i modelli di piccole sequenze e i casi d'uso dello streaming. L'esecuzione delimitata consente inoltre un'interoperabilità più efficiente con altri componenti che possono segnalare o attendere sync_fence . Per ulteriori informazioni su sync_fence , vedere Framework di sincronizzazione .

In un'esecuzione delimitata, il framework chiama il metodo IPreparedModel::executeFenced per avviare un'esecuzione asincrona delimitata su un modello preparato con un vettore di recinzioni di sincronizzazione da attendere. Se l'attività asincrona viene completata prima che la chiamata venga restituita, è possibile restituire un handle vuoto per sync_fence . È inoltre necessario restituire un oggetto IFencedExecutionCallback per consentire al framework di eseguire query sullo stato dell'errore e sulle informazioni sulla durata.

Al termine di un'esecuzione, è possibile eseguire query sui due valori temporali seguenti che misurano la durata dell'esecuzione tramite IFencedExecutionCallback::getExecutionInfo .

  • timingLaunched : durata dal momento in cui viene richiamato executeFenced al momento in cui executeFenced segnala il syncFence restituito.
  • timingFenced : durata da quando vengono segnalati tutti i limiti di sincronizzazione in attesa dell'esecuzione fino a executeFenced segnala il syncFence restituito.

Flusso di controllo

Per i dispositivi che eseguono Android 11 o versioni successive, la NNAPI include due operazioni del flusso di controllo, IF e WHILE , che accettano altri modelli come argomenti e li eseguono in modo condizionale ( IF ) o ripetutamente ( WHILE ). Per ulteriori informazioni su come implementarlo, vedere Flusso di controllo .

Qualità del servizio

In Android 11, la NNAPI include una migliore qualità del servizio (QoS) consentendo a un'app di indicare le priorità relative dei suoi modelli, il tempo massimo previsto per la preparazione di un modello e il tempo massimo previsto per un'esecuzione essere completato. Per ulteriori informazioni, vedere Qualità del servizio .

Ripulire

Quando un'app termina di utilizzare un modello preparato, il framework rilascia il riferimento all'oggetto @1.3::IPreparedModel . Quando non viene più fatto riferimento all'oggetto IPreparedModel , viene automaticamente distrutto nel servizio driver che lo ha creato. Le risorse specifiche del modello possono essere recuperate in questo momento nell'implementazione del distruttore da parte del driver. Se il servizio driver desidera che l'oggetto IPreparedModel venga distrutto automaticamente quando non è più necessario al client, non deve contenere alcun riferimento all'oggetto IPreparedModel dopo che l'oggetto IPreparedeModel è stato restituito tramite IPreparedModelCallback::notify_1_3 .

uso della CPU

Si prevede che i conducenti utilizzino la CPU per impostare i calcoli. I conducenti non dovrebbero utilizzare la CPU per eseguire calcoli sui grafici perché ciò interferisce con la capacità del framework di allocare correttamente il lavoro. Il conducente dovrebbe segnalare le parti che non è in grado di gestire al framework e lasciare che sia il framework a gestire il resto.

Il framework fornisce un'implementazione della CPU per tutte le operazioni NNAPI ad eccezione delle operazioni definite dal fornitore. Per ulteriori informazioni, vedere Estensioni del fornitore .

Le operazioni introdotte in Android 10 (livello API 29) hanno solo un'implementazione CPU di riferimento per verificare che i test CTS e VTS siano corretti. Le implementazioni ottimizzate incluse nei framework di machine learning mobile sono preferite rispetto all'implementazione della CPU NNAPI.

Funzioni di utilità

La codebase NNAPI include funzioni di utilità che possono essere utilizzate dai servizi driver.

Il file frameworks/ml/nn/common/include/Utils.h contiene funzioni di utilità assortite, come quelle utilizzate per la registrazione e per la conversione tra diverse versioni NN HAL.

  • VLogging: VLOG è una macro wrapper attorno LOG di Android che registra il messaggio solo se il tag appropriato è impostato nella proprietà debug.nn.vlog . initVLogMask() deve essere chiamato prima di qualsiasi chiamata a VLOG . La macro VLOG_IS_ON può essere utilizzata per verificare se VLOG è attualmente abilitato, consentendo di ignorare il codice di registrazione complicato se non è necessario. Il valore dell'immobile deve essere uno dei seguenti:

    • Una stringa vuota, che indica che non è necessario eseguire alcuna registrazione.
    • Il token 1 o all , che indica che tutta la registrazione deve essere eseguita.
    • Un elenco di tag, delimitati da spazi, virgole o due punti, che indicano quale registrazione deve essere eseguita. I tag sono compilation , cpuexe , driver , execution , manager e model .
  • compliantWithV1_* : Restituisce true se un oggetto HAL NN può essere convertito nello stesso tipo di una versione HAL diversa senza perdere informazioni. Ad esempio, la chiamata a compliantWithV1_0 su un V1_2::Model restituisce false se il modello include tipi di operazione introdotti in NN HAL 1.1 o NN HAL 1.2.

  • convertToV1_* : converte un oggetto NN HAL da una versione all'altra. Viene registrato un avviso se la conversione comporta una perdita di informazioni (ovvero se la nuova versione del tipo non può rappresentare completamente il valore).

  • Capabilities: le funzioni nonExtensionOperandPerformance e update possono essere utilizzate per creare il campo Capabilities::operandPerformance .

  • Interrogazione delle proprietà dei tipi: isExtensionOperandType , isExtensionOperationType , nonExtensionSizeOfData , nonExtensionOperandSizeOfData , nonExtensionOperandTypeIsScalar , tensorHasUnspecifiedDimensions .

Il file frameworks/ml/nn/common/include/ValidateHal.h contiene funzioni di utilità per verificare che un oggetto NN HAL sia valido in base alle specifiche della versione HAL.

  • validate* : restituisce true se l'oggetto NN HAL è valido secondo le specifiche della sua versione HAL. I tipi OEM e i tipi di estensione non vengono convalidati. Ad esempio, validateModel restituisce false se il modello contiene un'operazione che fa riferimento a un indice di operando che non esiste o un'operazione che non è supportata in quella versione dell'HAL.

Il file frameworks/ml/nn/common/include/Tracing.h contiene macro per semplificare l'aggiunta di informazioni di systracing al codice delle reti neurali. Per un esempio, vedere le chiamate di macro NNTRACE_* nel driver di esempio .

Il file frameworks/ml/nn/common/include/GraphDump.h contiene una funzione di utilità per eseguire il dump del contenuto di un Model in forma grafica per scopi di debug.

  • graphDump : scrive una rappresentazione del modello in formato Graphviz ( .dot ) nel flusso specificato (se fornito) o nel logcat (se non viene fornito alcun flusso).

Validazione

Per testare la tua implementazione della NNAPI, utilizza i test VTS e CTS inclusi nel framework Android. VTS esercita i tuoi driver direttamente (senza utilizzare il framework), mentre CTS li esercita indirettamente attraverso il framework. Questi testano ciascun metodo API e verificano che tutte le operazioni supportate dai driver funzionino correttamente e forniscano risultati che soddisfano i requisiti di precisione.

I requisiti di precisione in CTS e VTS per NNAPI sono i seguenti:

  • In virgola mobile: abs(previsto - effettivo) <= atol + rtol * abs(previsto); Dove:

    • Per fp32, atol = 1e-5f, rtol = 5.0f * 1.1920928955078125e-7
    • Per fp16, atol = rtol = 5.0f * 0.0009765625f
  • Quantizzato: off-by-one (ad eccezione di mobilenet_quantized , che è off-by-thre)

  • Booleano: corrispondenza esatta

Un modo in cui CTS testa la NNAPI è generare grafici pseudocasuali fissi utilizzati per testare e confrontare i risultati di esecuzione di ciascun driver con l'implementazione di riferimento NNAPI. Per i driver con NN HAL 1.2 o versione successiva, se i risultati non soddisfano i criteri di precisione, CTS segnala un errore e scarica un file di specifiche per il modello non riuscito in /data/local/tmp per il debug. Per ulteriori dettagli sui criteri di precisione, vedere TestRandomGraph.cpp e TestHarness.h .

Test fuzz

Lo scopo del fuzz test è individuare arresti anomali, asserzioni, violazioni della memoria o comportamenti generali indefiniti nel codice sottoposto a test a causa di fattori quali input imprevisti. Per i test fuzz NNAPI, Android utilizza test basati su libFuzzer , che sono efficienti nel fuzzing perché utilizzano la copertura della linea dei casi di test precedenti per generare nuovi input casuali. Ad esempio, libFuzzer favorisce i casi di test eseguiti su nuove righe di codice. Ciò riduce notevolmente la quantità di tempo necessaria ai test per trovare il codice problematico.

Per eseguire test fuzz per convalidare l'implementazione del driver, modificare frameworks/ml/nn/runtime/test/android_fuzzing/DriverFuzzTest.cpp nell'utilità di test libneuralnetworks_driver_fuzzer trovata in AOSP per includere il codice del driver. Per ulteriori informazioni sul test fuzz NNAPI, vedere frameworks/ml/nn/runtime/test/android_fuzzing/README.md .

Sicurezza

Poiché i processi dell'app comunicano direttamente con il processo di un conducente, i conducenti devono convalidare gli argomenti delle chiamate che ricevono. Questa convalida è verificata da VTS. Il codice di convalida è in frameworks/ml/nn/common/include/ValidateHal.h .

I conducenti dovrebbero inoltre garantire che le app non possano interferire con altre app quando utilizzano lo stesso dispositivo.

Suite di test per l'apprendimento automatico di Android

Android Machine Learning Test Suite (MLTS) è un benchmark NNAPI incluso in CTS e VTS per convalidare l'accuratezza dei modelli reali sui dispositivi dei fornitori. Il benchmark valuta la latenza e la precisione e confronta i risultati dei driver con i risultati utilizzando TF Lite in esecuzione sulla CPU, per lo stesso modello e set di dati. Ciò garantisce che la precisione di un driver non sia peggiore dell'implementazione di riferimento della CPU.

Gli sviluppatori della piattaforma Android utilizzano anche MLTS per valutare la latenza e l'accuratezza dei driver.

Il benchmark NNAPI può essere trovato in due progetti in AOSP:

Modelli e set di dati

Il benchmark NNAPI utilizza i seguenti modelli e set di dati.

  • MobileNetV1 float e u8 quantizzati in diverse dimensioni, eseguiti su un piccolo sottoinsieme (1500 immagini) di Open Images Dataset v4.
  • MobileNetV2 float e u8 quantizzati in diverse dimensioni, eseguiti su un piccolo sottoinsieme (1500 immagini) di Open Images Dataset v4.
  • Modello acustico basato sulla memoria a breve termine (LSTM) per la sintesi vocale, eseguito su un piccolo sottoinsieme del set artico CMU.
  • Modello acustico basato su LSTM per il riconoscimento vocale automatico, eseguito su un piccolo sottoinsieme del set di dati LibriSpeech.

Per ulteriori informazioni, consulta platform/test/mlts/models .

Prove di stress

La Android Machine Learning Test Suite include una serie di crash test per convalidare la resilienza dei conducenti in condizioni di utilizzo intenso o in casi limite del comportamento dei clienti.

Tutti i crash test forniscono le seguenti funzionalità:

  • Rilevamento del blocco: se il client NNAPI si blocca durante un test, il test fallisce con il motivo dell'errore HANG e la suite di test passa al test successivo.
  • Rilevamento arresto anomalo del client NNAPI: i test sopravvivono agli arresti anomali del client e i test falliscono con il motivo dell'errore CRASH .
  • Rilevamento arresto anomalo del driver: i test possono rilevare un arresto anomalo del driver che causa un errore su una chiamata NNAPI. Tieni presente che potrebbero verificarsi arresti anomali nei processi del driver che non causano un errore NNAPI e non causano il fallimento del test. Per coprire questo tipo di errore, si consiglia di eseguire il comando tail nel registro di sistema per errori o arresti anomali relativi al driver.
  • Targeting di tutti gli acceleratori disponibili: i test vengono eseguiti su tutti i driver disponibili.

Tutti i crash test hanno i seguenti quattro possibili risultati:

  • SUCCESS : Esecuzione completata senza errori.
  • FAILURE : esecuzione non riuscita. In genere causato da un errore durante il test di un modello, che indica che il driver non è riuscito a compilare o eseguire il modello.
  • HANG : il processo di test non ha risposto.
  • CRASH : il processo di test si è bloccato.

Per ulteriori informazioni sugli stress test e un elenco completo dei crash test, vedere platform/test/mlts/benchmark/README.txt .

Usa MLTS

Per utilizzare l'MLTS:

  1. Collega un dispositivo di destinazione alla tua workstation e assicurati che sia raggiungibile tramite adb . Esporta la variabile di ambiente ANDROID_SERIAL del dispositivo di destinazione se è connesso più di un dispositivo.
  2. cd nella directory dei sorgenti di primo livello di Android.

    source build/envsetup.sh
    lunch aosp_arm-userdebug # Or aosp_arm64-userdebug if available.
    ./test/mlts/benchmark/build_and_run_benchmark.sh
    

    Al termine di un'esecuzione del benchmark, i risultati vengono presentati come una pagina HTML e passati a xdg-open .

Per ulteriori informazioni, vedere platform/test/mlts/benchmark/README.txt .

Versioni HAL delle reti neurali

Questa sezione descrive le modifiche introdotte nelle versioni HAL per Android e reti neurali.

Androide 11

Android 11 introduce NN HAL 1.3, che include le seguenti modifiche notevoli.

  • Supporto per la quantizzazione con segno a 8 bit in NNAPI. Aggiunge il tipo di operando TENSOR_QUANT8_ASYMM_SIGNED . I driver con NN HAL 1.3 che supportano operazioni con quantizzazione senza segno devono supportare anche le varianti con segno di tali operazioni. Quando si eseguono versioni firmate e non firmate della maggior parte delle operazioni quantizzate, i driver devono produrre gli stessi risultati fino a un offset di 128. Esistono cinque eccezioni a questo requisito: CAST , HASHTABLE_LOOKUP , LSH_PROJECTION , PAD_V2 e QUANTIZED_16BIT_LSTM . L'operazione QUANTIZED_16BIT_LSTM non supporta gli operandi con segno e le altre quattro operazioni supportano la quantizzazione con segno ma non richiedono che i risultati siano gli stessi.
  • Supporto per esecuzioni delimitate in cui il framework chiama il metodo IPreparedModel::executeFenced per avviare un'esecuzione asincrona delimitata su un modello preparato con un vettore di recinzioni di sincronizzazione da attendere. Per ulteriori informazioni, vedere Esecuzione delimitata .
  • Supporto per il flusso di controllo. Aggiunge le operazioni IF e WHILE , che accettano altri modelli come argomenti e li eseguono in modo condizionale ( IF ) o ripetutamente ( WHILE ). Per ulteriori informazioni, consulta Flusso di controllo .
  • Qualità del servizio (QoS) migliorata poiché le app possono indicare le priorità relative dei suoi modelli, il tempo massimo previsto per la preparazione di un modello e il tempo massimo previsto per il completamento di un'esecuzione. Per ulteriori informazioni, vedere Qualità del servizio .
  • Supporto per domini di memoria che forniscono interfacce di allocazione per buffer gestiti dal driver. Ciò consente di trasferire le memorie native del dispositivo tra le esecuzioni, eliminando la copia e la trasformazione non necessaria dei dati tra esecuzioni consecutive sullo stesso driver. Per ulteriori informazioni, vedere Domini di memoria .

Androide 10

Android 10 introduce NN HAL 1.2, che include le seguenti modifiche notevoli.

  • La struttura Capabilities include tutti i tipi di dati, inclusi i tipi di dati scalari, e rappresenta prestazioni non rilassate utilizzando un vettore anziché campi denominati.
  • I metodi getVersionString e getType consentono al framework di recuperare informazioni sul tipo di dispositivo ( DeviceType ) e sulla versione. Vedere Individuazione e assegnazione dei dispositivi .
  • Il executeSynchronously viene chiamato per impostazione predefinita per eseguire un'esecuzione in modo sincrono. Il execute_1_2 indica al framework di eseguire un'esecuzione in modo asincrono. Vedi Esecuzione .
  • Il parametro MeasureTiming per executeSynchronously , execute_1_2 e l'esecuzione burst specifica se il driver deve misurare la durata dell'esecuzione. I risultati sono riportati nella struttura Timing . Vedi Tempistiche .
  • Supporto per esecuzioni in cui uno o più operandi di output hanno una dimensione o un rango sconosciuto. Vedere Forma di output .
  • Supporto per le estensioni del fornitore, che sono raccolte di operazioni e tipi di dati definiti dal fornitore. Il driver segnala le estensioni supportate tramite il metodo IDevice::getSupportedExtensions . Vedere Estensioni del fornitore .
  • Possibilità per un oggetto burst di controllare una serie di esecuzioni burst utilizzando code di messaggi veloci (FMQ) per comunicare tra i processi dell'app e del driver, riducendo la latenza. Vedere Esecuzioni burst e code di messaggi veloci .
  • Supporto per AHardwareBuffer per consentire al driver di eseguire esecuzioni senza copiare i dati. Vedere AHardwareBuffer .
  • Supporto migliorato per la memorizzazione nella cache degli artefatti di compilazione per ridurre il tempo utilizzato per la compilazione all'avvio di un'app. Vedere Memorizzazione nella cache della compilazione .

Android 10 introduce i seguenti tipi di operandi e operazioni.

  • Tipi di operandi

    • 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
  • Operazioni

    • 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 introduce aggiornamenti a molte delle operazioni esistenti. Gli aggiornamenti riguardano principalmente:

  • Supporto per il layout di memoria NCHW
  • Supporto per tensori con rango diverso da 4 nelle operazioni softmax e di normalizzazione
  • Supporto per convoluzioni dilatate
  • Supporto per input con quantizzazione mista in ANEURALNETWORKS_CONCATENATION

L'elenco seguente mostra le operazioni modificate in Android 10. Per i dettagli completi delle modifiche, consulta OperationCode nella documentazione di riferimento 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

Androide 9

NN HAL 1.1 viene introdotto in Android 9 e include le seguenti modifiche importanti.

  • IDevice::prepareModel_1_1 include un parametro ExecutionPreference . Un conducente può utilizzarlo per regolare la sua preparazione, sapendo che l'app preferisce risparmiare la batteria o eseguirà il modello in rapide chiamate successive.
  • Sono state aggiunte nove nuove operazioni: BATCH_TO_SPACE_ND , DIV , MEAN , PAD , SPACE_TO_BATCH_ND , SQUEEZE , STRIDED_SLICE , SUB , TRANSPOSE .
  • Un'app può specificare che i calcoli float a 32 bit possono essere eseguiti utilizzando l'intervallo float a 16 bit e/o la precisione impostando Model.relaxComputationFloat32toFloat16 su true . La struttura Capabilities ha il campo aggiuntivo relaxedFloat32toFloat16Performance in modo che il conducente possa segnalare le sue prestazioni rilassate al framework.

Android 8.1

Il primo Neural Networks HAL (1.0) è stato rilasciato in Android 8.1. Per ulteriori informazioni, vedere /neuralnetworks/1.0/ .