Delegat TensorFlow Lite GPU

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.

uruchamiam demo Androida i przełącz się 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 .

konfigurowanie wydania

Następnie kliknij kartę Options i zmień GPU Frame Capture na Disabled , a Metal API Validation na Disabled .

konfigurowanie opcji metalowych

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.

konfigurowanie opcji wydania

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 .