Delegato GPU TensorFlow Lite

TensorFlow Lite supporta diversi acceleratori hardware. Questo documento descrive come utilizzare il back-end GPU utilizzando le API delegate TensorFlow Lite su Android e iOS.

Le GPU sono progettate per offrire un throughput elevato per carichi di lavoro estremamente parallelizzabili. Pertanto, sono adatti per reti neurali profonde, che consistono in un numero enorme di operatori, ognuno dei quali lavora su alcuni tensori di input che possono essere facilmente suddivisi in carichi di lavoro più piccoli ed eseguiti in parallelo, con conseguente latenza generalmente inferiore. Nello scenario migliore, l'inferenza sulla GPU potrebbe ora essere sufficientemente veloce per applicazioni in tempo reale precedentemente non disponibili.

A differenza delle CPU, le GPU calcolano con numeri in virgola mobile a 16 o 32 bit e non richiedono la quantizzazione per prestazioni ottimali. Il delegato accetta modelli quantizzati a 8 bit, ma il calcolo verrà eseguito in numeri in virgola mobile. Fare riferimento alla documentazione avanzata per i dettagli.

Un altro vantaggio dell'inferenza GPU è la sua efficienza energetica. Le GPU eseguono i calcoli in modo molto efficiente e ottimizzato, in modo da consumare meno energia e generare meno calore rispetto a quando lo stesso compito viene eseguito sulle CPU.

Tutorial dell'app demo

Il modo più semplice per provare il delegato GPU è seguire i tutorial seguenti, che illustrano la creazione delle nostre applicazioni demo di classificazione con supporto GPU. Il codice della GPU è solo binario per ora; sarà presto open source. Una volta capito come far funzionare le nostre demo, puoi provarlo sui tuoi modelli personalizzati.

Android (con Android Studio)

Per un tutorial passo-passo, guarda il video del delegato GPU per Android .

Passaggio 1. Clona il codice sorgente di TensorFlow e aprilo in Android Studio

git clone https://github.com/tensorflow/tensorflow

Passaggio 2. Modifica app/build.gradle per utilizzare l'AAR GPU notturno

Aggiungi il tensorflow-lite-gpu insieme al pacchetto tensorflow-lite esistente nel blocco delle dependencies esistente.

dependencies {
    ...
    implementation 'org.tensorflow:tensorflow-lite:2.3.0'
    implementation 'org.tensorflow:tensorflow-lite-gpu:2.3.0'
}

Passaggio 3. Crea ed esegui

Esegui → Esegui 'app'. Quando esegui l'applicazione vedrai un pulsante per abilitare la GPU. Passa da quantizzato a un modello float, quindi fai clic su GPU per eseguire sulla GPU.

eseguire la demo di Android gpu e passare a gpu

iOS (con XCode)

Per un tutorial passo-passo, guarda il video del delegato GPU per iOS .

Passaggio 1. Ottieni il codice sorgente della demo e assicurati che venga compilato.

Segui il nostro tutorial sull'app demo per iOS. Questo ti porterà a un punto in cui la demo della fotocamera iOS non modificata funziona sul tuo telefono.

Passaggio 2. Modificare il Podfile per utilizzare la GPU CocoaPod TensorFlow Lite

Dalla versione 2.3.0, per impostazione predefinita, il delegato GPU è escluso dal pod per ridurre le dimensioni binarie. Puoi includerli specificando sottospec. Per il pod TensorFlowLiteSwift :

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

O

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

Puoi fare in modo simile per TensorFlowLiteObjC o TensorFlowLitC se vuoi usare Objective-C (dalla versione 2.4.0) o C API.

Prima della versione 2.3.0

Fino a TensorFlow Lite 2.0.0

Abbiamo creato un CocoaPod binario che include il delegato GPU. Per cambiare il progetto in modo che lo utilizzi, modifica il file `tensorflow/tensorflow/lite/examples/ios/camera/Podfile` per usare il pod `TensorFlowLiteGpuExperimental` invece di `TensorFlowLite`.


    target 'YourProjectName'
      # pod 'TensorFlowLite', '1.12.0'
      pod 'TensorFlowLiteGpuExperimental'
    

