Sterowniki interfejsu Neural Networks API

Ta strona zawiera omówienie implementacji sterownika interfejsu Neural Networks API (NNAPI). Więcej informacji znajdziesz w dokumentacji w plikach definicji HAL dostępnych w folderze hardware/interfaces/neuralnetworks. Przykładowa implementacja sterownika znajduje się w pliku frameworks/ml/nn/driver/sample.

Więcej informacji o interfejsie Neural Networks API znajdziesz w artykule Interfejs Neural Networks API.

Neural Networks HAL

Interfejs HAL dla sieci neuronowych (NN) definiuje abstrakcję różnych urządzeń, takich jak jednostki przetwarzania graficznego (GPU) i procesory sygnałowe (DSP), które są częścią produktu (np. telefonu lub tabletu). Sterowniki tych urządzeń muszą być zgodne z interfejsem NN HAL. Interfejs jest określony w plikach definicji HAL w hardware/interfaces/neuralnetworks.

Ogólny przepływ danych między interfejsem a sterownikami przedstawia rysunek 1.

Sieci neuronowe

Rysunek 1. Sieci neuronowe

Inicjowanie

Podczas inicjowania platforma wysyła zapytanie do sterownika o jego możliwości za pomocą funkcji IDevice::getCapabilities_1_3. Struktura @1.3::Capabilities obejmuje wszystkie typy danych i reprezentuje wydajność bez relaksacji za pomocą wektora.

Aby określić, jak przydzielić obliczenia do dostępnych urządzeń, framework korzysta z możliwości, aby określić, jak szybko i energooszczędnie każdy sterownik może wykonać dane zadanie. Aby podać te informacje, producent sterownika musi podać ujednolicone dane o wydajności na podstawie wykonania referencyjnych obciążeń.

Aby określić wartości zwracane przez sterownik w odpowiedzi na IDevice::getCapabilities_1_3, użyj aplikacji NNAPI do pomiaru wydajności dla odpowiednich typów danych. Modele MobileNet v1 i v2, asr_float oraz tts_float są zalecane do pomiaru wydajności w przypadku 32-bitowych wartości zmiennoprzecinkowych, a modele zaokrąglone MobileNet v1 i v2 – do pomiaru wydajności w przypadku 8-bitowych wartości zaokrąglonych. Więcej informacji znajdziesz w kompletacie testów uczenia maszynowego na Androida.

W Androidzie 9 i starszych struktura Capabilities zawiera informacje o wydajności sterownika tylko w przypadku tensorów zmiennoprzecinkowych i kwantowanych, a nie typów danych skalarnych.

W ramach procesu inicjowania framework może wysyłać więcej zapytań o informacje, używając do tego celu funkcji IDevice::getType, IDevice::getVersionString, IDevice:getSupportedExtensionsIDevice::getNumberOfCacheFilesNeeded.

Pomiędzy ponownymi uruchamianiem aplikacji framework oczekuje, że wszystkie zapytania opisane w tym rozdziale zawsze będą zwracać te same wartości dla danego sterownika. W przeciwnym razie aplikacja korzystająca z tego sterownika może działać wolniej lub nieprawidłowo.

Kompilacja

Gdy framework otrzyma żądanie od aplikacji, określa, których urządzeń użyć. W Androidzie 10 aplikacje mogą wykrywać i określać urządzenia, których framework ma używać. Więcej informacji znajdziesz w artykule Wykrywanie i przypisywanie urządzeń.

Podczas kompilowania modelu framework wysyła go do każdego kandydata na kierowcę, wywołując funkcję IDevice::getSupportedOperations_1_3. Każdy z nich zwraca tablicę wartości logicznych wskazujących, które operacje modelu są obsługiwane. Sterownik może stwierdzić, że nie może wykonać danej operacji z różnych powodów. Przykład:

  • Sterownik nie obsługuje tego typu danych.
  • Sterownik obsługuje tylko operacje z określonymi parametrami wejściowymi. Na przykład sterownik może obsługiwać operacje konwolucji 3 × 3 i 5 × 5, ale nie 7 × 7.
  • Sterownik ma ograniczenia pamięci, które uniemożliwiają obsługę dużych wykresów lub danych wejściowych.

