Delegados de GPU para LiteRT

Como usar unidades de processamento gráfico (GPUs) para executar modelos de machine learning (ML) pode melhorar drasticamente o desempenho do seu modelo e a experiência do usuário dos seus aplicativos com ML. A LiteRT permite o uso de GPUs e outros processadores especializados por meio de drivers de hardware chamados delega. Como ativar o uso de GPUs com o LiteRT ML aplicativos podem oferecer os seguintes benefícios:

  • Velocidade: as GPUs foram criadas para uma alta capacidade de processamento do Google Cloud. Esse design os torna adequados para redes neurais profundas, que consistem em um grande número de operadores, cada um trabalhando com tensores de entrada podem ser processados em paralelo, o que normalmente resulta em menor latência. Em o melhor cenário, executar o modelo em uma GPU pode ser rápido o suficiente para permitir aplicativos em tempo real que não eram possíveis antes.
  • Eficiência de energia: as GPUs realizam cálculos de ML de maneira muito eficiente e otimizada, normalmente consumindo menos energia e gerando menos do que a mesma tarefa em execução nas CPUs.

Este documento fornece uma visão geral do suporte a GPUs no LiteRT e alguns usos avançados para processadores de GPU. Para informações mais específicas sobre para implementar o suporte a GPUs em plataformas específicas, consulte os seguintes guias:

Suporte a operações de ML da GPU

Há algumas limitações em relação às operações, ou ops, de ML do TensorFlow é acelerado pelo delegado da GPU LiteRT. O delegado permite o operações a seguir com precisão de ponto flutuante de 16 e 32 bits:

  • ADD
  • AVERAGE_POOL_2D
  • CONCATENATION
  • CONV_2D
  • DEPTHWISE_CONV_2D v1-2
  • EXP
  • FULLY_CONNECTED
  • LOGICAL_AND
  • LOGISTIC
  • LSTM v2 (Basic LSTM only)
  • MAX_POOL_2D
  • MAXIMUM
  • MINIMUM
  • MUL
  • PAD
  • PRELU
  • RELU
  • RELU6
  • RESHAPE
  • RESIZE_BILINEAR v1-3
  • SOFTMAX
  • STRIDED_SLICE
  • SUB
  • TRANSPOSE_CONV

Por padrão, todas as operações são suportadas apenas na versão 1. Ativar a quantização support ativa as versões apropriadas, por exemplo, ADD v2.

Solução de problemas de suporte a GPUs

Se algumas das operações não tiverem suporte do delegado da GPU, o framework executar apenas uma parte do gráfico na GPU e o restante na CPU. Data de entrega devido ao alto custo da sincronização entre CPU/GPU, um modo de execução dividido como esse geralmente resulta em um desempenho mais lento do que quando a rede inteira é executada na usando apenas a CPU. Nesse caso, o aplicativo gera um aviso, como:

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

Não há callback para falhas desse tipo, porque não se trata de um falha no ambiente de execução. Ao testar a execução do seu modelo com o delegado da GPU, você deve ficar alerta para esses avisos. Um grande número desses avisos pode indicam que o modelo não é o mais adequado para uso para aceleração de GPU pode exigir a refatoração do modelo.

Exemplos de modelos

Os modelos de exemplo a seguir foram criados para aproveitar a aceleração de GPU com LiteRT e são fornecidas para referência e teste:

Como otimizar para GPUs

As técnicas a seguir podem ajudar você a ter um melhor desempenho ao executar modelos no hardware da GPU usando o delegado de GPU LiteRT:

  • Operações de remodelação: algumas operações rápidas em uma CPU podem o custo da GPU em dispositivos móveis é alto. As operações de remodelação são particularmente caras de executar, incluindo BATCH_TO_SPACE, SPACE_TO_BATCH, SPACE_TO_DEPTH e assim por diante. Examine com cuidado o uso de remodelamento operações e considere que elas podem ter sido aplicadas apenas para análise de dados ou para iterações iniciais do seu modelo. A remoção deles pode afetar significativamente para melhorar o desempenho.

  • Canais de dados de imagem: na GPU, os dados do tensor são divididos em quatro canais. Portanto, o cálculo de um tensor com o formato [B,H,W,5] é semelhante ao o mesmo em um tensor de forma [B,H,W,8], mas significativamente pior do que [B,H,W,4]. Se o hardware da câmera que você está usando for compatível com frames de imagem RGBA, porque essa entrada de quatro canais é significativamente mais rápida, porque evita uma cópia de memória de RGB de três canais para RGBX de quatro canais.

  • Modelos otimizados para dispositivos móveis: para conseguir o melhor desempenho, considere treinar novamente seu classificador com uma arquitetura de rede otimizada para dispositivos móveis. A otimização para inferências no dispositivo pode reduzir drasticamente a latência e o consumo de energia ao aproveitar os recursos de hardware do celular.

Suporte avançado a GPUs

É possível usar técnicas adicionais e avançadas com o processamento de GPU para permitir ainda para melhorar o desempenho dos modelos, incluindo quantização e serialização. As seções a seguir descrevem essas técnicas em mais detalhes.

Como usar modelos quantizados

Esta seção explica como o delegado da GPU acelera modelos quantizados de 8 bits, incluindo o seguinte:

Para otimizar o desempenho, use modelos que tenham entrada de ponto flutuante e de entrada e de saída.

Como funciona?

Como o back-end da GPU só oferece suporte à execução de ponto flutuante, executamos com uma "visualização de ponto flutuante" do modelo original. Em um geral, isso envolve as seguintes etapas:

  • Tensores constantes (como pesos/viés) são desquantizados uma vez no Memória da GPU. Essa operação acontece quando o delegado é ativado para LiteRT.

  • Entradas e saídas do programa de GPU, se quantizadas de 8 bits, serão desquantizados e quantizados (respectivamente) para cada inferência. Essa operação é feita na CPU usando os kernels otimizados do LiteRT.

  • Simuladores de quantização são inseridos entre as operações para imitar a quantização do seu modelo. Essa abordagem é necessária para modelos em que as operações esperam ativações devem seguir os limites aprendidos durante a quantização.

Para informações sobre como ativar esse recurso com o delegado da GPU, consulte o seguintes:

Como reduzir o tempo de inicialização com serialização

O recurso delegado da GPU permite carregar a partir do código de kernel pré-compilado e dados de modelo serializados e salvos em disco de execuções anteriores. Essa abordagem evita recompilação e pode reduzir o tempo de inicialização em até 90%. Essa melhoria é trocando espaço em disco pela economia de tempo. É possível ativar esse recurso com algumas opções de configuração, conforme mostrado nos exemplos de código abaixo:

C++

    TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
    options.experimental_flags |= TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_SERIALIZATION;
    options.serialization_dir = kTmpDir;
    options.model_token = kModelToken;

    auto* delegate = TfLiteGpuDelegateV2Create(options);
    if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
      

Java

    GpuDelegate delegate = new GpuDelegate(
      new GpuDelegate.Options().setSerializationParams(
        /* serializationDir= */ serializationDir,
        /* modelToken= */ modelToken));

    Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);
      

Ao usar o recurso de serialização, verifique se o código está em conformidade com estas regras de implementação:

  • Armazenar os dados de serialização em um diretório que não possa ser acessado por outras pessoas apps. Em dispositivos Android, use getCodeCacheDir() que aponta para um local que é privado para o aplicativo atual.
  • O token do modelo precisa ser exclusivo do dispositivo do modelo específico. Você pode computar um token de modelo gerando uma impressão digital com base nos dados dele usando bibliotecas, como farmhash::Fingerprint64
.