Driver dell'API Neural Networks

Questa pagina fornisce una panoramica su come implementare un driver 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 GPU (Graphics Processing Unit) e i processori di segnali digitali (DSP), presenti all'interno di 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 comprendere la velocità e l'efficienza energetica di ogni driver per 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 a 32 bit, mentre i modelli quantizzati MobileNet v1 e v2 sono consigliati per valori quantizzati a 8 bit. Per maggiori informazioni, consulta Test Suite di Android Machine Learning.

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 del processo di inizializzazione, il framework può eseguire query su 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.

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 da cui il framework sceglie. 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. Ecco alcuni esempi:

  • Il driver non supporta il tipo di dati.
  • Il driver supporta solo le 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 indica a ogni 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 gli artefatti di compilazione. Per ulteriori informazioni, consulta la sezione Compilation memorizzazione nella cache.

Attuazione

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 l'overhead del thread 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 Esecuzione elenca gli operandi di input e output utilizzati per l'esecuzione. La memoria in cui sono archiviati i dati degli operandi deve utilizzare l'ordine principale delle righe e la prima dimensione deve ripetere la dimensione più lenta e non avere spaziatura interna alla fine di ogni riga. Per ulteriori informazioni sui tipi di operandi, consulta la pagina Operandi.

Per i driver NN HAL 1.2 o successivi, quando una richiesta viene completata, al framework vengono restituiti lo stato di errore, la forma di output e le informazioni sulle tempistiche. 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 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 completamento della richiesta. Affinché l'esecuzione venga completata correttamente, le dimensioni degli operandi di input e output devono essere completamente specificate. 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 sulla stessa @1.3::IPreparedModel. Il driver può eseguire le richieste in parallelo o serializzare le esecuzioni.

Il framework può chiedere al conducente di tenere 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 un'esperienza utente scadente (ad esempio, lo stuttering del primo frame), il driver deve eseguire la maggior parte delle inizializzazioni nella fase di compilazione. L'inizializzazione alla prima esecuzione dovrebbe essere limitata ad azioni che incidono negativamente sull'integrità del sistema se eseguite in anticipo, come la prenotazione di buffer temporanei di grandi dimensioni o l'aumento della frequenza di clock di un dispositivo. I driver in grado di preparare solo un numero limitato di modelli simultanei potrebbero dover eseguire la propria 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ò mantenere i buffer temporanei o aumentare le frequenze di clock. Ti consigliamo di creare un thread di watchdog per rilasciare risorse se non vengono create nuove richieste dopo un periodo di tempo prestabilito.

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 riesce a causa di un buffer di output ridotto, il driver deve indicare quali operandi di output hanno dimensioni del buffer insufficienti nell'elenco di forme di output e deve riportare quante più informazioni dimensionali possibile, utilizzando zero per le dimensioni sconosciute.

Sincronizzazione

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 riporta le seguenti durate in microsecondi nella struttura di Timing:

  • 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 momento in cui l'esecuzione è sospesa, ad esempio quando è 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 se si verifica un errore di esecuzione, 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 conducente indica entrambe le durate come un valore diverso da UINT64_MAX, il tempo di esecuzione nel driver deve essere uguale o superiore a quello sul dispositivo.

Esecuzione protetta

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. Questo riduce l'overhead per i modelli di piccole sequenze e i casi d'uso relativi ai flussi di dati. L'esecuzione vincolata 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 protetta, 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. Se l'attività asincrona viene completata prima della chiamata, è possibile restituire un handle vuoto per sync_fence. È necessario restituire anche un oggetto IFencedExecutionCallback per consentire al framework di eseguire query sulle informazioni relative allo stato e alla durata degli errori.

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 executeFenced viene chiamato al momento 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, la NNAPI include due operazioni del flusso di controllo, IF e WHILE, che prendono altri modelli come argomenti e li eseguono in modo condizionale (IF) o ripetutamente (WHILE). Per maggiori informazioni su come eseguire questa operazione, 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 maggiori 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 dovrebbero utilizzare la CPU per eseguire calcoli grafici perché questo 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 maggiori informazioni, consulta la pagina relativa alle 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 preferibili 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 relativa a LOG di Android che registra il messaggio solo se è impostato il tag appropriato nella proprietà debug.nn.vlog. initVLogMask() deve essere chiamato prima di qualsiasi chiamata al numero VLOG. La macro VLOG_IS_ON può essere utilizzata per verificare se VLOG è attualmente abilitato, consentendo di saltare il codice di logging 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 a compliantWithV1_0 su un V1_2::Model restituisce false se il modello include tipi di operazioni introdotti in NN HAL 1.1 o NN HAL 1.2.

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

  • Funzionalità: le funzioni nonExtensionOperandPerformance e update possono essere utilizzate per 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 convalidare la validità di un oggetto NN HAL in base alla specifica della versione HAL.

  • validate*: restituisce true se l'oggetto NN HAL è valido secondo le specifiche della 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 eseguire il dump dei contenuti di un elemento Model in forma grafica a scopo 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).

Convalida

