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 nei file di definizione HAL in hardware/interfaces/neuralnetworks. Un'implementazione di driver di esempio è disponibile in frameworks/ml/nn/driver/sample.

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

HAL reti neurali

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 all'HAL NN. L'interfaccia è specificata nei file di definizione HAL in hardware/interfaces/neuralnetworks.

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

Flusso delle reti neurali

Figura 1. Flusso delle reti neurali

Inizializzazione

All'inizializzazione, il framework esegue una query sul driver per conoscere le sue funzionalità utilizzando IDevice::getCapabilities_1_3. La struttura @1.3::Capabilities include tutti i tipi di dati e rappresenta il rendimento non rilassato 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 driver deve fornire numeri di prestazioni standardizzati in base all'esecuzione dei carichi di lavoro di riferimento.

Per determinare i valori restituiti dal driver in risposta a IDevice::getCapabilities_1_3, utilizza l'app di benchmark NNAPI per misurare il funzionamento per i tipi di dati corrispondenti. I modelli MobileNet v1 e v2, asr_float e tts_float sono consigliati per la misurazione delle 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 sul rendimento del driver solo per i tensori quantizzati e a virgola mobile e non include i tipi di dati scalari.

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 si aspetta 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 lo invia a ogni candidato driver chiamando IDevice::getSupportedOperations_1_3. Ogni driver restituisce un array di valori booleani che indicano quali operazioni del modello sono supportate. Un driver può stabilire di non supportare una determinata operazione per diversi 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 3 x 3 e 5 x 5, ma non le operazioni di convolvezione 7 x 7.
  • Il driver ha limitazioni di memoria che gli impediscono di gestire input o grafici 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 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 un tempo considerevole tra la compilazione del modello e l'esecuzione delle richieste, le risorse come grandi blocchi di memoria del dispositivo non devono essere assegnate durante la compilazione.

In caso di esito positivo, 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 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ò essere eseguita anche in modo asincrono utilizzando il metodo execute_1_3, il metodo executeFenced (vedi Esecuzione con barriere) o utilizzando un'esecuzione a raffica.

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 driver 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 notificare al framework il completamento 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 dell'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 dell'output ha una dimensione o un ranking sconosciuto, il driver deve restituire informazioni sull'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 ranking specificato.

Per le richieste degli utenti che interessano più driver, il framework è responsabile della prenotazione della memoria intermedia e dell'ordinamento 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 rilascia 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, nei casi in cui più esecutioni con lo stesso modello preparato vengono eseguite in rapida successione, il client può scegliere di utilizzare un oggetto esplosione di esecuzione per comunicare tra i processi dell'app e del driver. Per ulteriori informazioni, consulta la sezione Esecuzioni in batch 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 rilasciare 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 specificate tutte le dimensioni, il driver deve fornire un elenco di forme di output contenenti le informazioni sulle dimensioni per ciascun operando di output dopo l'esecuzione. Per ulteriori informazioni 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 ha specificato un singolo dispositivo da utilizzare durante il processo di compilazione. Per maggiori dettagli, consulta 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 eventuali penalizzazioni delle prestazioni derivanti dalla misurazione della durata dell'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 se 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 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 termine 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 attenderesync_fence. Per ulteriori 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 seguenti due valori di tempi 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: durata dal momento in cui vengono segnalati tutti i recinti di sincronizzazione che l'esecuzione attende a quando executeFenced segnala il 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, NNAPI include una qualità del servizio (QoS) migliorata 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 maggiori informazioni, consulta la pagina Qualità del servizio.

Pulizia

Quando un'app ha terminato di utilizzare un modello preparato, il framework rilascia il suo riferimento all'oggetto @1.3::IPreparedModel. Quando non viene più fatto riferimento all'oggetto IPreparedModel, viene distrutto automaticamente nel servizio del driver che lo ha creato. Al momento, le risorse specifiche del modello possono essere recuperate nell'implementazione del distruttore da parte del driver. Se il servizio del driver vuole che l'oggetto IPreparedModel venga distrutto automaticamente quando non è più necessario per il cliente, non deve contenere riferimenti all'oggetto IPreparedModel dopo che l'oggetto IPreparedeModel è stato restituito tramite IPreparedModelCallback::notify_1_3.

Utilizzo CPU

I driver dovrebbero 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 driver deve segnalare al framework le parti che non può gestire 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 solo un'implementazione della 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 all'implementazione della CPU NNAPI.

Funzioni di utilità

La base di codice NNAPI include funzioni di utilità che possono essere utilizzate dai servizi del driver.

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

  • 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 deve essere eseguito tutto il logging.
    • Un elenco di tag delimitati da spazi, virgole o due punti, che indica quali dati devono essere registrati. I tag sono compilation, cpuexe, driver, execution, manager e model.
  • compliantWithV1_*: restituisce true se un oggetto HAL NN può essere convertito allo stesso tipo di una versione HAL diversa senza perdita di 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.

  • Eseguire query sulle proprietà di tipi: isExtensionOperandType, isExtensionOperationType, nonExtensionSizeOfData, nonExtensionOperandSizeOfData, nonExtensionOperandTypeIsScalar, tensorHasUnspecifiedDimensions.

