Délégué d'accélération du GPU pour iOS

Utiliser des processeurs graphiques (GPU) pour exécuter vos modèles de machine learning (ML) peut considérablement améliorer les performances de votre modèle et l'expérience utilisateur de vos applications compatibles avec le ML. Sur les appareils iOS, vous pouvez activer l'utilisation une exécution accélérée par le GPU de vos modèles à l'aide d'un délégué. Les délégués agissent comme pilotes matériels pour LiteRT, qui vous permet d'exécuter le code de votre modèle sur des processeurs GPU.

Cette page explique comment activer l'accélération GPU pour les modèles LiteRT dans Applications iOS. Pour en savoir plus sur l'utilisation du délégué de GPU pour LiteRT, y compris les bonnes pratiques et les techniques avancées, consultez la documentation sur les GPU délégués.

Utiliser un GPU avec l'API Interpreter

L'interprète LiteRT fournit un ensemble pour créer des applications de machine learning. Les éléments suivants : les instructions vous guident dans l'ajout de la prise en charge du GPU à une application iOS. Ce guide suppose que vous disposez déjà d'une application iOS capable d'exécuter un modèle de ML avec LiteRT.

Modifier le Podfile pour inclure la compatibilité GPU

À partir de la version LiteRT 2.3.0, le délégué de GPU est exclu du pod pour réduire la taille binaire. Vous pouvez les inclure en spécifiant pour le pod TensorFlowLiteSwift:

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

OU

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

Vous pouvez également utiliser TensorFlowLiteObjC ou TensorFlowLiteC si vous souhaitez utiliser Objective-C, disponible pour les versions 2.4.0 et ultérieures, ou l'API C.

Initialiser et utiliser le délégué de GPU

Vous pouvez utiliser le délégué de GPU avec l'interpréteur LiteRT API avec de nombreuses possibilités de programmation langues. Swift et Objective-C sont recommandés, mais vous pouvez aussi utiliser C++ et C. L'utilisation du langage C est obligatoire si vous utilisez une version de LiteRT antérieure. supérieure à 2,4. Les exemples de code suivants décrivent comment utiliser le délégué avec chaque de ces langues.

Swift

import TensorFlowLite

// Load model ...

// Initialize LiteRT 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 (antérieures à la version 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);
      

Remarques sur l'utilisation de la langue de l'API GPU

  • Les versions LiteRT antérieures à la version 2.4.0 ne peuvent utiliser l'API C que pour Objectif C.
  • L'API C++ n'est disponible que lorsque vous utilisez Bazel ou compilez TensorFlow En mode simplifié, seul. L'API C++ ne peut pas être utilisée avec CocoaPods.
  • Lorsque vous utilisez LiteRT avec le délégué de GPU en C++, obtenez le GPU. déléguer via la fonction TFLGpuDelegateCreate(), puis le transmettre à Interpreter::ModifyGraphWithDelegate(), au lieu d'appeler Interpreter::AllocateTensors()

Compiler et tester avec le mode de publication

Passez à un build avec les paramètres d'accélérateur appropriés de l'API Metal pour améliorer les performances et pour les tests finaux. Cette section vous explique comment activer un build et configurer le paramètre d'accélération Metal ;

Pour passer à un build:

  1. Modifiez les paramètres de compilation en sélectionnant Product > Schéma > Modifier le schéma... puis en sélectionnant Exécuter.
  2. Dans l'onglet Info, remplacez Build Configuration (Configuration de la compilation) par Release (Publier). décochez la case Déboguer le fichier exécutable. configuration
lever
  3. Cliquez sur l'onglet Options et définissez Capture d'image GPU sur Désactivé. et Validation de l'API Metal sur Désactivé.
    configuration de métal
Options
  4. Veillez à sélectionner "Versions uniquement" sur une architecture 64 bits. Au-dessous Navigateur de projets > tflite_camera_example > PROJET > nom_de_votre_projet > Build Settings (Paramètres de compilation) définissez Build Active Architecture Only > Publier sur Oui. configuration de la version
Options

Compatibilité avancée avec les GPU

Cette section aborde les utilisations avancées du délégué de GPU pour iOS, y compris les options déléguées, les tampons d'entrée et de sortie, et l'utilisation de modèles quantifiés.

Déléguer des options pour iOS

Le constructeur du délégué de GPU accepte un struct d'options dans Swift l'API, Objective-C de Google, et C Google Cloud. Transmettre nullptr (API C) ou rien (API Objective-C et Swift) à la initialiseur définit les options par défaut (détaillées dans la section "Utilisation de base" dans l'exemple ci-dessus).

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);
      

Tampons d'entrée/de sortie à l'aide de l'API C++

Le calcul sur le GPU nécessite que les données soient disponibles pour le GPU. Ce signifie souvent que vous devez effectuer une copie de la mémoire. Vous devez éviter d'avoir vos données dépassent la limite de mémoire du processeur/GPU, si possible, beaucoup de temps. En général, ce passage est inévitable, mais dans certains cas, des cas particuliers, l'un ou l'autre peut être omis.

Si l'entrée du réseau est une image déjà chargée dans la mémoire GPU (par (par exemple, une texture GPU contenant le flux de l'appareil photo), celle-ci peut rester dans la mémoire du GPU. sans jamais entrer dans la mémoire CPU. De même, si la sortie du réseau est dans la forme d'une image restituable, comme un style d'image transfert vous pouvez afficher directement le résultat à l'écran.

Pour optimiser les performances, LiteRT permet aux utilisateurs lire et écrire directement dans le tampon matériel TensorFlow, et contourner des copies de mémoire évitables.

En supposant que l'entrée de l'image se trouve dans la mémoire GPU, vous devez d'abord la convertir en Objet MTLBuffer pour Metal. Vous pouvez associer un TfLiteTensor à un MTLBuffer préparé par l'utilisateur avec le TFLGpuDelegateBindMetalBufferToTensor() . Notez que cette fonction doit être appelée après Interpreter::ModifyGraphWithDelegate() De plus, le résultat de l'inférence est par défaut, copiées de la mémoire du GPU vers la mémoire du processeur. Vous pouvez désactiver ce comportement en appelant Interpreter::SetAllowBufferHandleOutput(true) pendant l'initialisation.

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;
      

Une fois le comportement par défaut désactivé, copier la sortie d'inférence à partir du GPU mémoire vers la mémoire CPU nécessite un appel explicite à Interpreter::EnsureTensorDataIsReadable() pour chaque Tensor de sortie. Ce fonctionne également pour les modèles quantifiés, mais vous devez tout de même tampon de taille float32 avec des données de type float32, car il est lié au tampon interne dé-quantifié.

Modèles quantifiés

Les bibliothèques déléguées de GPU iOS acceptent les modèles quantifiés par défaut. Vous ne devez pas modifier le code pour utiliser des modèles quantifiés avec le délégué de GPU. La La section suivante explique comment désactiver la prise en charge quantifiée pour les tests ou à des fins expérimentales.

Désactiver la compatibilité avec les modèles quantifiés

Le code suivant montre comment désactiver la prise en charge des modèles quantifiés.

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);
      

Pour en savoir plus sur l'exécution de modèles quantifiés avec l'accélération GPU, consultez Présentation de la délégué de GPU.