Na tej stronie znajdziesz omówienie sposobu wdrażania sterownika interfejsu Neural Networks API (NNAPI). Więcej informacji znajdziesz w dokumentacji w plikach definicji HAL w 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 Neural Networks API.
Warstwa HAL sieci neuronowych
Warstwa HAL sieci neuronowych (NN) definiuje abstrakcję różnych urządzeń, takich jak procesory graficzne (GPU) i procesory sygnałowe (DSP), które znajdują się w produkcie (np. telefonie lub tablecie). Sterowniki tych urządzeń muszą być zgodne z NN HAL. Interfejs jest określony w plikach definicji HAL w katalogu hardware/interfaces/neuralnetworks
.
Ogólny przepływ interfejsu między platformą a sterownikiem przedstawiono na rysunku 1.
Rysunek 1. Przepływ sieci neuronowych
Inicjowanie
Podczas inicjowania platforma wysyła do sterownika zapytanie o jego możliwości za pomocą funkcji IDevice::getCapabilities_1_3
.
Struktura @1.3::Capabilities
obejmuje wszystkie typy danych i reprezentuje nieograniczone wyniki za pomocą wektora.
Aby określić, jak rozdzielić obliczenia między dostępne urządzenia, platforma korzysta z informacji o możliwościach, aby dowiedzieć się, jak szybko i jak energooszczędnie każdy sterownik może wykonać zadanie. Aby podać te informacje, sterownik musi udostępniać standardowe wartości wydajności na podstawie wykonania referencyjnych zadań.
Aby określić wartości zwracane przez sterownik w odpowiedzi na IDevice::getCapabilities_1_3
, użyj aplikacji testu porównawczego NNAPI do pomiaru wydajności w przypadku odpowiednich typów danych. Do pomiaru wydajności w przypadku 32-bitowych wartości zmiennoprzecinkowych zalecane są modele MobileNet v1 i v2, asr_float
oraz tts_float
, a do pomiaru wydajności w przypadku 8-bitowych wartości skwantyzowanych zalecane są modele skwantyzowane MobileNet v1 i v2. Więcej informacji znajdziesz w artykule Android Machine Learning Test Suite.
W Androidzie 9 i starszych wersjach struktura Capabilities
zawiera informacje o wydajności sterownika tylko w przypadku tensorów zmiennoprzecinkowych i skwantyzowanych, a nie zawiera skalarnych typów danych.
W ramach procesu inicjowania platforma może wysyłać zapytania o dodatkowe informacje za pomocą tych interfejsów API: IDevice::getType
, IDevice::getVersionString
, IDevice:getSupportedExtensions
i IDevice::getNumberOfCacheFilesNeeded
.
Między ponownymi uruchomieniami produktu platforma oczekuje, że wszystkie zapytania opisane w tej sekcji będą zawsze zwracać te same wartości dla danego sterownika. W przeciwnym razie aplikacja korzystająca z tego sterownika może działać mniej wydajnie lub nieprawidłowo.
Kompilacja
Platforma określa, których urządzeń użyć, gdy otrzyma żądanie z aplikacji. W Androidzie 10 aplikacje mogą wykrywać i określać urządzenia, z których platforma wybiera te, których ma użyć. Więcej informacji znajdziesz w artykule Wykrywanie i przypisywanie urządzeń.
Podczas kompilacji modelu platforma wysyła model do każdego potencjalnego sterownika, wywołując funkcję IDevice::getSupportedOperations_1_3
.
Każdy sterownik zwraca tablicę wartości logicznych wskazujących, które operacje modelu są obsługiwane. Sterownik może stwierdzić, że nie może obsługiwać danej operacji z kilku 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 splotu 3x3 i 5x5, ale nie 7x7.
- 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 operandy modelu, jak opisano w OperandLifeTime
, mogą mieć nieznane wymiary lub rangę. Więcej informacji znajdziesz w artykule Kształt danych wyjściowych.
Framework instruuje każdego wybranego sterownika, 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 sterownik może wygenerować kod lub utworzyć kopię wag w innej kolejności. Między kompilacją modelu a wykonaniem żądań może upłynąć sporo czasu, dlatego podczas kompilacji nie należy przydzielać zasobów takich jak duże fragmenty pamięci urządzenia.
Jeśli operacja się powiedzie, sterownik 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 kompilacji podczas uruchamiania aplikacji, sterownik może buforować artefakty kompilacji. Więcej informacji znajdziesz w sekcji Kompilacja pamięci podręcznej.
Realizacja
Gdy aplikacja poprosi platformę o wykonanie żądania, platforma domyślnie wywoła metodę HAL IPreparedModel::executeSynchronously_1_3
, aby wykonać synchroniczne działanie na przygotowanym modelu.
Żądanie można też wykonać asynchronicznie za pomocą metody
execute_1_3
lub metody
executeFenced
(patrz Wykonanie w izolacji) albo za pomocą wykonania w serii.
Wywołania synchroniczne zwiększają wydajność i ograniczają narzut związany z wątkami w porównaniu z wywołaniami asynchronicznymi, ponieważ kontrola jest zwracana do procesu aplikacji dopiero po zakończeniu wykonania. Oznacza to, że sterownik nie potrzebuje osobnego mechanizmu, aby powiadomić proces aplikacji o zakończeniu wykonania.
W przypadku metody asynchronicznej execute_1_3
kontrola wraca do procesu aplikacji po rozpoczęciu wykonania, a sterownik musi powiadomić platformę o zakończeniu wykonania za pomocą funkcji @1.3::IExecutionCallback
.
Parametr Request
przekazywany do metody execute zawiera listę operandów wejściowych i wyjściowych używanych do wykonania. Pamięć, w której przechowywane są dane operandu, musi używać kolejności wierszowej, w której pierwszy wymiar iteruje najwolniej, i nie może zawierać dopełnienia na końcu żadnego wiersza. Więcej informacji o typach operandów znajdziesz w sekcji Operandy.
W przypadku sterowników NN HAL w wersji 1.2 lub nowszej po zakończeniu żądania do platformy zwracany jest stan błędu, kształt danych wyjściowych i informacje o czasie. Podczas wykonywania dane wyjściowe lub wewnętrzne operandy modelu mogą mieć co najmniej 1 nieznany wymiar lub nieznaną rangę. Jeśli co najmniej 1 operand wyjściowy ma nieznany wymiar lub rangę, sterownik musi zwrócić informacje o dynamicznie określonym rozmiarze danych wyjściowych.
W przypadku sterowników z NN HAL w wersji 1.1 lub starszej po zakończeniu żądania zwracany jest tylko stan błędu. Aby wykonanie zakończyło się pomyślnie, wymiary operandów wejściowych i wyjściowych muszą być w pełni określone. Operandy wewnętrzne mogą mieć co najmniej 1 nieznany wymiar, ale muszą mieć określony rangę.
W przypadku żądań użytkowników obejmujących wiele sterowników platforma jest odpowiedzialna za rezerwowanie pamięci pośredniej i sekwencjonowanie wywołań poszczególnych sterowników.
Wiele żądań można inicjować równolegle w ramach tego samego @1.3::IPreparedModel
.
Sterownik może wykonywać żądania równolegle lub szeregowo.
Platforma może poprosić sterownik o przechowywanie więcej niż 1 przygotowanego modelu. Przygotuj na przykład model m1
, przygotuj m2
, wykonaj żądanie r1
na m1
, wykonaj r2
na m2
, wykonaj r3
na m1
, wykonaj r4
na m2
, zwolnij (opisane w sekcji Czyszczenie) m1
i zwolnij m2
.
Aby uniknąć powolnego pierwszego wykonania, które mogłoby pogorszyć komfort użytkownika (np. zacięcie pierwszej klatki), sterownik powinien przeprowadzić większość inicjalizacji w fazie kompilacji. Inicjowanie przy pierwszym wykonaniu powinno być ograniczone do działań, które negatywnie wpływają na stan systemu, jeśli są wykonywane zbyt wcześnie, np. rezerwowanie dużych buforów tymczasowych lub zwiększanie częstotliwości zegara urządzenia. Sterowniki, które mogą przygotować tylko ograniczoną liczbę modeli równoległych, mogą wymagać inicjowania przy pierwszym wykonaniu.
W Androidzie 10 lub nowszym w przypadku, gdy kilka wykonań tego samego przygotowanego modelu jest wykonywanych w szybkiej kolejności, klient może użyć obiektu serii wykonań do komunikacji między procesami aplikacji i sterownika. Więcej informacji znajdziesz w artykule Burst Executions and Fast Message Queues (w języku angielskim).
Aby poprawić wydajność w przypadku wielu kolejnych wykonań, sterownik może przechowywać tymczasowe bufory lub zwiększać częstotliwość taktowania. Zalecamy utworzenie wątku nadzorującego, który będzie zwalniać zasoby, jeśli po upływie określonego czasu nie zostaną utworzone żadne nowe żądania.
Kształt wyjściowy
W przypadku żądań, w których co najmniej 1 operand wyjściowy nie ma określonych wszystkich wymiarów, sterownik musi po wykonaniu podać listę kształtów wyjściowych zawierającą informacje o wymiarach każdego operandu wyjściowego. Więcej informacji o wymiarach znajdziesz w sekcji OutputShape
.
Jeśli wykonanie nie powiedzie się z powodu zbyt małego bufora wyjściowego, sterownik musi wskazać, które operandy wyjściowe mają niewystarczający rozmiar bufora, na liście kształtów wyjściowych i powinien podać jak najwięcej informacji o wymiarach, używając zera w przypadku wymiarów, które są nieznane.
Czas
W Androidzie 10 aplikacja może poprosić o czas wykonania, jeśli podczas procesu kompilacji określiła jedno urządzenie, którego ma używać. Szczegółowe informacje znajdziesz w sekcjach 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 jest niedostępny) podczas wykonywania żądania. Sterownik powinien zminimalizować wszelkie spadki wydajności wynikające z pomiaru czasu trwania wykonania.
Sterownik zgłasza te czasy w mikrosekundach w strukturze Timing
:
- Czas wykonania na urządzeniu: nie obejmuje czasu wykonania w sterowniku, który działa na procesorze hosta.
- Czas wykonania w sterowniku: obejmuje czas wykonania na urządzeniu.
Te czasy trwania muszą obejmować czas, w którym wykonywanie jest zawieszone, np. gdy zostało wyprzedzone przez inne zadania lub gdy czeka na udostępnienie zasobu.
Jeśli kierowca nie został poproszony o pomiar czasu trwania wykonania lub wystąpił błąd wykonania, musi zgłosić czas trwania jako UINT64_MAX
. Nawet jeśli sterownik został poproszony o pomiar czasu wykonania, może zamiast tego zgłosić wartość UINT64_MAX
dla czasu na urządzeniu, czasu w sterowniku lub obu tych wartości. Jeśli sterownik zgłasza oba czasy trwania jako wartość inną niż UINT64_MAX
, czas wykonania w sterowniku musi być równy lub dłuższy niż czas na urządzeniu.
Wykonywanie w izolacji
W Androidzie 11 interfejs NNAPI umożliwia oczekiwanie na listę uchwytów sync_fence
i opcjonalne zwracanie obiektu sync_fence
, który jest sygnalizowany po zakończeniu wykonania. Zmniejsza to obciążenie w przypadku modeli krótkich sekwencji i przypadków użycia związanych ze strumieniowaniem. Wykonanie w ograniczonym środowisku 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 przypadku wykonania w izolacji platforma wywołuje metodę IPreparedModel::executeFenced
, aby uruchomić izolowane wykonanie asynchroniczne na przygotowanym modelu z wektorem barier synchronizacji, na które trzeba poczekać. Jeśli zadanie asynchroniczne zostanie ukończone przed zwróceniem wywołania, dla sync_fence
można zwrócić pusty uchwyt. Należy też zwrócić obiekt IFencedExecutionCallback
, aby umożliwić frameworkowi sprawdzanie stanu błędu i informacji o czasie trwania.
Po zakończeniu wykonania można za pomocą IFencedExecutionCallback::getExecutionInfo
uzyskać dostęp do tych 2 wartości czasowych, które mierzą czas trwania wykonania:
timingLaunched
: czas od wywołania funkcjiexecuteFenced
do momentu, w którym funkcjaexecuteFenced
sygnalizuje zwrócony obiektsyncFence
.timingFenced
: czas od momentu, w którym wszystkie bariery synchronizacji, na które czeka wykonanie, zostaną zasygnalizowane, do momentu, w którymexecuteFenced
zasygnalizuje zwrócony elementsyncFence
.
Kontrola przepływu
W przypadku urządzeń z Androidem 11 lub nowszym NNAPI zawiera 2 operacje sterowania przepływem: 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 wdrożyć, znajdziesz w sekcji Sterowanie przepływem.
Jakość usługi
W Androidzie 11 interfejs NNAPI ma ulepszoną jakość usług (QoS), ponieważ umożliwia aplikacji określanie 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, platforma zwalnia odniesienie do obiektu @1.3::IPreparedModel
. Gdy obiekt IPreparedModel
nie jest już używany, jest automatycznie usuwany w usłudze sterownika, która go utworzyła. Zasoby specyficzne dla modelu można w tym momencie odzyskać w implementacji destruktora sterownika. Jeśli usługa sterownika chce, aby obiekt IPreparedModel
był automatycznie niszczony, gdy klient nie będzie go już potrzebować, nie może przechowywać żadnych odwołań do obiektu IPreparedModel
po zwróceniu obiektu IPreparedeModel
za pomocą funkcji IPreparedModelCallback::notify_1_3
.
Wykorzystanie procesora
Sterowniki powinny używać procesora do konfigurowania obliczeń. Sterowniki nie powinny używać procesora do obliczeń grafów, ponieważ zakłóca to prawidłowe przydzielanie zadań przez platformę. Sterownik powinien zgłaszać platformie części, których nie może obsłużyć, i pozwalać jej na obsługę pozostałych.
Platforma zapewnia implementację na procesorze 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 29 interfejsu API) mają tylko referencyjną implementację na procesorze, która służy do weryfikacji poprawności testów CTS i VTS. Zoptymalizowane implementacje zawarte w platformach uczenia maszynowego na urządzeniach mobilnych są preferowane w stosunku do implementacji NNAPI CPU.
Funkcje narzędziowe
Baza kodu NNAPI zawiera funkcje narzędziowe, z których mogą korzystać usługi sterowników.
Plik
frameworks/ml/nn/common/include/Utils.h
zawiera różne funkcje narzędziowe, takie jak funkcje używane do rejestrowania i konwertowania między różnymi wersjami NN HAL.
VLogging:
VLOG
to makro opakowująceLOG
na Androidzie, które rejestruje wiadomość tylko wtedy, gdy w właściwościdebug.nn.vlog
ustawiony jest odpowiedni tag.initVLogMask()
musi zostać wywołana przed wywołaniem funkcjiVLOG
. MakroVLOG_IS_ON
może służyć do sprawdzania, czy funkcjaVLOG
jest obecnie włączona. Umożliwia to pomijanie skomplikowanego kodu rejestrowania, jeśli nie jest on potrzebny. Wartość właściwości musi być jedną z tych wartości:- Pusty ciąg znaków, który oznacza, że nie należy rejestrować żadnych informacji.
- Token
1
luball
, który oznacza, że należy rejestrować wszystkie zdarzenia. - Lista tagów rozdzielonych spacjami, przecinkami lub dwukropkami, określająca, które logowanie ma być wykonywane. Tagi to
compilation
,cpuexe
,driver
,execution
,manager
imodel
.
compliantWithV1_*
: zwraca wartośćtrue
, jeśli obiekt NN HAL można przekonwertować na ten sam typ innej wersji HAL bez utraty informacji. Na przykład wywołaniecompliantWithV1_0
naV1_2::Model
zwracafalse
, jeśli model zawiera typy operacji wprowadzone w NN HAL 1.1 lub NN HAL 1.2.convertToV1_*
: przekształca obiekt NN HAL z jednej wersji na inną. Jeśli konwersja spowoduje utratę informacji (tzn. nowa wersja typu nie może w pełni reprezentować wartości), zostanie zarejestrowane ostrzeżenie.Możliwości: funkcje
nonExtensionOperandPerformance
iupdate
mogą pomóc w tworzeniu polaCapabilities::operandPerformance
.Właściwości zapytań o typy:
isExtensionOperandType
,isExtensionOperationType
,nonExtensionSizeOfData
,nonExtensionOperandSizeOfData
,nonExtensionOperandTypeIsScalar
,tensorHasUnspecifiedDimensions
.
Plik frameworks/ml/nn/common/include/ValidateHal.h
zawiera funkcje narzędziowe do sprawdzania, czy obiekt NN HAL jest prawidłowy zgodnie ze specyfikacją wersji HAL.
validate*
: zwraca wartośćtrue
, 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 operację, która nie jest obsługiwana w danej wersji HAL.
Plik
frameworks/ml/nn/common/include/Tracing.h
zawiera makra, które ułatwiają dodawanie informacji o systracingu do kodu sieci neuronowych.
Przykład znajdziesz w NNTRACE_*
wywołaniach makr w przykładowym sterowniku.
Plik frameworks/ml/nn/common/include/GraphDump.h
zawiera funkcję narzędziową do zrzucania zawartości Model
w formie graficznej na potrzeby debugowania.
graphDump
: zapisuje reprezentację modelu w formacie Graphviz.dot
w określonym strumieniu (jeśli jest podany) lub w logcat (jeśli nie podano strumienia).
Weryfikacja
Aby przetestować implementację NNAPI, użyj testów VTS i CTS zawartych w platformie Androida. VTS testuje sterowniki bezpośrednio (bez użycia platformy), a CTS testuje je pośrednio za pomocą platformy. Testy te sprawdzają każdą metodę interfejsu API i weryfikują, czy wszystkie operacje obsługiwane przez sterowniki działają prawidłowo i dają wyniki spełniające wymagania dotyczące precyzji.
Wymagania dotyczące precyzji w testach CTS i VTS dla interfejsu NNAPI są następujące:
Liczby zmiennoprzecinkowe: abs(wartość oczekiwana – wartość rzeczywista) <= atol + rtol * abs(wartość oczekiwana); gdzie:
- W przypadku fp32 atol = 1e-5f, rtol = 5.0f * 1.1920928955078125e-7
- W przypadku fp16: atol = rtol = 5.0f * 0.0009765625f
Skwantyzowane: różnica o 1 (z wyjątkiem
mobilenet_quantized
, gdzie różnica wynosi 3)Wartość logiczna: dopasowanie ścisłe
Jednym ze sposobów testowania NNAPI w ramach CTS jest generowanie stałych pseudolosowych grafów
używanych do testowania i porównywania wyników wykonania każdego sterownika z implementacją referencyjną NNAPI. W przypadku sterowników z NN HAL w wersji 1.2 lub nowszej, jeśli wyniki nie spełniają kryteriów precyzji, CTS zgłasza błąd i zrzuca plik specyfikacji nieudanego modelu w folderze /data/local/tmp
na potrzeby debugowania.
Więcej informacji o kryteriach precyzji znajdziesz w sekcjach TestRandomGraph.cpp
i TestHarness.h
.
Testowanie losowe
Testy fuzzingowe mają na celu wykrywanie awarii, asercji, naruszeń pamięci lub ogólnych niezdefiniowanych zachowań w testowanym kodzie z powodu takich czynników jak nieoczekiwane dane wejściowe. Do testowania NNAPI Android używa testów opartych na libFuzzer, które są skuteczne w testowaniu, ponieważ wykorzystują pokrycie wierszy poprzednich przypadków testowych do generowania nowych losowych danych wejściowych. Na przykład libFuzzer preferuje przypadki testowe, które działają w nowych wierszach kodu. Dzięki temu testy znacznie szybciej wykrywają problematyczny kod.
Aby przeprowadzić testowanie fuzzingowe w celu sprawdzenia implementacji sterownika, zmodyfikuj
frameworks/ml/nn/runtime/test/android_fuzzing/DriverFuzzTest.cpp
w narzędziu testowym libneuralnetworks_driver_fuzzer
znajdującym się w AOSP, aby uwzględnić
kod sterownika. Więcej informacji o testowaniu NNAPI znajdziesz w frameworks/ml/nn/runtime/test/android_fuzzing/README.md
.
Bezpieczeństwo
Procesy aplikacji komunikują się bezpośrednio z procesem sterownika, dlatego sterowniki muszą weryfikować argumenty otrzymywanych wywołań. Ta weryfikacja jest sprawdzana 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.
Android Machine Learning Test Suite
Android Machine Learning Test Suite (MLTS) to test NNAPI uwzględniony w CTS i VTS, który służy do weryfikowania dokładności rzeczywistych modeli na urządzeniach dostawców. Test porównawczy ocenia opóźnienie i dokładność oraz porównuje wyniki sterowników z wynikami uzyskanymi przy użyciu TF Lite działającego na procesorze w przypadku tego samego modelu i zestawów danych. Dzięki temu dokładność sterownika nie będzie gorsza niż w przypadku implementacji referencyjnej procesora.
Programiści platformy Androida używają też MLTS do oceny opóźnienia i dokładności sterowników.
Benchmark NNAPI można znaleźć w 2 projektach w AOSP:
platform/test/mlts/benchmark
(aplikacja testowa)platform/test/mlts/models
(modele i zbiory danych)
Modele i zbiory danych
Test porównawczy NNAPI korzysta z tych modeli i zbiorów danych.
- Model MobileNetV1 w wersji zmiennoprzecinkowej i skwantowanej do 8 bitów w różnych rozmiarach, przetestowany na małym podzbiorze (1500 obrazów) zbioru danych Open Images Dataset v4.
- Model MobileNetV2 w wersji zmiennoprzecinkowej i skwantowanej do 8 bitów w różnych rozmiarach, uruchomiony na małym podzbiorze (1500 obrazów) zbioru danych Open Images Dataset v4.
- Model akustyczny oparty na długiej pamięci krótkotrwałej (LSTM) do syntezy mowy, testowany na niewielkim podzbiorze zbioru CMU Arctic.
- Model akustyczny oparty na LSTM do automatycznego rozpoznawania mowy, uruchamiany na małym podzbiorze zbioru danych LibriSpeech.
Więcej informacji znajdziesz w sekcji platform/test/mlts/models
.
Testy warunków skrajnych
Zestaw testów uczenia maszynowego na Androidzie obejmuje serię testów awaryjnych, które sprawdzają odporność sterowników w warunkach intensywnego użytkowania lub w przypadku nietypowych zachowań klientów.
Wszystkie testy zderzeniowe mają te funkcje:
- Wykrywanie zawieszenia: jeśli klient NNAPI zawiesi się podczas testu, test zakończy się niepowodzeniem z przyczyną
HANG
, a pakiet testów przejdzie do następnego testu. - Wykrywanie awarii klienta NNAPI: testy przetrwają awarie klienta, a testy
zakończą się niepowodzeniem z przyczyną
CRASH
. - Wykrywanie awarii sterownika: testy mogą wykryć awarię sterownika, która powoduje błąd wywołania NNAPI. Pamiętaj, że w procesach sterownika mogą wystąpić awarie, które nie spowodują błędu NNAPI ani nie spowodują niepowodzenia testu. Aby zapobiec tego rodzaju awariom, zalecamy uruchomienie polecenia
tail
w dzienniku systemowym w celu wykrycia błędów lub awarii związanych ze sterownikami. - Kierowanie na wszystkie dostępne akceleratory: testy są przeprowadzane na wszystkich dostępnych sterownikach.
Wszystkie testy zderzeniowe mogą mieć 4 możliwe wyniki:
SUCCESS
: Wykonanie zakończone bez błędu.FAILURE
: nie udało się wykonać. Zwykle jest to spowodowane błędem podczas testowania modelu, co oznacza, że sterownik nie skompilował lub nie wykonał modelu.HANG
: proces testowania przestał odpowiadać.CRASH
: Proces testowania uległ awarii.
Więcej informacji o testach obciążeniowych i pełną listę testów awaryjnych znajdziesz w platform/test/mlts/benchmark/README.txt
.
Korzystanie z MLTS
Aby skorzystać z MLTS:
- Podłącz urządzenie docelowe do stacji roboczej i upewnij się, że jest ono dostępne za pomocą polecenia adb.
Eksportuj zmienną środowiskową urządzenia docelowego
ANDROID_SERIAL
jeśli podłączonych jest więcej niż jedno urządzenie. 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ą 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 Androida i warstwy HAL sieci neuronowych.
Android 11
W Androidzie 11 wprowadzono NN HAL 1.3, który zawiera te ważne zmiany:
- Obsługa kwantyzacji 8-bitowej ze znakiem w NNAPI. Dodaje typ operandu
TENSOR_QUANT8_ASYMM_SIGNED
. Sterowniki z NN HAL 1.3, które obsługują operacje z kwantyzacją bez znaku, muszą też obsługiwać warianty tych operacji ze znakiem. Podczas wykonywania podpisanych i niepodpisanych wersji większości operacji kwantyzowanych sterowniki muszą generować te same wyniki z odchyleniem do 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 operandów ze znakiem, a pozostałe 4 operacje obsługują kwantyzację ze znakiem, ale nie wymagają, aby wyniki były takie same. - Obsługa wykonywania w izolacji, w którym platforma wywołuje metodę
IPreparedModel::executeFenced
, aby uruchomić w izolacji asynchroniczne wykonywanie na przygotowanym modelu z wektorem barier synchronizacji, na które trzeba poczekać. Więcej informacji znajdziesz w artykule Ograniczone wykonywanie. - 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 sekcji Przepływ sterowania. - Lepsza 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ługi.
- Obsługa domen pamięci, które udostępniają interfejsy alokatora dla buforów zarządzanych przez sterownik. Umożliwia to przekazywanie natywnych pamięci urządzenia między wykonaniami, co eliminuje niepotrzebne kopiowanie i przekształcanie danych między kolejnymi wykonaniami na tym samym sterowniku. Więcej informacji znajdziesz w artykule Domeny pamięci.
Android 10
W Androidzie 10 wprowadzono NN HAL 1.2, który zawiera te ważne zmiany:
- Struktura
Capabilities
zawiera wszystkie typy danych, w tym skalarne typy danych, i reprezentuje wydajność bez ograniczeń za pomocą wektora, a nie nazwanych pól. - Metody
getVersionString
igetType
umożliwiają platformie pobieranie informacji o typie (DeviceType
) i wersji urządzenia. Zobacz Odkrywanie i przypisywanie urządzeń. - Metoda
executeSynchronously
jest domyślnie wywoływana w celu synchronicznego wykonania. Metodaexecute_1_2
informuje platformę, że ma wykonać działanie asynchronicznie. Zobacz Podpisanie. - Parametr
MeasureTiming
w przypadkuexecuteSynchronously
,execute_1_2
i wykonywania w serii określa, czy sterownik ma mierzyć czas trwania wykonywania. Wyniki są raportowane w strukturzeTiming
. Zobacz Harmonogram. - Obsługa wykonań, w których co najmniej jeden operand wyjściowy ma nieznany wymiar lub rangę. Zobacz Kształt danych wyjściowych.
- Obsługa rozszerzeń dostawców, czyli zbiorów zdefiniowanych przez dostawców operacji i typów danych. Sterownik zgłasza obsługiwane rozszerzenia za pomocą metody
IDevice::getSupportedExtensions
. Zobacz rozszerzenia dostawcy. - Możliwość kontrolowania przez obiekt burst zestawu wykonań burst za pomocą szybkich kolejek wiadomości (FMQ) do komunikacji między procesami aplikacji i sterownika, co zmniejsza opóźnienie. Zobacz Wykonywanie pakietowe i szybkie kolejki wiadomości.
- Obsługa AHardwareBuffer, która umożliwia sterownikowi wykonywanie operacji bez kopiowania danych. Zobacz AHardwareBuffer.
- Ulepszona obsługa buforowania artefaktów kompilacji, aby skrócić czas kompilacji podczas uruchamiania aplikacji. Zobacz pamięć podręczną kompilacji.
Android 10 wprowadza te typy operandów i operacje.
-
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 aktualizacje wielu dotychczasowych operacji. Aktualizacje dotyczą głównie tych kwestii:
- Obsługa układu pamięci NCHW
- Obsługa tensorów o randze innej niż 4 w operacjach softmax i normalizacji
- Obsługa rozszerzonych splotów
- Obsługa danych wejściowych z mieszaną kwantyzacją w
ANEURALNETWORKS_CONCATENATION
Poniżej znajdziesz listę operacji, które zostały zmodyfikowane w Androidzie 10. Szczegółowe informacje o zmianach znajdziesz w OperationCode w dokumentacji 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 istotne zmiany:
IDevice::prepareModel_1_1
zawiera parametrExecutionPreference
. Może to pomóc kierowcy w dostosowaniu przygotowań, ponieważ wie, że aplikacja woli oszczędzać baterię lub będzie wykonywać model w szybkich, kolejnych wywołaniach.- Dodaliśmy 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 zmiennoprzecinkowe 32-bitowe mogą być wykonywane przy użyciu zakresu i/lub precyzji zmiennoprzecinkowej 16-bitowej, ustawiając wartość
Model.relaxComputationFloat32toFloat16
natrue
. StrukturaCapabilities
ma dodatkowe polerelaxedFloat32toFloat16Performance
, dzięki czemu sterownik może zgłaszać do platformy swoje obniżone wymagania dotyczące wydajności.
Android 8.1
Początkowa warstwa HAL sieci neuronowych (1.0) została opublikowana w Androidzie 8.1. Więcej informacji znajdziesz w sekcji /neuralnetworks/1.0/
.