Sterowniki interfejsu Neural Networks API

Ta strona zawiera omówienie sposobu wdrażania sterownika Neural Networks API (NNAPI). Więcej informacji znajdziesz w dokumentacji znajdującej się w plikach definicji HAL w hardware/interfaces/neuralnetworks. Przykładową implementację sterownika znajdziesz w frameworks/ml/nn/driver/sample.

Więcej informacji o interfejsie Neural Networks API znajdziesz na stronie Neural Networks API.

HAL sieci neuronowych

HAL Neural Networks (NN) określa abstrakcyjne dane o różnych urządzeniach, takich jak procesory graficzne (GPU) i procesory sygnału cyfrowego (DSP), które są częścią produktu (np. telefonu lub tabletu). Sterowniki tych urządzeń muszą być zgodne z normą NN HAL. Interfejs jest określony w plikach definicji HAL w hardware/interfaces/neuralnetworks.

Ogólny przepływ interfejsu między platformą a sterownikiem został przedstawiony na ilustracji 1.

Przepływ sieci neuronowych

Rysunek 1. Przepływ sieci neuronowych

Inicjalizacja

Podczas inicjowania platforma wysyła zapytanie do sterownika za pomocą narzędzia IDevice::getCapabilities_1_3. Struktura @1.3::Capabilities obejmuje wszystkie typy danych i reprezentuje niezrelaksowaną wydajność za pomocą wektora.

Aby określić sposób przydziału obliczeń do dostępnych urządzeń, schemat wykorzystuje funkcje pozwalające określić szybkość i wydajność energetyczną, które może wykonać każdy sterownik. Aby udostępnić te informacje, sterownik musi podać ustandaryzowane dane o wydajności oparte na wykonaniu zadań referencyjnych.

Aby określić wartości, które sterownik zwraca w odpowiedzi na żądanie IDevice::getCapabilities_1_3, użyj aplikacji analizy porównawczej NNAPI do pomiaru wydajności odpowiednich typów danych. Do pomiaru skuteczności 32-bitowych wartości zmiennoprzecinkowych zalecamy modele MobileNet v1, v2, asr_float i tts_float, a kwantowe modele MobileNet v1 i v2 – w przypadku wartości 8-bitowych. Więcej informacji znajdziesz na stronie Android Machine Learning Test Suite.

W Androidzie 9 i starszych wersjach struktura Capabilities zawiera informacje o wydajności sterownika tylko dla tensorów zmiennoprzecinkowych i kwantowych, nie uwzględnia typów danych skalarnych.

W ramach procesu inicjowania platforma może wysyłać zapytania o więcej informacji przy użyciu metod IDevice::getType, IDevice::getVersionString, IDevice:getSupportedExtensions i IDevice::getNumberOfCacheFilesNeeded.

Po ponownym uruchomieniu usługi platforma oczekuje, że wszystkie zapytania opisane w tej sekcji będą zawsze zgłaszać te same wartości dla danego sterownika. W przeciwnym razie aplikacja korzystająca z tego sterownika może wykazywać zmniejszoną wydajność lub nieprawidłowe działanie.

Kompilacja

Określa ona, z których urządzeń należy korzystać w przypadku otrzymania żądania z aplikacji. W Androidzie 10 aplikacje mogą wykrywać i określać urządzenia, z których platforma wybiera. Więcej informacji znajdziesz w artykule Wykrywanie i przypisywanie urządzeń.

Podczas kompilacji modelu platforma wysyła model do każdego kandydującego sterownika, wywołując metodę IDevice::getSupportedOperations_1_3. Każdy sterownik zwraca tablicę wartości logicznych wskazujących, które operacje modelu są obsługiwane. Sterownik może z różnych powodów stwierdzić, że nie może obsłużyć danej operacji. Na przykład:

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

Podczas kompilacji dane wejściowe, wyjściowe i wewnętrzne modelu, zgodnie z opisem w OperandLifeTime, mogą mieć nieznane wymiary lub pozycję w rankingu. Więcej informacji znajdziesz w artykule Kształt wyjściowy.

