Delegacje GPU dla TensorFlow Lite

Zastosowanie procesorów graficznych (GPU) do uruchamiania modeli systemów uczących się może znacznie zwiększyć wydajność modelu i wygodę użytkowników aplikacji obsługujących systemy uczące się. TensorFlow Lite umożliwia korzystanie z procesorów graficznych i innych wyspecjalizowanych procesorów za pomocą sterownika sprzętowego nazywanego delegates. Włączenie procesorów graficznych w aplikacjach TensorFlow Lite ML może przynieść te korzyści:

  • Szybkość – procesory graficzne są zaprojektowane z myślą o dużej przepustowości przy masowo równoległych zadaniach. Taka konstrukcja sprawia, że są one szczególnie przydatne w przypadku głębokich sieci neuronowych, które składają się z dużej liczby operatorów. Każdy z nich pracuje na tensorach wejściowych, które można przetwarzać równolegle, co zwykle skraca czas oczekiwania. W najlepszym przypadku uruchomienie modelu na GPU może działać z wystarczającą szybkością, aby umożliwić działanie aplikacji w czasie rzeczywistym, które wcześniej nie były możliwe.
  • Wydajność energetyczna – procesory graficzne wykonują obliczenia za pomocą systemów uczących się w bardzo skuteczny 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ługiwanych GPU w TensorFlow Lite, a także niektóre zaawansowane zastosowania procesorów GPU. Więcej informacji o wdrażaniu obsługi GPU na określonych platformach znajdziesz w tych przewodnikach:

Obsługa operacji GPU ML

Istnieją pewne ograniczenia dotyczące operacji, czyli operacji TensorFlow ML, które mogą być przyspieszane przez delegata GPU TensorFlow Lite. Delegat obsługuje te operacje z 16-bitową i 32-bitową precyzją zmiennoprzecinkową:

  • ADD
  • AVERAGE_POOL_2D
  • CONCATENATION
  • CONV_2D
  • DEPTHWISE_CONV_2D v1-2
  • EXP
  • FULLY_CONNECTED
  • LOGICAL_AND
  • LOGISTIC
  • LSTM v2 (Basic LSTM only)
  • MAX_POOL_2D
  • MAXIMUM
  • MINIMUM
  • MUL
  • PAD
  • PRELU
  • RELU
  • RELU6
  • RESHAPE
  • RESIZE_BILINEAR v1-3
  • SOFTMAX
  • STRIDED_SLICE
  • SUB
  • TRANSPOSE_CONV

Domyślnie wszystkie operacje są obsługiwane tylko w wersji 1. Włączenie obsługi kwantyzacji włącza odpowiednie wersje, np. DODAJ wersję 2.

Rozwiązywanie problemów z obsługą GPU

Jeśli niektóre działania nie są obsługiwane przez delegata GPU, platforma uruchomi tylko część wykresu na GPU, a pozostałą część na procesorze. Ze względu na wysokie koszty synchronizacji CPU/GPU taki tryb podzielonego wykonywania często powoduje wolniejsze działanie niż gdy cała sieć działa na samym procesorze. W takim przypadku aplikacja generuje ostrzeżenie, takie jak:

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 podczas działania. Zwracaj uwagę na te ostrzeżenia, testując wykonanie modelu z osobą z przekazanym dostępem do GPU. Duża liczba tych ostrzeżeń może oznaczać, że Twój model nie najlepiej nadaje się do akceleracji GPU i może wymagać refaktoryzacji modelu.

Przykładowe modele

Poniższe przykładowe modele zostały utworzone z myślą o korzystaniu z akceleracji GPU w przypadku TensorFlow Lite i są udostępnione w celach informacyjnych i testowych:

Optymalizuję pod kątem GPU

