Delegado de GPU do TensorFlow Lite

O TensorFlow Lite oferece suporte a vários aceleradores de hardware. Este documento descreve como usar o back-end da GPU usando as APIs delegadas do TensorFlow Lite no Android e no iOS.

As GPUs são projetadas para ter alta taxa de transferência para cargas de trabalho massivamente paralelizáveis. Assim, eles são adequados para redes neurais profundas, que consistem em um grande número de operadores, cada um trabalhando em alguns tensores de entrada que podem ser facilmente divididos em cargas de trabalho menores e executados em paralelo, normalmente resultando em menor latência. No melhor cenário, a inferência na GPU agora pode ser executada com rapidez suficiente para aplicativos em tempo real anteriormente não disponíveis.

Ao contrário das CPUs, as GPUs computam com números de ponto flutuante de 16 bits ou 32 bits e não requerem quantização para um desempenho ideal. O delegado aceita modelos quantizados de 8 bits, mas o cálculo será realizado em números de ponto flutuante. Consulte a documentação avançada para obter detalhes.

Outro benefício com a inferência de GPU é sua eficiência de energia. As GPUs realizam os cálculos de forma muito eficiente e otimizada, de modo que consomem menos energia e geram menos calor do que quando a mesma tarefa é executada em CPUs.

Tutoriais de aplicativos de demonstração

A maneira mais fácil de experimentar o delegado de GPU é seguir os tutoriais abaixo, que passam pela construção de nossos aplicativos de demonstração de classificação com suporte a GPU. O código da GPU é apenas binário por enquanto; será de código aberto em breve. Depois de entender como fazer nossas demonstrações funcionarem, você pode experimentar isso em seus próprios modelos personalizados.

Android (com Android Studio)

Para um tutorial passo a passo, assista ao vídeo GPU Delegate para Android .

Etapa 1. Clone o código-fonte do TensorFlow e abra-o no Android Studio

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

Etapa 2. Edite app/build.gradle para usar o GPU AAR noturno

Adicione o tensorflow-lite-gpu junto com o pacote tensorflow-lite existente no bloco de dependencies existente.

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

Etapa 3. Construir e executar

Executar → Executar 'aplicativo'. Ao executar o aplicativo, você verá um botão para habilitar a GPU. Mude de modelo quantizado para flutuante e clique em GPU para executar na GPU.

executando a demonstração da gpu android e mude para gpu

iOS (com XCode)

Para um tutorial passo a passo, assista ao vídeo GPU Delegate para iOS .

Etapa 1. Obtenha o código-fonte de demonstração e certifique-se de compilar.

Siga nosso tutorial do aplicativo de demonstração para iOS. Isso levará você a um ponto em que a demonstração da câmera iOS não modificada está funcionando no seu telefone.

Etapa 2. Modifique o Podfile para usar o TensorFlow Lite GPU CocoaPod

A partir da versão 2.3.0, por padrão, o delegado da GPU é excluído do pod para reduzir o tamanho do binário. Você pode incluí-los especificando subspec. Para o pod TensorFlowLiteSwift :

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

OU

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

Você pode fazer o mesmo para TensorFlowLiteObjC ou TensorFlowLitC se quiser usar o Objective-C (da versão 2.4.0) ou a API C.

Antes da versão 2.3.0

Até TensorFlow Lite 2.0.0

Construímos um CocoaPod binário que inclui o delegado da GPU. Para mudar o projeto para usá-lo, modifique o arquivo `tensorflow/tensorflow/lite/examples/ios/camera/Podfile` para usar o pod `TensorFlowLiteGpuExperimental` em vez de `TensorFlowLite`.


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

Até TensorFlow Lite 2.2.0

Do TensorFlow Lite 2.1.0 ao 2.2.0, o delegado da GPU está incluído no pod `TensorFlowLiteC`. Você pode escolher entre `TensorFlowLiteC` e `TensorFlowLiteSwift` dependendo do idioma.

Etapa 3. Ative o delegado da GPU

Para habilitar o código que usará o delegado da GPU, você precisará alterar TFLITE_USE_GPU_DELEGATE de 0 para 1 em CameraExampleViewController.h .

#define TFLITE_USE_GPU_DELEGATE 1

Etapa 4. Crie e execute o aplicativo de demonstração

Depois de seguir a etapa anterior, você poderá executar o aplicativo.

Etapa 5. Modo de liberação

Enquanto na Etapa 4 você executou no modo de depuração, para obter melhor desempenho, você deve mudar para uma versão de versão com as configurações ideais do Metal apropriadas. Em particular, para editar essas configurações, vá para Product > Scheme > Edit Scheme... . Selecione Run . Na guia Info , altere Build Configuration , de Debug para Release , desmarque Debug executable .

configurando o lançamento

Em seguida, clique na guia Options e altere GPU Frame Capture para Disabled e Metal API Validation para Disabled .

configurando opções de metal

Por último, certifique-se de selecionar compilações somente de versão na arquitetura de 64 bits. Em Project navigator -> tflite_camera_example -> PROJECT -> tflite_camera_example -> Build Settings defina Build Active Architecture Only > Release para Yes.

configurando opções de lançamento

Tentando o delegado da GPU em seu próprio modelo

Android

Há duas maneiras de invocar a aceleração de modelo, dependendo de você estar usando o Android Studio ML Model Binding ou o TensorFlow Lite Interpreter.

Interpretador do TensorFlow Lite

Veja a demonstração para ver como adicionar o delegado. Em seu aplicativo, adicione o AAR como acima, importe o módulo org.tensorflow.lite.gpu.GpuDelegate e use a função addDelegate para registrar o delegado da GPU no interpretador:

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

Objetivo-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 (Até 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.
```

Não fornecemos um retorno de chamada para essa falha, pois essa não é uma falha real em tempo de execução, mas algo que o desenvolvedor pode observar enquanto tenta fazer com que a rede seja executada no delegado.

Dicas para otimização

Otimização para dispositivos móveis

Algumas operações que são triviais na CPU podem ter um alto custo para a GPU em dispositivos móveis. As operações de remodelação são particularmente caras para executar, incluindo BATCH_TO_SPACE , SPACE_TO_BATCH , SPACE_TO_DEPTH e assim por diante. Você deve examinar de perto o uso de operações de remodelação e considerar que pode ter sido aplicado apenas para explorar dados ou para iterações iniciais de seu modelo. Removê-los pode melhorar significativamente o desempenho.

Na GPU, os dados do tensor são divididos em 4 canais. Assim, um cálculo em um tensor de forma [B,H,W,5] terá o mesmo desempenho em um tensor de forma [B,H,W,8] mas significativamente pior do que [B,H,W,4] . Nesse sentido, se o hardware da câmera suportar quadros de imagem em RGBA, alimentar essa entrada de 4 canais é significativamente mais rápido, pois uma cópia de memória (de RGB de 3 canais a RGBX de 4 canais) pode ser evitada.

Para obter o melhor desempenho, considere treinar novamente o classificador com uma arquitetura de rede otimizada para dispositivos móveis. A otimização para inferência no dispositivo pode reduzir drasticamente a latência e o consumo de energia aproveitando os recursos de hardware móvel.

Reduzindo o tempo de inicialização com serialização

O recurso de delegado de GPU permite que você carregue a partir de código de kernel pré-compilado e dados de modelo serializados e salvos em disco de execuções anteriores. Essa abordagem evita a recompilação e reduz o tempo de inicialização em até 90%. Para obter instruções sobre como aplicar a serialização ao seu projeto, consulte GPU Delegate Serialization .