Podczas kompilacji dane wejściowe, dane wyjściowe i operandy wewnętrzne modelu (jak opisano w OperandLifeTime) mogą mieć nieznane wymiary lub rangę. Więcej informacji znajdziesz w artykule Format wyjściowy.

Platforma instruuje każdy wybrany moduł sterujący, aby przygotował się do wykonania podzbioru modelu, wywołując funkcję IDevice::prepareModel_1_3. Każdy sterownik kompiluje swój podzbiór. Na przykład kierowca może wygenerować kod lub utworzyć kopię wag o zmienionej kolejności. Ponieważ między kompilacją modelu a wykonywaniem żądań może upłynąć sporo czasu, podczas kompilacji nie należy przydzielać zasobów takich jak duże fragmenty pamięci urządzenia.

W przypadku powodzenia sterownik zwraca @1.3::IPreparedModel uchwyt. Jeśli sterownik zwróci kod błędu podczas przygotowywania podzbioru modelu, framework uruchomi cały model na procesorze CPU.

Aby skrócić czas kompilacji podczas uruchamiania aplikacji, sterownik może przechowywać w pamięci podręcznej artefakty kompilacji. Więcej informacji znajdziesz w artykule Pamięć podręczna kompilacji.

Realizacja

Gdy aplikacja prosi platformę o wykonanie żądania, platforma domyślnie wywołuje metodę IPreparedModel::executeSynchronously_1_3 HAL, aby wykonać działanie synchroniczne na przygotowanym modelu. Żądanie może też być wykonywane asynchronicznie za pomocą metody execute_1_3 lub executeFenced (patrz wyodrębnianie zasobów) albo za pomocą wykonania w trybie burst.

Wywołania synchronicznego wykonania poprawiają wydajność i zmniejszają obciążenie wątku w porównaniu z wywołaniami asynchronicznymi, ponieważ kontrola jest przekazywana procesowi aplikacji dopiero po zakończeniu wykonania. Oznacza to, że sterownik nie potrzebuje osobnego mechanizmu, aby powiadomić proces aplikacji o zakończeniu wykonywania.

W przypadku asynchronicznej metody execute_1_3 kontrola wraca do procesu aplikacji po rozpoczęciu wykonania, a sterownik musi powiadomić framework o zakończeniu wykonania za pomocą funkcji @1.3::IExecutionCallback.

Parametr Request przekazany metodzie execute zawiera listę operandów wejściowych i wyjściowych użytych do wykonania. Pamięć, w której przechowywane są dane operandu, musi używać kolejności wiersza, w której pierwszy wymiar jest iterowany najwolniej, i nie może mieć wypełnień na końcu żadnego wiersza. Więcej informacji o typach operandów znajdziesz w artykule Operandy.

W przypadku sterowników NN HAL 1.2 lub nowszych po zakończeniu przetwarzania żądania do frameworka zwracane są stan błędu, kształt danych wyjściowychinformacje o czasie wykonania. Podczas wykonywania dane wyjściowe lub operandy wewnętrzne modelu mogą mieć co najmniej 1 nieznaną wymianę lub nieznaną rangę. Jeśli co najmniej 1 element wyjściowy ma nieznany wymiar lub nieznaną rangę, moduł musi zwrócić informacje o wyjściu o dynamicznej wielkości.

W przypadku sterowników z NN HAL 1.1 lub niższym po zakończeniu żądania zwracany jest tylko stan błędu. Aby wykonanie mogło się powieść, wymiary operandów wejściowych i wyjściowych muszą być w pełni określone. Operandy wewnętrzne mogą mieć co najmniej 1 nieznaną wymiar, ale muszą mieć określoną rangę.

W przypadku żądań użytkownika, które obejmują wiele sterowników, framework odpowiada za rezerwowanie pamięci pośredniej i porządkowanie wywołań poszczególnych sterowników.

Na tym samym koncie można równolegle inicjować wiele żądań.@1.3::IPreparedModel Sterownik może wykonywać żądania równolegle lub sekwencyjnie.

Platforma może poprosić kierowcę o zatrzymanie więcej niż 1 przygotowanego modelu. Na przykład: przygotuj model m1, przygotuj m2, wykonaj żądanie r1 w przypadku m1, wykonaj r2 w przypadku m2, wykonaj r3 w przypadku m1, wykonaj r4 w przypadku m2, opublikuj (jak opisano w sekcji Usuwanie) m1 i opublikuj m2.