Poniższe techniki mogą pomóc w uzyskaniu lepszej wydajności podczas uruchamiania modeli na sprzęcie GPU z użyciem delegata GPU TensorFlow Lite:

  • Zmiana kształtu operacji – niektóre operacje, które są szybkie na procesorach, mogą powodować wysokie koszty GPU na urządzeniach mobilnych. Operacje zmiany kształtu są szczególnie kosztowne, takie jak BATCH_TO_SPACE, SPACE_TO_BATCH, SPACE_TO_DEPTH itp. Musisz uważnie przyjrzeć się wykorzystaniu operacji zmiany kształtu i zastanów się, że mogły one zostać zastosowane tylko do eksploracji danych lub we wczesnych iteracjach modelu. Ich usunięcie może znacznie poprawić wydajność.

  • Kanały danych obrazu – w przypadku GPU dane tensora są podzielone na 4 kanały, więc obliczenia na tensorze o kształcie [B,H,W,5] dają podobne wyniki w przypadku tensora kształtu [B,H,W,8], ale znacznie gorsze niż w przypadku elementu [B,H,W,4]. Jeśli używany aparat obsługuje klatki obrazu w formacie RGBA, przesyłanie obrazu z 4-kanałowego wejścia odbywa się znacznie szybciej, ponieważ unikamy kopiowania pamięci z 3-kanałowego RGB na 4-kanałowy RGBX.

  • Modele zoptymalizowane pod kątem urządzeń mobilnych – aby uzyskać najlepszą skuteczność, spróbuj ponownie wytrenować klasyfikator, korzystając z architektury sieci zoptymalizowanej pod kątem urządzeń mobilnych. Dzięki wykorzystaniu funkcji sprzętu mobilnego optymalizacja pod kątem wnioskowania na urządzeniu może znacznie zmniejszyć opóźnienia i zużycie energii.

Zaawansowana obsługa GPU

W przypadku przetwarzania GPU możesz korzystać z dodatkowych, zaawansowanych metod, aby zapewnić jeszcze lepszą wydajność modeli, w tym kwantyzację i serializację. W poniższych sekcjach szczegółowo opisano te techniki.

Używanie modeli kwantyzowanych

W tej sekcji wyjaśniamy, jak delegat GPU przyspiesza 8-bitowe modele poddane kwantyzacji, w tym:

Aby zoptymalizować wydajność, używaj modeli zawierających zarówno tensory wejściowe i wyjściowe, jak i zmiennoprzecinkowe.

Jak to działa?

Backend GPU obsługuje tylko wykonywanie zmiennoprzecinkowe, więc uruchamiamy modele poddane kwantyzacji, nadając mu „widok zmiennoprzecinkowy” oryginalnego modelu. Ogólnie oznacza to, że:

  • Tensory stałe (np. wagi/odchylenia) są dekwantyzowane raz w pamięci GPU. Ta operacja ma miejsce, gdy delegat jest włączony dla TensorFlow Lite.

  • Dane wejściowe i wyjściowe przesyłane do programu GPU, jeśli 8-bitowe dane są poddawane kwantyzacji, są poddawane kwantyzacji i kwantyzowane (odpowiednio) w przypadku każdego wnioskowania. Ta operacja jest wykonywana na procesorze za pomocą zoptymalizowanych jąder TensorFlow Lite.

  • Symulatory kwantyzacji są wstawiane między operacjami, aby naśladować zachowanie skwantyzowane. To podejście jest niezbędne w przypadku modeli, w przypadku których operacje oczekują, że aktywacje będą zgodne z granicami ustalonymi podczas kwantyzacji.

Informacje o włączaniu tej funkcji za pomocą delegata GPU znajdziesz w tych artykułach:

Skrócenie czasu inicjowania dzięki serializacji

Funkcja delegowania GPU umożliwia wczytywanie ze wstępnie skompilowanego kodu jądra oraz danych modelu zserializowanych i zapisanych na dysku z poprzednich uruchomień. To podejście pozwala uniknąć ponownej kompilacji i skrócić czas uruchamiania nawet o 90%. Jest to możliwe dzięki zamianie miejsca na dysku na oszczędzanie czasu. Możesz włączyć tę funkcję za pomocą kilku opcji konfiguracji, tak jak w tych przykładach 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);
      

Jeśli korzystasz z funkcji serializacji, upewnij się, że Twój kod jest zgodny z tymi regułami implementacji:

  • Przechowuj dane serializacji w katalogu, który nie jest dostępny dla innych aplikacji. Na urządzeniach z Androidem parametr getCodeCacheDir() wskazuje lokalizację, która jest prywatna dla bieżącej aplikacji.
  • Token modelu musi być unikalny dla urządzenia konkretnego modelu. Token modelu możesz obliczyć, generując odcisk cyfrowy na podstawie danych modelu za pomocą bibliotek takich jak farmhash::Fingerprint64.