Delegato dell'accelerazione GPU per iOS

Utilizzo delle GPU (Graphics Processing Unit) per eseguire i modelli di machine learning (ML) può migliorare notevolmente le prestazioni del modello e l'esperienza utente delle tue applicazioni abilitate per il machine learning. Sui dispositivi iOS, puoi attivare l'utilizzo di L'esecuzione dei modelli con accelerazione GPU utilizzando un delegato. I delegati agiscono da driver hardware per LiteRT, che ti consente di eseguire il codice del tuo modello sui processori GPU.

In questa pagina viene descritto come attivare l'accelerazione GPU per i modelli LiteRT in app per iOS Per saperne di più sull'utilizzo del delegato GPU per LiteRT: incluse best practice e tecniche avanzate, consulta la GPU delegata.

Utilizza GPU con l'API Interpreter

L'interprete di LiteRT dell'API fornisce un insieme di parametri per creare applicazioni di machine learning. Le seguenti istruzioni ti guidano nell'aggiunta del supporto GPU a un'app per iOS. Questa guida presuppone che tu abbia già un'app per iOS in grado di eseguire correttamente un modello ML con LiteRT.

Modifica il podfile per includere il supporto GPU

A partire dalla release LiteRT 2.3.0, il delegato GPU è escluso dal pod per ridurre le dimensioni binarie. Puoi includerli specificando un per il pod TensorFlowLiteSwift:

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

OPPURE

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

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

Inizializza e utilizza il delegato GPU

Puoi utilizzare il delegato GPU con LiteRT Interpreter API con una serie di funzionalità lingue diverse. Le opzioni Swift e Objective-C sono consigliate, ma puoi anche usare C++ e C. Se usi una versione di LiteRT precedente, è necessario utilizzare C. rispetto a 2.4. I seguenti esempi di codice spiegano come utilizzare il delegato con ogni di queste lingue.

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 (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 LiteRT precedenti alla 2.4.0 possono utilizzare solo l'API C per Obiettivo-C.
  • L'API C++ è disponibile solo se utilizzi bazel o crei TensorFlow Lite, in autonomia. L'API C++ non può essere utilizzata con CocoaPods.
  • Quando utilizzi LiteRT con il delegato GPU con C++, recupera la GPU delegare tramite la funzione TFLGpuDelegateCreate() e poi passarla Interpreter::ModifyGraphWithDelegate(), anziché chiamare Interpreter::AllocateTensors().

Creazione e test con la modalità di rilascio

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

Per passare a una build di release:

  1. Modifica le impostazioni della build selezionando Prodotto > Schema > Modifica schema... e selezionando Esegui.
  2. Nella scheda Informazioni, cambia Configurazione build in Release e deseleziona Esegui il debug dell'eseguibile. configurazione in corso
rilasciare
  3. Fai clic sulla scheda Opzioni e imposta Acquisizione frame GPU su Disabilitata. e Metal API Validation su Disabled (Disabilitata).
    configurazione del metallo
opzioni
  4. Assicurati di selezionare Build di sola release su architettura a 64 bit. Sottopeso Navigazione progetti > esempio_fotocamera_tflite > PROGETTO > tuo_nome_progetto > Impostazioni build imposta Build Active Architecture Only > Rilascia per . configurazione della release
opzioni

Supporto GPU avanzato

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

Delega opzioni per iOS

Il costruttore per il delegato GPU accetta un struct di opzioni in Swift API, Objective-C API, e C tramite Google Cloud. Trasmettere nullptr (API C) o nulla (API Objective-C e Swift) alla l'inizializzatore imposta le opzioni predefinite (spiegate nella sezione esempio 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 spesso significa che devi eseguire una copia della memoria. Dovresti evitare di avere se possibile, i tuoi dati superano il limite di memoria di CPU/GPU, poiché questo può per una quantità di tempo significativa. Di solito, questo tipo di attraversamento è inevitabile, ma in alcuni per i casi speciali, si può omettere l'uno o l'altro.

Se l'input della rete è un'immagine già caricata nella memoria GPU (ad 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 di un'immagine di cui è possibile eseguire il rendering, ad esempio uno stile immagine trasferimento operativa, puoi visualizzare il risultato direttamente sullo schermo.

Per ottenere le migliori prestazioni, LiteRT consente agli utenti di le operazioni di lettura e scrittura direttamente nel buffer hardware di TensorFlow e di bypass di copie di memoria evitabili.

Supponendo che l'input dell'immagine sia nella memoria GPU, devi prima convertirlo in un Oggetto MTLBuffer per metallo. Puoi associare un TfLiteTensor a un MTLBuffer preparato dall'utente con TFLGpuDelegateBindMetalBufferToTensor() personalizzata. Tieni presente che questa funzione deve essere chiamata dopo Interpreter::ModifyGraphWithDelegate(). Inoltre, l'output di inferenza è per impostazione predefinita, copiati dalla memoria GPU alla memoria CPU. Puoi disattivare questa impostazione. chiamando il numero Interpreter::SetAllowBufferHandleOutput(true) durante 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, copia l'output di inferenza dalla GPU dalla memoria alla memoria della CPU richiede una chiamata esplicita Interpreter::EnsureTensorDataIsReadable() per ogni tensore di output. Questo funziona anche per i modelli quantizzati, ma devi comunque utilizzare una Buffer con dimensioni float32 e dati float32, perché il buffer è associato alla buffer dequantizzato interno.

Modelli quantificati

Le librerie delegati GPU iOS supportano i modelli quantizzati per impostazione predefinita. Non devi devi apportare modifiche al codice per usare modelli quantizzati con il delegato della GPU. La la seguente sezione spiega come disattivare il supporto quantizzato per i test o a scopi sperimentali.

Disabilita il supporto dei modelli quantiizzati

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

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 Panoramica dei delegati alle GPU.