Usar unidades de processamento gráfico (GPUs) para executar seus modelos de machine learning (ML) pode melhorar muito a performance do modelo e a experiência do usuário dos aplicativos habilitados para ML. O LiteRT permite o uso de GPUs e outros processadores especializados por um driver de hardware chamado delegados. Ativar o uso de GPUs com seus aplicativos de ML LiteRT pode trazer os seguintes benefícios:
- Velocidade: as GPUs são criadas para alto throughput de cargas de trabalho paralelas. Esse design os torna adequados para redes neurais profundas, que consistem em um grande número de operadores, cada um trabalhando em tensores de entrada que podem ser processados em paralelo, o que geralmente resulta em menor latência. No melhor cenário, a execução do modelo em uma GPU pode ser rápida o suficiente para permitir aplicativos em tempo real que não eram possíveis antes.
- Eficiência energética: as GPUs realizam cálculos de ML de maneira muito eficiente e otimizada, normalmente consumindo menos energia e gerando menos calor do que a mesma tarefa executada em CPUs.
Este documento oferece 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 como implementar o suporte a GPU em plataformas específicas, consulte os seguintes guias:
Suporte a operações de ML com GPU
Há algumas limitações sobre quais operações de ML do TensorFlow, ou ops, podem ser aceleradas pelo delegado de GPU do LiteRT. O delegado é compatível com as seguintes operações em precisão de ponto flutuante de 16 e 32 bits:
ADDAVERAGE_POOL_2DCONCATENATIONCONV_2DDEPTHWISE_CONV_2D v1-2EXPFULLY_CONNECTEDLOGICAL_ANDLOGISTICLSTM v2 (Basic LSTM only)MAX_POOL_2DMAXIMUMMINIMUMMULPADPRELURELURELU6RESHAPERESIZE_BILINEAR v1-3SOFTMAXSTRIDED_SLICESUBTRANSPOSE_CONV
Por padrão, todas as operações são compatíveis apenas com a versão 1. Ao ativar o suporte à quantização, as versões adequadas são ativadas, por exemplo, ADDv2.
Solução de problemas de suporte a GPU
Se algumas das operações não forem compatíveis com o delegado de GPU, o framework executará apenas uma parte do gráfico na GPU e o restante na CPU. Devido ao alto custo da sincronização de CPU/GPU, um modo de execução dividida como esse geralmente resulta em um desempenho mais lento do que quando toda a rede é executada apenas na CPU. Nesse caso, o aplicativo gera um aviso, como:
WARNING: op code #42 cannot be handled by this delegate.
Não há um callback para falhas desse tipo, já que não é uma falha real de tempo de execução. Ao testar a execução do modelo com o delegado de GPU, fique atento a esses avisos. Um grande número desses avisos pode indicar que seu modelo não é a melhor opção para uso com aceleração de GPU e pode exigir refatoração.
Exemplos de modelos
Os exemplos de modelos a seguir foram criados para aproveitar a aceleração de GPU com o LiteRT e são fornecidos para referência e teste:
- Classificação de imagens MobileNet v1 (224x224)
- Um modelo de classificação de imagens projetado para aplicativos de visão baseados em dispositivos móveis e incorporados.
(model)
* Segmentação DeepLab (257x257)
- modelo de segmentação de imagens que atribui rótulos semânticos, como cachorro, gato, carro, a cada pixel na imagem de entrada.
(modelo)
* Detecção de objetos MobileNet SSD
- Um modelo de classificação de imagens que detecta vários objetos com caixas delimitadoras.
(model)
* PoseNet para estimativa de postura
- Um modelo de visão que estima as poses das pessoas em imagens ou vídeos. (modelo)
- Um modelo de classificação de imagens que detecta vários objetos com caixas delimitadoras.
(model)
* PoseNet para estimativa de postura
- modelo de segmentação de imagens que atribui rótulos semânticos, como cachorro, gato, carro, a cada pixel na imagem de entrada.
(modelo)
* Detecção de objetos MobileNet SSD
- Um modelo de classificação de imagens projetado para aplicativos de visão baseados em dispositivos móveis e incorporados.
(model)
* Segmentação DeepLab (257x257)
Otimização para GPUs
As técnicas a seguir podem ajudar você a ter uma performance melhor ao executar modelos em hardware de GPU usando o delegado de GPU do LiteRT:
Operações de redimensionamento: algumas operações rápidas em uma CPU podem ter um custo alto para a GPU em dispositivos móveis. As operações de redimensionamento são particularmente caras para serem executadas, incluindo
BATCH_TO_SPACE,SPACE_TO_BATCH,SPACE_TO_DEPTHe assim por diante. Examine de perto o uso de operações de redimensionamento e considere que elas podem ter sido aplicadas apenas para explorar dados ou para as primeiras iterações do modelo. A remoção pode melhorar significativamente a performance.Canais de dados de imagem: na GPU, os dados de tensor são divididos em quatro canais. Portanto, um cálculo em um tensor com a forma
[B,H,W,5]tem aproximadamente o mesmo desempenho 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 em RGBA, fornecer essa entrada de quatro canais será significativamente mais rápido, já que evita uma cópia da memória de RGB de três canais para RGBX de quatro canais.Modelos otimizados para dispositivos móveis: para ter a melhor performance, considere treinar novamente seu 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.
Suporte avançado a GPU
É possível usar outras técnicas avançadas com o processamento de GPU para melhorar ainda mais 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 de GPU acelera modelos quantizados de 8 bits, incluindo:
- Modelos treinados com treinamento com reconhecimento de quantização
- Quantização de intervalo dinâmico pós-treinamento
- Quantização de número inteiro completa pós-treinamento
Para otimizar o desempenho, use modelos com tensores de entrada e saída de ponto flutuante.
Como funciona?
Como o backend da GPU suporta apenas execução em ponto flutuante, executamos modelos quantizados fornecendo a ele uma "visão em ponto flutuante" do modelo original. Em geral, isso envolve as seguintes etapas:
Tensores constantes (como pesos/vieses) são desquantizados uma vez na memória da GPU. Essa operação acontece quando o delegado é ativado para o LiteRT.
As entradas e saídas do programa de GPU, se quantizadas em 8 bits, são desquantizadas e quantizadas (respectivamente) para cada inferência. Essa operação é feita na CPU usando os kernels otimizados do LiteRT.
Os simuladores de quantização são inseridos entre as operações para imitar o comportamento quantizado. Essa abordagem é necessária para modelos em que as operações esperam que as ativações sigam os limites aprendidos durante a quantização.
Para informações sobre como ativar esse recurso com o delegado de GPU, consulte o seguinte:
Como reduzir o tempo de inicialização com serialização
O recurso de delegação de GPU permite carregar dados de modelo e código de kernel pré-compilados serializados e salvos em disco de execuções anteriores. Essa abordagem evita a recompilação e pode reduzir o tempo de inicialização em até 90%. Essa melhoria é alcançada trocando espaço em disco por economia de tempo. É possível ativar esse recurso com algumas opções de configuração, conforme mostrado nos exemplos de código a seguir:
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:
- Armazene os dados de serialização em um diretório que não esteja acessível a outros
apps. Em dispositivos Android, use
getCodeCacheDir()que aponta para um local particular do aplicativo atual. - O token do modelo precisa ser exclusivo do dispositivo para o modelo específico. É possível
calcular um token de modelo gerando uma impressão digital dos dados do modelo usando
bibliotecas como
farmhash::Fingerprint64.