Delegato di accelerazione GPU per iOS

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

L'utilizzo di unità di elaborazione grafica (GPU) per eseguire i modelli di machine learning (ML) può migliorare notevolmente le prestazioni del modello e l'esperienza utente delle applicazioni abilitate per ML. Sui dispositivi iOS, puoi abilitare l'uso dell'esecuzione con accelerazione GPU dei tuoi modelli utilizzando un delegato . I delegati fungono da driver hardware per TensorFlow Lite, consentendoti di eseguire il codice del tuo modello su processori GPU.

Questa pagina descrive come abilitare l'accelerazione GPU per i modelli TensorFlow Lite nelle app iOS. Per ulteriori informazioni sull'utilizzo del delegato GPU per TensorFlow Lite, comprese le best practice e le tecniche avanzate, vedere la pagina dei delegati GPU .

Usa la GPU con l'API interprete

L' API dell'interprete TensorFlow Lite fornisce una serie di API generiche per la creazione di applicazioni di machine learning. Le seguenti istruzioni ti guidano attraverso l'aggiunta del supporto GPU a un'app iOS. Questa guida presuppone che tu disponga già di un'app iOS in grado di eseguire correttamente un modello ML con TensorFlow Lite.

Modifica il Podfile per includere il supporto GPU

A partire dalla versione TensorFlow Lite 2.3.0, il delegato GPU viene escluso dal pod per ridurre le dimensioni binarie. Puoi includerli specificando una sottospecifica per il pod TensorFlowLiteSwift :

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

O

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

Puoi anche utilizzare TensorFlowLiteObjC o TensorFlowLiteC se desideri utilizzare Objective-C, disponibile per le versioni 2.4.0 e successive, o l'API C.

Inizializza e usa il delegato GPU

È possibile utilizzare il delegato GPU con l' API TensorFlow Lite Interpreter con diversi linguaggi di programmazione. Swift e Objective-C sono consigliati, ma puoi anche usare C++ e C. Se utilizzi una versione di TensorFlow Lite precedente alla 2.4, è necessario utilizzare C. Gli esempi di codice seguenti descrivono come usare il delegato con ciascuno di questi linguaggi.

Veloce

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

Obiettivo-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 (prima della 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);
      

Note sull'uso della lingua dell'API della GPU

  • Le versioni di TensorFlow Lite precedenti alla 2.4.0 possono utilizzare solo l'API C per Objective-C.
  • L'API C++ è disponibile solo quando utilizzi bazel o crei TensorFlow Lite da solo. L'API C++ non può essere usata con CocoaPods.
  • Quando si utilizza TensorFlow Lite con il delegato GPU con C++, ottenere il delegato GPU tramite la funzione TFLGpuDelegateCreate() e quindi passarlo a Interpreter::ModifyGraphWithDelegate() , invece di chiamare Interpreter::AllocateTensors() .

Crea e testa con la modalità di rilascio

Passa a una build di rilascio con le impostazioni dell'acceleratore API Metal appropriate per ottenere prestazioni migliori e per il test finale. Questa sezione spiega come abilitare una build di rilascio e configurare l'impostazione per l'accelerazione Metal.

Per passare a una build di rilascio:

  1. Modifica le impostazioni di build selezionando Prodotto > Schema > Modifica schema... e quindi selezionando Esegui .
  2. Nella scheda Info , cambia Configurazione build in Release e deseleziona Debug eseguibile .impostazione del rilascio
  3. Fare clic sulla scheda Opzioni e modificare GPU Frame Capture su Disabled e Metal API Validation su Disabled .
    creazione di opzioni di metallo
  4. Assicurati di selezionare build solo versione su architettura a 64 bit. In Project navigator > tflite_camera_example > PROJECT > your_project_name > Build Settings imposta Build Active Architecture Only > Release to Yes . impostazione delle opzioni di rilascio

Supporto GPU avanzato

Questa sezione illustra gli usi avanzati del delegato GPU per iOS, incluse le opzioni di delega, i buffer di input e output e l'uso di modelli quantizzati.

Opzioni del delegato per iOS

Il costruttore per il delegato GPU accetta una struct di opzioni nell'API Swift, nell'API Objective-C e nell'API C. Il passaggio di nullptr (API C) o nulla (Objective-C e Swift API) all'inizializzatore imposta le opzioni predefinite (che sono spiegate nell'esempio di utilizzo di base sopra).

Veloce

// 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()
      

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

Buffer di input/output utilizzando l'API C++

Il calcolo sulla GPU richiede che i dati siano disponibili per la GPU. Questo requisito spesso significa che è necessario eseguire una copia in memoria. Dovresti evitare che i tuoi dati oltrepassino il limite di memoria CPU/GPU, se possibile, poiché ciò può richiedere una notevole quantità di tempo. Di solito, tale incrocio è inevitabile, ma in alcuni casi speciali l'uno o l'altro può essere omesso.

Se l'input della rete è un'immagine già caricata nella memoria della GPU (ad esempio, una texture GPU contenente il feed della telecamera), può rimanere nella memoria della GPU senza mai entrare nella memoria della CPU. Allo stesso modo, se l'output della rete è sotto forma di un'immagine renderizzabile, come un'operazione di trasferimento di uno stile di immagine , è possibile visualizzare direttamente il risultato sullo schermo.

Per ottenere le migliori prestazioni, TensorFlow Lite consente agli utenti di leggere e scrivere direttamente nel buffer hardware di TensorFlow e bypassare le copie evitabili della memoria.

Supponendo che l'input dell'immagine sia nella memoria della GPU, devi prima convertirlo in un oggetto MTLBuffer per Metal. È possibile associare un TfLiteTensor a un MTLBuffer preparato dall'utente con la funzione TFLGpuDelegateBindMetalBufferToTensor() . Si noti che questa funzione deve essere chiamata dopo Interpreter::ModifyGraphWithDelegate() . Inoltre, l'output dell'inferenza viene, per impostazione predefinita, copiato dalla memoria della GPU alla memoria della CPU. È possibile disattivare questo comportamento chiamando Interpreter::SetAllowBufferHandleOutput(true) durante l'inizializzazione.

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;
      

Una volta disattivato il comportamento predefinito, la copia dell'output dell'inferenza dalla memoria della GPU alla memoria della CPU richiede una chiamata esplicita a Interpreter::EnsureTensorDataIsReadable() per ogni tensore di output. Questo approccio funziona anche per i modelli quantizzati, ma è comunque necessario utilizzare un buffer di dimensioni float32 con float32 data , poiché il buffer è associato al buffer dequantizzato interno.

Modelli quantizzati

Le librerie dei delegati GPU iOS supportano i modelli quantizzati per impostazione predefinita . Non è necessario apportare modifiche al codice per utilizzare i modelli quantizzati con il delegato GPU. La sezione seguente spiega come disabilitare il supporto quantizzato per scopi di test o sperimentali.

Disabilita il supporto del modello quantizzato

Il codice seguente mostra come disabilitare il supporto per i modelli quantizzati.

Veloce

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

Obiettivo-C

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

C

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

    TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
      

Per ulteriori informazioni sull'esecuzione di modelli quantizzati con accelerazione GPU, vedere Panoramica dei delegati GPU .