Aby uniknąć powolnego pierwszego wykonania, które może pogorszyć komfort użytkownika (np. powodować zacinanie się pierwszego klatka), sterownik powinien przeprowadzić większość inicjalizacji na etapie kompilacji. Inicjalizowanie podczas pierwszego uruchomienia powinno być ograniczone do działań, które negatywnie wpływają na stan systemu, gdy są wykonywane wcześnie, takich jak rezerwowanie dużych tymczasowych buforów lub zwiększanie częstotliwości zegara urządzenia. Sterowniki, które mogą przygotowywać tylko ograniczoną liczbę równoczesnych modeli, mogą wymagać inicjalizacji podczas pierwszego uruchomienia.

W Androidzie 10 lub nowszym, gdy wiele wykonań z tą samą przygotowaną wcześniej wersją modelu jest wykonywanych szybko po sobie, klient może użyć obiektu wykonania burst, aby umożliwić komunikację między procesami aplikacji a sterownika. Więcej informacji znajdziesz w artykule Burzliwe wykonywanie zadań i kolejki szybkich wiadomości.

Aby poprawić wydajność podczas wielokrotnego wykonywania kodu w krótkich odstępach czasu, sterownik może przechowywać tymczasowe bufory lub zwiększać częstotliwość zegara. Zalecamy utworzenie wątku nadzorczego, aby zwolnić zasoby, jeśli po określonym czasie nie zostaną utworzone żadne nowe żądania.

Kształt wyjściowy

W przypadku żądań, w których co najmniej 1 operand wyjściowy nie ma wszystkich wymiarów, sterownik musi podać listę kształtów wyjściowych zawierającą informacje o wymiarach dla każdego operanda wyjściowego po wykonaniu. Więcej informacji o wymiarach znajdziesz w artykule OutputShape.

Jeśli wykonanie nie powiedzie się z powodu zbyt małego rozmiaru bufora wyjściowego, sterownik musi wskazać na liście kształtów wyjściowych, które operandy wyjściowe mają niewystarczający rozmiar bufora, oraz przekazać jak najwięcej informacji o wymiarach, używając zera w przypadku wymiarów o nieznanych wartościach.

Czas

W Androidzie 10 aplikacja może poprosić o czas wykonania, jeśli w trakcie kompilacji korzysta z jednego urządzenia. Więcej informacji znajdziesz w artykule MeasureTimingWykrywanie i przypisywanie urządzeń. W takim przypadku sterownik NN HAL 1.2 musi mierzyć czas wykonania lub zgłaszać wartość UINT64_MAX (aby wskazać, że czas nie jest dostępny) podczas wykonywania żądania. Sterownik powinien zminimalizować wszelkie straty wydajności wynikające z mierzenia czasu trwania wykonania.

Sterownik podaje te czasy trwania w mikrosekundach w strukturze Timing:

  • Czas wykonywania na urządzeniu: nie obejmuje czasu wykonywania w sterowniku, który działa na procesorze hosta.
  • Czas wykonywania w sterowniku: obejmuje czas wykonywania na urządzeniu.

Czasy te muszą obejmować czas zawieszenia wykonania, na przykład gdy zostało ono wywłaszczone przez inne zadania lub gdy oczekuje na dostępność zasobu.

Jeśli sterownik nie został poproszony o zmierzenie czasu wykonania lub wystąpił błąd wykonania, sterownik musi podać czas jako UINT64_MAX. Nawet jeśli sterownik został poproszony o zmierzenie czasu wykonania, może zamiast tego podać wartość UINT64_MAX dla czasu na urządzeniu, czasu w sterowniku lub obu tych wartości. Jeśli czasy działania zgłaszane przez sterownik są wartościami innymi niż UINT64_MAX, czas wykonania w sterowniku musi być równy lub dłuższy niż czas na urządzeniu.

Wykonywanie w ogrodzie

W Androidzie 11 interfejs NNAPI umożliwia oczekiwanie na listę uchwytów sync_fence i opcjonalnie zwracanie obiektu sync_fence, który jest sygnalizowany po zakończeniu wykonania. Dzięki temu zmniejsza się obciążenie w przypadku małych modeli sekwencji i przypadków użycia strumieniowego przesyłania danych. Wykonywanie w ogrodzie umożliwia też bardziej wydajne współdziałanie z innymi komponentami, które mogą wysyłać sygnały lub oczekiwać na sync_fence. Więcej informacji o sync_fence znajdziesz w artykule Framework synchronizacji.