Platforma instruuje każdego wybranego sterownika, aby przygotował się do wykonania podzbioru modelu, wywołując metodę IDevice::prepareModel_1_3. Każdy sterownik następnie kompiluje swój podzbiór. Kierowca może na przykład wygenerować kod lub utworzyć nową kopię wag. Między skompilowaniem modelu a wykonaniem żądań może upłynąć dużo czasu, dlatego podczas kompilacji nie należy przypisywać zasobów, takich jak duże porcje pamięci urządzenia.

Po udanym działaniu kierowca zwraca uchwyt @1.3::IPreparedModel. Jeśli sterownik zwróci kod błędu podczas przygotowywania podzbioru modelu, platforma uruchomi cały model na procesorze.

Aby skrócić czas potrzebny na kompilację przy uruchamianiu aplikacji, sterownik może umieścić artefakty kompilacji w pamięci podręcznej. Więcej informacji znajdziesz w sekcji Pamięć podręczna kompilacji.

Realizacja

Gdy aplikacja prosi platformę o wykonanie żądania, platforma domyślnie wywołuje metodę HAL IPreparedModel::executeSynchronously_1_3, aby wykonać synchroniczne wykonanie na gotowym modelu. Żądanie może być też wykonywane asynchronicznie z użyciem metody execute_1_3, metody executeFenced (patrz Wykonywanie zabezpieczone) lub wykonane z użyciem wykonania burstowego.

Synchroniczne wywołania wykonania poprawiają wydajność i zmniejszają narzut wątków w porównaniu z wywołaniami asynchronicznymi, ponieważ kontrola jest zwracana do procesu aplikacji dopiero po zakończeniu wykonywania. Oznacza to, że sterownik nie potrzebuje osobnego mechanizmu, który powiadamia proces aplikacji o zakończeniu wykonania.

W przypadku asynchronicznego metody execute_1_3 element sterujący wraca do procesu aplikacji po jego rozpoczęciu, a sterownik musi powiadomić platformę o zakończeniu wykonywania za pomocą metody @1.3::IExecutionCallback.

Parametr Request przekazany do metody wykonywania zawiera listę operandów wejściowych i wyjściowych użytych do wykonania. Pamięć, w której przechowywane są dane operandu, musi być w kolejności wiersza-duża, przy czym pierwszy wymiar będzie powtarzał najwolniejszy wymiar, i nie musi mieć dopełnienia na końcu żadnego wiersza. Więcej informacji o typach operandów znajdziesz w opisie argumentów.

W przypadku sterowników NN HAL 1.2 lub nowszych po zrealizowaniu żądania do platformy zwracane są stan błędu, kształt danych wyjściowych i informacje o czasie. Podczas wykonywania dane wyjściowe lub operandy wewnętrzne modelu mogą mieć co najmniej 1 nieznany wymiar lub nieznaną pozycję w rankingu. Gdy co najmniej 1 operand wyjściowy ma nieznany wymiar lub pozycję, system musi zwrócić informacje wyjściowe o rozmiarach dynamicznych.

W przypadku sterowników z NN HAL 1.1 lub starszym po zakończeniu żądania zwracany jest tylko stan błędu. Wymiary operandów wejściowych i wyjściowych muszą być w pełni określone, aby wykonanie zostało ukończone. Wewnętrzne operandy mogą mieć co najmniej 1 nieznany wymiar, ale muszą mieć określoną pozycję.

W przypadku żądań użytkowników, które obejmują wiele sterowników, platforma odpowiada za rezerwowanie pamięci pośredniej i sekwencjonowanie wywołań każdego sterownika.

W tym samym miejscu @1.3::IPreparedModel można inicjować równolegle wiele żądań. Sterownik może wykonywać żądania równolegle lub zserializować wykonania.