Fino a TensorFlow Lite 2.2.0

Da TensorFlow Lite 2.1.0 a 2.2.0, il delegato GPU è incluso nel pod `TensorFlowLiteC`. Puoi scegliere tra "TensorFlowLiteC" e "TensorFlowLiteSwift" a seconda della lingua.

Passaggio 3. Abilita il delegato GPU

Per abilitare il codice che utilizzerà il delegato GPU, dovrai modificare TFLITE_USE_GPU_DELEGATE da 0 a 1 in CameraExampleViewController.h .

#define TFLITE_USE_GPU_DELEGATE 1

Passaggio 4. Crea ed esegui l'app demo

Dopo aver seguito il passaggio precedente, dovresti essere in grado di eseguire l'app.

Passaggio 5. Modalità di rilascio

Mentre nel passaggio 4 è stato eseguito in modalità di debug, per ottenere prestazioni migliori, è necessario passare a una build di rilascio con le impostazioni Metal ottimali appropriate. In particolare, per modificare queste impostazioni vai su Product > Scheme > Edit Scheme... . Seleziona Run . Nella scheda Info , modifica Build Configuration , da Debug a Release , deseleziona Debug executable .

impostazione del rilascio

Quindi fare clic sulla scheda Options e modificare GPU Frame Capture su Disabled e Metal API Validation su Disabled .

creazione di opzioni di metallo

Infine, assicurati di selezionare build di sola versione su architettura a 64 bit. In Project navigator -> tflite_camera_example -> PROJECT -> tflite_camera_example -> Build Settings build imposta Build Active Architecture Only > Release su Sì.

impostazione delle opzioni di rilascio

Provare il delegato GPU sul tuo modello

Androide

Esistono due modi per richiamare l'accelerazione del modello a seconda che si utilizzi Android Studio ML Model Binding o TensorFlow Lite Interpreter.

Interprete TensorFlow Lite

Guarda la demo per vedere come aggiungere il delegato. Nella tua applicazione, aggiungi l'AAR come sopra, importa il modulo org.tensorflow.lite.gpu.GpuDelegate e usa la funzione addDelegate per registrare il delegato GPU all'interprete:

Kotlin

    import org.tensorflow.lite.Interpreter
    import org.tensorflow.lite.gpu.CompatibilityList
    import org.tensorflow.lite.gpu.GpuDelegate

    val compatList = CompatibilityList()

    val options = Interpreter.Options().apply{
        if(compatList.isDelegateSupportedOnThisDevice){
            // if the device has a supported GPU, add the GPU delegate
            val delegateOptions = compatList.bestOptionsForThisDevice
            this.addDelegate(GpuDelegate(delegateOptions))
        } else {
            // if the GPU is not supported, run on 4 threads
            this.setNumThreads(4)
        }
    }

    val interpreter = Interpreter(model, options)

    // Run inference
    writeToInput(input)
    interpreter.run(input, output)
    readFromOutput(output)
      

Giava

    import org.tensorflow.lite.Interpreter;
    import org.tensorflow.lite.gpu.CompatibilityList;
    import org.tensorflow.lite.gpu.GpuDelegate;

    // Initialize interpreter with GPU delegate
    Interpreter.Options options = new Interpreter.Options();
    CompatibilityList compatList = CompatibilityList();

    if(compatList.isDelegateSupportedOnThisDevice()){
        // if the device has a supported GPU, add the GPU delegate
        GpuDelegate.Options delegateOptions = compatList.getBestOptionsForThisDevice();
        GpuDelegate gpuDelegate = new GpuDelegate(delegateOptions);
        options.addDelegate(gpuDelegate);
    } else {
        // if the GPU is not supported, run on 4 threads
        options.setNumThreads(4);
    }

    Interpreter interpreter = new Interpreter(model, options);

    // Run inference
    writeToInput(input);
    interpreter.run(input, output);
    readFromOutput(output);
      