W ramach wykonania w ogrodzie framework wywołuje metodę IPreparedModel::executeFenced, aby uruchomić ogrodzenie, asynchroniczne wykonanie przygotowanego modelu z wektorem ogrodzeń synchronizacji, na które ma czekać. Jeśli zadanie asynchroniczne zostanie ukończone przed zakończeniem wywołania, sync_fence może zwrócić pusty identyfikator. Aby umożliwić frameworkowi wysyłanie zapytań o stan i czas trwania błędu, musisz też zwrócić obiekt IFencedExecutionCallback.

Po zakończeniu wykonania można zapytać o te 2 wartości czasu, które mierzą czas wykonania: IFencedExecutionCallback::getExecutionInfo.

  • timingLaunched: Czas od wywołania funkcji executeFenced do momentu, gdy funkcja executeFenced sygnalizuje zwróconą wartość syncFence.
  • timingFenced: czas od momentu, gdy wszystkie sygnały synchronizacji, na które oczekuje wykonanie, są sygnalizowane, do momentu, gdy executeFenced sygnalizuje zwrócony syncFence.

Kontrola przepływu

W przypadku urządzeń z Androidem 11 lub nowszym NNAPI zawiera 2 operacje sterowania przepływem danych, IFWHILE, które przyjmują inne modele jako argumenty i wykonują je warunkowo (IF) lub wielokrotnie (WHILE). Więcej informacji o tym, jak to zaimplementować, znajdziesz w artykule Przepływ sterowania.

Jakość usługi

W Androidzie 11 interfejs NNAPI zapewnia wyższą jakość usług (QoS), umożliwiając aplikacji wskazywanie względnych priorytetów modeli, maksymalnego czasu oczekiwania na przygotowanie modelu i maksymalnego czasu oczekiwania na zakończenie wykonania. Więcej informacji znajdziesz w artykule na temat jakości usług.

Uporządkuj

Gdy aplikacja skończy korzystać z przygotowanego modelu, framework zwolni odwołanie do obiektu @1.3::IPreparedModel. Gdy obiekt IPreparedModel nie jest już używany, jest automatycznie usuwany w usłudze kierowcy, która go utworzyła. Zasoby związane z poszczególnymi modelami można obecnie odzyskać w implementacji destruktora sterownika. Jeśli usługa kierowcy wymaga automatycznego usunięcia obiektu IPreparedModel, gdy nie jest już potrzebny klientowi, nie może on zawierać żadnych odwołań do obiektu IPreparedModel po zwróceniu obiektu IPreparedeModel za pomocą interfejsu IPreparedModelCallback::notify_1_3.

Wykorzystanie procesora

Sterowniki powinny używać procesora do konfigurowania obliczeń. Sterowniki nie powinny używać procesora do wykonywania obliczeń grafu, ponieważ zakłóca to możliwość prawidłowego przydzielenia pracy przez framework. Sterownik powinien przekazać do frameworku te części, których nie może obsłużyć, a framework powinien obsłużyć pozostałe.

Framework zapewnia implementację na procesorze dla wszystkich operacji NNAPI z wyjątkiem operacji zdefiniowanych przez dostawcę. Więcej informacji znajdziesz w artykule Rozszerzenia dostawców.

Operacje wprowadzone w Androidzie 10 (poziom interfejsu API 29) mają tylko referencyjną implementację procesora, aby umożliwić weryfikację poprawności testów CTS i VTS. Zoptymalizowane implementacje zawarte w ramkach uczenia maszynowego na urządzeniach mobilnych są preferowane w porównaniu z implementacją NNAPI na procesorze.

Funkcje użyteczności

Kod źródłowy NNAPI zawiera funkcje pomocnicze, których mogą używać usługi kierowcy.