Platforma może poprosić sterownika o zachowanie więcej niż 1 gotowego modelu. Na przykład przygotuj model m1, przygotuj m2, wykonaj żądanie r1 na m1, wykonaj r2 na m2, r3 na m1, r4 na m2, wersję (opisaną w sekcji Czyszczenie) m1 i m2.

Aby uniknąć powolnego pierwszego wykonania, które mogłoby pogorszyć wrażenia użytkownika (np. zacinanie się pierwszej klatki), sterownik powinien wykonywać większość inicjacji na etapie kompilacji. Inicjowanie przy pierwszym uruchomieniu powinno ograniczać się do działań, które negatywnie wpływają na stan systemu, takich jak rezerwowanie dużych tymczasowych buforów lub zwiększanie częstotliwości zegara urządzenia. Sterowniki, które mogą przygotować tylko ograniczoną liczbę równoczesnych modeli, mogą wymagać zainicjowania ich przy pierwszym uruchomieniu.

W Androidzie 10 lub nowszym, w których w krótkich odstępach czasu jest wykonywane wiele uruchomień tego samego przygotowanego modelu, klient może zdecydować się na komunikację między aplikacją a procesem sterownika za pomocą obiektu Burst wykonywania. Więcej informacji znajdziesz w artykule o wykonywaniu serii i kolejkach szybkich wiadomości.

Aby poprawić wydajność w krótkich odstępach czasu w przypadku wielu wykonań, sterownik może zachować tymczasowe bufory lub zwiększyć częstotliwość zegara. Zalecamy utworzenie wątku watchdoga, aby zwolnić zasoby, jeśli po ustalonym czasie nie zostaną utworzone żadne nowe żądania.

Kształt wyjściowy

W przypadku żądań, w których co najmniej jeden operand wyjściowy nie ma określonych wymiarów, sterownik musi po wykonaniu wyświetlić listę kształtów danych wyjściowych zawierających informacje o wymiarach dla każdego argumentu wyjściowego. Więcej informacji o wymiarach znajdziesz tutaj: OutputShape.

Jeśli wykonanie zakończy się niepowodzeniem z powodu zbyt małego bufora wyjściowego, sterownik musi wskazać na liście kształtów wyjściowych, które operandy wyjściowe mają niewystarczający rozmiar bufora. Powinien on też zgłosić jak najwięcej informacji o wymiarach, używając 0 w przypadku nieznanych wymiarów.

Czas

W Androidzie 10 aplikacja może poprosić o czas wykonania, jeśli w ramach procesu kompilacji ma wskazane urządzenie do użycia. Szczegółowe informacje znajdziesz w sekcjach MeasureTiming oraz Wykrywanie i przypisywanie urządzeń. W takim przypadku podczas wykonywania żądania sterownik NN HAL 1.2 musi zmierzyć czas wykonania lub zgłosić UINT64_MAX (aby wskazać, że czas trwania jest niedostępny). Decydujący powinien zminimalizować wszelkie ograniczenia wydajności wynikające z pomiaru czasu trwania wykonywania.

Sterownik zgłasza w strukturze Timing te czasy trwania w mikrosekundach:

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

Czasy trwania muszą uwzględniać czas zawieszenia wykonania, np. czas, gdy wykonanie zostało wywłaszczone przez inne zadania lub oczekiwanie na udostępnienie zasobu.

Jeśli sterownik nie został poproszony o zmierzenie czasu wykonywania lub jeśli wystąpi błąd wykonywania, musi zgłaszać czasy trwania jako UINT64_MAX. Nawet jeśli sterownik został poproszony o zmierzenie czasu wykonywania, może zamiast tego zgłosić UINT64_MAX przez czas na urządzeniu, czas na sterowniku lub w obu tych miejscach. Gdy sterownik zgłasza oba czasy trwania jako wartość inną niż UINT64_MAX, czas wykonywania w sterowniku musi być równy lub dłuższy niż czas na urządzeniu.

