Ayuda a proteger la Gran Barrera de Coral con TensorFlow en Kaggle Únete Challenge

Delegado de GPU de TensorFlow Lite

TensorFlow Lite es compatible con varios aceleradores de hardware. Este documento describe cómo usar el backend de la GPU con las API delegadas de TensorFlow Lite en Android e iOS.

Las GPU están diseñadas para tener un alto rendimiento para cargas de trabajo masivamente paralelizables. Por lo tanto, son adecuados para redes neuronales profundas, que constan de una gran cantidad de operadores, cada uno de los cuales trabaja en algunos tensores de entrada que pueden dividirse fácilmente en cargas de trabajo más pequeñas y llevarse a cabo en paralelo, lo que generalmente resulta en una latencia más baja. En el mejor de los casos, la inferencia en la GPU ahora puede ejecutarse lo suficientemente rápido para aplicaciones en tiempo real que antes no estaban disponibles.

A diferencia de las CPU, las GPU calculan con números de punto flotante de 16 o 32 bits y no requieren cuantificación para un rendimiento óptimo. El delegado acepta modelos cuantificados de 8 bits, pero el cálculo se realizará en números de coma flotante. Consulte la documentación avanzada para más detalles.

Otro beneficio de la inferencia de GPU es su eficiencia energética. Las GPU realizan los cálculos de una manera muy eficiente y optimizada, de modo que consumen menos energía y generan menos calor que cuando se ejecuta la misma tarea en las CPU.

Tutoriales de la aplicación de demostración

La forma más fácil de probar el delegado de GPU es seguir los tutoriales a continuación, que describen la construcción de nuestras aplicaciones de demostración de clasificación con soporte de GPU. El código de la GPU es solo binario por ahora; pronto será de código abierto. Una vez que comprenda cómo hacer que nuestras demostraciones funcionen, puede probar esto en sus propios modelos personalizados.

Android (con Android Studio)

Para ver un tutorial paso a paso, ver la GPU Delegado para Android de vídeo.

Paso 1. Clona el código fuente de TensorFlow y ábrelo en Android Studio

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

Paso 2. Editar app/build.gradle utilizar la AAR GPU nocturno

Añadir el tensorflow-lite-gpu paquete contigua a la actual tensorflow-lite paquete en el vigente dependencies bloque.

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

Paso 3. Construya y ejecute

Ejecutar → Ejecutar 'aplicación'. Cuando ejecute la aplicación, verá un botón para habilitar la GPU. Cambie de modelo cuantizado a flotante y luego haga clic en GPU para ejecutar en la GPU.

ejecutar la demostración de gpu de android y cambiar a gpu

iOS (con XCode)

Para ver un tutorial paso a paso, ver la GPU Delegado para iOS vídeo.

Paso 1. Obtenga el código fuente de la demostración y asegúrese de que se compile.

Sigue nuestra demostración iOS App tutorial . Esto lo llevará a un punto en el que la demostración de la cámara iOS sin modificar está funcionando en su teléfono.

Paso 2. Modifica el Podfile para usar TensorFlow Lite GPU CocoaPod

A partir de la versión 2.3.0, el delegado de GPU predeterminado se excluye del pod para reducir el tamaño binario. Puede incluirlos especificando subespec. Para TensorFlowLiteSwift vaina:

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

O

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

Usted puede hacer lo mismo para TensorFlowLiteObjC o TensorFlowLitC si desea utilizar el Objective-C (de liberación 2.4.0) o C API.

Antes de la versión 2.3.0

Hasta TensorFlow Lite 2.0.0

Hemos construido un CocoaPod binario que incluye el delegado de la GPU. Para cambiar el proyecto y usarlo, modifique el archivo `tensorflow / tensorflow / lite / examples / ios / camera / Podfile` para usar el pod` TensorFlowLiteGpuExperimental` en lugar de `TensorFlowLite`.


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

Hasta TensorFlow Lite 2.2.0

Desde TensorFlow Lite 2.1.0 a 2.2.0, el delegado de GPU se incluye en el pod `TensorFlowLiteC`. Puede elegir entre `TensorFlowLiteC` y` TensorFlowLiteSwift` según el idioma.

