Odpowiedz już dziś na lokalne wydarzenie TensorFlow Everywhere!
Ta strona została przetłumaczona przez Cloud Translation API.
Switch to English

Delegat GPU TensorFlow Lite

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.

z systemem Android GPU i przełącz się 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 .

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 Build Active Architecture Only > Release na Yes.

konfigurowanie opcji wydania

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:

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.