Zabezpieczona realizacja

W Androidzie 11 interfejs NNAPI umożliwia wykonaniom oczekiwanie na listę nicków sync_fence i opcjonalnie zwrócenie obiektu sync_fence, który jest sygnalizowany po zakończeniu wykonywania. Zmniejsza to wymagania związane z małymi modelami sekwencji i przypadkami użycia strumieniowania. Wykonywanie graniczne pozwala też na bardziej efektywną interoperacyjność z innymi komponentami, które mogą sygnalizować lub zaczekać na polecenie sync_fence. Więcej informacji na temat sync_fence znajdziesz w artykule o platformie synchronizacji.

W zabezpieczonym wykonaniu platforma wywołuje metodę IPreparedModel::executeFenced, aby uruchomić ogrodzone, asynchroniczne wykonanie na gotowym modelu z wektorem zabezpieczeń przed synchronizacją. Jeśli zadanie asynchroniczne zostanie ukończone przed ponownym wywołaniem, dla funkcji sync_fence może zostać zwrócony pusty uchwyt. Aby platforma mogła wysyłać zapytania o stan błędu i informacje o czasie trwania, musi też zostać zwrócony obiekt IFencedExecutionCallback.

Po zakończeniu wykonania 2 poniższe wartości czasu mierzące czas trwania wykonania można przesłać do zapytania IFencedExecutionCallback::getExecutionInfo.

  • timingLaunched: czas od wywołania funkcji executeFenced do momentu, gdy executeFenced zasygnalizuje zwrócony kod syncFence.
  • timingFenced: czas od momentu, w którym wszystkie blokady synchronizacji, na które oczekuje wykonanie, są sygnalizowane, gdy executeFenced zasygnalizuje zwrócony błąd syncFence.

Sterowanie przepływem pracy

W przypadku urządzeń z Androidem 11 lub nowszym NNAPI obejmuje 2 operacje przepływu sterowania (IF i WHILE), które przyjmują inne modele jako argumenty i wykonują je warunkowo (IF) lub wielokrotnie (WHILE). Więcej informacji o tym, jak to zrobić, znajdziesz w artykule na temat procesu sterowania.

Jakość usługi

W Androidzie 11 NNAPI zapewnia lepszą jakość usługi (QoS), umożliwiając aplikacji określenie względnych priorytetów swoich modeli, maksymalnego czasu potrzebnego na przygotowanie modelu i maksymalnego czasu oczekiwanego na wykonanie wykonania. Więcej informacji znajdziesz w artykule Jakość usługi.

Uporządkuj

Gdy aplikacja zakończy pracę przy użyciu przygotowanego modelu, platforma udostępnia swoje odwołanie do obiektu @1.3::IPreparedModel. Gdy obiekt IPreparedModel nie jest już przywoływany, jest on automatycznie zniszczony w usłudze sterownika, która go utworzyła. Zasoby specyficzne dla modelu można obecnie odzyskać podczas implementacji destruatora przez sterownik. Jeśli usługa sterownika chce, aby obiekt IPreparedModel był automatycznie niszczony, gdy nie jest już potrzebny przez klienta, nie może zawierać żadnych odwołań do obiektu IPreparedModel po zwróceniu obiektu IPreparedeModel przez IPreparedModelCallback::notify_1_3.

Wykorzystanie procesora

Sterowniki powinny używać procesora do konfigurowania obliczeń. Sterowniki nie powinny używać procesora do wykonywania obliczeń grafów, ponieważ koliduje to z prawidłowym przydzielaniem pracy przez platformę. Sterownik powinien zgłosić części, których nie obsługuje, i pozwolić, żeby platforma się zajęła.

Platforma zapewnia implementację procesora na potrzeby wszystkich operacji NNAPI z wyjątkiem operacji zdefiniowanych przez dostawcę. Więcej informacji znajdziesz na stronie Rozszerzenia dostawców.

