Driver dell'API Neural Networks

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

Per ulteriori informazioni sull'API Neural Networks, consulta la pagina relativa all'API Neural Networks.

Reti neurali HAL

L'HAL per le reti neurali (NN) definisce un'astrazione dei vari dispositivi, come le unità di elaborazione grafica (GPU) e gli elaboratori di segnale digitale (DSP), presenti in un prodotto (ad esempio uno smartphone o un tablet). I driver di questi dispositivi devono essere conformi alla 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 esegue query sul driver per verificare le sue funzionalità utilizzando IDevice::getCapabilities_1_3. La struttura @1.3::Capabilities include tutti i tipi di dati e rappresenta le prestazioni non rallentate utilizzando un vettore.

Per determinare come allocare i calcoli ai dispositivi disponibili, il framework utilizza le funzionalità per capire quanto velocemente e con quanta efficienza energetica ciascun driver può eseguire un'esecuzione. Per fornire queste informazioni, il conducente deve fornire valori standardizzati per le prestazioni in base all'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 di 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 di 32 bit, mentre i modelli quantizzati MobileNet v1 e v2 sono consigliati per valori quantizzati di 8 bit. Per ulteriori informazioni, consulta Android Machine Learning Test Suite.

In Android 9 e versioni precedenti, la struttura Capabilities include informazioni sulle prestazioni dei driver solo per i tensori quantizzati e in virgola mobile e non include i tipi di dati più scalabili.

Nell'ambito della procedura di inizializzazione, il framework potrebbe 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 il driver potrebbe mostrare prestazioni ridotte o un comportamento errato.

Compilation

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

Al momento della compilazione del modello, il framework invia il modello a ogni driver candidato chiamando IDevice::getSupportedOperations_1_3. Ogni driver restituisce un array di valori booleani che indicano le operazioni del modello supportate. Un conducente può stabilire di non poter supportare una determinata operazione per vari motivi. Ad 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 3 x 3 e 5 x 5, ma non 7 x 7.
  • Il driver ha vincoli di memoria che gli impediscono di gestire grafici o input di grandi dimensioni.

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

Il framework chiede a ciascun driver selezionato di prepararsi a eseguire un sottoinsieme del modello chiamando IDevice::prepareModel_1_3. Ogni driver compila quindi il proprio sottoinsieme. Ad esempio, un driver potrebbe generare codice o creare una copia riordinata dei pesi. Poiché può trascorrere una quantità di tempo significativa tra la compilazione del modello e l'esecuzione delle richieste, non è consigliabile assegnare risorse come grandi blocchi di memoria del dispositivo durante la compilazione.

Se l'operazione riesce, il conducente 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 elementi di compilazione. Per ulteriori informazioni, consulta la sezione Memorizzazione nella cache della compilazione.

Esecuzione

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

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

Con il metodo execute_1_3 asincrono, il controllo torna al processo dell'app dopo l'avvio dell'esecuzione e il driver deve inviare una notifica al framework al termine dell'esecuzione, utilizzando @1.3::IExecutionCallback.

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

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

Per i driver con NN HAL 1.1 o versioni precedenti, viene restituito solo lo stato di errore al termine di una richiesta. Le dimensioni per gli operandi di input e output devono essere completamente specificate per il completamento dell'esecuzione. Gli operandi interni possono avere una o più dimensioni sconosciute, ma devono avere un rango specificato.

Per le richieste degli utenti che interessano più driver, il framework è responsabile della prenotazione della memoria intermedia e della sequenza delle chiamate a ciascun driver.

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

Il framework può chiedere a un driver di mantenere 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 Pulizia) m1 e release m2.

Per evitare una prima esecuzione lenta che potrebbe comportare una scarsa esperienza utente (ad esempio, un primo frame a scatti), il driver deve eseguire la maggior parte delle inizializzazioni nella fase di compilazione. L'inizializzazione alla prima esecuzione deve essere limitata alle azioni che influiscono negativamente sulla salute del sistema se eseguite in anticipo, ad esempio la prenotazione di buffer temporanei di grandi dimensioni o l'aumento della 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, qualora vengano eseguite in rapida successione più esecuzioni con lo stesso modello preparato, 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 la sezione Esecuzioni a raffica e code di messaggi rapide.

Per migliorare le prestazioni per più esecuzioni in rapida successione, il driver può trattenere buffer temporanei o aumentare le frequenze di clock. È consigliabile creare un thread di monitoraggio per liberare le risorse se non vengono create nuove richieste dopo un determinato periodo di tempo.

Forma di output

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

Se un'esecuzione non va a buon fine a causa di un buffer di output di dimensioni insufficienti, il driver deve indicare quali operandi di output hanno dimensioni del buffer insufficienti nell'elenco delle forme di output e deve segnalare quante più informazioni dimensionali possibili, utilizzando zero per le dimensioni sconosciute.

