Sehen Sie sich Keynotes, Produktsitzungen, Workshops und mehr in Google I / O an. Siehe Wiedergabeliste

TensorFlow Lite GPU-Delegat

TensorFlow Lite unterstützt mehrere Hardwarebeschleuniger. In diesem Dokument wird beschrieben, wie Sie das GPU-Backend mithilfe der TensorFlow Lite-Delegaten-APIs unter Android und iOS verwenden.

GPUs sind für einen hohen Durchsatz bei massiv parallelisierbaren Workloads ausgelegt. Daher eignen sie sich gut für tiefe neuronale Netze, die aus einer großen Anzahl von Operatoren bestehen, die jeweils an einem oder mehreren Eingangstensoren arbeiten, die leicht in kleinere Arbeitslasten unterteilt und parallel ausgeführt werden können, was typischerweise zu einer geringeren Latenz führt. Im besten Fall kann die Inferenz auf der GPU jetzt schnell genug für zuvor nicht verfügbare Echtzeitanwendungen ausgeführt werden.

Im Gegensatz zu CPUs berechnen GPUs mit 16-Bit- oder 32-Bit-Gleitkommazahlen und erfordern für eine optimale Leistung keine Quantisierung. Der Delegat akzeptiert quantisierte 8-Bit-Modelle, die Berechnung wird jedoch in Gleitkommazahlen durchgeführt. Weitere Informationen finden Sie in der erweiterten Dokumentation .

Ein weiterer Vorteil der GPU-Inferenz ist die Energieeffizienz. GPUs führen die Berechnungen sehr effizient und optimiert durch, sodass sie weniger Strom verbrauchen und weniger Wärme erzeugen als wenn dieselbe Aufgabe auf CPUs ausgeführt wird.

Demo-App-Tutorials

Der einfachste Weg, den GPU-Delegierten auszuprobieren, besteht darin, die folgenden Tutorials zu befolgen, in denen unsere Klassifizierungs-Demo-Anwendungen mit GPU-Unterstützung erstellt werden. Der GPU-Code ist derzeit nur binär. es wird bald Open-Source sein. Sobald Sie verstanden haben, wie unsere Demos funktionieren, können Sie dies an Ihren eigenen benutzerdefinierten Modellen ausprobieren.

Android (mit Android Studio)

Eine schrittweise Anleitung finden Sie im Video zum GPU-Delegierten für Android .

Schritt 1. Klonen Sie den TensorFlow-Quellcode und öffnen Sie ihn in Android Studio

git clone https://github.com/tensorflow/tensorflow

Schritt 2. Bearbeiten Sie app/build.gradle , um den nächtlichen GPU-AAR zu verwenden

Fügen Sie das tensorflow-lite-gpu Paket neben dem vorhandenen tensorflow-lite Paket im vorhandenen dependencies .

dependencies {
    ...
    implementation 'org.tensorflow:tensorflow-lite:2.3.0'
    implementation 'org.tensorflow:tensorflow-lite-gpu:2.3.0'
}

Schritt 3. Erstellen und ausführen

Ausführen → 'App' ausführen. Wenn Sie die Anwendung ausführen, wird eine Schaltfläche zum Aktivieren der GPU angezeigt. Wechseln Sie von einem quantisierten zu einem Float-Modell und klicken Sie dann auf GPU, um es auf der GPU auszuführen.

Laufen Android GPU Demo und wechseln Sie zu GPU

iOS (mit XCode)

Sehen Sie sich das GPU Delegate für iOS- Video an, um eine schrittweise Anleitung zu erhalten.

Schritt 1. Holen Sie sich den Demo-Quellcode und stellen Sie sicher, dass er kompiliert wird.

Folgen Sie unserem iOS Demo App Tutorial . Dies bringt Sie zu einem Punkt, an dem die unveränderte iOS-Kamera-Demo auf Ihrem Telefon funktioniert.

Schritt 2. Ändern Sie die Poddatei, um den TensorFlow Lite GPU CocoaPod zu verwenden

Ab Version 2.3.0 wird der GPU-Delegat standardmäßig aus dem Pod ausgeschlossen, um die Binärgröße zu verringern. Sie können sie einschließen, indem Sie eine Unterspezifikation angeben. Für TensorFlowLiteSwift Pod:

pod 'TensorFlowLiteSwift/Metal', '~> 0.0.1-nightly',

ODER

pod 'TensorFlowLiteSwift', '~> 0.0.1-nightly', :subspecs => ['Metal']

Sie können dies auch für TensorFlowLiteObjC oder TensorFlowLitC tun, wenn Sie die Objective-C- (ab Version 2.4.0) oder C-API verwenden möchten.

Vor der Veröffentlichung von 2.3.0

Bis TensorFlow Lite 2.0.0

Wir haben einen binären CocoaPod erstellt, der den GPU-Delegaten enthält. Ändern Sie die Datei "tensorflow / tensorflow / lite / examples / ios / camera / Podfile", um das Projekt "TensorFlowLiteGpuExperimental" anstelle von "TensorFlowLite" zu verwenden.


    target 'YourProjectName'
      # pod 'TensorFlowLite', '1.12.0'
      pod 'TensorFlowLiteGpuExperimental'
    

Bis TensorFlow Lite 2.2.0

