GPU-Beschleunigungsdelegat für iOS

Wenn Sie Ihre Modelle für maschinelles Lernen (ML) mit Grafikprozessoren (Graphics Processing Units, GPUs) ausführen, können Sie die Leistung Ihres Modells und die Nutzererfahrung Ihrer ML-fähigen Anwendungen erheblich verbessern. Auf iOS-Geräten können Sie die GPU-beschleunigte Ausführung Ihrer Modelle mit einem Bevollmächtigten aktivieren. Delegate fungieren als Hardwaretreiber für TensorFlow Lite, sodass Sie den Code Ihres Modells auf GPU-Prozessoren ausführen können.

Auf dieser Seite wird beschrieben, wie Sie die GPU-Beschleunigung für TensorFlow Lite-Modelle in iOS-Apps aktivieren. Weitere Informationen zur Verwendung des GPU-Delegaten für TensorFlow Lite, einschließlich Best Practices und erweiterter Techniken, finden Sie auf der Seite GPU-Bevollmächtigte.

GPU mit Interpreter API verwenden

Die Interpreter API von TensorFlow Lite bietet eine Reihe von allgemeinen APIs zum Erstellen von Anwendungen für maschinelles Lernen. In der folgenden Anleitung wird beschrieben, wie Sie einer iOS-App GPU-Unterstützung hinzufügen. In dieser Anleitung wird davon ausgegangen, dass Sie bereits eine iOS-App haben, die ein ML-Modell mit TensorFlow Lite ausführen kann.

Passen Sie die Podfile-Datei so an, dass sie GPU-Unterstützung enthält

Ab Version 2.3.0 von TensorFlow Lite wird der GPU-Delegat aus dem Pod ausgeschlossen, um die Binärgröße zu reduzieren. Sie können sie einschließen, indem Sie eine Unterspezifikation für den Pod TensorFlowLiteSwift angeben:

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

ODER

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

Sie können auch TensorFlowLiteObjC oder TensorFlowLiteC verwenden, wenn Sie Objective-C verwenden möchten, das ab Version 2.4.0 verfügbar ist, oder die C API.

Initialisieren und GPU-Delegaten verwenden

Sie können den GPU-Delegaten mit der TensorFlow Lite Interpreter API mit einer Reihe von Programmiersprachen verwenden. Swift und Objective-C werden empfohlen, Sie können aber auch C++ und C verwenden. Die Verwendung von C ist erforderlich, wenn Sie eine frühere Version von TensorFlow Lite als 2.4 verwenden. In den folgenden Codebeispielen wird dargestellt, wie der Delegate mit jeder dieser Sprachen verwendet wird.

Swift

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

Objective-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++

// Set up interpreter.
auto model = FlatBufferModel::BuildFromFile(model_path);
if (!model) return false;
tflite::ops::builtin::BuiltinOpResolver op_resolver;
std::unique_ptr<Interpreter> interpreter;
InterpreterBuilder(*model, op_resolver)(&interpreter);

// Prepare GPU delegate.
auto* delegate = TFLGpuDelegateCreate(/*default options=*/nullptr);
if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;

// Run inference.
WriteToInputTensor(interpreter->typed_input_tensor<float>(0));
if (interpreter->Invoke() != kTfLiteOk) return false;
ReadFromOutputTensor(interpreter->typed_output_tensor<float>(0));

// Clean up.
TFLGpuDelegateDelete(delegate);
      

C (vor 2.4.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);
      

Hinweise zur Verwendung der GPU API-Sprache

  • TensorFlow Lite-Versionen vor 2.4.0 können nur die C API für Objective-C verwenden.
  • Die C++ API steht nur dann zur Verfügung, wenn Sie TensorFlow verwenden oder TensorFlow Lite selbst erstellen. Die C++ API kann nicht mit CocoaPods verwendet werden.
  • Wenn Sie TensorFlow Lite mit dem GPU-Delegaten mit C++ verwenden, rufen Sie den GPU-Delegat über die Funktion TFLGpuDelegateCreate() ab und übergeben ihn dann an Interpreter::ModifyGraphWithDelegate(), anstatt Interpreter::AllocateTensors() aufzurufen.

