Delegacje GPU dla TensorFlow Lite

Użycie jednostek procesora graficznego (GPU) do uruchamiania modeli uczenia maszynowego może znacznie poprawić wydajność modelu i wygodę użytkowników aplikacji korzystających z tego systemu. TensorFlow Lite umożliwia korzystanie z GPU i innych wyspecjalizowanych procesorów za pomocą sterownika sprzętowego o nazwie delegaty. Włączenie korzystania z GPU w aplikacjach TensorFlow Lite ML może przynieść te korzyści:

  • Szybkość – GPU są tworzone z myślą o dużej przepustowości bardzo równoległych zadań. Taka konstrukcja sprawia, że dobrze nadają się do stosowania głębokich sieci neuronowych, które składają się z ogromnej liczby operatorów, z których każdy pracuje nad tensorami wejściowymi, które można przetwarzać równolegle, co zwykle skraca czas oczekiwania. W najlepszym przypadku uruchomienie modelu z GPU może działać wystarczająco szybko, by umożliwić działanie aplikacji w czasie rzeczywistym, które wcześniej nie były możliwe.
  • Oszczędzanie energii – GPU wykonuje obliczenia związane z systemami uczącymi się w bardzo wydajny i zoptymalizowany sposób, zwykle zużywając mniej energii i generując mniej ciepła niż w przypadku tego samego zadania wykonywanego na procesorach.

Ten dokument zawiera omówienie obsługiwanych GPU w TensorFlow Lite i niektórych zaawansowanych zastosowań z procesorami GPU. Bardziej szczegółowe informacje o wdrażaniu obsługi GPU na konkretnych platformach znajdziesz w tych przewodnikach:

Obsługa operacji GPU ML

Istnieją pewne ograniczenia co do tego, jakie operacje (operacje TensorFlow ML) mogą być przyspieszone przez delegację GPU TensorFlow Lite. Delegat obsługuje te operacje z 16- 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, na przykład ADD v2.

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

Jeśli niektóre operacje nie są obsługiwane przez delegację GPU, platforma uruchomi tylko część grafu w GPU, a resztę na procesorze CPU. Ze względu na wysokie koszty synchronizacji CPU/GPU taki tryb podzielonego wykonywania kodu często powoduje wolniejsze działanie niż przy korzystaniu z samego procesora w całej sieci. W takim przypadku aplikacja wygeneruje ostrzeżenie, na przykład:

WARNING: op code #42 cannot be handled by this delegate.

Nie ma wywołania zwrotnego dla błędów tego typu, ponieważ nie jest to rzeczywisty błąd środowiska wykonawczego. Gdy testujesz wykonanie modelu z użyciem delegowanego GPU, musisz zwracać uwagę na te ostrzeżenia. Duża liczba tych ostrzeżeń może wskazywać, że Twój model nie najlepiej nadaje się do przyspieszania za pomocą GPU i może wymagać refaktoryzacji modelu.

Przykładowe modele

Te przykładowe modele zostały opracowane z myślą o wykorzystaniu akceleracji GPU za pomocą TensorFlow Lite i są dostępne do celów referencyjnych i testowania:

Optymalizacja pod kątem GPU

Opisane tu techniki mogą pomóc Ci uzyskać lepszą wydajność w przypadku uruchamiania modeli na sprzęcie GPU z wykorzystaniem delegacji GPU TensorFlow Lite:

  • Operacje zmiany kształtu – niektóre operacje, które są szybkie na procesorze, mogą wiązać się z wysokim kosztem GPU na urządzeniach mobilnych. Wykonywanie operacji zmiany kształtu jest szczególnie kosztowne, np. BATCH_TO_SPACE, SPACE_TO_BATCH czy SPACE_TO_DEPTH. Trzeba dokładnie przeanalizować użycie operacji zmiany kształtu i wziąć pod uwagę, że mogły one zostać zastosowane tylko do eksploracji danych lub wczesnych iteracji modelu. Usunięcie ich może znacznie poprawić skuteczność.

  • Kanały danych obrazu – w przypadku GPU dane tensora są dzielone na 4 kanały, więc obliczenia na tensorze o kształcie [B,H,W,5] są mniej więcej takie same na tensorze o kształcie [B,H,W,8], ale znacznie gorzej niż [B,H,W,4]. Jeśli używany aparat obsługuje ramki obrazu w formacie RGBA, przesyłanie obrazu z 4-kanałowego źródła danych jest znacznie szybsze, ponieważ pozwala uniknąć kopiowania z pamięci 3-kanałowej RGB na 4-kanałową RGBX.

  • Modele zoptymalizowane pod kątem urządzeń mobilnych – aby uzyskać najlepszą skuteczność, spróbuj ponownie przetrenować klasyfikator z architekturą sieci zoptymalizowaną pod kątem urządzeń mobilnych. Optymalizacja pod kątem wnioskowania na urządzeniu może znacznie zmniejszyć czas oczekiwania i zużycie energii dzięki wykorzystaniu funkcji sprzętu mobilnego.

Zaawansowana obsługa GPU

Aby zapewnić jeszcze większą wydajność modeli, w tym kwantyzacji i serializacji, możesz użyć dodatkowych, zaawansowanych technik przetwarzania GPU. W sekcjach poniżej szczegółowo opisujemy te metody.

Korzystanie z modeli kwantowych

W tej sekcji wyjaśniamy, jak delegowany GPU przyspiesza 8-bitowe modele kwantyzowane, w tym:

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

Jak to działa?

Backend GPU obsługuje tylko wykonywanie zmiennoprzecinkowe, dlatego uruchamiamy kwantyzowane modele, zapewniając mu „widok zmiennoprzecinkowy” oryginalnego modelu. Ogólnie obejmuje to te czynności:

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

  • Dane wejściowe i wyjściowe do programu GPU, w przypadku kwantyzacji 8-bitowej, są dekwantyzowane i (odpowiednio) poddane kwantyzacji w przypadku każdego wnioskowania. Ta operacja jest wykonywana na CPU z użyciem zoptymalizowanych jąder TensorFlow Lite.

  • Symulatory kwantyzacji są umieszczane między operacjami, aby naśladować poddane kwantyzacji zachowanie. To podejście jest konieczne w przypadku modeli, w których operatorzy oczekują, że aktywacje będą spełniać granice ustalone podczas kwantyzacji.

Informacje o włączaniu tej funkcji z użyciem delegata GPU znajdziesz w tych artykułach:

Skrócenie czasu inicjowania za pomocą serializacji

Funkcja przekazywania dostępu do GPU umożliwia wczytywanie ze wstępnie skompilowanego kodu jądra oraz zserializowanych i zapisanych na dysku danych modelu z poprzednich uruchomień. Takie podejście pozwala uniknąć ponownej kompilacji i może skrócić czas uruchamiania nawet o 90%. Jest to możliwe dzięki zamianie miejsca na dysku w celu zaoszczędzenia czasu. Możesz włączyć tę funkcję, wybierając kilka 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 użyj parametru getCodeCacheDir(), który wskazuje lokalizację, która jest prywatna dla bieżącej aplikacji.
  • Token modelu musi być unikalny dla urządzenia w przypadku danego modelu. Token modelu możesz obliczyć, generując odcisk cyfrowy z danych modelu za pomocą bibliotek takich jak farmhash::Fingerprint64.