Path: blob/master/site/pt-br/lite/ios/delegates/gpu.md
25118 views
Delegado de aceleração de GPU para iOS
O uso de unidades de processamento gráfico (GPUs) para executar seus modelos de aprendizado de máquina (ML) pode melhorar drasticamente o desempenho do modelo e a experiência do usuário dos seus aplicativos com tecnologia de ML. Nos dispositivos iOS, você pode ativar a execução dos seus modelos com a aceleração de GPU usando um delegado. Os delegados atuam como drivers de hardware para o TensorFlow Lite, permitindo que você execute o código do modelo em processadores com GPU.
Esta página descreve como ativar a aceleração de GPU para os modelos do TensorFlow Lite nos apps para iOS. Confira mais informações sobre como usar o delegado de GPU para o TensorFlow Lite, incluindo práticas recomendadas e técnicas avançadas, na página delegados de GPU.
Use o GPU com a API Interpreter
A API Interpreter do TensorFlow Lite conta com um conjunto de APIs de finalidade geral para criar aplicativos de aprendizado de máquina. As instruções abaixo mostram como adicionar suporte a GPUs em um aplicativo para iOS. Este guia pressupõe que você já tenha um aplicativo para iOS que consiga executar um modelo de ML com o TensorFlow Lite.
Observação: caso você ainda não tenha um aplicativo para iOS que use o TensorFlow Lite, confira o Guia de início rápido para iOS e compile o aplicativo de demonstração. Após concluir o tutorial, você pode seguir as instruções aqui para acrescentar suporte a GPUs.
Modifique o Podfile para incluir suporte a GPUs
A partir do TensorFlow Lite versão 2.3.0, o delegado de GPU é excluído do pod para reduzir o tamanho do binário. Você pode incluí-lo especificando uma subespecificação do pod TensorFlowLiteSwift
:
OU
Você também pode usar TensorFlowLiteObjC
ou TensorFlowLiteC
se quiser utilizar a API do Objective-C, que está disponível nas versões 2.4.0 e posteriores, ou a API do C.
Observação: para o TensorFlow Lite versões 2.1.0 a 2.2.0, o delegado de GPU está incluído no pod TensorFlowLiteC
. Você pode escolher entre TensorFlowLiteC
e TensorFlowLiteSwift
, dependendo da linguagem de programação utilizada.
Inicialize e use o delegado de GPU
Você pode usar o delegado de GPU com a API Interpreter do TensorFlow Lite com diversas linguagens de programação. É recomendável utilizar Swift e Objective-C, mas também é possível usar C++ e C. É obrigatório usar o C se você estiver utilizando uma versão do TensorFlow Lite abaixo da 2.4. Os exemplos de código abaixo mostram como usar o delegado com cada uma dessas linguagens.
Swift
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 ...
// Set up interpreter. auto model = FlatBufferModel::BuildFromFile(model_path); if (!model) return false; tflite::ops::builtin::BuiltinOpResolver op_resolver; std::unique_ptr<Interpreter> interpreter; InterpreterBuilder(*model, op_resolver)(&interpreter); // Prepare GPU delegate. auto* delegate = TFLGpuDelegateCreate(/*default options=*/nullptr); if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false; // Run inference. WriteToInputTensor(interpreter->typed_input_tensor<float>(0)); if (interpreter->Invoke() != kTfLiteOk) return false; ReadFromOutputTensor(interpreter->typed_output_tensor<float>(0)); // Clean up. TFLGpuDelegateDelete(delegate);
#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);
Notas de uso das linguagens de API de GPU
Versões do TensorFlow Lite anteriores à 2.4.0 só podem usar a API do C para Objective-C.
A API do C++ está disponível somente ao usar o Bazel ou se você compilar o TensorFlow Lite. A API do C++ não pode ser usada com CocoaPods.
Ao usar o TensorFlow Lite com o delegado de GPU e C++, obtenha o delegado de GPU pela função
TFLGpuDelegateCreate()
e depois passe-o paraInterpreter::ModifyGraphWithDelegate()
em vez de chamarInterpreter::AllocateTensors()
.
Compile e teste com o modo de release
Altere para uma build de release com as configurações apropriadas do acelerador da API Metal para obter um maior desempenho e para testes finais. Esta seção explica como ativar uma build de release e definir as configurações de aceleração Metal.
Observação: para acompanhar estas instruções, é necessário ter o XCode v.10.1 ou posterior.
Para mudar para uma build de release:
Para editar as configurações da build, selecione Product > Scheme > Edit Scheme... (Produto > Esquema > Editar esquema...) e depois selecione Run (Executar).
Na guia Info (Informações), altere Build Configuration (Configuração da build) para Release e desmarque Debug executable (Depurar executável).
Clique na guia Options (Opções) e altere GPU Frame Capture (Captura de quadro de GPU) para Disabled (Desativada) e Metal API Validation (Validação da API Metal) para Disabled (Desativada).
Você deve selecionar Release-only builds on 64-bit architecture (Builds somente release em arquitetura de 64 bits). Em Project navigator > tflite_camera_example > PROJECT > your_project_name > Build Settings (Navegador do projeto > tflite_camera_example > PROJETO > nome_do_seu_projeto > Configurações da build), defina Build Active Architecture Only > Release (Compilar somente arquitetura ativa > Release) como Yes (Sim).
Suporte avançado à GPU
Esta seção fala sobre usos avançados de delegado de GPU para iOS, incluindo opções de delegado, buffers de entrada e saída e uso de modelos quantizados.
Opções de delegado para iOS
O construtor do delegado de GPU recebe uma struct
de opções na API da Swift, na API do Objective-C e na API do C. Ao passar nullptr
(API do C) ou nada (APIs do Objective-C e da Swift) ao inicializador, as opções padrão são definidas (o que é explicado no exemplo Uso básico acima).
Swift
// THIS: var options = MetalDelegate.Options() options.isPrecisionLossAllowed = false options.waitType = .passive options.isQuantizationEnabled = true let delegate = MetalDelegate(options: options)
// IS THE SAME AS THIS: let delegate = MetalDelegate() Objective-C
// THIS: TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init]; options.precisionLossAllowed = false; options.waitType = TFLMetalDelegateThreadWaitTypePassive; options.quantizationEnabled = true; TFLMetalDelegate* delegate = [[TFLMetalDelegate alloc] initWithOptions:options]; // IS THE SAME AS THIS: TFLMetalDelegate* delegate = [[TFLMetalDelegate alloc] init];
// THIS: const TFLGpuDelegateOptions options = { .allow_precision_loss = false, .wait_type = TFLGpuDelegateWaitType::TFLGpuDelegateWaitTypePassive, .enable_quantization = true, }; TfLiteDelegate* delegate = TFLGpuDelegateCreate(options); // IS THE SAME AS THIS: TfLiteDelegate* delegate = TFLGpuDelegateCreate(nullptr);
Dica: embora seja conveniente usar nullptr
ou os construtores padrão, você deve definir explicitamente as opções para evitar qualquer comportamento inesperado se os valores padrão forem alterados no futuro.
Buffers de entrada/saída usando a API do C++
Fazer computação na GPU requer que os dados estejam disponíveis para a GPU. Em geral, este requisito exige que você faça uma cópia da memória. Se possível, você deve evitar que os dados cruzem a fronteira de memória entre CPU/GPU, pois isso pode levar um tempo considerável. Geralmente, esse cruzamento é inevitável, mas, em alguns casos, um ou o outro pode ser omitido.
Observação: a técnica abaixo está disponível somente ao usar o Bazel ou se você compilar o TensorFlow Lite. A API do C++ não pode ser usada com CocoaPods.
Se a entrada da rede for uma imagem já carregada na memória da GPU (por exemplo: uma textura de GPU contendo o feed da câmera), ela pode permanecer na memória da GPU sem nunca entrar na memória da CPU. De maneira similar, se a saída da rede estiver na forma de uma imagem renderizável, como a operação de transferência de estilo de imagem, você pode exibir o resultado diretamente na tela.
Para obter o melhor desempenho, o TensorFlow Lite possibilita que os usuários leiam e escrevam diretamente no buffer de hardware do TensorFlow, evitando cópias de memória desnecessárias.
Supondo que a entrada de imagem esteja na memória da GPU, primeiro você precisa convertê-la em um objeto MTLBuffer
para a API Metal. Você pode associar um TfLiteTensor
a um MTLBuffer
preparado pelo usuário por meio da função TFLGpuDelegateBindMetalBufferToTensor()
. Atenção: essa função precisa ser chamada após Interpreter::ModifyGraphWithDelegate()
. Além disso, a saída da inferência é, por padrão, copiada da memória da GPU para a memória da CPU. Para desativar esse comportamento, basta chamar Interpreter::SetAllowBufferHandleOutput(true)
durante a inicialização.
C++
#include "tensorflow/lite/delegates/gpu/metal_delegate.h" #include "tensorflow/lite/delegates/gpu/metal_delegate_internal.h"
// ...
// Prepare GPU delegate. auto* delegate = TFLGpuDelegateCreate(nullptr);
if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
interpreter->SetAllowBufferHandleOutput(true); // disable default gpu->cpu copy if (!TFLGpuDelegateBindMetalBufferToTensor( delegate, interpreter->inputs()[0], user_provided_input_buffer)) { return false; } if (!TFLGpuDelegateBindMetalBufferToTensor( delegate, interpreter->outputs()[0], user_provided_output_buffer)) { return false; }
// Run inference. if (interpreter->Invoke() != kTfLiteOk) return false;
Quando o comportamento padrão é desativado, copiar a saída da inferência da memória da GPU para a memória da CPU requer uma chamada explícita a Interpreter::EnsureTensorDataIsReadable()
para cada tensor de saída. Essa estratégia também funciona para modelos quantizados, mas você ainda precisa usar um buffer float32 com dados float32, pois esse buffer é vinculado ao buffer interno dequantizado.
Modelos quantizados {:#quantized-models}
As bibliotecas de delegados de GPU do iOS são compatíveis com os modelos quantizados por padrão. Você não precisa fazer nenhuma alteração no código para usar modelos quantizados com o delegado de GPU. A seção a seguir explica como desativar o suporte quantizado para testes ou fins experimentais.
Desative o suporte a modelos quantizados
O código a seguir mostra como desativar o suporte a modelos quantizados.
Swift
var options = MetalDelegate.Options() options.isQuantizationEnabled = false let delegate = MetalDelegate(options: options)
Objective-C
TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init]; options.quantizationEnabled = false;
C
TFLGpuDelegateOptions options = TFLGpuDelegateOptionsDefault(); options.enable_quantization = false;
Para mais informações sobre como executar modelos quantizados com a aceleração de GPU, confira a visão geral do delegado de GPU.