Delegato dell'accelerazione GPU per iOS

L'utilizzo di GPU (Graphics Processing Unit) per l'esecuzione dei 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 consentire 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 sui processori GPU.

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

Utilizza GPU con l'API Interpreter

L'API Interpreter di TensorFlow Lite fornisce un set di API generiche per la creazione di applicazioni di machine learning. Le seguenti istruzioni illustrano come aggiungere il supporto per GPU a un'app per iOS. Questa guida presuppone che tu disponga già di un'app per iOS in grado di eseguire correttamente un modello ML con TensorFlow Lite.

Modifica il podfile in modo da includere il supporto GPU

A partire dalla release 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',

OR

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

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

Inizializza e utilizza il delegato GPU

Puoi utilizzare il delegato GPU con l'API Interpreter di TensorFlow Lite con una serie di linguaggi di programmazione. Sono consigliati Swift e Objective-C, ma puoi anche usare C++ e C. L'uso di C è obbligatorio se usi una versione di TensorFlow Lite precedente alla 2.4. I seguenti esempi di codice descrivono come utilizzare il delegato con ciascuna di queste lingue.

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 (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'utilizzo del linguaggio dell'API 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 in autonomia. L'API C++ non può essere utilizzata con CocoaPods.
  • Quando utilizzi TensorFlow Lite con il delegato GPU con C++, ottieni la delega GPU tramite la funzione TFLGpuDelegateCreate() e poi passala a Interpreter::ModifyGraphWithDelegate(), anziché chiamare Interpreter::AllocateTensors().

Crea e testa con la modalità di release

Passa a una build di release con le impostazioni appropriate dell'acceleratore dell'API Metal per migliorare le prestazioni e per i test finali. Questa sezione spiega come abilitare una build di release e configurare l'impostazione per l'accelerazione Metal.

Per passare a una build di release:

  1. Per modificare le impostazioni di build, seleziona Prodotto > Schema > Modifica schema..., quindi seleziona Esegui.
  2. Nella scheda Informazioni, cambia Configurazione build in Release e deseleziona Debug eseguibile. la configurazione della release
  3. Fai clic sulla scheda Opzioni e cambia GPU Frame Capture in Disabled (Disabilitata) e Metal API Validation (Convalida API Metal) su Disabled (Disabilitata).
    la configurazione di opzioni in metallo
  4. Assicurati di selezionare Build-only release su architettura a 64 bit. In Navigatore progetti > tflite_camera_example > PROGETTO > nome_progetto > Impostazioni build imposta Crea solo architettura attiva > Release su . l&#39;impostazione delle opzioni
di rilascio

Supporto avanzato delle GPU

Questa sezione illustra gli utilizzi avanzati del delegato GPU per iOS, tra cui le opzioni di delega, i buffer di input e di output e l'uso di modelli quantiizzati.

Delega opzioni per iOS

Il costruttore per il delegato GPU accetta un struct di opzioni nell'API Swift, nell'API Objective-C e nell'API C. Il passaggio di nullptr (API C) o di nessun elemento (Obiettivo-C e API Swift) all'inizializzazione imposta le opzioni predefinite (descritte nell'esempio di utilizzo di base riportato sopra).

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

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

Il calcolo sulla GPU richiede che i dati siano disponibili per la GPU. Questo requisito spesso richiede di eseguire una copia della memoria. Se possibile, dovresti evitare che i tuoi dati superino il limite di memoria CPU/GPU, poiché ciò può richiedere molto tempo. Solitamente, questo attraversamento è inevitabile, ma in alcuni casi speciali può essere omesso.

Se l'input della rete è un'immagine già caricata nella memoria GPU (ad esempio, una texture GPU contenente il feed della videocamera), può rimanere nella memoria GPU senza mai entrare nella memoria della CPU. Analogamente, se l'output della rete è sotto forma di un'immagine di cui è possibile eseguire il rendering, come un'operazione di trasferimento dello stile immagine, puoi visualizzare direttamente il risultato sullo schermo.

Per ottenere le migliori prestazioni, TensorFlow Lite consente agli utenti di leggere e scrivere direttamente dal buffer hardware di TensorFlow, nonché di bypassare le copie in memoria evitabili.

Supponendo che l'immagine di input sia nella memoria GPU, devi prima convertirla in un oggetto MTLBuffer per Metal. Puoi associare un TfLiteTensor a un MTLBuffer preparato dall'utente con la funzione TFLGpuDelegateBindMetalBufferToTensor(). Tieni presente che questa funzione deve essere chiamata dopo il giorno Interpreter::ModifyGraphWithDelegate(). Inoltre, l'output di inferenza viene, per impostazione predefinita, copiato dalla memoria GPU alla memoria della CPU. Puoi 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 di 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 quantistici, ma devi comunque utilizzare un buffer con dimensioni float32 con dati float32, perché il buffer è associato al buffer de-quantizzato interno.

Modelli quantizzati

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

Disabilita il supporto del modello quantizzato

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

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

Per ulteriori informazioni sull'esecuzione di modelli quantizzati con l'accelerazione GPU, consulta la panoramica relativa al delegato GPU.