Plik frameworks/ml/nn/common/include/Utils.h zawiera różne funkcje pomocnicze, takie jak te używane do rejestrowania i konwertowania między różnymi wersjami HAL sieci neuronowej.

  • VLogging: VLOG to makro opakowujące makro LOG w Androidzie, które rejestruje wiadomość tylko wtedy, gdy w właściwości debug.nn.vlog ustawiony jest odpowiedni tag. initVLogMask()musi być wywoływana przed każdym wywołaniem funkcji VLOG. Makra VLOG_IS_ON można użyć do sprawdzenia, czy makro VLOG jest obecnie włączone. Dzięki temu można pominąć skomplikowany kod rejestrowania, jeśli nie jest on potrzebny. Wartość właściwości musi być jedną z tych wartości:

    • Pusty ciąg, który wskazuje, że nie ma potrzeby rejestrowania.
    • Token 1 lub all, który wskazuje, że wszystkie logi mają zostać utworzone.
    • Lista tagów rozdzielona spacjami, przecinkami lub dwukropkami, wskazująca, jakie żądania mają być rejestrowane. Tagi to compilation, cpuexe, driver, execution, manager i model.
  • compliantWithV1_*: zwraca true, jeśli obiekt NN HAL można przekonwertować do tego samego typu w innej wersji HAL bez utraty informacji. Na przykład wywołanie funkcji compliantWithV1_0 w obiekcie V1_2::Model zwraca wartość false, jeśli model zawiera typy operacji wprowadzone w NN HAL 1.1 lub NN HAL 1.2.

  • convertToV1_*: konwertuje obiekt NN HAL z jednej wersji na inną. Jeśli konwersja powoduje utratę informacji (czyli jeśli nowa wersja typu nie może w pełni odzwierciedlać wartości), rejestrowane jest ostrzeżenie.

  • Możliwości: do tworzenia pola Capabilities::operandPerformance możesz używać funkcji nonExtensionOperandPerformance i update.

  • W zapytaniu można używać właściwości o typach: isExtensionOperandType, isExtensionOperationType, nonExtensionSizeOfData, nonExtensionOperandSizeOfData, nonExtensionOperandTypeIsScalar, tensorHasUnspecifiedDimensions.

Plik frameworks/ml/nn/common/include/ValidateHal.h zawiera funkcje pomocnicze do sprawdzania, czy obiekt NN HAL jest prawidłowy zgodnie ze specyfikacją wersji HAL.

  • validate*: zwraca true, jeśli obiekt NN HAL jest prawidłowy zgodnie ze specyfikacją wersji HAL. Typy OEM i typy rozszerzeń nie są weryfikowane. Na przykład validateModel zwraca false, jeśli model zawiera operację, która odwołuje się do indeksu operandu, który nie istnieje, lub do operacji, która nie jest obsługiwana w danej wersji HAL.

Plik frameworks/ml/nn/common/include/Tracing.h zawiera makro, które ułatwia dodawanie informacji systracing do kodu sieci neuronowych. Przykładowo NNTRACE_* wywołania makra w przykładowym sterowniku.

Plik frameworks/ml/nn/common/include/GraphDump.h zawiera funkcję pomocniczą, która umożliwia zapisywanie treści funkcji Model w postaci graficznej na potrzeby debugowania.

  • graphDump: zapisuje reprezentację modelu w formacie Graphviz (.dot) w wybranym strumieniu (jeśli został podany) lub w logcat (jeśli nie został podany żaden strumień).

Weryfikacja

Aby przetestować implementację interfejsu NNAPI, użyj testów VTS i CTS dostępnych w ramach Androida. VTS testuje sterowniki bezpośrednio (bez używania frameworku), a CTS testuje je pośrednio za pomocą frameworku. Testują one każdą metodę interfejsu API i sprawdzają, czy wszystkie operacje obsługiwane przez sterowniki działają prawidłowo i zapewniają wyniki zgodne z wymaganiami dotyczącymi dokładności.

Wymagania dotyczące dokładności w CTS i VTS w przypadku NNAPI:

  • Liczba zmiennoprzecinkowa: abs(expected - actual) <= atol + rtol  * abs(expected); gdzie:

    • W przypadku fp32 atol = 1e-5f, rtol = 5.0f * 1.1920928955078125e-7
    • W przypadku fp16: atol = rtol = 5.0f * 0.0009765625f
  • Zakwantowana: przesunięcie o 1 (z wyjątkiem mobilenet_quantized, która jest przesunięta o 3).

  • Wartość logiczna: dopasowanie ścisłe

