O Dia da Comunidade de ML é dia 9 de novembro! Junte-nos para atualização de TensorFlow, JAX, e mais Saiba mais

Delegado da GPU TensorFlow Lite

O TensorFlow Lite é compatível com 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 iOS.

As GPUs são projetadas para ter alto rendimento 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 realizados em paralelo, normalmente resultando em menor latência. No melhor cenário, a inferência na GPU pode agora ser executada com rapidez suficiente para aplicativos em tempo real não disponíveis anteriormente.

Ao contrário das CPUs, as GPUs computam com números de ponto flutuante de 16 ou 32 bits e não requerem quantização para desempenho ideal. O delegado aceita modelos quantizados de 8 bits, mas o cálculo será executado 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 maneira muito eficiente e otimizada, de forma 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 testar o delegado da GPU é seguir os tutoriais abaixo, que descrevem a construção de nossos aplicativos de demonstração de classificação com suporte para GPU. O código da GPU é apenas binário por enquanto; ele terá o código aberto em breve. Depois de entender como fazer nossas demonstrações funcionarem, você pode experimentar em seus próprios modelos personalizados.

Android (com Android Studio)

Para obter 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 ao lado do 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

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

executando demonstração gpu do Android e alternar para gpu

iOS (com XCode)

Para obter um tutorial passo a passo, assista ao vídeo Delegado da GPU para iOS .

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

Siga o nosso iOS Demo App tutorial . Isso o levará a um ponto em que a demonstração não modificada da câmera iOS está funcionando em seu telefone.

Etapa 2. Modificar 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 subespec. 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 a API Objective-C (da versão 2.4.0) ou C.

Antes do lançamento 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. Habilite o delegado GPU

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

#define TFLITE_USE_GPU_DELEGATE 1

Etapa 4. Construir e executar o aplicativo de demonstração

Depois de seguir a etapa anterior, você deve conseguir 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 alterar para uma versão de compilação com as configurações de Metal ideais adequadas. 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 a liberação

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 lançamento na arquitetura de 64 bits. Em Project navigator -> tflite_camera_example -> PROJECT -> tflite_camera_example -> Build Settings defina Build Active Architecture Only > Release como Yes.

configurando opções de lançamento

Experimentando o delegado GPU em seu próprio modelo

Android

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

Intérprete TensorFlow Lite

Veja a demonstração para ver como adicionar o delegado. Em seu aplicativo, adicione o AAR conforme acima, importe o módulo org.tensorflow.lite.gpu.GpuDelegate e use a função addDelegate para registrar o delegado GPU para o 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 ...
    }
      

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

Modelos e operações compatíveis

Com o lançamento do delegado GPU, incluímos alguns modelos que podem ser executados no back-end:

Para ver uma lista completa de operações com suporte, consulte a documentação avançada .

Modelos e operações não suportados

Se algumas das operações não forem suportadas pelo delegado da GPU, a estrutura executará apenas uma parte do gráfico na GPU e a parte restante na CPU. Devido ao alto custo de sincronização de CPU / GPU, um modo de execução dividido como este geralmente resulta em desempenho mais lento do que quando toda a rede é executada apenas na CPU. Nesse caso, o usuário receberá um aviso como:

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

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

Dicas para otimização

Algumas operações que são triviais na CPU podem ter um custo alto para a GPU. Uma classe de tal operação são várias formas de operações de remodelagem, incluindo BATCH_TO_SPACE , SPACE_TO_BATCH , SPACE_TO_DEPTH e assim por diante. Se esses ops forem inseridos na rede apenas para o pensamento lógico do arquiteto de rede, vale a pena removê-los para 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á aproximadamente 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 para RGBX de 4 canais) pode ser evitada.

Para obter o melhor desempenho, não hesite em treinar novamente seu classificador com uma arquitetura de rede otimizada para dispositivos móveis. Essa é uma parte significativa da otimização para inferência no dispositivo.