Operacje wprowadzone w Androidzie 10 (poziom interfejsu API 29) mają tylko referencyjną implementację procesora, która pozwala sprawdzić, czy testy CTS i VTS są prawidłowe. Zoptymalizowane implementacje uwzględnione w ramach systemów uczących się dla urządzeń mobilnych są preferowane zamiast implementacji procesora NNAPI.

Funkcje użytkowe

Baza kodu NNAPI zawiera funkcje narzędziowe, których usługi sterowników mogą używać.

Plik frameworks/ml/nn/common/include/Utils.h zawiera różne funkcje użytkowe, takie jak te używane do logowania i konwersji między różnymi wersjami NN HAL.

  • VLogging: VLOG to makro kodu otaczające tag LOG Androida, które rejestruje komunikat tylko wtedy, gdy we właściwości debug.nn.vlog jest ustawiony odpowiedni tag. Przed wywołaniem funkcji VLOG należy wywołać metodę initVLogMask(). Za pomocą makra VLOG_IS_ON można sprawdzić, czy usługa VLOG jest obecnie włączona. Dzięki temu skomplikowany kod logowania może być pomijany, jeśli nie jest potrzebny. Właściwość musi mieć jedną z tych wartości:

    • Pusty ciąg znaków wskazujący, że nie jest wymagane logowanie.
    • Token 1 lub all, który wskazuje, że logowanie jest wymagane.
    • Lista tagów rozdzielonych spacjami, przecinkami lub dwukropkami wskazującymi, które logowanie należy wykonać. Tagi to compilation, cpuexe, driver, execution, manager i model.
  • compliantWithV1_*: zwraca wartość true, jeśli obiekt NN HAL może zostać przekonwertowany na ten sam typ innej wersji HAL bez utraty informacji. Na przykład wywołanie funkcji compliantWithV1_0 w elemencie V1_2::Model zwraca wartość false, jeśli model zawiera operacje wprowadzone w NN HAL 1.1 lub NN HAL 1.2.

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

  • Uprawnienia: do tworzenia pola Capabilities::operandPerformance można wykorzystać funkcje nonExtensionOperandPerformance i update.

  • Właściwości zapytania tych typów: isExtensionOperandType, isExtensionOperationType, nonExtensionSizeOfData, nonExtensionOperandSizeOfData, nonExtensionOperandTypeIsScalar, tensorHasUnspecifiedDimensions.

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

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

Plik frameworks/ml/nn/common/include/Tracing.h zawiera makra, które upraszczają dodawanie informacji systracing do kodu sieci neuronowych. Przykładowe wywołania makr NNTRACE_* znajdziesz w przykładowym sterowniku.

Plik frameworks/ml/nn/common/include/GraphDump.h zawiera funkcję narzędzia do zrzutu zawartości pliku Model w formie graficznej na potrzeby debugowania.

  • graphDump: zapisuje reprezentację modelu w formacie Graphviz (.dot) w określonym strumieniu (jeśli jest dostępny) lub w logcat (jeśli nie podano strumienia).

Weryfikacja

Aby przetestować implementację NNAPI, użyj testów VTS i CTS dostępnych w platformie Androida. VTS ćwiczy sterowniki bezpośrednio (bez korzystania z platformy), podczas gdy CTS wykorzystuje je pośrednio. Sprawdzą one każdą metodę interfejsu API i sprawdzają, czy wszystkie operacje obsługiwane przez sterowniki działają prawidłowo, a także dają wyniki spełniające wymagania dotyczące dokładności.

Wymagania dotyczące dokładności w przypadku CTS i VTS dla NNAPI są następujące:

  • 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
  • Poddane kwantyzacji: wyłączone po kolei (z wyjątkiem wartości mobilenet_quantized, która jest dopasowywana do trzech)

  • Wartość logiczna: dopasowanie ścisłe.