Jednym ze sposobów testowania NNAPI przez CTS jest generowanie stałych, pseudolosowych grafów, które służą do testowania i porównywania wyników wykonania każdego sterownika z implementacją referencyjną NNAPI. Jeśli sterowniki z NN HAL 1.2 lub nowszym nie spełniają kryteriów dokładności, CTS zgłasza błąd i wypisuje plik specyfikacji nieudanego modelu w folderze /data/local/tmp na potrzeby debugowania. Więcej informacji o kryteriach dokładności znajdziesz w artykułach TestRandomGraph.cppTestHarness.h.

Testowanie niejednoznaczności

Celem testowania fuzz jest znajdowanie awarii, stwierdzeń, naruszeń pamięci lub ogólnie nieokreślonego zachowania w testowanym kodzie z powodu czynników takich jak nieoczekiwane dane wejściowe. W przypadku testów fuzzingu NNAPI Android używa testów opartych na libFuzzer, które są skuteczne, ponieważ do generowania nowych losowych danych wejściowych używają pokrycia linii poprzednich przypadków testowych. Na przykład libFuzzer preferuje przypadki testowe, które działają na nowych liniach kodu. Dzięki temu testy znacznie szybciej znajdą problematyczny kod.

Aby przeprowadzić testowanie fuzz w celu sprawdzenia implementacji sterownika, zmodyfikuj zmienną frameworks/ml/nn/runtime/test/android_fuzzing/DriverFuzzTest.cpp w narzędziu testowym libneuralnetworks_driver_fuzzer w AOSP, aby uwzględnić kod sterownika. Więcej informacji o testowaniu z generowaniem przypadków testowych NNAPI znajdziesz w artykule frameworks/ml/nn/runtime/test/android_fuzzing/README.md.

Bezpieczeństwo

Procesy aplikacji komunikują się bezpośrednio z procesem kierowcy, dlatego kierowcy muszą weryfikować argumenty wywołań, które otrzymują. Ta weryfikacja jest przeprowadzana przez VTS. Kod weryfikacyjny znajduje się w frameworks/ml/nn/common/include/ValidateHal.h.

Kierowcy powinni też zadbać o to, aby aplikacje nie zakłócały działania innych aplikacji na tym samym urządzeniu.

(pakiet) Android Machine Learning Test Suite

Zbiór testów uczenia maszynowego na Androida (MLTS) to test porównawczy NNAPI zawarty w CTS i VTS, który służy do sprawdzania dokładności rzeczywistych modeli na urządzeniach dostawców. Test porównuje opóźnienie i dokładność, a także wyniki uzyskane przez sterowniki z wynikami uzyskanymi przez TF Lite działające na procesorze CPU w przypadku tego samego modelu i tych samych zbiorów danych. Dzięki temu dokładność sterownika nie jest gorsza niż w implementacji referencyjnej dla procesora.

Programiści platformy Android korzystają z MLTS do oceny opóźnień i dokładności sterowników.

Benchmark NNAPI można znaleźć w 2 projektach w AOSP:

Modele i zbiory danych

Test porównawczy NNAPI korzysta z tych modeli i zbiorów danych.

  • MobileNetV1 z użyciem kodowania stałopółtonowego i u8 w różnych rozmiarach, uruchomione na małej podzbiorze (1500 obrazów) zbioru Open Images Dataset w wersji 4.
  • MobileNetV2 z użyciem kodowania stałopółkowego i u8 w różnych rozmiarach, uruchomione na małej podzbiorze (1500 obrazów) zbioru Open Images Dataset w wersji 4.
  • Model akustyczny oparty na długotrwałej pamięci krótkotrwałej (LSTM) do konwersji tekstu na mowę, uruchomiony na małej podzbiorze zbioru CMU Arctic.
  • Model akustyczny oparty na LSTM do automatycznego rozpoznawania mowy, uruchomiony na niewielkim podzbiorze zbioru danych LibriSpeech.

Więcej informacji znajdziesz w sekcji platform/test/mlts/models.

Testy obciążeniowe

Pakiet testów uczenia maszynowego na Androidzie obejmuje serię testów odporności na awarie, które mają na celu weryfikację odporności sterowników w warunkach intensywnego użytkowania lub w przypadkach szczególnego zachowania klientów.

