Używanie procesorów graficznych (GPU) do uruchamiania modeli uczenia maszynowego (ML) może znacznie zwiększyć wydajność modelu i poprawić komfort korzystania z aplikacji wykorzystujących ML. LiteRT umożliwia korzystanie z procesorów graficznych i innych procesorów specjalistycznych za pomocą sterownika sprzętowego zwanego delegatami. Włączenie obsługi procesorów graficznych w aplikacjach ML LiteRT może przynieść te korzyści:
- Szybkość – procesory graficzne są przeznaczone do obsługi zadań o wysokiej przepustowości, które można wykonywać równolegle. Dzięki temu doskonale nadają się do głębokich sieci neuronowych, które składają się z ogromnej liczby operatorów, z których każdy przetwarza tensory wejściowe, które można przetwarzać równolegle, co zwykle skutkuje mniejszym opóźnieniem. W najlepszym przypadku uruchomienie modelu na procesorze graficznym może być wystarczająco szybkie, aby umożliwić działanie aplikacji w czasie rzeczywistym, co wcześniej nie było możliwe.
- Energooszczędność – układy GPU wykonują obliczenia związane z uczeniem maszynowym w bardzo wydajny i zoptymalizowany sposób, zwykle zużywając mniej energii i generując mniej ciepła niż to samo zadanie uruchomione na procesorach.
Ten dokument zawiera omówienie obsługi procesorów graficznych w LiteRT oraz kilka zaawansowanych zastosowań procesorów graficznych. Bardziej szczegółowe informacje o wdrażaniu obsługi GPU na konkretnych platformach znajdziesz w tych przewodnikach:
Obsługa operacji ML na GPU
Istnieją pewne ograniczenia dotyczące tego, które operacje uczenia maszynowego TensorFlow, czyli operacje, mogą być przyspieszane przez delegata GPU LiteRT. Delegat obsługuje te operacje z 16-bitową i 32-bitową precyzją zmiennoprzecinkową:
ADDAVERAGE_POOL_2DCONCATENATIONCONV_2DDEPTHWISE_CONV_2D v1-2EXPFULLY_CONNECTEDLOGICAL_ANDLOGISTICLSTM v2 (Basic LSTM only)MAX_POOL_2DMAXIMUMMINIMUMMULPADPRELURELURELU6RESHAPERESIZE_BILINEAR v1-3SOFTMAXSTRIDED_SLICESUBTRANSPOSE_CONV
Domyślnie wszystkie operacje są obsługiwane tylko w wersji 1. Włączenie obsługi kwantyzacji powoduje włączenie odpowiednich wersji, np. ADDv2.
Rozwiązywanie problemów z obsługą GPU
Jeśli niektóre operacje nie są obsługiwane przez delegata GPU, platforma uruchomi tylko część wykresu na GPU, a pozostałą część na CPU. Ze względu na wysoki koszt synchronizacji procesora i GPU tryb wykonywania dzielonego, taki jak ten, często skutkuje niższą wydajnością niż w przypadku, gdy cała sieć jest uruchamiana tylko na procesorze. W takim przypadku aplikacja wygeneruje ostrzeżenie, np.:
WARNING: op code #42 cannot be handled by this delegate.
W przypadku błędów tego typu nie ma wywołania zwrotnego, ponieważ nie jest to rzeczywisty błąd w czasie działania. Podczas testowania wykonywania modelu za pomocą delegata GPU zwróć uwagę na te ostrzeżenia. Duża liczba tych ostrzeżeń może wskazywać, że model nie jest najlepiej przystosowany do akceleracji GPU i może wymagać refaktoryzacji.
Przykładowe modele
Poniższe przykładowe modele zostały opracowane z myślą o wykorzystaniu akceleracji GPU za pomocą LiteRT i są udostępniane w celach referencyjnych i testowych:
- Klasyfikacja obrazów MobileNet v1 (224x224)
- Model klasyfikacji obrazów przeznaczony do aplikacji wizyjnych na urządzenia mobilne i wbudowane.
(model)
* Segmentacja DeepLab (257 x 257)
- model segmentacji obrazu, który przypisuje etykiety semantyczne, takie jak pies, kot, samochód, do każdego piksela na obrazie wejściowym.
(model)
* Wykrywanie obiektów za pomocą MobileNet SSD
- Model klasyfikacji obrazów, który wykrywa wiele obiektów z ramkami ograniczającymi.
(model)
* PoseNet do szacowania pozycji
- Model wizyjny, który szacuje pozy osób na obrazie lub filmie. (model)
- Model klasyfikacji obrazów, który wykrywa wiele obiektów z ramkami ograniczającymi.
(model)
* PoseNet do szacowania pozycji
- model segmentacji obrazu, który przypisuje etykiety semantyczne, takie jak pies, kot, samochód, do każdego piksela na obrazie wejściowym.
(model)
* Wykrywanie obiektów za pomocą MobileNet SSD
- Model klasyfikacji obrazów przeznaczony do aplikacji wizyjnych na urządzenia mobilne i wbudowane.
(model)
* Segmentacja DeepLab (257 x 257)
Optymalizacja pod kątem procesorów GPU
Te techniki mogą pomóc Ci zwiększyć skuteczność modeli uruchamianych na sprzęcie GPU za pomocą delegata LiteRT GPU:
Operacje zmiany kształtu – niektóre operacje, które są szybkie na procesorze, mogą być kosztowne dla procesora graficznego na urządzeniach mobilnych. Operacje zmiany kształtu są szczególnie kosztowne, w tym
BATCH_TO_SPACE,SPACE_TO_BATCH,SPACE_TO_DEPTHitd. Dokładnie przeanalizuj użycie operacji zmiany kształtu i pamiętaj, że mogły one zostać zastosowane tylko do eksplorowania danych lub w pierwszych iteracjach modelu. Usunięcie ich może znacząco poprawić skuteczność.Kanały danych obrazu – na procesorze graficznym dane tensora są dzielone na 4 kanały, więc obliczenia na tensorze o kształcie
[B,H,W,5]są wykonywane w przybliżeniu tak samo jak na tensorze o kształcie[B,H,W,8], ale znacznie gorzej niż na tensorze o kształcie[B,H,W,4]. Jeśli używany sprzęt kamery obsługuje ramki obrazu w formacie RGBA, podawanie danych wejściowych 4-kanałowych jest znacznie szybsze, ponieważ pozwala uniknąć kopiowania z pamięci z 3-kanałowego formatu RGB do 4-kanałowego formatu RGBX.Modele zoptymalizowane pod kątem urządzeń mobilnych – aby uzyskać najlepsze wyniki, warto ponownie wytrenować klasyfikator z użyciem architektury sieci zoptymalizowanej pod kątem urządzeń mobilnych. Optymalizacja pod kątem wnioskowania na urządzeniu może znacznie skrócić czas oczekiwania i zmniejszyć zużycie energii dzięki wykorzystaniu funkcji sprzętowych urządzenia mobilnego.
Zaawansowana obsługa GPU
Możesz używać dodatkowych, zaawansowanych technik przetwarzania na GPU, aby jeszcze bardziej zwiększyć skuteczność modeli, w tym kwantyzacji i serializacji. W sekcjach poniżej znajdziesz szczegółowe informacje o tych technikach.
Korzystanie ze skwantyzowanych modeli
Z tej sekcji dowiesz się, jak delegat GPU przyspiesza 8-bitowe modele skwantyzowane, w tym:
- Modele wytrenowane za pomocą trenowania z uwzględnieniem kwantyzacji
- Kwantyzacja dynamiczna po szkoleniu
- Kwantyzacja pełnoliczbowa po trenowaniu
Aby zoptymalizować wydajność, używaj modeli, które mają zarówno wejściowe, jak i wyjściowe tensory zmiennoprzecinkowe.
Jak to działa?
Backend GPU obsługuje tylko wykonywanie operacji na liczbach zmiennoprzecinkowych, dlatego uruchamiamy modele skwantyzowane, udostępniając im „widok zmiennoprzecinkowy” oryginalnego modelu. Ogólnie rzecz biorąc, obejmuje to te czynności:
Stałe tensory (np. wagi lub odchylenia) są dekwantyzowane raz do pamięci GPU. Ta operacja jest wykonywana, gdy delegat jest włączony w przypadku LiteRT.
Dane wejściowe i wyjściowe programu GPU, jeśli są skwantowane w 8-bitowej precyzji, są dekwantowane i kwantowane (odpowiednio) dla każdego wnioskowania. Ta operacja jest wykonywana na procesorze przy użyciu zoptymalizowanych jąder LiteRT.
Symulatory kwantyzacji są wstawiane między operacjami, aby naśladować skwantyzowane zachowanie. Jest to konieczne w przypadku modeli, w których operacje mają być aktywowane w zakresach wyznaczonych podczas kwantyzacji.
Informacje o włączaniu tej funkcji za pomocą delegata GPU znajdziesz w tych artykułach:
- Korzystanie z skwantyzowanych modeli z GPU na Androidzie
- Korzystanie z skwantyzowanych modeli z GPU na iOS
Skracanie czasu inicjowania za pomocą serializacji
Funkcja delegata GPU umożliwia wczytywanie wstępnie skompilowanego kodu jądra i danych modelu serializowanych i zapisywanych na dysku z poprzednich uruchomień. Takie podejście pozwala uniknąć ponownej kompilacji i skrócić czas uruchamiania nawet o 90%. To ulepszenie jest możliwe dzięki wymianie miejsca na dysku na oszczędność czasu. Możesz włączyć tę funkcję za pomocą kilku opcji konfiguracji, jak pokazują poniższe przykłady kodu:
C++
TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default(); options.experimental_flags |= TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_SERIALIZATION; options.serialization_dir = kTmpDir; options.model_token = kModelToken; auto* delegate = TfLiteGpuDelegateV2Create(options); if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
Java
GpuDelegate delegate = new GpuDelegate( new GpuDelegate.Options().setSerializationParams( /* serializationDir= */ serializationDir, /* modelToken= */ modelToken)); Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);
Podczas korzystania z funkcji serializacji upewnij się, że Twój kod jest zgodny z tymi zasadami implementacji:
- Przechowuj dane serializacji w katalogu, do którego inne aplikacje nie mają dostępu. Na urządzeniach z Androidem używaj
getCodeCacheDir()wskazującego lokalizację prywatną dla bieżącej aplikacji. - Token modelu musi być unikalny dla urządzenia w przypadku danego modelu. Token modelu możesz obliczyć, generując odcisk palca na podstawie danych modelu za pomocą bibliotek takich jak
farmhash::Fingerprint64.