Jednym ze sposobów testowania NNAPI przez CTS jest generowanie stałych pseudorandomów, które służą do testowania i porównywania wyników wykonania każdego sterownika z implementacją referencyjną NNAPI. W przypadku sterowników z NN HAL 1.2 lub nowszym, jeśli wyniki nie spełniają kryteriów dokładności, CTS zgłasza błąd i umieszcza plik specyfikacji modelu z błędem w usłudze /data/local/tmp do debugowania. Więcej informacji o kryteriach dokładności znajdziesz w sekcjach TestRandomGraph.cpp i TestHarness.h.

Testowanie rozmycia

Celem testów wymazywania jest wykrywanie awarii, asercji, przypadków naruszenia pamięci i ogólnego nieokreślonego zachowania w testowanym kodzie z powodu takich czynników jak nieoczekiwane dane wejściowe. Do testowania rozmycia NNAPI Android używa testów opartych na libFuzzer, które skutecznie ukrywają dane, ponieważ do generowania nowych losowych danych wejściowych wykorzystują pokrycie wierszy z poprzednich przypadków testowych. Na przykład libFuzzer preferuje przypadki testowe, które działają w nowych wierszach kodu. To znacznie skraca czas potrzebny na znalezienie problematycznego kodu.

Aby przeprowadzić testy zamazania w celu zweryfikowania implementacji sterownika, zmodyfikuj frameworks/ml/nn/runtime/test/android_fuzzing/DriverFuzzTest.cpp w narzędziu testowym libneuralnetworks_driver_fuzzer w AOSP, tak aby zawierał kod sterownika. Więcej informacji o testowaniu rozmycia NNAPI znajdziesz tutaj: frameworks/ml/nn/runtime/test/android_fuzzing/README.md.

Zabezpieczenia

Procesy aplikacji komunikują się bezpośrednio z procesem kierowcy, dlatego kierowcy muszą zweryfikować argumenty otrzymywanych wywołań. Tę weryfikację weryfikuje VTS. Kod weryfikacyjny znajduje się w regionie frameworks/ml/nn/common/include/ValidateHal.h.

Podczas korzystania z tego samego urządzenia sterowniki powinni też mieć pewność, że aplikacje nie mogą zakłócać działania innych aplikacji.

Android Machine Learning Test Suite

Android Machine Learning Test Suite (MLTS) to narzędzie do analizy porównawczej NNAPI zawarte w CTS i VTS, służące do sprawdzania dokładności rzeczywistych modeli na urządzeniach dostawców. W ramach testów porównawczych ocenia się czas oczekiwania i dokładność oraz porównuje wyniki sterowników z wynikami za pomocą narzędzia TF Lite uruchomionego na procesorze dla tego samego modelu i zbiorów danych. Dzięki temu dokładność sterownika nie jest niższa niż w przypadku referencyjnej implementacji procesora.

Deweloperzy platform Androida używają też MLTS do oceny czasu oczekiwania i dokładności sterowników.

Test porównawczy NNAPI można znaleźć w 2 projektach w AOSP:

Modele i zbiory danych

Test porównawczy NNAPI wykorzystuje poniższe modele i zbiory danych.

  • Obiekty zmiennoprzecinkowe MobileNetV1 i u8 poddane kwantyzacji w różnych rozmiarach są analizowane na niewielkim podzbiorze (1500 obrazów) zbioru danych Open Images v4.
  • Obiekty zmiennoprzecinkowe MobileNetV2 i u8 poddane kwantyzacji w różnych rozmiarach są analizowane na niewielkim podzbiorze (1500 obrazów) zbioru danych Open Images v4.
  • Zamiana tekstu na mowę z modelu akustycznego opartego na pamięci krótkoterminowej (LSTM) na niewielkim podzbiorze grupy Arktyki CMU.
  • Oparty na LSTM model akustyczny do automatycznego rozpoznawania mowy, uruchamiany na niewielkim podzbiorze zbioru danych LibriSpeech.

Więcej informacji: platform/test/mlts/models.

Testy stresu

