TensorFlow Lite obsługuje kilka akceleratorów sprzętowych. W tym dokumencie opisano sposób korzystania z zaplecza procesora GPU przy użyciu interfejsów API delegatów TensorFlow Lite w systemach Android i iOS.
Procesory GPU zaprojektowano tak, aby zapewniały wysoką przepustowość w przypadku obciążeń z możliwością masowej zrównoleglania. W związku z tym dobrze nadają się do głębokich sieci neuronowych, które składają się z ogromnej liczby operatorów, z których każdy pracuje na jakimś tensorze wejściowym, który można łatwo podzielić na mniejsze obciążenia i wykonywać równolegle, co zwykle skutkuje mniejszym opóźnieniem. W najlepszym scenariuszu wnioskowanie na GPU może teraz działać wystarczająco szybko dla wcześniej niedostępnych aplikacji czasu rzeczywistego.
W przeciwieństwie do procesorów, procesory graficzne obliczają 16- lub 32-bitowe liczby zmiennoprzecinkowe i nie wymagają kwantyzacji w celu uzyskania optymalnej wydajności. Delegat akceptuje 8-bitowe skwantowane modele, ale obliczenia będą wykonywane w liczbach zmiennoprzecinkowych. Szczegółowe informacje można znaleźć w zaawansowanej dokumentacji .
Inną korzyścią wynikającą z wnioskowania GPU jest wydajność energetyczna. Procesory graficzne wykonują obliczenia w bardzo wydajny i zoptymalizowany sposób, dzięki czemu zużywają mniej energii i generują mniej ciepła niż w przypadku wykonywania tego samego zadania na procesorach.
Samouczki aplikacji demonstracyjnej
Najłatwiejszym sposobem wypróbowania delegata GPU jest skorzystanie z poniższych samouczków, które obejmują tworzenie naszych aplikacji demonstracyjnych klasyfikacji z obsługą GPU. Kod GPU jest na razie tylko binarny; wkrótce będzie dostępny na zasadach open source. Kiedy już zrozumiesz, jak uruchomić nasze wersje demonstracyjne, możesz wypróbować to na swoich własnych modelach niestandardowych.
Android (z Android Studio)
Aby zapoznać się z samouczkiem krok po kroku, obejrzyj wideo Delegat GPU dla systemu Android .
Krok 1. Sklonuj kod źródłowy TensorFlow i otwórz go w Android Studio
git clone https://github.com/tensorflow/tensorflow
Krok 2. Edytuj app/build.gradle
aby używać nocnego AAR GPU
Dodaj tensorflow-lite-gpu
obok istniejącego pakietu tensorflow-lite
w istniejącym bloku dependencies
.
dependencies {
...
implementation 'org.tensorflow:tensorflow-lite:2.3.0'
implementation 'org.tensorflow:tensorflow-lite-gpu:2.3.0'
}
Krok 3. Zbuduj i uruchom
Uruchom → Uruchom „aplikację”. Po uruchomieniu aplikacji zobaczysz przycisk umożliwiający włączenie GPU. Zmień model kwantowany na model zmiennoprzecinkowy, a następnie kliknij GPU, aby uruchomić na GPU.
iOS (z XCode)
Aby zapoznać się z samouczkiem krok po kroku, obejrzyj wideo Delegat GPU dla systemu iOS .
Krok 1. Pobierz demo kod źródłowy i upewnij się, że się kompiluje.
Postępuj zgodnie z naszym samouczkiem dotyczącym aplikacji demonstracyjnej na iOS. To doprowadzi Cię do punktu, w którym niezmodyfikowana wersja demonstracyjna aparatu iOS działa na Twoim telefonie.
Krok 2. Zmodyfikuj plik Podfile, aby używał TensorFlow Lite GPU CocoaPod
Od wersji 2.3.0 delegat GPU jest domyślnie wykluczony z poda, aby zmniejszyć rozmiar binarny. Możesz je dołączyć, określając podgatunek. Dla TensorFlowLiteSwift
:
pod 'TensorFlowLiteSwift/Metal', '~> 0.0.1-nightly',
LUB
pod 'TensorFlowLiteSwift', '~> 0.0.1-nightly', :subspecs => ['Metal']
Możesz zrobić podobnie dla TensorFlowLiteObjC
lub TensorFlowLitC
jeśli chcesz użyć Objective-C (z wersji 2.4.0) lub C API.
Przed wydaniem 2.3.0
Do wersji TensorFlow Lite 2.0.0
Zbudowaliśmy binarny CocoaPod, który zawiera delegata GPU. Aby przełączyć projekt na jego użycie, zmodyfikuj plik `tensorflow / tensorflow / lite / examples / ios / camera / Podfile` tak, aby używał poda` TensorFlowLiteGpuExperimental` zamiast `TensorFlowLite`.
target 'YourProjectName'
# pod 'TensorFlowLite', '1.12.0'
pod 'TensorFlowLiteGpuExperimental'
Do wersji TensorFlow Lite 2.2.0
Od TensorFlow Lite 2.1.0 do 2.2.0 delegat GPU jest zawarty w module `TensorFlowLiteC`. W zależności od języka można wybrać pomiędzy `TensorFlowLiteC` i` TensorFlowLiteSwift`.
Krok 3. Włącz delegata GPU
Aby włączyć kod, który będzie korzystał z delegata GPU, musisz zmienić TFLITE_USE_GPU_DELEGATE
z 0 na 1 w CameraExampleViewController.h
.
#define TFLITE_USE_GPU_DELEGATE 1
Krok 4. Zbuduj i uruchom aplikację demonstracyjną
Po wykonaniu poprzedniego kroku powinno być możliwe uruchomienie aplikacji.
Krok 5. Tryb zwolnienia
Podczas gdy w kroku 4 działałeś w trybie debugowania, aby uzyskać lepszą wydajność, powinieneś zmienić wersję na wydanie z odpowiednimi optymalnymi ustawieniami metalu. W szczególności w celu edycji tych ustawień przejdź do Product > Scheme > Edit Scheme...
Wybierz Run
. Na karcie Info
zmień Build Configuration
z Debug
na Release
, odznacz opcję Debug executable
.
Następnie kliknij kartę Options
i zmień GPU Frame Capture
na Disabled
a Metal API Validation
na Disabled
.
Na koniec upewnij się, że wybrałeś kompilacje tylko do wydania w architekturze 64-bitowej. W Project navigator -> tflite_camera_example -> PROJECT -> tflite_camera_example -> Build Settings
ustaw Build Active Architecture Only > Release
na Yes.
Wypróbowanie delegata GPU na własnym modelu
Android
Istnieją dwa sposoby wywołania akceleracji modelu w zależności od tego, czy używasz powiązania modelu Android Studio ML czy interpretera TensorFlow Lite.
Tłumacz TensorFlow Lite
Obejrzyj prezentację, aby zobaczyć, jak dodać pełnomocnika. W swojej aplikacji dodaj AAR jak powyżej, zaimportuj moduł org.tensorflow.lite.gpu.GpuDelegate
i użyj funkcji addDelegate
aby zarejestrować delegata GPU do interpretera:
Kotlin
import org.tensorflow.lite.Interpreter import org.tensorflow.lite.gpu.CompatibilityList import org.tensorflow.lite.gpu.GpuDelegate val compatList = CompatibilityList() val options = Interpreter.Options().apply{ if(compatList.isDelegateSupportedOnThisDevice){ // if the device has a supported GPU, add the GPU delegate val delegateOptions = compatList.bestOptionsForThisDevice this.addDelegate(GpuDelegate(delegateOptions)) } else { // if the GPU is not supported, run on 4 threads this.setNumThreads(4) } } val interpreter = Interpreter(model, options) // Run inference writeToInput(input) interpreter.run(input, output) readFromOutput(output)
Jawa
import org.tensorflow.lite.Interpreter; import org.tensorflow.lite.gpu.CompatibilityList; import org.tensorflow.lite.gpu.GpuDelegate; // Initialize interpreter with GPU delegate Interpreter.Options options = new Interpreter.Options(); CompatibilityList compatList = CompatibilityList(); if(compatList.isDelegateSupportedOnThisDevice()){ // if the device has a supported GPU, add the GPU delegate GpuDelegate.Options delegateOptions = compatList.getBestOptionsForThisDevice(); GpuDelegate gpuDelegate = new GpuDelegate(delegateOptions); options.addDelegate(gpuDelegate); } else { // if the GPU is not supported, run on 4 threads options.setNumThreads(4); } Interpreter interpreter = new Interpreter(model, options); // Run inference writeToInput(input); interpreter.run(input, output); readFromOutput(output);
iOS
Szybki
import TensorFlowLite // Load model ... // Initialize TensorFlow Lite interpreter with the GPU delegate. let delegate = MetalDelegate() if let interpreter = try Interpreter(modelPath: modelPath, delegates: [delegate]) { // Run inference ... }
Cel C
// Import module when using CocoaPods with module support @import TFLTensorFlowLite; // Or import following headers manually #import "tensorflow/lite/objc/apis/TFLMetalDelegate.h" #import "tensorflow/lite/objc/apis/TFLTensorFlowLite.h" // Initialize GPU delegate TFLMetalDelegate* metalDelegate = [[TFLMetalDelegate alloc] init]; // Initialize interpreter with model path and GPU delegate TFLInterpreterOptions* options = [[TFLInterpreterOptions alloc] init]; NSError* error = nil; TFLInterpreter* interpreter = [[TFLInterpreter alloc] initWithModelPath:modelPath options:options delegates:@[ metalDelegate ] error:&error]; if (error != nil) { /* Error handling... */ } if (![interpreter allocateTensorsWithError:&error]) { /* Error handling... */ } if (error != nil) { /* Error handling... */ } // Run inference ... ```
C (do 2.3.0)
#include "tensorflow/lite/c/c_api.h" #include "tensorflow/lite/delegates/gpu/metal_delegate.h" // Initialize model TfLiteModel* model = TfLiteModelCreateFromFile(model_path); // Initialize interpreter with GPU delegate TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate(); TfLiteDelegate* delegate = TFLGPUDelegateCreate(nil); // default config TfLiteInterpreterOptionsAddDelegate(options, metal_delegate); TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options); TfLiteInterpreterOptionsDelete(options); TfLiteInterpreterAllocateTensors(interpreter); NSMutableData *input_data = [NSMutableData dataWithLength:input_size * sizeof(float)]; NSMutableData *output_data = [NSMutableData dataWithLength:output_size * sizeof(float)]; TfLiteTensor* input = TfLiteInterpreterGetInputTensor(interpreter, 0); const TfLiteTensor* output = TfLiteInterpreterGetOutputTensor(interpreter, 0); // Run inference TfLiteTensorCopyFromBuffer(input, inputData.bytes, inputData.length); TfLiteInterpreterInvoke(interpreter); TfLiteTensorCopyToBuffer(output, outputData.mutableBytes, outputData.length); // Clean up TfLiteInterpreterDelete(interpreter); TFLGpuDelegateDelete(metal_delegate); TfLiteModelDelete(model);
Obsługiwane modele i operacje
Wraz z wydaniem delegata GPU dołączyliśmy kilka modeli, które można uruchomić na zapleczu:
- Klasyfikacja obrazów MobileNet v1 (224x224) [pobieranie]
(model klasyfikacji obrazu zaprojektowany dla mobilnych i wbudowanych aplikacji wizyjnych) - Segmentacja DeepLab (257x257) [pobierz]
(model segmentacji obrazu, który przypisuje etykiety semantyczne (np. pies, kot, samochód) do każdego piksela w obrazie wejściowym) - Wykrywanie obiektów MobileNet SSD [pobieranie]
(model klasyfikacji obrazu, który wykrywa wiele obiektów z obwiedniami) - PoseNet do oceny pozy [pobierz]
(model widzenia, który szacuje pozy osoby (osób) na obrazie lub wideo)
Aby zobaczyć pełną listę obsługiwanych operacji, zapoznaj się z zaawansowaną dokumentacją .
Nieobsługiwane modele i operacje
Jeśli niektóre operacje nie są obsługiwane przez delegata GPU, platforma uruchomi tylko część wykresu na GPU, a pozostałą część na procesorze. Ze względu na wysoki koszt synchronizacji CPU / GPU, tryb podzielonego wykonania, taki jak ten, często skutkuje wolniejszą wydajnością niż wtedy, gdy cała sieć jest uruchamiana na samym CPU. W takim przypadku użytkownik otrzyma ostrzeżenie takie jak:
WARNING: op code #42 cannot be handled by this delegate.
Nie udostępniliśmy wywołania zwrotnego dla tego niepowodzenia, ponieważ nie jest to prawdziwa awaria w czasie wykonywania, ale coś, co deweloper może zaobserwować, próbując uruchomić sieć na delegacie.
Wskazówki dotyczące optymalizacji
Niektóre operacje, które są trywialne na CPU, mogą wiązać się z wysokimi kosztami dla GPU. Jedną z klas takich operacji są różne formy operacji zmiany kształtu, w tym BATCH_TO_SPACE
, SPACE_TO_BATCH
, SPACE_TO_DEPTH
i tak dalej. Jeśli te operacje są wstawiane do sieci tylko ze względu na logiczne myślenie architekta sieci, warto je usunąć w celu zwiększenia wydajności.
Na GPU dane tensora są dzielone na 4 kanały. Zatem obliczenie na tensorze kształtu [B,H,W,5]
będzie działać mniej więcej tak samo na tensorze kształtu [B,H,W,8]
ale znacznie gorzej niż [B,H,W,4]
.
W tym sensie, jeśli sprzęt kamery obsługuje ramki obrazu w RGBA, podawanie tego 4-kanałowego wejścia jest znacznie szybsze, ponieważ można uniknąć kopiowania pamięci (z 3-kanałowego RGB do 4-kanałowego RGBX).
Aby uzyskać najlepszą wydajność, nie wahaj się przekwalifikować swojego klasyfikatora za pomocą architektury sieci zoptymalizowanej pod kątem urządzeń mobilnych. To ważna część optymalizacji pod kątem wnioskowania na urządzeniu.