Paso 3. Habilite el delegado de GPU

Para activar el código que va a utilizar el delegado de la GPU, que tendrá que cambiar TFLITE_USE_GPU_DELEGATE de 0 a 1 en CameraExampleViewController.h .

#define TFLITE_USE_GPU_DELEGATE 1

Paso 4. Cree y ejecute la aplicación de demostración

Después de seguir el paso anterior, debería poder ejecutar la aplicación.

Paso 5. Modo de liberación

Mientras que en el Paso 4 se ejecutó en modo de depuración, para obtener un mejor rendimiento, debe cambiar a una versión de lanzamiento con la configuración de Metal óptima adecuada. En particular, para editar estos ajustes van al Product > Scheme > Edit Scheme... . Seleccione Run . En la Info pestaña, el cambio Build Configuration , de Debug de Release , desmarque Debug executable .

configurando la liberación

A continuación, haga clic en el Options pestaña y el cambio GPU Frame Capture para Disabled y Metal API Validation a Disabled .

configurar opciones de metal

Por último, asegúrese de seleccionar compilaciones de solo versión en arquitectura de 64 bits. Bajo Project navigator -> tflite_camera_example -> PROJECT -> tflite_camera_example -> Build Settings establecer Build Active Architecture Only > Release Yes.

configurar opciones de lanzamiento

Probar el delegado de GPU en su propio modelo

Androide

Hay dos maneras de invocar la aceleración modelo dependiendo de si está utilizando Encuadernación Android Studio ML Modelo o TensorFlow Lite intérprete.

Intérprete de TensorFlow Lite

Mire la demostración para ver cómo agregar el delegado. En su aplicación, añadir el AAR que el anterior, importación org.tensorflow.lite.gpu.GpuDelegate módulo, y el uso de la addDelegate función para registrar el delegado GPU para el intérprete:

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)
      

Java

    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

Rápido

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

C objetivo

    // 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 (hasta 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.
```

No proporcionamos una devolución de llamada por este error, ya que no se trata de un verdadero error en tiempo de ejecución, sino algo que el desarrollador puede observar mientras intenta que la red se ejecute en el delegado.

Consejos para la optimización

Optimización para dispositivos móviles

Algunas operaciones que son triviales en la CPU pueden tener un alto costo para la GPU en dispositivos móviles. Las operaciones de formar de nuevo son particularmente caros de mantener, incluyendo BATCH_TO_SPACE , SPACE_TO_BATCH , SPACE_TO_DEPTH , y así sucesivamente. Debe examinar de cerca el uso de las operaciones de remodelación y considerar que pueden haberse aplicado solo para explorar datos o para las primeras iteraciones de su modelo. Eliminarlos puede mejorar significativamente el rendimiento.

En la GPU, los datos del tensor se dividen en 4 canales. Por lo tanto, un cálculo en un tensor de la forma [B,H,W,5] llevará a cabo sobre el mismo en un tensor de la forma [B,H,W,8] pero significativamente peor que [B,H,W,4] . En ese sentido, si el hardware de la cámara admite cuadros de imagen en RGBA, la alimentación de esa entrada de 4 canales es significativamente más rápida, ya que se puede evitar una copia de memoria (desde RGB de 3 canales a RGBX de 4 canales).

Para obtener el mejor rendimiento, debe considerar volver a capacitar al clasificador con una arquitectura de red optimizada para dispositivos móviles. La optimización para la inferencia en el dispositivo puede reducir drásticamente la latencia y el consumo de energía al aprovechar las funciones de hardware móvil.

Reducir el tiempo de inicialización con serialización

La función de delegado de GPU le permite cargar desde el código del kernel precompilado y los datos del modelo serializados y guardados en el disco de ejecuciones anteriores. Este enfoque evita la recompilación y reduce el tiempo de inicio hasta en un 90%. Para obtener instrucciones sobre cómo aplicar la serialización a su proyecto, consulte la GPU Delegado serialización .