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. Dlatego 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-bitowe 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 demonstracja aparatu iOS działa na Twoim telefonie.

Krok 2. Zmodyfikuj plik Podfile, aby używał TensorFlow Lite GPU CocoaPod

Do 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' `` ``

Od wersji TensorFlow Lite 2.1.0 delegat GPU jest zawarty w TensorFlowLiteC . W zależności od języka możesz wybrać między TensorFlowLiteC i TensorFlowLiteSwift .

W przypadku wersji nightly i nadchodzącej wersji 2.3.0 delegat GPU jest domyślnie wykluczony z kapsuły w celu zmniejszenia rozmiaru binarnego. 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ć TensorFlowLiteC dla TensorFlowLiteC jeśli chcesz używać C API.

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 , usuń zaznaczenie opcji 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

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

Zainicjuj interpreter TensorFlow Lite z delegatem GPU.

import TensorFlowLite

// Load model ...

let delegate = MetalDelegate()

if let interpreter = try Interpreter(modelPath: modelPath,
                                     delegates: [delegate]) {
  // Run inference ...
}

Cel C

W kodzie aplikacji Interpreter::ModifyGraphWithDelegate nagłówek delegata GPU i wywołaj funkcję Interpreter::ModifyGraphWithDelegate aby zarejestrować delegata GPU do interpretera:

#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 trywialne operacje 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 obliczenia na tensorze kształtu [B,H,W,5] wykonają mniej więcej to 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 znaczna część optymalizacji pod kątem wnioskowania na urządzeniu.