Delegaty umożliwiają akcelerację sprzętową modeli LiteRT dzięki wykorzystaniu akceleratorów na urządzeniu, takich jak GPU i procesor sygnałowy (DSP).
Domyślnie LiteRT korzysta z jąder procesora zoptymalizowanych pod kątem zestawu instrukcji ARM Neon. Procesor to jednak procesor wielofunkcyjny, który niekoniecznie jest zoptymalizowany pod kątem złożonych obliczeń arytmetycznych typowych dla modeli uczenia maszynowego (np. obliczeń macierzowych w warstwach splotowych i gęstych).
Z drugiej strony większość nowoczesnych telefonów komórkowych zawiera układy, które lepiej radzą sobie z takimi złożonymi operacjami. Wykorzystanie ich do operacji sieci neuronowych daje ogromne korzyści w zakresie opóźnień i efektywności energetycznej. Na przykład procesory GPU mogą zapewnić nawet 5-krotne przyspieszenie w zakresie opóźnienia.
Każdy z tych akceleratorów ma powiązane interfejsy API, które umożliwiają niestandardowe obliczenia, np. OpenCL lub OpenGL ES w przypadku mobilnego procesora graficznego. Zwykle do uruchomienia sieci neuronowej za pomocą tych interfejsów trzeba napisać dużo kodu niestandardowego. Sytuacja staje się jeszcze bardziej skomplikowana, gdy weźmiesz pod uwagę, że każdy akcelerator ma swoje zalety i wady oraz nie może wykonywać wszystkich operacji w sieci neuronowej. Interfejs Delegate API TensorFlow Lite rozwiązuje ten problem, działając jako pomost między środowiskiem wykonawczym TFLite a tymi interfejsami API niższego poziomu.

