TensorFlow Lite obsługuje kilka akceleratorów sprzętowych. W tym dokumencie opisano, jak korzystać z zaplecza GPU przy użyciu interfejsów API delegatów TensorFlow Lite w systemach Android i iOS.
Procesory GPU są zaprojektowane tak, aby zapewnić wysoką przepustowość dla obciążeń, które można zrównoleglać na dużą skalę. W związku z tym są dobrze przystosowane do głębokich sieci neuronowych, które składają się z ogromnej liczby operatorów, z których każdy pracuje nad pewnymi tensorami wejściowymi, które można łatwo podzielić na mniejsze obciążenia i wykonywać równolegle, co zwykle skutkuje mniejszymi opóźnieniami. 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 przetwarzają 16-bitowe lub 32-bitowe liczby zmiennoprzecinkowe i nie wymagają kwantyzacji w celu uzyskania optymalnej wydajności. Delegat akceptuje 8-bitowe modele skwantowane, ale obliczenia będą wykonywane na liczbach zmiennoprzecinkowych. Szczegółowe informacje można znaleźć w zaawansowanej dokumentacji .
Kolejną korzyścią wynikającą z wnioskowania GPU jest jego wydajność energetyczna. Procesory GPU 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, w których przedstawiono tworzenie naszych aplikacji demonstracyjnych klasyfikacji z obsługą GPU. Kod GPU jest na razie tylko binarny; wkrótce będzie open-source. Gdy zrozumiesz, jak uruchomić nasze wersje demonstracyjne, możesz wypróbować to na własnych, niestandardowych modelach.
Android (z Android Studio)
Aby zapoznać się z samouczkiem krok po kroku, obejrzyj wideo Delegata 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 korzystać z nocnego GPU AAR
Dodaj tensorflow-lite-gpu
obok istniejącego pakietu tensorflow-lite
w bloku istniejących 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 do włączenia GPU. Zmień model skwantyzowany na model pływakowy, a następnie kliknij GPU, aby uruchomić na GPU.
iOS (z XCode)
Aby zapoznać się z samouczkiem krok po kroku, obejrzyj wideo Delegata GPU dla systemu iOS .
Krok 1. Pobierz kod źródłowy demo i upewnij się, że się kompiluje.
Postępuj zgodnie z naszym samouczkiem iOS Demo App . To doprowadzi Cię do punktu, w którym niezmodyfikowana wersja demonstracyjna aparatu iOS działa na Twoim telefonie.
Krok 2. Zmodyfikuj plik Podfile, aby korzystać z procesora graficznego TensorFlow Lite CocoaPod
Od wersji 2.3.0 domyślnie delegat GPU jest wykluczony z pod, aby zmniejszyć rozmiar binarny. Możesz je uwzględnić, określając subspec. W przypadku 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 (od wersji 2.4.0) lub C API.
Przed wydaniem 2.3.0
Do czasu TensorFlow Lite 2.0.0
Zbudowaliśmy binarny CocoaPod, który zawiera delegata GPU. Aby przełączyć projekt tak, aby z niego korzystał, zmodyfikuj plik `tensorflow/tensorflow/lite/examples/ios/camera/Podfile` tak, aby używał pod `TensorFlowLiteGpuExperimental` zamiast `TensorFlowLite`.
target 'YourProjectName'
# pod 'TensorFlowLite', '1.12.0'
pod 'TensorFlowLiteGpuExperimental'
Aż do TensorFlow Lite 2.2.0
Od TensorFlow Lite 2.1.0 do 2.2.0 delegat GPU jest zawarty w podeście `TensorFlowLiteC`. Możesz wybrać pomiędzy „TensorFlowLiteC” i „TensorFlowLiteSwift” w zależności od języka.
Krok 3. Włącz delegata GPU
Aby włączyć kod, który będzie używał 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 powinieneś być w stanie uruchomić aplikację.
Krok 5. Tryb zwolnienia
Podczas gdy w kroku 4 uruchomiłeś tryb debugowania, aby uzyskać lepszą wydajność, powinieneś zmienić kompilację na wydanie z odpowiednimi optymalnymi ustawieniami Metal. W szczególności, aby edytować te ustawienia, przejdź do Product > Scheme > Edit Scheme...
. Wybierz Run
. Na karcie Info
zmień Build Configuration
z Debug
na Release
, odznacz 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 opcję Build Active Architecture Only > Release
na Tak.
Wypróbowanie delegata GPU na własnym modelu
Android
Istnieją dwa sposoby wywoływania akceleracji modelu, w zależności od tego, czy używasz Android Studio ML Model Binding czy TensorFlow Lite Interpreter.
Tłumacz TensorFlow Lite
Obejrzyj demo, aby zobaczyć, jak dodać pełnomocnika. W swojej aplikacji dodaj AAR jak wyż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);
## Supported Models and Ops
With the release of the GPU delegate, we included a handful of models that can
be run on the backend:
* [MobileNet v1 (224x224) image classification](https://ai.googleblog.com/2017/06/mobilenets-open-source-models-for.html) [[download]](https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/mobilenet_v1_1.0_224.tflite)
<br /><i>(image classification model designed for mobile and embedded based vision applications)</i>
* [DeepLab segmentation (257x257)](https://ai.googleblog.com/2018/03/semantic-image-segmentation-with.html) [[download]](https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/deeplabv3_257_mv_gpu.tflite)
<br /><i>(image segmentation model that assigns semantic labels (e.g., dog, cat, car) to every pixel in the input image)</i>
* [MobileNet SSD object detection](https://ai.googleblog.com/2018/07/accelerated-training-and-inference-with.html) [[download]](https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/mobile_ssd_v2_float_coco.tflite)
<br /><i>(image classification model that detects multiple objects with bounding boxes)</i>
* [PoseNet for pose estimation](https://github.com/tensorflow/tfjs-models/tree/master/posenet) [[download]](https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/multi_person_mobilenet_v1_075_float.tflite)
<br /><i>(vision model that estimates the poses of a person(s) in image or video)</i>
To see a full list of supported ops, please see the
[advanced documentation](gpu_advanced).
## Non-supported models and ops
If some of the ops are not supported by the GPU delegate, the framework will
only run a part of the graph on the GPU and the remaining part on the CPU. Due
to the high cost of CPU/GPU synchronization, a split execution mode like this
will often result in slower performance than when the whole network is run on
the CPU alone. In this case, the user will get a warning like:
```none
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ć podczas próby uruchomienia sieci na delegatze.
Wskazówki dotyczące optymalizacji
Optymalizacja pod kątem urządzeń mobilnych
Niektóre operacje, które są trywialne na procesorze, mogą wiązać się z wysokimi kosztami procesora graficznego na urządzeniach mobilnych. Operacje zmiany kształtu są szczególnie kosztowne w obsłudze, w tym BATCH_TO_SPACE
, SPACE_TO_BATCH
, SPACE_TO_DEPTH
i tak dalej. Należy 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ć wydajność.
Na GPU dane tensorowe są dzielone na 4 kanały. Zatem obliczenia na tensorze kształtu [B,H,W,5]
będą mniej więcej takie same 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 obrazów w RGBA, podawanie 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ść, należy rozważyć ponowne przeszkolenie klasyfikatora przy użyciu architektury sieci zoptymalizowanej pod kątem urządzeń mobilnych. Optymalizacja pod kątem wnioskowania na urządzeniu może znacznie zmniejszyć opóźnienia i zużycie energii dzięki wykorzystaniu funkcji sprzętu mobilnego.
Skrócenie czasu inicjalizacji dzięki serializacji
Funkcja delegata GPU umożliwia ładowanie ze wstępnie skompilowanego kodu jądra i danych modelu serializowanych i zapisanych na dysku z poprzednich uruchomień. Takie podejście pozwala uniknąć ponownej kompilacji i skraca czas uruchamiania nawet o 90%. Aby uzyskać instrukcje dotyczące stosowania serializacji do projektu, zobacz Serializacja delegata GPU .