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. Em dispositivos iOS, você pode ativar o uso de a execução acelerada por GPU dos modelos usando uma delegar. Os delegados atuam como drivers de hardware para LiteRT, que permite que você execute o código do seu modelo em processadores GPU.
Esta página descreve como ativar a aceleração de GPU para modelos LiteRT em Apps iOS. Para mais informações sobre como usar o delegado da GPU para o LiteRT, incluindo práticas recomendadas e técnicas avançadas, consulte a GPU delegados.
Usar GPU com a API Interpreter
O intérprete do LiteRT API oferece um conjunto de instruções APIs específicas para criar aplicativos de machine learning. O seguinte ajudam você a adicionar suporte a GPUs em um app iOS. Este guia pressupõe que você já tem um app iOS capaz de executar um modelo de ML com a LiteRT.
Modificar o Podfile para incluir suporte a GPU
A partir da versão LiteRT 2.3.0, o delegado da GPU será excluído
do pod para reduzir o tamanho do binário. É possível incluí-las especificando uma
para o pod TensorFlowLiteSwift
:
pod 'TensorFlowLiteSwift/Metal', '~> 0.0.1-nightly',
OU
pod 'TensorFlowLiteSwift', '~> 0.0.1-nightly', :subspecs => ['Metal']
Também é possível usar TensorFlowLiteObjC
ou TensorFlowLiteC
o Objective-C, disponível para as versões 2.4.0 e superiores, ou a API C.
Inicializar e usar o delegado da GPU
Você pode usar o delegado da GPU com o Intérprete de LiteRT com diversas APIs de programação idiomas. Swift e Objective-C são recomendados, mas você também pode usar C++ e C) É necessário usar C se você estiver usando uma versão LiteRT anterior do que 2.4. Os exemplos de código a seguir descrevem como usar o delegado com cada dessas linguagens.
Swift
import TensorFlowLite // Load model ... // Initialize LiteRT 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++
// 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);
C (antes da versão 2.4.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);
Observações sobre o uso de linguagem da API GPU
- As versões LiteRT anteriores à 2.4.0 só podem usar a API C para usando o Objective-C.
- A API C++ só está disponível quando você usa o Bazel ou cria o TensorFlow Use o Lite por conta própria. A API C++ não pode ser usada com o CocoaPods.
- Ao usar o LiteRT com o delegado de GPU com C++, você recebe a GPU
delegado usando a função
TFLGpuDelegateCreate()
e a transmita paraInterpreter::ModifyGraphWithDelegate()
, em vez de chamarInterpreter::AllocateTensors()
Criar e testar com o modo de lançamento
Mude para um build de lançamento com as configurações apropriadas do acelerador da API Metal para melhorar o desempenho e para os testes finais. Esta seção explica como Ativar um build de lançamento e definir a configuração para aceleração de metal.
Para mudar para um build de lançamento:
- Edite as configurações do build selecionando Product > Esquema > Editar esquema... e selecionando Executar.
- Na guia Info, altere Build Configuration para Release e
desmarque a opção Depurar executável.
- Clique na guia Opções e altere a Captura de frames da GPU para Desativado.
e Validação da API Metal como Disabled.
- Selecione builds somente para lançamento em arquiteturas de 64 bits. Abaixo
Navegador do projeto > tflite_camera_example > PROJETO > nome_do_projeto >
"Build Settings" e defina Build Active Architecture Only > Liberar para
Sim.
Suporte avançado a GPUs
Esta seção aborda os usos avançados do delegado da GPU para iOS, incluindo: opções de delegação, buffers de entrada e saída e uso de modelos quantizados.
Delegar opções para iOS
O construtor do delegado da GPU aceita um struct
de opções no elemento Swift
API,
Objective-C
API,
e C
API.
Transmitir nullptr
(API C) ou nada (Objective-C e Swift API) para a
inicializador define as opções padrão (que são explicadas no 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];
C
// 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);
Buffers de entrada/saída usando a API C++
A computação na GPU exige que os dados estejam disponíveis para ela. Isso o que geralmente significa que você precisa fazer uma cópia na memória. Você deve evitar ter porque seus dados cruzam o limite de memória da CPU/GPU, se possível, um período significativo. Normalmente, essa travessia é inevitável, mas, em alguns casos especiais, um ou outro pode ser omitido.
Se a entrada da rede for uma imagem já carregada na memória da GPU (por exemplo, uma textura de GPU que contém o feed da câmera) que pode permanecer na memória da GPU sem nunca entrar na memória da CPU. Da mesma forma, se a saída da rede estiver em a forma de uma imagem renderizável, como um estilo de imagem transferência você poderá exibir o resultado diretamente na tela.
Para alcançar o melhor desempenho, a LiteRT possibilita que os usuários ler e gravar diretamente no buffer de hardware do TensorFlow e ignorar evitáveis de memória.
Supondo que a entrada de imagem esteja na memória da GPU, primeiro é preciso convertê-la em um
Objeto MTLBuffer
para Metal. Você pode associar um TfLiteTensor
a um
MTLBuffer
preparou o usuário com TFLGpuDelegateBindMetalBufferToTensor()
função. Esta função precisa ser chamada após
Interpreter::ModifyGraphWithDelegate()
Além disso, a saída de inferência
copiado da memória da GPU para a memória da CPU. É possível desativar esse comportamento
chamando Interpreter::SetAllowBufferHandleOutput(true)
durante
inicialização do sistema.
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 estiver desativado, copiar a saída de inferência da GPU
de memória para memória de CPU exige uma chamada explícita para
Interpreter::EnsureTensorDataIsReadable()
para cada tensor de saída. Isso
abordagem também funciona para modelos quantizados, mas você ainda precisa usar uma
buffer de tamanho float32 com dados de float32, porque o buffer está vinculado à
ou um buffer desquantizado interno.
Modelos quantizados
As bibliotecas de delegação de GPU do iOS oferecem suporte a modelos quantizados por padrão. Você não fazer alterações no código para usar modelos quantizados com o delegado da GPU. A seção a seguir explica como desativar o suporte quantizado para testes ou para fins experimentais.
Desativar 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; TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
Para mais informações sobre como executar modelos quantizados com aceleração de GPU, consulte Visão geral do delegado da GPU.