Android Machine Learning Test Suite obejmuje serię testów awaryjnych, które pozwalają sprawdzić odporność sterowników w intensywnych warunkach użytkowania lub w szczególnych sytuacjach związanych z działaniem klientów.

Wszystkie testy awarii obejmują te funkcje:

  • Wykrywanie zawieszenia: jeśli klient NNAPI zawiesi się podczas testu, test zakończy się niepowodzeniem z powodu błędu HANG, a zestaw testów zostanie przeniesiony do następnego testu.
  • Wykrywanie awarii klienta NNAPI: testy eliminują awarie klienta, a testy kończą się niepowodzeniem z powodu błędu CRASH.
  • Wykrywanie awarii kierowców: testy mogą wykryć wypadek kierowcy, który powoduje awarię wywołania NNAPI. Pamiętaj, że w procesach sterownika mogą występować awarie, które nie powodują awarii NNAPI ani nie powodują niepowodzenia testu. Aby uwzględnić tego rodzaju awarie, w logu systemowym zalecamy uruchomienie polecenia tail dotyczące błędów lub awarii sterowników.
  • Kierowanie wszystkich dostępnych akceleratorów: testy są przeprowadzane pod kątem wszystkich dostępnych sterowników.

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

  • SUCCESS: wykonanie zostało ukończone bez błędu.
  • FAILURE: nie udało się wykonać. Zwykle jest to spowodowane błędem podczas testowania modelu, który wskazuje, że sterownik nie skompilował lub nie wykonał modelu.
  • HANG: proces testowy nie odpowiada.
  • CRASH: proces testowy uległ awarii.

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

Korzystanie z MLTS

Aby korzystać z MLTS:

  1. Podłącz urządzenie docelowe do stacji roboczej i upewnij się, że jest ono osiągalne za pomocą narzędzia adb. Jeśli podłączone jest więcej niż 1 urządzenie, wyeksportuj zmienną środowiskową ANDROID_SERIAL urządzenia docelowego.
  2. cd do katalogu źródłowego najwyższego poziomu 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ą wyświetlane w formie strony HTML i przekazywane do xdg-open.

Więcej informacji: platform/test/mlts/benchmark/README.txt.

Wersje HAL Neural Networks

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

Android 11

Android 11 wprowadza NN HAL 1.3, co obejmuje następujące ważne zmiany.

  • Obsługa kwantyzacji ze znakiem 8-bitowego w NNAPI. Dodaje typ operandu TENSOR_QUANT8_ASYMM_SIGNED. Sterowniki z NN HAL 1.3, które obsługują operacje z kwantyzacją bez podpisu, muszą też obsługiwać podpisane warianty tych operacji. W przypadku uruchamiania podpisanych i niepodpisanych wersji większości operacji kwantowych sterowniki muszą zapewniać te same wyniki, ale nie więcej niż z przesunięciem wynoszącym 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 podpisanych operandów, a pozostałe 4 operacje obsługują kwantyzację z podpisem, ale nie wymagają, aby wyniki były takie same.
  • Obsługa chronionych wykonań, w przypadku których platforma wywołuje metodę IPreparedModel::executeFenced, aby uruchomić ogrodzone, asynchroniczne wykonanie na gotowym modelu z wektorem zabezpieczeń synchronizacji w czasie oczekiwania. Więcej informacji znajdziesz w artykule o wykonaniu zabezpieczonym.
  • Obsługa procesu sterowania. Dodaje operacje IF i WHILE, które przyjmują inne modele jako argumenty i wykonują je warunkowo (IF) lub wielokrotnie (WHILE). Więcej informacji znajdziesz w sekcji Proces sterowania.
  • Poprawiona jakość usług (QoS), ponieważ aplikacje mogą wskazywać względne priorytety swoich modeli, maksymalny spodziewany czas przygotowania modelu i maksymalny spodziewany czas wykonania wykonania. Więcej informacji znajdziesz w artykule Jakość usługi.
  • Obsługa domen pamięci, które udostępniają interfejsy rozdzielające dla buforów zarządzanych przez sterownika. Pozwala to na przekazywanie natywnych pamięci urządzenia między uruchomieniami, co eliminuje niepotrzebne kopiowanie i przekształcanie danych między kolejnymi wykonaniami na tym samym sterowniku. Więcej informacji znajdziesz w sekcji Domeny pamięci.