Wszystkie testy kolizji zapewniają te funkcje:

  • Wykrywanie zawieszania się: jeśli klient NNAPI zawiesi się podczas testu, test zakończy się niepowodzeniem z powodem HANG, a pakiet testów przejdzie do następnego testu.
  • Wykrywanie awarii klienta NNAPI: testy przetrwają awarie klienta i testy kończą się niepowodzeniem z powodem CRASH.
  • Wykrywanie awarii sterownika: testy mogą wykrywać awarie sterownika, która powoduje błąd wywołania NNAPI. Pamiętaj, że w procesach sterownika mogą wystąpić awarie, które nie powodują błędu NNAPI ani niepowodzenia testu. Aby uwzględnić tego typu awarię, zalecamy uruchomienie polecenia tailw dzienniku systemowym w przypadku błędów lub awarii związanych z sterownikami.
  • Kierowanie na wszystkie dostępne akceleratory: testy są przeprowadzane na wszystkich dostępnych czynnikach.

Wszystkie testy kolizji mogą mieć 4 możliwe wyniki:

  • SUCCESS: wykonanie zostało zakończone bez błędów.
  • FAILURE: nie udało się wykonać. Zwykle jest to spowodowane niepowodzeniem podczas testowania modelu i wskazuje, że skompilowanie lub wykonanie modelu nie powiodło się.
  • HANG: proces testowania przestał odpowiadać.
  • CRASH: proces testowania uległ awarii.

Więcej informacji o testach obciążeniowych i pełną listę testów awarii znajdziesz w artykule platform/test/mlts/benchmark/README.txt.

Używanie MTLS

Aby korzystać z MLTS:

  1. Podłącz urządzenie docelowe do stacji roboczej i upewnij się, że jest ono dostępne przez adb. Wyeksportuj zmienną środowiskową ANDROID_SERIALurządzenia docelowego, jeśli jest połączonych więcej niż jedno urządzenie.
  2. cd do najwyższego katalogu źródłowego Androida.

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

    Po zakończeniu testu porównawczego wyniki są prezentowane jako strona HTML i przekazywane do xdg-open.

Więcej informacji znajdziesz w sekcji platform/test/mlts/benchmark/README.txt.

Wersje HAL sieci neuronowych

W tej sekcji opisano zmiany wprowadzone w wersjach HAL Androida i Neural Networks.

Android 11

Android 11 wprowadza interfejs NN HAL 1.3, który zawiera te ważne zmiany:

  • Obsługa zaokrągleń 8-bitowych z znakami w NNAPI. DodajeTENSOR_QUANT8_ASYMM_SIGNEDtyp operandu. Sterowniki z NN HAL 1.3, które obsługują operacje z niezakodowanym zagęszczaniem, muszą też obsługiwać ich zaszyfrowane warianty. Podczas wykonywania wersji z podpisem i bez podpisu większości operacji kwantowanych sterowniki muszą dawać takie same wyniki z dokładnością do przesunięcia o 128. Od tego wymagania jest 5 wyjątków: CAST, HASHTABLE_LOOKUP, LSH_PROJECTION, PAD_V2 i QUANTIZED_16BIT_LSTM. Operacja QUANTIZED_16BIT_LSTM nie obsługuje zaokrągleń z zaokrągleniem na plus, a cztery pozostałe operacje obsługują zaokrąglenie z zaokrągleniem na plus, ale nie wymagają, aby wyniki były takie same.
  • Obsługa odizolowanych wykonań, w których framework wywołuje metodę IPreparedModel::executeFenced, aby uruchomić odizolowane, asynchroniczne wykonanie przygotowanego modelu z wektorem ogrodzeń synchronizacji, na które ma czekać. Więcej informacji znajdziesz w artykule Wykonywanie w ogrodzie.
  • Obsługa przepływu sterowania. Dodaje operacje IFWHILE, które przyjmują inne modele jako argumenty i wykonują je warunkowo (IF) lub wielokrotnie (WHILE). Więcej informacji znajdziesz w artykule Przepływ sterowania.
  • Zwiększona jakość usług (QoS), ponieważ aplikacje mogą wskazywać względne priorytety swoich modeli, maksymalny czas oczekiwania na przygotowanie modelu i maksymalny czas oczekiwania na zakończenie wykonania. Więcej informacji znajdziesz w artykule Jakość usług.
  • Obsługa domen pamięci, które zapewniają interfejsy alokatora dla buforów zarządzanych przez sterownik. Umożliwia to przekazywanie danych natywnych urządzeń w różnych wykonaniach, co eliminuje niepotrzebne kopiowanie i przekształcanie danych między kolejnymi wykonaniami na tym samym sterowniku. Więcej informacji znajdziesz w artykule Pamięć domen.