Tempi

In Android 10, un'app può chiedere il tempo di esecuzione se l'app ha specificato un singolo dispositivo da utilizzare durante il processo di compilazione. Per maggiori dettagli, vedi MeasureTiming e Rilevamento e assegnazione dei dispositivi. 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 driver deve ridurre al minimo l'eventuale perdita di prestazioni derivante dalla misurazione della durata di esecuzione.

Il driver registra le seguenti durate in microsecondi nella struttura Timing:

  • Tempo di esecuzione sul dispositivo: non è incluso 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 momento in cui l'esecuzione è sospesa, ad esempio quando l'esecuzione è stata prerilasciata 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 conducente è stato chiesto di misurare la durata dell'esecuzione, può invece registrare UINT64_MAX per il tempo sul dispositivo, il tempo del conducente o entrambi. Quando il driver riporta 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 con recinzione

In Android 11, NNAPI consente alle esecuzioni di attendere un elenco di handle sync_fence e, facoltativamente, di restituire un oggetto sync_fence, che viene segnalato al completamento dell'esecuzione. In questo modo si riduce l'overhead per i modelli di piccole sequenze e i casi d'uso in streaming. L'esecuzione con recinzione consente inoltre un'interoperabilità più efficiente con altri componenti che possono segnalare o attendere sync_fence. Per maggiori informazioni su sync_fence, consulta Framework di sincronizzazione.

In un'esecuzione con barriere, il framework chiama il metodo IPreparedModel::executeFenced per avviare un'esecuzione asincrona con barriere su un modello preparato con un vettore di barriere di sincronizzazione da attendere. Se l'attività asincrona è stata completata prima del ritorno della chiamata, è possibile restituire un handle vuoto per sync_fence. Deve essere restituito anche un oggetto IFencedExecutionCallback per consentire al framework di eseguire query sulle informazioni relative allo stato e alla durata dell'errore.

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

  • timingLaunched: durata dal momento in cui viene chiamato executeFenced a quello in cui executeFenced indica il valore syncFence restituito.
  • timingFenced: la durata compresa tra il momento in cui tutti i limiti di sincronizzazione attendi dall'esecuzione vengono segnalati e il momento in cui executeFenced segnala il valore di syncFence restituito.

Flusso di controllo

Per i dispositivi con Android 11 o versioni successive, NNAPI include due operazioni di flusso di controllo, IF e WHILE, che prendono altri modelli come argomenti ed eseguono in modo condizionale (IF) o ripetuto (WHILE). Per maggiori informazioni su come implementare questa funzionalità, consulta Flusso di controllo.

Qualità del servizio

In Android 11, la NNAPI offre 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 il completamento di un'esecuzione. Per ulteriori informazioni, consulta la pagina Qualità del servizio.

Pulizia

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, questo viene eliminato automaticamente nel servizio driver che lo ha creato. Le risorse specifiche del modello possono essere recuperate in questo momento nell'implementazione del driver del distruttore. Se il servizio driver vuole che l'oggetto IPreparedModel venga eliminato automaticamente quando non è più necessario dal client, non deve contenere nessun riferimento all'oggetto IPreparedModel dopo che l'oggetto IPreparedeModel è stato restituito tramite IPreparedModelCallback::notify_1_3.

Utilizzo CPU

I driver devono utilizzare la CPU per configurare i calcoli. I driver non devono usare la CPU per eseguire calcoli grafici perché ciò interferisce con la capacità del framework di allocare correttamente il lavoro. Il conducente deve 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 di quelle definite dal fornitore. Per ulteriori informazioni, consulta la sezione Estensioni del fornitore.

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

Funzioni di utilità

Il codebase NNAPI include funzioni di utilità che possono essere utilizzate dai servizi di conducenti.

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

  • Vlogging: VLOG è una macro wrapper per 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 impiegata per verificare se VLOG è attualmente attivata, consentendo di saltare il codice di registrazione complicato se non è necessario. Il valore della proprietà deve essere uno dei seguenti:

    • Una stringa vuota, che indica che non deve essere eseguito alcun logging.
    • Il token 1 o all, che indica che tutti i log devono essere eseguiti.
    • Un elenco di tag, delimitati da spazi, virgole o due punti, che indicano il logging da eseguire. 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 di compliantWithV1_0 su un V1_2::Model restituisce false se il modello include i tipi di operazioni introdotti in NN HAL 1.1 o NN HAL 1.2.

  • convertToV1_*: converte un oggetto HAL NN 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).

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

  • Proprietà di query 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 HAL NN sia valido secondo la specifica della relativa versione HAL.

  • validate*: restituisce true se l'oggetto HAL NN è valido secondo la specifica della relativa versione HAL. I tipi di estensione e i tipi di OEM non vengono convalidati. Ad esempio, validateModel restituisce false se il modello contiene un'operazione che fa riferimento a un indice degli operandi che non esiste o un'operazione 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. Ad esempio, vedi le chiamate della macro NNTRACE_* nel driver di esempio.