Il file frameworks/ml/nn/common/include/ValidateHal.h contiene funzioni di utilità per convalidare la validità di un oggetto HAL NN in base alla specifica della relativa versione HAL.

  • validate*: restituisce true se l'oggetto HAL NN è valido secondo la specifica della relativa versione HAL. I tipi di OEM e di estensioni non sono 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 non supportata dalla versione HAL in questione.

Il frameworks/ml/nn/common/include/Tracing.h file contiene macro per semplificare l'aggiunta di informazioni su systracing al codice delle reti neurali. Per un esempio, consulta le chiamate alle 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. Questi test esaminano ogni metodo dell'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(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
  • Quantizzato: errore di 1 (tranne per mobilenet_quantized, che ha un errore di 3)

  • 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 indefiniti 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 preferisce i casi di test che vengono eseguiti su nuove righe di codice. In questo modo si riduce notevolmente il tempo necessario per trovare il codice problematico.

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

Sicurezza

Poiché i processi delle app comunicano direttamente con il processo di un driver, i driver 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.

Android Machine Learning Test Suite

La 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. In questo modo, la precisione di un driver non è peggiore dell'implementazione di 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.
  • MobileNetV2 quantizzato in formato float e u8 in dimensioni diverse, eseguito su un piccolo sottoinsieme (1500 immagini) del set di dati Open Images Dataset 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

Android Machine Learning Test Suite include una serie di crash test per verificare la resilienza dei driver in condizioni di utilizzo intenso o in casi estremi di 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 degli arresti anomali del client NNAPI: i test superano gli arresti anomali del client e i test non superano il motivo di 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 coprire questo tipo di errore, ti consigliamo di eseguire il comando tail nel log di sistema per rilevare 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: l'esecuzione è stata completata senza errori.
  • 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 il 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 di un'esecuzione del 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 HAL di Android e Neural Networks.

Android 11

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

  • Supporto della quantizzazione a 8 bit con segno in NNAPI. Aggiunge il TENSOR_QUANT8_ASYMM_SIGNED tipo di operando. I driver con NN HAL 1.3 che supportano operazioni con quantizzazione non firmate devono supportare anche le varianti firmate di queste operazioni. Quando esegui versioni con firma 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 isolate in cui il framework chiama il metodo IPreparedModel::executeFenced per avviare un'esecuzione asincrona e con barriere su un modello preparato con un vettore di barriere di sincronizzazione da attendere. Per ulteriori informazioni, consulta la sezione Esecuzione con recinzione.
  • 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.
  • Miglioramento della qualità del servizio (QoS) in quanto le app possono indicare le priorità relative dei 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 le 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 significative.

  • La struttura Capabilities include tutti i tipi di dati, inclusi i tipi di dati scalari, e rappresenta le prestazioni non rilassate utilizzando un vettore anziché campi denominati.
  • I metodi getVersionString e getType consentono al framework di recuperare il tipo di dispositivo (DeviceType) e le informazioni 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 e l'esecuzione in burst specifica se il driver deve misurare la durata dell'esecuzione. I risultati vengono riportati nella struttura Timing. Consulta la sezione Tempistiche.
  • Supporto per le esecuzioni in cui uno o più operandi di output hanno una dimensione o un ranking sconosciuti. Vedi Forma dell'output.
  • Supporto per le estensioni del fornitore, ovvero raccolte di operazioni e tipi di dati definiti dal fornitore. Il driver segnala le estensioni supportate tramite il metodo IDevice::getSupportedExtensions. Consulta 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 in batch e code di messaggi rapide.
  • Supporto di AHardwareBuffer per consentire al driver di eseguire le esecuzioni senza copiare i dati. Consulta AHardwareBuffer.
  • Supporto migliorato per la memorizzazione nella cache degli elementi di compilazione per ridurre il tempo impiegato per la compilazione all'avvio di un'app. Consulta 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 sono principalmente correlati a quanto segue:

  • Supporto per il layout della memoria NCHW
  • Supporto per i tensori con rango diverso da 4 nelle operazioni di softmax e di normalizzazione
  • Supporto per le convoluzioni dilatate
  • Supporto per gli 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 è stato 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. La struct Capabilities ha il campo aggiuntivo relaxedFloat32toFloat16Performance in modo che il driver possa segnalare al framework il suo rendimento rilassato.

Android 8.1

La versione iniziale dell'HAL Neural Networks (1.0) è stata rilasciata in Android 8.1. Per ulteriori informazioni, consulta /neuralnetworks/1.0/.