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.
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:getSupportedExtensions
i IDevice::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ściowych i informacje 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 MeasureTiming
i Wykrywanie 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 funkcjiexecuteFenced
do momentu, gdy funkcjaexecuteFenced
sygnalizuje zwróconą wartośćsyncFence
.timingFenced
: czas od momentu, gdy wszystkie sygnały synchronizacji, na które oczekuje wykonanie, są sygnalizowane, do momentu, gdyexecuteFenced
sygnalizuje zwróconysyncFence
.
Kontrola przepływu
W przypadku urządzeń z Androidem 11 lub nowszym NNAPI zawiera 2 operacje sterowania przepływem danych, 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 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 makroLOG
w Androidzie, które rejestruje wiadomość tylko wtedy, gdy w właściwościdebug.nn.vlog
ustawiony jest odpowiedni tag.initVLogMask()
musi być wywoływana przed każdym wywołaniem funkcjiVLOG
. MakraVLOG_IS_ON
można użyć do sprawdzenia, czy makroVLOG
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
luball
, 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
imodel
.
compliantWithV1_*
: zwracatrue
, jeśli obiekt NN HAL można przekonwertować do tego samego typu w innej wersji HAL bez utraty informacji. Na przykład wywołanie funkcjicompliantWithV1_0
w obiekcieV1_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ć funkcjinonExtensionOperandPerformance
iupdate
.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*
: zwracatrue
, jeśli obiekt NN HAL jest prawidłowy zgodnie ze specyfikacją wersji HAL. Typy OEM i typy rozszerzeń nie są weryfikowane. Na przykładvalidateModel
zwracafalse
, 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.cpp
i TestHarness.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:
platform/test/mlts/benchmark
(aplikacja do testów porównawczych)platform/test/mlts/models
(modele i zbiory danych)
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
tail
w 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:
- Podłącz urządzenie docelowe do stacji roboczej i upewnij się, że jest ono dostępne przez adb.
Wyeksportuj zmienną środowiskową
ANDROID_SERIAL
urządzenia docelowego, jeśli jest połączonych więcej niż jedno urządzenie. 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. Dodaje
TENSOR_QUANT8_ASYMM_SIGNED
typ 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
iQUANTIZED_16BIT_LSTM
. OperacjaQUANTIZED_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
IF
iWHILE
, 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
getVersionString
igetType
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
. Metodaexecute_1_2
informuje platformę, aby wykonała kod asynchronicznie. Zobacz Wykonanie. - Parametr
MeasureTiming
ma wartośćexecuteSynchronously
lubexecute_1_2
, a wykonanie w trybie burst określa, czy sterownik ma mierzyć czas trwania wykonania. Wyniki są raportowane w strukturzeTiming
. 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:
-
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
-
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 parametrExecutionPreference
. 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
natrue
. StrukturaCapabilities
zawiera dodatkowe polerelaxedFloat32toFloat16Performance
, 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/
.