Android 10

Android 10 wprowadza NN HAL 1.2, co obejmuje następujące ważne zmiany.

  • Struktura Capabilities obejmuje wszystkie typy danych, w tym typy danych skalarnych, i reprezentuje niezłagodzoną wydajność z użyciem pól wektorowych, a nie nazwanych.
  • Metody getVersionString i getType umożliwiają platformie pobieranie informacji o typie urządzenia (DeviceType) i wersji. Zobacz Wykrywanie i przypisywanie urządzeń.
  • Domyślnie metoda executeSynchronously jest wywoływana, aby wykonywać wykonanie synchronicznie. Metoda execute_1_2 informuje platformę, że ma wykonywać wykonanie asynchronicznie. Zobacz Wykonanie.
  • Parametr MeasureTiming do executeSynchronously, execute_1_2 i wykonania burst określa, czy sterownik ma mierzyć czas wykonywania. Wyniki są raportowane w strukturze Timing. Zobacz Terminy.
  • Obsługa wykonań, w których co najmniej 1 operand wyjściowy ma nieznany rozmiar lub pozycję w rankingu. Zobacz Kształt wyjściowy.
  • Obsługa rozszerzeń dostawców, czyli zbiorów operacji i typów danych zdefiniowanych przez dostawcę. Sterownik zgłasza obsługiwane rozszerzenia za pomocą metody IDevice::getSupportedExtensions. Zobacz Rozszerzenia dostawców.
  • Zdolność obiektu serii burst do kontrolowania zestawu wykonań burst przy użyciu szybkich kolejek wiadomości (FMQ) do komunikacji między aplikacją a procesami sterowników, co skraca czas oczekiwania. Zapoznaj się z sekcją Wykonywanie serii i szybkie kolejki wiadomości.
  • Obsługa AHardwareBuffer, która umożliwia sterownikowi wykonywanie wykonań bez kopiowania danych. Zobacz AHardwareBuffer.
  • Ulepszona obsługa buforowania artefaktów kompilacji w celu skrócenia czasu potrzebnego na kompilację przy uruchamianiu aplikacji. Zapoznaj się z sekcją Buforowanie kompilacji.

Android 10 wprowadza poniższe typy operandów i operacji.

  • Typy argumentó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 aktualizacje do wielu dotychczasowych operacji. Są one głównie związane z:

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

Poniższa lista przedstawia operacje zmodyfikowane w Androidzie 10. Szczegółowe informacje o zmianach znajdziesz w sekcji OperationCode w dokumentacji referencyjnej 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

W Androidzie 9 wprowadzono NN HAL 1.1 i zawierają te ważne zmiany.

  • IDevice::prepareModel_1_1 zawiera parametr ExecutionPreference. Kierowca może wykorzystać tę informację, aby dostosować swoje przygotowanie, wiedząc, że aplikacja woli oszczędzać baterię lub będzie wykonywać model w krótkich odstępach czasu.
  • 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 32-bitowe obliczenia zmiennoprzecinkowe mogą być wykonywane z użyciem 16-bitowego zakresu zmiennoprzecinkowego lub precyzji, ustawiając Model.relaxComputationFloat32toFloat16 na true. Struktura Capabilities zawiera dodatkowe pole relaxedFloat32toFloat16Performance, dzięki któremu kierowca może raportować do platformy dane o swojskiej wydajności.

Android 8.1

Pierwsza wersja HAL Neural Networks (1.0) została opublikowana w Androidzie 8.1. Więcej informacji znajdziesz tutaj: /neuralnetworks/1.0/.