Wybieranie osoby upoważnionej
LiteRT obsługuje wielu delegatów, z których każdy jest zoptymalizowany pod kątem określonych platform i typów modeli. Zwykle w zależności od 2 głównych kryteriów: platformy (Android lub iOS), na którą kierujesz aplikację, i typu modelu (zmiennoprzecinkowy lub skwantyzowany), który chcesz przyspieszyć, dostępnych jest wiele delegatów.
Delegaci według platformy
Na wielu platformach (Android i iOS)
- Delegat GPU – delegata GPU można używać zarówno na Androidzie, jak i iOS. Jest zoptymalizowany pod kątem uruchamiania modeli 32-bitowych i 16-bitowych opartych na liczbach zmiennoprzecinkowych, w których dostępny jest procesor graficzny. Obsługuje też 8-bitowe modele skwantyzowane i zapewnia wydajność GPU porównywalną z wersjami zmiennoprzecinkowymi. Szczegółowe informacje o delegacie GPU znajdziesz w artykule LiteRT na GPU.
iOS
- Delegat Core ML na nowsze iPhone'y i iPady – na nowszych iPhone'ach i iPadach, na których dostępny jest Neural Engine, możesz używać delegata Core ML, aby przyspieszyć wnioskowanie w przypadku modeli zmiennoprzecinkowych 32-bitowych lub 16-bitowych. Neural Engine jest dostępny na urządzeniach mobilnych Apple z układem SoC A12 lub nowszym. Omówienie delegata Core ML i szczegółowe instrukcje znajdziesz w artykule Delegat LiteRT Core ML.
Delegowanie według typu modelu
Każdy akcelerator jest zaprojektowany z myślą o określonej szerokości bitowej danych. Jeśli przekażesz model zmiennoprzecinkowy do delegata, który obsługuje tylko 8-bitowe operacje kwantyzowane, odrzuci on wszystkie operacje, a model będzie działać w całości na procesorze. Aby uniknąć takich niespodzianek, w tabeli poniżej znajdziesz przegląd obsługi delegowania w zależności od typu modelu:
| Typ modelu | GPU | CoreML |
|---|---|---|
| Liczba zmiennoprzecinkowa (32-bitowa) | Tak | Tak |
| Kwantyzacja po trenowaniu w formacie float16 | Tak | Tak |
| Kwantyzacja zakresu dynamicznego po wytrenowaniu | Tak | Nie |
| Kwantyzacja liczb całkowitych po trenowaniu | Tak | Nie |
| Trenowanie z uwzględnieniem kwantyzacji | Tak | Nie |
Sprawdzanie skuteczności
Informacje w tej sekcji stanowią ogólne wytyczne dotyczące wyboru delegatów, którzy mogą ulepszyć Twoją aplikację. Należy jednak pamiętać, że każdy delegat ma predefiniowany zestaw obsługiwanych operacji i może działać inaczej w zależności od modelu i urządzenia. Dlatego zwykle zalecamy przeprowadzenie testów porównawczych, aby ocenić, jak przydatny jest delegat w Twoim przypadku. Pomaga to również uzasadnić zwiększenie rozmiaru pliku binarnego związanego z dołączeniem delegata do środowiska wykonawczego LiteRT.
LiteRT ma rozbudowane narzędzia do oceny wydajności i dokładności, które mogą zapewnić deweloperom pewność co do używania delegatów w aplikacji. Narzędzia te omówimy w następnej sekcji.
Narzędzia do oceny
Opóźnienie i wykorzystanie pamięci
Narzędzie benchmarkowe LiteRT można stosować z odpowiednimi parametrami do szacowania wydajności modelu, w tym średniego opóźnienia wnioskowania, kosztów inicjowania, zajętości pamięci itp. To narzędzie obsługuje wiele flag, które pomagają określić najlepszą konfigurację delegata dla Twojego modelu. Na przykład --gpu_backend=gl można określić za pomocą --use_gpu, aby mierzyć wykonywanie GPU za pomocą OpenGL. Pełna lista obsługiwanych parametrów delegowania jest dostępna w szczegółowej dokumentacji.
Oto przykład uruchomienia skwantyzowanego modelu z GPU za pomocą adb:
adb shell /data/local/tmp/benchmark_model \
--graph=/data/local/tmp/mobilenet_v1_224_quant.tflite \
--use_gpu=true
Gotową wersję tego narzędzia na Androida z architekturą 64-bitową ARM możesz pobrać tutaj (więcej informacji).
Dokładność i poprawność
Delegaty zwykle wykonują obliczenia z inną precyzją niż ich odpowiedniki na procesorze. W związku z tym korzystanie z delegata na potrzeby akceleracji sprzętowej wiąże się z (zwykle niewielkim) kompromisem w zakresie dokładności. Pamiętaj, że nie zawsze tak jest.Na przykład GPU używa precyzji zmiennoprzecinkowej do uruchamiania modeli skwantyzowanych, więc może nastąpić niewielka poprawa precyzji (np. Poprawa o mniej niż 1% w klasyfikacji obrazów ILSVRC w przypadku 5 najlepszych wyników).
LiteRT ma 2 rodzaje narzędzi do pomiaru dokładności działania delegata w przypadku danego modelu: oparte na zadaniach i niezależne od zadań. Wszystkie narzędzia opisane w tej sekcji obsługują parametry delegowania zaawansowanego używane przez narzędzie do testów porównawczych z poprzedniej sekcji. Pamiętaj, że podrozdziały poniżej skupiają się na ocenie delegowania (czy delegat działa tak samo jak procesor?), a nie na ocenie modelu (czy model jest odpowiedni do danego zadania?).
Ocena na podstawie zadań
LiteRT zawiera narzędzia do oceny poprawności w przypadku 2 zadań opartych na obrazach:
ILSVRC 2012 (klasyfikacja obrazów) z dokładnością top-K
Wykrywanie obiektów COCO (z ramkami ograniczającymi) z średnią precyzją
Wstępnie skompilowane pliki binarne tych narzędzi (Android, architektura 64-bitowa ARM) wraz z dokumentacją znajdziesz tutaj:
Poniższy przykład pokazuje ocenę klasyfikacji obrazów za pomocą procesora GPU na Pixelu 4:
adb shell /data/local/tmp/run_eval \
--model_file=/data/local/tmp/mobilenet_quant_v1_224.tflite \
--ground_truth_images_path=/data/local/tmp/ilsvrc_images \
--ground_truth_labels=/data/local/tmp/ilsvrc_validation_labels.txt \
--model_output_labels=/data/local/tmp/model_output_labels.txt \
--output_file_path=/data/local/tmp/accuracy_output.txt \
--num_images=0 # Run on all images. \
--use_gpu=true
Oczekiwane dane wyjściowe to lista wartości Top-K od 1 do 10:
Top-1 Accuracy: 0.733333
Top-2 Accuracy: 0.826667
Top-3 Accuracy: 0.856667
Top-4 Accuracy: 0.87
Top-5 Accuracy: 0.89
Top-6 Accuracy: 0.903333
Top-7 Accuracy: 0.906667
Top-8 Accuracy: 0.913333
Top-9 Accuracy: 0.92
Top-10 Accuracy: 0.923333
Ocena niezależna od zadania
W przypadku zadań, dla których nie ma ustalonego narzędzia do oceny na urządzeniu, lub jeśli eksperymentujesz z modelami niestandardowymi, LiteRT ma narzędzie Różnica w zakresie wnioskowania. (Android, 64-bitowa architektura binarna ARM tutaj)
Różnica wnioskowania porównuje wykonanie LiteRT (pod względem opóźnienia i odchylenia wartości wyjściowej) w 2 ustawieniach:
- Wnioskowanie na procesorze jednowątkowym
- Wnioskowanie zdefiniowane przez użytkownika – zdefiniowane przez te parametry
W tym celu narzędzie generuje losowe dane Gaussa i przekazuje je do 2 interpreterów TFLite – jeden z nich uruchamia jądra procesora z pojedynczym wątkiem, a drugi jest sparametryzowany argumentami użytkownika.
Mierzy opóźnienie obu tych elementów, a także bezwzględną różnicę między tensorami wyjściowymi każdego interpretera na poziomie poszczególnych elementów.
W przypadku modelu z jednym tensorem wyjściowym dane wyjściowe mogą wyglądać tak:
Num evaluation runs: 50
Reference run latency: avg=84364.2(us), std_dev=12525(us)
Test run latency: avg=7281.64(us), std_dev=2089(us)
OutputDiff[0]: avg_error=1.96277e-05, std_dev=6.95767e-06
Oznacza to, że w przypadku tensora wyjściowego o indeksie 0 elementy z danych wyjściowych procesora różnią się od danych wyjściowych delegata średnio o 1.96e-05.
Pamiętaj, że interpretacja tych liczb wymaga głębszej wiedzy o modelu i o tym, co oznacza każdy tensor wyjściowy. Jeśli jest to prosta regresja, która określa jakiś rodzaj wyniku lub osadzania, różnica powinna być niewielka (w przeciwnym razie jest to błąd w delegacie). Dane wyjściowe, takie jak „klasa wykrywania” z modeli SSD, są jednak nieco trudniejsze do interpretacji. Na przykład to narzędzie może wykazać różnicę, ale nie musi to oznaczać, że z delegatem jest coś nie tak. Rozważmy 2 (fikcyjne) klasy: „Telewizor (ID: 10)” i „Monitor (ID: 20)”. Jeśli delegat jest nieco odchylony od prawdy i zamiast telewizora pokazuje monitor, różnica w danych wyjściowych dla tego tensora może wynosić nawet 20–10 = 10.