Il file frameworks/ml/nn/common/include/GraphDump.h contiene una funzione di utilità per scaricare i contenuti di un Model in formato grafico per scopi di debug.

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

Convalida

Per testare l'implementazione di 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 tramite il framework. Testano ogni metodo API e verificano che tutte le operazioni supportate dai conducenti 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(expected - actual) <= atol + rtol  * abs(expected); dove:

    • Per fp32, atol = 1e-5f, rtol = 5.0f * 1.1920928955078125e-7
    • Per fp16, atol = rtol = 5.0f * 0.0009765625f
  • Quantizzata: di sconto di uno (tranne per mobilenet_quantized, che è disattivato per tre)

  • Booleano: corrispondenza esatta

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

Test di fuzzing

Lo scopo del test di fuzz è trovare arresti anomali, asserzioni, violazioni della memoria o comportamenti non definiti generali nel codice in test a causa di fattori come input imprevisti. Per i test di fuzzing NNAPI, Android utilizza test basati su libFuzzer, che sono efficienti per il fuzzing perché utilizzano la copertura delle righe degli scenari di test precedenti per generare nuovi input casuali. Ad esempio, libFuzzer favorisce gli scenari di test che vengono eseguiti su nuove righe di codice. In questo modo si riduce notevolmente il tempo necessario ai test per trovare il codice problematico.

Per eseguire fuzz test al fine di convalidare l'implementazione del driver, modifica frameworks/ml/nn/runtime/test/android_fuzzing/DriverFuzzTest.cpp nell'utilità di test libneuralnetworks_driver_fuzzer trovata in AOSP in modo da includere il codice del driver. Per maggiori informazioni sui test di fuzz NNAPI, consulta frameworks/ml/nn/runtime/test/android_fuzzing/README.md.

Sicurezza

Poiché i processi delle app comunicano direttamente con quelli del conducente, i conducenti devono convalidare gli argomenti delle chiamate che ricevono. Questa convalida viene verificata da VTS. Il codice di convalida si trova in frameworks/ml/nn/common/include/ValidateHal.h.

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

Test Suite di Android Machine Learning

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 l'accuratezza e confronta i risultati dei driver con quelli ottenuti utilizzando TF Lite in esecuzione sulla CPU per lo stesso modello e gli stessi set di dati. Ciò garantisce che l'accuratezza di un driver non sia peggiore dell'implementazione del riferimento della CPU.

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

Il benchmark NNAPI è disponibile in due progetti in AOSP:

Modelli e set di dati

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

  • MobileNetV1 quantizzato in formato float e u8 in dimensioni diverse, eseguito su un piccolo sottoinsieme (1500 immagini) del set di dati Open Images Dataset v4.
  • I dati MobileNetV2 sono in virgola mobile e u8 quantizzati in dimensioni diverse ed eseguono un piccolo sottoinsieme (1500 immagini) del set di dati Open Images v4.
  • Modello acustico basato su memoria a lungo termine (LSTM) per la sintesi vocale, eseguito su un piccolo sottoinsieme dell'insieme CMU Arctic.
  • 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.

Stress test

La Test Suite di Android Machine Learning include una serie di test di arresto anomalo per confermare la resilienza dei driver in condizioni di utilizzo gravose o nei casi secondari del comportamento dei clienti.

Tutti i test di arresto anomalo forniscono le seguenti funzionalità:

  • Rilevamento di blocchi: se il client NNAPI si blocca durante un test, il test non va a buon fine con il motivo dell'errore HANG e la suite di test passa al test successivo.
  • Rilevamento di arresti anomali del client NNAPI: i test superano gli arresti anomali del client e i test non hanno esito positivo per il motivo dell'errore CRASH.
  • Rilevamento di arresti anomali del driver: i test possono rilevare un arresto anomalo del driver che causa un errore in una chiamata NNAPI. Tieni presente che potrebbero verificarsi arresti anomali nei processi del driver che non causano un errore NNAPI e non causano l'interruzione del test. Per risolvere questo tipo di errore, ti consigliamo di eseguire il comando tail nel log 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 test di collisione hanno i seguenti quattro possibili risultati:

  • SUCCESS: esecuzione completata senza un errore.
  • FAILURE: esecuzione non riuscita. In genere è causato da un errore durante il test di un modello e indica che il driver non è riuscito a compilare o eseguire il modello.
  • HANG: il processo di test non risponde.
  • CRASH: il processo di test ha avuto un arresto anomalo.

Per ulteriori informazioni sui test di stress e un elenco completo dei test di arresto anomalo, consulta platform/test/mlts/benchmark/README.txt.

Utilizza MTLS