Im Release-Modus erstellen und testen

Wechseln Sie zu einem Release-Build mit den entsprechenden Einstellungen für den Metal API-Beschleuniger, um die Leistung zu verbessern und für endgültige Tests zu sorgen. In diesem Abschnitt wird erläutert, wie Sie einen Release-Build aktivieren und die Einstellung für die Metal-Beschleunigung konfigurieren.

So wechseln Sie zu einem Release-Build:

  1. Wählen Sie Produkt > Schema > Schema bearbeiten... und dann Ausführen aus, um die Build-Einstellungen zu bearbeiten.
  2. Ändern Sie auf dem Tab Info die Option Build-Konfiguration in Release und entfernen Sie das Häkchen bei Ausführbare Datei debuggen. dem Einrichten des Release
  3. Klicken Sie auf den Tab Options (Optionen) und ändern Sie GPU Frame Capture in Disabled und Metal API Validation in Disabled.
    Einrichtung von Metalloptionen
  4. Achten Sie darauf, dass Sie Release-Builds mit einer 64-Bit-Architektur auswählen. Legen Sie unter Projektnavigation > tflite_camera_example > PROJECT > your_project_name > Build-Einstellungen die Option Nur aktive Architektur erstellen > Release auf Ja fest. das Einrichten von Releaseoptionen

Erweiterte GPU-Unterstützung

In diesem Abschnitt werden erweiterte Verwendungsmöglichkeiten des GPU-Delegaten für iOS behandelt, einschließlich Delegierungsoptionen, Eingabe- und Ausgabezwischenspeicher und Verwendung quantisierter Modelle.

Optionen für iOS delegieren

Der Konstruktor für den GPU-Delegaten akzeptiert einen struct mit Optionen in der Swift API, der Objective-C API und der C API. Wenn nullptr (C API) oder nichts (Objective-C und Swift API) an den Initialisierer übergeben wird, werden die Standardoptionen festgelegt (siehe Beispiel für die grundlegende Nutzung oben).

Swift

// THIS:
var options = MetalDelegate.Options()
options.isPrecisionLossAllowed = false
options.waitType = .passive
options.isQuantizationEnabled = true
let delegate = MetalDelegate(options: options)

// IS THE SAME AS THIS:
let delegate = MetalDelegate()
      

Objective-C

// THIS:
TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init];
options.precisionLossAllowed = false;
options.waitType = TFLMetalDelegateThreadWaitTypePassive;
options.quantizationEnabled = true;

TFLMetalDelegate* delegate = [[TFLMetalDelegate alloc] initWithOptions:options];

// IS THE SAME AS THIS:
TFLMetalDelegate* delegate = [[TFLMetalDelegate alloc] init];
      

C

// THIS:
const TFLGpuDelegateOptions options = {
  .allow_precision_loss = false,
  .wait_type = TFLGpuDelegateWaitType::TFLGpuDelegateWaitTypePassive,
  .enable_quantization = true,
};

TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);

// IS THE SAME AS THIS:
TfLiteDelegate* delegate = TFLGpuDelegateCreate(nullptr);
      

Eingabe-/Ausgabezwischenspeicher mit der C++ API

Für die Berechnung auf der GPU müssen die Daten für die GPU verfügbar sein. Dies bedeutet häufig, dass Sie eine Kopie des Arbeitsspeichers ausführen müssen. Sie sollten nach Möglichkeit vermeiden, dass Ihre Daten die CPU-/GPU-Speichergrenze überschreiten, da dies viel Zeit in Anspruch nehmen kann. Normalerweise ist eine solche Überschneidung unvermeidlich, aber in einigen Sonderfällen kann einer dieser beiden Fälle weggelassen werden.