iOS

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 (fino a 2.3.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);
          

## Supported Models and Ops

With the release of the GPU delegate, we included a handful of models that can
be run on the backend:

*   [MobileNet v1 (224x224) image classification](https://ai.googleblog.com/2017/06/mobilenets-open-source-models-for.html) [[download]](https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/mobilenet_v1_1.0_224.tflite)
    <br /><i>(image classification model designed for mobile and embedded based vision applications)</i>
*   [DeepLab segmentation (257x257)](https://ai.googleblog.com/2018/03/semantic-image-segmentation-with.html) [[download]](https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/deeplabv3_257_mv_gpu.tflite)
    <br /><i>(image segmentation model that assigns semantic labels (e.g., dog, cat, car) to every pixel in the input image)</i>
*   [MobileNet SSD object detection](https://ai.googleblog.com/2018/07/accelerated-training-and-inference-with.html) [[download]](https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/mobile_ssd_v2_float_coco.tflite)
    <br /><i>(image classification model that detects multiple objects with bounding boxes)</i>
*   [PoseNet for pose estimation](https://github.com/tensorflow/tfjs-models/tree/master/posenet) [[download]](https://storage.googleapis.com/download.tensorflow.org/models/tflite/gpu/multi_person_mobilenet_v1_075_float.tflite)
    <br /><i>(vision model that estimates the poses of a person(s) in image or video)</i>

To see a full list of supported ops, please see the
[advanced documentation](gpu_advanced).

## Non-supported models and ops

If some of the ops are not supported by the GPU delegate, the framework will
only run a part of the graph on the GPU and the remaining part on the CPU. Due
to the high cost of CPU/GPU synchronization, a split execution mode like this
will often result in slower performance than when the whole network is run on
the CPU alone. In this case, the user will get a warning like:

```none
WARNING: op code #42 cannot be handled by this delegate.
```

Non è stato fornito un callback per questo errore, poiché non si tratta di un vero errore di runtime, ma qualcosa che lo sviluppatore può osservare durante il tentativo di eseguire la rete sul delegato.

Suggerimenti per l'ottimizzazione

Ottimizzazione per dispositivi mobili

Alcune operazioni banali sulla CPU possono avere un costo elevato per la GPU sui dispositivi mobili. Le operazioni di rimodellamento sono particolarmente costose da eseguire, inclusi BATCH_TO_SPACE , SPACE_TO_BATCH , SPACE_TO_DEPTH e così via. È necessario esaminare attentamente l'uso delle operazioni di rimodellamento e considerare che potrebbe essere stato applicato solo per esplorare i dati o per le prime iterazioni del modello. La loro rimozione può migliorare notevolmente le prestazioni.

Sulla GPU, i dati del tensore vengono suddivisi in 4 canali. Pertanto, un calcolo su un tensore di forma [B,H,W,5] funzionerà più o meno allo stesso modo su un tensore di forma [B,H,W,8] ma significativamente peggiore di [B,H,W,4] . In tal senso, se l'hardware della fotocamera supporta i frame di immagine in RGBA, l'alimentazione di quell'input a 4 canali è significativamente più veloce poiché è possibile evitare una copia della memoria (da RGB a 3 canali a RGBX a 4 canali).

Per ottenere prestazioni ottimali, dovresti considerare di riqualificare il classificatore con un'architettura di rete ottimizzata per dispositivi mobili. L'ottimizzazione per l'inferenza sul dispositivo può ridurre drasticamente la latenza e il consumo energetico sfruttando le funzionalità dell'hardware mobile.

Riduzione del tempo di inizializzazione con la serializzazione

La funzione di delegato GPU consente di caricare dal codice del kernel precompilato e i dati del modello serializzati e salvati su disco da esecuzioni precedenti. Questo approccio evita la ricompilazione e riduce i tempi di avvio fino al 90%. Per istruzioni su come applicare la serializzazione al tuo progetto, consulta Serializzazione dei delegati GPU .