Von TensorFlow Lite 2.1.0 bis 2.2.0 ist der GPU-Delegat im Pod "TensorFlowLiteC" enthalten. Sie können je nach Sprache zwischen "TensorFlowLiteC" und "TensorFlowLiteSwift" wählen.

Schritt 3. Aktivieren Sie den GPU-Delegaten

Um den Code zu aktivieren, der den GPU-Delegaten verwendet, müssen Sie TFLITE_USE_GPU_DELEGATE in TFLITE_USE_GPU_DELEGATE von 0 auf 1 CameraExampleViewController.h .

#define TFLITE_USE_GPU_DELEGATE 1

Schritt 4. Erstellen Sie die Demo-App und führen Sie sie aus

Nachdem Sie den vorherigen Schritt ausgeführt haben, sollten Sie in der Lage sein, die App auszuführen.

Schritt 5. Freigabemodus

Während Sie in Schritt 4 im Debug-Modus ausgeführt haben, sollten Sie zu einem Release-Build mit den entsprechenden optimalen Metal-Einstellungen wechseln, um eine bessere Leistung zu erzielen. Um diese Einstellungen zu bearbeiten, gehen Sie insbesondere zu Product > Scheme > Edit Scheme... Wählen Sie Run . Ändern Sie auf der Registerkarte " Info Option " Build Configuration von " Debug in " Release und deaktivieren Sie die Option " Debug executable .

Release einrichten

Klicken Sie dann auf die Registerkarte Options und ändern Sie GPU Frame Capture in Disabled und Metal API Validation in Disabled .

Einrichten von Metalloptionen

Stellen Sie schließlich sicher, dass Sie Nur-Release-Builds auf 64-Bit-Architektur auswählen. Unter Project navigator -> tflite_camera_example -> PROJECT -> tflite_camera_example -> Build Settings setzen Sie Build Active Architecture Only > Release auf Yes.

Freigabeoptionen einrichten

Versuchen Sie den GPU-Delegaten auf Ihrem eigenen Modell

Android

Es gibt zwei Möglichkeiten, die Modellbeschleunigung aufzurufen, je nachdem, ob Sie Android Studio ML Model Binding oder TensorFlow Lite Interpreter verwenden.

TensorFlow Lite Interpreter

Sehen Sie sich die Demo an, um zu sehen, wie Sie den Delegaten hinzufügen. org.tensorflow.lite.gpu.GpuDelegate in Ihrer Anwendung den AAR wie oben hinzu, importieren org.tensorflow.lite.gpu.GpuDelegate Modul addDelegate und registrieren Sie den GPU-Delegaten mit der Funktion addDelegate beim Interpreter:

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)
      

Java

    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

Schnell

    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 ...
    }
      

Ziel 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 (bis 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);
      

Unterstützte Modelle und Operationen

Mit der Veröffentlichung des GPU-Delegaten haben wir eine Handvoll Modelle hinzugefügt, die im Backend ausgeführt werden können:

Eine vollständige Liste der unterstützten Operationen finden Sie in der erweiterten Dokumentation .

Nicht unterstützte Modelle und Operationen

Wenn einige der Operationen vom GPU-Delegaten nicht unterstützt werden, führt das Framework nur einen Teil des Diagramms auf der GPU und den verbleibenden Teil auf der CPU aus. Aufgrund der hohen Kosten für die CPU / GPU-Synchronisation führt ein geteilter Ausführungsmodus wie dieser häufig zu einer langsameren Leistung als wenn das gesamte Netzwerk nur auf der CPU ausgeführt wird. In diesem Fall erhält der Benutzer eine Warnung wie:

WARNING: op code #42 cannot be handled by this delegate.

Wir haben keinen Rückruf für diesen Fehler bereitgestellt, da dies kein echter Laufzeitfehler ist, sondern etwas, das der Entwickler beobachten kann, wenn er versucht, das Netzwerk auf dem Delegaten zum Laufen zu bringen.

Tipps zur Optimierung

Einige Operationen, die auf der CPU trivial sind, können hohe Kosten für die GPU verursachen. Eine Klasse solcher Operationen sind verschiedene Formen von BATCH_TO_SPACE , einschließlich BATCH_TO_SPACE , SPACE_TO_BATCH , SPACE_TO_DEPTH usw. Wenn diese Operationen nur aus logischen Gründen des Netzwerkarchitekten in das Netzwerk eingefügt werden, lohnt es sich, sie aus Gründen der Leistung zu entfernen.

Auf der GPU werden Tensordaten in 4 Kanäle unterteilt. Somit wird eine Berechnung auf einem Tensor der Form [B,H,W,5] ungefähr gleich auf einem Tensor der Form [B,H,W,8] jedoch signifikant schlechter als [B,H,W,4] .

In diesem Sinne kann, wenn die Kamerahardware Bilderrahmen in RGBA unterstützt, das Zuführen dieses 4-Kanal-Eingangs erheblich schneller erfolgen, da eine Speicherkopie (von 3-Kanal-RGB zu 4-Kanal-RGBX) vermieden werden kann.

Zögern Sie nicht, Ihren Klassifikator mit einer für Mobilgeräte optimierten Netzwerkarchitektur neu zu trainieren, um eine optimale Leistung zu erzielen. Dies ist ein wesentlicher Teil der Optimierung für die Inferenz auf dem Gerät.