Per utilizzare MLTS:

  1. Collega un dispositivo di destinazione alla tua workstation e assicurati che sia accessibile tramite adb. Esporta la variabile di ambiente ANDROID_SERIAL del dispositivo di destinazione se è collegato più di un dispositivo.
  2. cd nella directory di origine 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 dell'esecuzione di un benchmark, i risultati vengono presentati come pagina HTML e trasmessi a xdg-open.

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

Versioni HAL delle reti neurali

Questa sezione descrive le modifiche introdotte nelle versioni Android e Neural Reti HAL.

Android 11

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

  • Supporto per la quantizzazione firmata 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 non firmata devono supportare anche le varianti firmate di queste operazioni. Quando eseguono versioni con e senza firma 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 uguali.
  • Supporto per le esecuzioni protette in cui il framework chiama il metodo IPreparedModel::executeFenced per avviare un'esecuzione asincrona e protetta su un modello preparato con un vettore di restrizioni di sincronizzazione da attendere. Per maggiori informazioni, consulta Esecuzione vincolata.
  • Supporto per il flusso di controllo. Aggiunge le operazioni IF e WHILE, che prendono altri modelli come argomenti ed eseguono in modo condizionale (IF) o ripetuto (WHILE). Per ulteriori informazioni, consulta Flusso di controllo.
  • Il miglioramento della qualità del servizio (QoS) in quanto le app possono indicare le priorità relative dei relativi 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, consulta Qualità del servizio.
  • Supporto per i domini di memoria che forniscono interfacce di allocazione per i buffer gestiti dal driver. Ciò consente di passare le memorie native del dispositivo tra le esecuzioni, eliminando la copia e la trasformazione non necessarie dei dati tra esecuzioni consecutive sullo stesso driver. Per ulteriori informazioni, consulta Domini di memoria.

Android 10

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

  • La struttura Capabilities include tutti i tipi di dati, inclusi quelli scalari, e rappresenta le prestazioni non rilassate utilizzando un vettore anziché campi denominati.
  • I metodi getVersionString e getType consentono al framework di recuperare le informazioni sul tipo di dispositivo (DeviceType) e sulla versione. Consulta Rilevamento e assegnazione dei dispositivi.
  • Il metodo executeSynchronously viene chiamato per impostazione predefinita per eseguire un'esecuzione in modo sincrono. Il metodo execute_1_2 indica al framework di eseguire un'esecuzione in modo asincrono. Vedi Esecuzione.
  • Il parametro MeasureTiming per executeSynchronously, execute_1_2 ed esecuzione burst specifica se il driver deve misurare la durata di esecuzione. I risultati sono riportati nella struttura Timing. Consulta la sezione Tempi.
  • Supporto per le esecuzioni in cui uno o più operandi di output hanno una dimensione o un ranking sconosciuti. Vedi Forma di output.
  • Supporto per le estensioni del fornitore, ovvero raccolte di operazioni e tipi di dati definiti dal fornitore. Il conducente segnala le estensioni supportate con il metodo IDevice::getSupportedExtensions. Vedi Estensioni del fornitore.
  • La possibilità per un oggetto burst di controllare un insieme di esecuzioni burst utilizzando code di messaggi rapide (FMQ) per comunicare tra i processi dell'app e del driver, riducendo la latenza. Consulta Esecuzioni raffica e code di messaggi rapide.
  • Supporto per AHardwareBuffer per consentire al driver di eseguire esecuzioni senza copiare i dati. Vedi AHardwareBuffer.
  • Supporto migliorato per la memorizzazione nella cache degli artefatti di compilazione al fine di ridurre il tempo utilizzato per la compilazione all'avvio di un'app. Vedi 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 per molte operazioni esistenti. Gli aggiornamenti sono principalmente correlati a quanto segue:

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

L'elenco seguente mostra le operazioni modificate in Android 10. Per tutti i dettagli delle modifiche, consulta OperationCode nella documentazione di riferimento di 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 viene introdotto in Android 9 e include le seguenti modifiche significative.

  • IDevice::prepareModel_1_1 include un parametro ExecutionPreference. Un conducente può utilizzarlo per modificare la propria preparazione, sapendo che l'app preferisce risparmiare la batteria o eseguirà il modello in chiamate successive rapide.
  • 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 con numeri in virgola mobile a 32 bit possono essere eseguiti utilizzando l'intervallo e/o la precisione dei numeri in virgola mobile a 16 bit impostando Model.relaxComputationFloat32toFloat16 su true. Lo struct Capabilities ha il campo aggiuntivo relaxedFloat32toFloat16Performance, che consente al driver di segnalare le sue prestazioni rilassate al framework.

Android 8.1

L'HAL iniziale di reti neurali (1.0) è stato rilasciato in Android 8.1. Per ulteriori informazioni, consulta /neuralnetworks/1.0/.