Wenn die Netzwerkeingabe ein Bild ist, das bereits in den GPU-Speicher geladen wurde (z. B. eine GPU-Textur mit dem Kamerafeed), kann es im GPU-Speicher bleiben, ohne jemals in den CPU-Speicher einzutragen. Ähnlich verhält es sich, wenn die Netzwerkausgabe in Form eines renderbaren Bilds vorliegt, z. B. bei einer Stilübertragung von Bildern. Das Ergebnis lässt sich ebenfalls direkt auf dem Bildschirm anzeigen.

Für eine optimale Leistung bietet TensorFlow Lite Nutzern die Möglichkeit, direkt aus dem TensorFlow-Hardwarepuffer zu lesen und in diesen zu schreiben und damit vermeidbare Speicherkopien zu umgehen.

Wenn sich die Bildeingabe im GPU-Arbeitsspeicher befindet, müssen Sie sie zuerst in ein MTLBuffer-Objekt für Metal konvertieren. Mit der Funktion TFLGpuDelegateBindMetalBufferToTensor() können Sie ein TfLiteTensor mit einer vom Nutzer vorbereiteten MTLBuffer verknüpfen. Beachten Sie, dass diese Funktion nach Interpreter::ModifyGraphWithDelegate() aufgerufen werden muss. Darüber hinaus wird die Inferenzausgabe standardmäßig aus dem GPU-Arbeitsspeicher in den CPU-Arbeitsspeicher kopiert. Sie können dieses Verhalten deaktivieren, indem Sie während der Initialisierung Interpreter::SetAllowBufferHandleOutput(true) aufrufen.

C++

#include "tensorflow/lite/delegates/gpu/metal_delegate.h"
#include "tensorflow/lite/delegates/gpu/metal_delegate_internal.h"

// ...

// Prepare GPU delegate.
auto* delegate = TFLGpuDelegateCreate(nullptr);

if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;

interpreter->SetAllowBufferHandleOutput(true);  // disable default gpu->cpu copy
if (!TFLGpuDelegateBindMetalBufferToTensor(
        delegate, interpreter->inputs()[0], user_provided_input_buffer)) {
  return false;
}
if (!TFLGpuDelegateBindMetalBufferToTensor(
        delegate, interpreter->outputs()[0], user_provided_output_buffer)) {
  return false;
}

// Run inference.
if (interpreter->Invoke() != kTfLiteOk) return false;
      

Wenn das Standardverhalten deaktiviert ist, erfordert das Kopieren der Inferenzausgabe aus dem GPU-Arbeitsspeicher in den CPU-Speicher einen expliziten Aufruf von Interpreter::EnsureTensorDataIsReadable() für jeden Ausgabetensor. Dieser Ansatz funktioniert auch für quantisierte Modelle. Sie müssen jedoch trotzdem einen Puffer der Größe FLOAT32 mit FLOAT32-Daten verwenden, da der Puffer an den internen de-quantisierten Puffer gebunden ist.

Quantisierte Modelle

Die GPU-Delegierungsbibliotheken für iOS unterstützen standardmäßig quantisierte Modelle. Sie müssen keine Änderungen am Code vornehmen, um quantisierte Modelle mit dem GPU-Delegaten zu verwenden. Im folgenden Abschnitt wird erläutert, wie Sie die quantisierte Unterstützung für Test- oder experimentelle Zwecke deaktivieren.

Unterstützung quantisierter Modelle deaktivieren

Der folgende Code zeigt, wie Sie die Unterstützung für quantisierte Modelle deaktivieren.

Swift

    var options = MetalDelegate.Options()
    options.isQuantizationEnabled = false
    let delegate = MetalDelegate(options: options)
      

Objective-C

    TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init];
    options.quantizationEnabled = false;
      

C

    TFLGpuDelegateOptions options = TFLGpuDelegateOptionsDefault();
    options.enable_quantization = false;

    TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
      

Weitere Informationen zum Ausführen quantisierter Modelle mit GPU-Beschleunigung finden Sie in der Übersicht zum GPU-Delegaten.