Sterowniki interfejsu Neural Networks API

Ta strona zawiera omówienie implementacji interfejsu 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.

Sieci neuronowe 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. Przepływ sieci neuronowych

Inicjowanie

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 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 inicjalizacji platforma może wysyłać więcej zapytań o informacje, korzystając z funkcji IDevice::getType, IDevice::getVersionString, IDevice:getSupportedExtensionsIDevice::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

Framework określa, których urządzeń używać, gdy otrzyma żądanie od aplikacji. 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 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 określić, że nie może wykonać danej operacji z różnych powodów. Na 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 Forma danych wyjściowych.

Framework instruuje każdy wybrany sterownik, aby przygotował się do wykonania podzbioru modelu, wywołując IDevice::prepareModel_1_3. Każdy sterownik kompiluje swój podzbiór. Kierowca może na przykład wygenerować kod lub utworzyć nową kopię wag. 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, platforma uruchomi cały model na procesorze.

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 Przyspieszanie kompilacji za pomocą pamięci podręcznej.

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 też być wykonywane asynchronicznie za pomocą metody execute_1_3 lub executeFenced (patrz wykonanie w ramach ograniczeń) lub za pomocą wykonania w trybie burst.

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 asynchronicznej metody execute_1_3 kontrola wraca do procesu aplikacji po rozpoczęciu wykonywania, a sterownik musi powiadomić framework o zakończeniu wykonywania za pomocą funkcji @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 może 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 zakończeniu przetwarzania żądania do frameworku 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ę. 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. Operandy wewnętrzne mogą mieć co najmniej 1 nieznaną wymiar, ale muszą mieć określoną rangę.

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 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 mogłoby pogorszyć wrażenia użytkownika (np. zacinanie się pierwszej klatki), sterownik powinien wykonywać większość inicjacji 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 tym samym przygotowanym modelem jest wykonywanych szybko po sobie, klient może użyć obiektu wykonania burst, aby komunikować się między procesami aplikacji a sterownika. Więcej informacji znajdziesz w artykule Wykonywanie w krótkim czasie i kolejki 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 watchdog, 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 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 koń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). Sterownik powinien zminimalizować wszelkie kary za wydajność wynikające z mierzenia czasu trwania wykonania.

Sterownik podaje te czasy trwania w mikrosekundach w strukturze Timing:

  • 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 wykonania, może zamiast tego podać wartość UINT64_MAX dla czasu na urządzeniu, czasu w sterowniku lub obu tych wartości. 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.

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. 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 można wysłać zapytanie o te 2 wartości czasu, które mierzą czas wykonania: 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 czeka wykonanie, są sygnalizowane, gdy executeFenced zasygnalizuje zwrócony błąd syncFence.

Kontrola przepływu

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 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 Jakość usługi.

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 specyficzne dla modelu można obecnie odzyskać podczas implementacji destruatora przez sterownik. Jeśli usługa kierowcy chce, aby obiekt IPreparedModel został automatycznie zniszczony, 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ń 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 w artykule 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 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 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. initVLogMask()musi być wywoływana przed każdym wywołaniem funkcji VLOG. 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, który wskazuje, że nie ma potrzeby rejestrowania.
    • 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 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 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ą. Jeśli konwersja powoduje utratę informacji (czyli jeśli nowa wersja typu nie może w pełni reprezentować 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żyć właściwości o typach: 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 typy 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ładem są wywołania makra NNTRACE_*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 wybranym strumieniu (jeśli został podany) lub w logcat (jeśli nie został podany żaden strumień).

Weryfikacja

Aby przetestować implementację NNAPI, użyj testów VTS i CTS dostępnych w platformie Androida. VTS testuje sterowniki bezpośrednio (bez używania frameworku), a CTS testuje je pośrednio za pomocą frameworku. 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 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 fuzz

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. 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ą na nowych liniach 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.

Bezpieczeństwo

Procesy aplikacji komunikują się bezpośrednio z procesem kierowcy, dlatego kierowcy muszą zweryfikować argumenty otrzymywanych wywołań. 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. 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 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.
  • 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.
  • Model akustyczny oparty na LSTM do automatycznego rozpoznawania mowy, uruchomiony na niewielkim podzbiorze zbioru danych LibriSpeech.

Więcej informacji: 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ólnych zachowań klientów.

Wszystkie testy awarii obejmują 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 kierowców: testy wykrywają 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 typu awarię, zalecamy uruchomienie polecenia tailw logu 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 komponentach.

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

  • SUCCESS: wykonanie zakończyło się bez błędów.
  • 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 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 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 postaci 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 zaokrągleń 8-bitowych z znakami 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. 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 podpisanych operandów, a pozostałe 4 operacje obsługują kwantyzację z podpisem, 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.
  • 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ług.
  • Obsługa domen pamięci, które udostępniają interfejsy rozdzielające dla buforów zarządzanych przez sterownika. Umożliwia to przekazywanie danych natywnych urządzeń w ramach poszczególnych wykonań, 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 skalarnych, i reprezentuje niezrelaksowaną wydajność przy użyciu pól wektorowych, a nie nazwanych.
  • Metody getVersionStringgetType umożliwiają frameworkowi 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ę o niesynchronicznym wykonywaniu. Zobacz Wykonanie.
  • Parametr MeasureTiming ma wartość executeSynchronously, execute_1_2 lub 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 kształt wyjściowy.
  • Obsługa rozszerzeń dostawcy, czyli zbiorów operacji i typów danych zdefiniowanych przez dostawcę. Sterownik zgłasza obsługiwane 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 kolejki szybkich wiadomości.
  • Obsługa AHardwareBuffer, która umożliwia sterownikowi wykonywanie wykonań bez kopiowania danych. Zobacz AHardwareBuffer.
  • Ulepszona obsługa buforowania artefaktów kompilacji, która pozwala skrócić czas kompilacji 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 aktualizacje do wielu dotychczasowych operacji. Są one głównie związane z następującymi kwestiami:

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

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ę, aby dostosować przygotowanie, 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 raportować do platformy dane o swojskiej wydajności.

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/.