Per testare l'implementazione di NNAPI, utilizza i test VTS e CTS inclusi nel framework Android. VTS esercita i conducenti direttamente (senza utilizzare il framework), mentre CTS li esercita indirettamente attraverso 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:

  • Valore con virgola mobile: AB(previsto - effettivo) <= atol + rtol * AB(previsto); 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 NNAPI. Per i conducenti con NN HAL 1.2 o versioni successive, se i risultati non soddisfano i criteri di precisione, CTS segnala un errore ed esegue il dump di un file di specifica per il modello in errore in /data/local/tmp per il debug. Per ulteriori dettagli sui criteri di precisione, consulta TestRandomGraph.cpp e TestHarness.h.

Test fuzz

Lo scopo dei test fuzz è trovare arresti anomali, asserzioni, violazioni della memoria o comportamenti generici non definiti nel codice sottoposto a test a causa di fattori come input imprevisti. Per i test di fuzz NNAPI, Android utilizza test basati su libFuzzer, che sono efficienti nel fuzzing perché utilizzano la copertura a linee 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 i risultati utilizzando TF Lite in esecuzione sulla CPU, per lo stesso modello e gli stessi set di dati. Ciò garantisce che la precisione di un driver non sia peggiore dell'implementazione del riferimento della CPU.

Gli sviluppatori di piattaforme Android utilizzano anche 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.

  • I dati MobileNetV1 sono in virgola mobile e u8 quantizzati in dimensioni diverse ed eseguono un piccolo sottoinsieme (1500 immagini) del set di dati Open Images v4.
  • MobileNetV2 è in virgola mobile e u8 quantificato in dimensioni diverse ed eseguito su un piccolo sottoinsieme (1500 immagini) del set di dati Open Images v4.
  • Modello acustico basato su LSTM (Long Short-Term Memory). Per la sintesi vocale, viene eseguito su un piccolo sottoinsieme dell'Artico CMU.
  • Modello acustico basato su LSTM per il riconoscimento vocale automatico, eseguito su un piccolo sottoinsieme del set di dati LibriSpeech.

Per maggiori informazioni, vedi platform/test/mlts/models.

Test di stress

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 offrono le seguenti funzionalità:

  • Rilevamento dei blocchi: se il client NNAPI si blocca durante un test, quest'ultimo non va a buon fine e 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 la mancata riuscita 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 arresto anomalo hanno i seguenti quattro risultati possibili:

  • SUCCESS: esecuzione completata senza un errore.
  • 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 risponde.
  • CRASH: arresto anomalo del processo di test.

Per ulteriori informazioni sui test di stress e per un elenco completo dei test di arresti anomali, vedi platform/test/mlts/benchmark/README.txt.

Utilizzo di MLTS

Per utilizzare MLTS:

  1. Connetti un dispositivo di destinazione alla workstation e assicurati che sia raggiungibile tramite adb. Esporta la variabile di ambiente del dispositivo di destinazione ANDROID_SERIAL se è connesso più di un dispositivo.
  2. cd nella directory di origine di primo livello 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 maggiori informazioni, vedi platform/test/mlts/benchmark/README.txt.

Versioni HAL per le 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 le operazioni con quantizzazione non firmata devono supportare anche le relative varianti con firma. 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 firmati e le altre quattro operazioni supportano la quantizzazione firmata, ma non richiedono che i risultati siano gli stessi.
  • 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 e li eseguono in modo condizionale (IF) o ripetutamente (WHILE). Per saperne di più, 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 la sezione Qualità del servizio.
  • Supporto per i domini di memoria che forniscono interfacce allocator per i buffer gestiti dal driver. Ciò consente di passare le memorie native dei dispositivi tra le esecuzioni, eliminando la copia e la trasformazione non necessarie dei dati tra esecuzioni consecutive sullo stesso driver. Per maggiori informazioni, vedi Domini di memoria.

Android 10

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

  • Lo struct Capabilities include tutti i tipi di dati, inclusi i tipi di dati scalari, e rappresenta le prestazioni non rallentate utilizzando un vettore anziché un campo con nome.
  • 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 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.
  • Possibilità di un oggetto burst di controllare un insieme di esecuzioni di burst tramite code di messaggi rapide (FMQ) per comunicare tra app e processi 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 Compilazione nella cache.

Android 10 introduce i seguenti tipi di operandi e operazioni.

  • Tipi di operando

    • 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 legati a quanto segue:

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

L'elenco che segue 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 importanti.

  • IDevice::prepareModel_1_1 include un parametro ExecutionPreference. Un conducente può usare questa funzionalità per regolare la sua preparazione, sapendo che l'app preferisce risparmiare 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 è possibile eseguire i calcoli in virgola mobile a 32 bit utilizzando l'intervallo in virgola mobile a 16 bit e/o la precisione impostando Model.relaxComputationFloat32toFloat16 su true. Lo struct Capabilities ha il campo aggiuntivo relaxedFloat32toFloat16Performance, che consente al driver di segnalare le prestazioni rilassate al framework.

Android 8.1

L'HAL iniziale per reti neurali (1.0) è stato rilasciato in Android 8.1. Per scoprire di più, visita la pagina /neuralnetworks/1.0/.