Android 10

Android 10 wprowadza interfejs NN HAL 1.2, który zawiera te ważne zmiany:

  • Struktura Capabilities obejmuje wszystkie typy danych, w tym typy danych skalarne, i reprezentuje wydajność bez relaksacji za pomocą wektora zamiast nazwanych pól.
  • Metody getVersionStringgetType umożliwiają frameworkowi pobieranie informacji o typie urządzenia (DeviceType) i wersji. Zobacz Wykrywanie i przypisywanie urządzeń.
  • Domyślnie do wykonania synchronicznego wykonania wywoływana jest metoda executeSynchronously. Metoda execute_1_2 informuje platformę, aby wykonała kod asynchronicznie. Zobacz Wykonanie.
  • Parametr MeasureTiming ma wartość executeSynchronously lub execute_1_2, a wykonanie w trybie burst określa, czy sterownik ma mierzyć czas trwania wykonania. Wyniki są raportowane w strukturze Timing. Zobacz Harmonogram.
  • Obsługa wykonywania, w którym co najmniej 1 wynik operacji ma nieznaną wymiar lub rangę. Zobacz Forma wyjściowa.
  • Obsługa rozszerzeń dostawcy, czyli zbiorów operacji i typów danych zdefiniowanych przez dostawcę. Raporty kierowcy obsługują rozszerzenia za pomocą metody IDevice::getSupportedExtensions. Zobacz rozszerzenia dostawcy.
  • Możliwość sterowania przez obiekt burst zbiorem operacji burst za pomocą kolejek szybkich wiadomości (FMQ) w celu komunikacji między procesami aplikacji i sterownika, co zmniejsza opóźnienie. Zobacz Wykonywanie w skoku i kole szybkich wiadomości.
  • Obsługa AHardwareBuffer, która umożliwia sterownikowi wykonywanie operacji bez kopiowania danych. Zobacz AHardwareBuffer.
  • Ulepszona obsługa buforowania artefaktów kompilacji, która pozwala skrócić czas potrzebny na kompilację podczas uruchamiania aplikacji. Zobacz Pamięć podręczna kompilacji.

Android 10 wprowadza te typy i operacje operandów:

  • Typy operandów

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

    • 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 wprowadza zmiany w wielu dotychczasowych operacjach. Aktualizacje dotyczą głównie tych kwestii:

  • Obsługa układu pamięci NCHW
  • Obsługa tensorów o rangach innych niż 4 w operacjach softmax i normalizacji
  • Obsługa rozszerzonych splotów
  • Obsługa danych wejściowych z mieszaną kwantyzacją ANEURALNETWORKS_CONCATENATION

Poniżej znajdziesz listę operacji, które zostały zmodyfikowane w Androidzie 10. Szczegółowe informacje o zmianach znajdziesz w dokumentacji referencyjnej NNAPI w sekcji OperationCode.

  • 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 został wprowadzony w Androidzie 9 i zawiera te ważne zmiany:

  • IDevice::prepareModel_1_1 zawiera parametr ExecutionPreference. Kierowca może wykorzystać tę funkcję do dostosowania przygotowania, wiedząc, że aplikacja woli oszczędzać baterię lub będzie uruchamiać model w szybkich kolejnych wywołaniach.
  • Dodano 9 nowych operacji: BATCH_TO_SPACE_ND, DIV, MEAN, PAD, SPACE_TO_BATCH_ND, SQUEEZE, STRIDED_SLICE, SUB, TRANSPOSE.
  • Aplikacja może określić, że obliczenia 32-bitowej liczby zmiennoprzecinkowej mogą być wykonywane przy użyciu zakresu lub dokładności 16-bitowej liczby zmiennoprzecinkowej, ustawiając wartość Model.relaxComputationFloat32toFloat16 na true. Struktura Capabilities zawiera dodatkowe pole relaxedFloat32toFloat16Performance, dzięki któremu kierowca może zgłaszać do frameworku zrelaksowaną wydajność.

Android 8.1

Pierwsza wersja HAL dla sieci neuronowych (1.0) została wydana w Androidzie 8.1. Więcej informacji znajdziesz w sekcji /neuralnetworks/1.0/.