Делегат ускорения GPU для iOS

Использование графических процессоров (GPU) для запуска моделей машинного обучения (ML) может значительно повысить производительность вашей модели и удобство работы пользователей с приложениями с поддержкой ML. На устройствах iOS вы можете включить использование GPU-ускоренного выполнения ваших моделей с помощью делегата . Делегаты действуют как аппаратные драйверы для TensorFlow Lite, позволяя вам запускать код вашей модели на процессорах графического процессора.

На этой странице описывается, как включить ускорение графического процессора для моделей TensorFlow Lite в приложениях iOS. Дополнительные сведения об использовании делегата графического процессора для TensorFlow Lite, включая рекомендации и передовые методы, см. на странице делегатов графического процессора .

Используйте GPU с интерпретатором API

API интерпретатора TensorFlow Lite предоставляет набор API общего назначения для создания приложений машинного обучения. Следующие инструкции помогут вам добавить поддержку графического процессора в приложение iOS. В этом руководстве предполагается, что у вас уже есть приложение для iOS, которое может успешно выполнять модель машинного обучения с помощью TensorFlow Lite.

Измените подфайл, чтобы включить поддержку графического процессора.

Начиная с выпуска TensorFlow Lite 2.3.0 делегат графического процессора исключается из модуля, чтобы уменьшить размер двоичного файла. Вы можете включить их, указав подспецификацию для модуля TensorFlowLiteSwift :

pod 'TensorFlowLiteSwift/Metal', '~> 0.0.1-nightly',

ИЛИ ЖЕ

pod 'TensorFlowLiteSwift', '~> 0.0.1-nightly', :subspecs => ['Metal']

Вы также можете использовать TensorFlowLiteObjC или TensorFlowLiteC , если хотите использовать Objective-C, доступный для версий 2.4.0 и выше, или C API.

Инициализировать и использовать делегат GPU

Вы можете использовать делегата графического процессора с API интерпретатора TensorFlow Lite с рядом языков программирования. Рекомендуется использовать Swift и Objective-C, но вы также можете использовать C++ и C. Использование C необходимо, если вы используете версию TensorFlow Lite до 2.4. В следующих примерах кода показано, как использовать делегат с каждым из этих языков.

Быстрый

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 ...
}
      

Цель-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);
      

С (до 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);
      

Примечания по использованию языка GPU API

  • Версии TensorFlow Lite до 2.4.0 могут использовать C API только для Objective-C.
  • C++ API доступен только в том случае, если вы используете bazel или создаете TensorFlow Lite самостоятельно. C++ API нельзя использовать с CocoaPods.
  • При использовании TensorFlow Lite с делегатом графического процессора с C++ получите делегат графического процессора с помощью функции TFLGpuDelegateCreate() , а затем передайте его в Interpreter::ModifyGraphWithDelegate() вместо вызова Interpreter::AllocateTensors() .

Сборка и тестирование в режиме выпуска

Перейдите на выпускную сборку с соответствующими настройками ускорителя Metal API, чтобы повысить производительность и провести окончательное тестирование. В этом разделе объясняется, как включить выпускную сборку и настроить параметры ускорения Metal.

Чтобы перейти на релизную сборку:

  1. Отредактируйте параметры сборки, выбрав Product > Scheme > Edit Scheme..., а затем выбрав Run .
  2. На вкладке « Информация » измените « Конфигурация сборки » на « Выпуск » и снимите флажок « Отладка исполняемого файла ».настройка выпуска
  3. Перейдите на вкладку « Параметры » и измените параметр « Захват кадра графического процессора » на « Отключено » и « Проверка API Metal » на « Отключено ».
    настройка металлических опций
  4. Обязательно выберите Сборки только для выпуска на 64-битной архитектуре. В разделе Project navigator > tflite_camera_example > PROJECT > your_project_name > Build Settings установите Build Active Architecture Only > Release на Yes . настройка параметров выпуска

Расширенная поддержка графического процессора

В этом разделе рассматриваются расширенные возможности использования делегата графического процессора для iOS, включая параметры делегата, входные и выходные буферы и использование квантованных моделей.

Параметры делегирования для iOS

Конструктор для делегата GPU принимает struct параметров в Swift API , Objective-C API и C API . Передача nullptr (C API) или ничего (Objective-C и Swift API) инициализатору устанавливает параметры по умолчанию (которые подробно описаны в примере базового использования выше).

Быстрый

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

Цель-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);
      

Буферы ввода/вывода с использованием C++ API

Вычисления на графическом процессоре требуют, чтобы данные были доступны для графического процессора. Это требование часто означает, что вы должны выполнить копирование памяти. Вам следует по возможности избегать пересечения данными границ памяти CPU/GPU, так как это может занять значительное количество времени. Обычно такое пересечение неизбежно, но в некоторых особых случаях можно и то, и другое опустить.

Если вход сети представляет собой изображение, уже загруженное в память графического процессора (например, текстура графического процессора, содержащая изображение с камеры), оно может оставаться в памяти графического процессора, никогда не попадая в память процессора. Точно так же, если выходные данные сети представлены в форме визуализируемого изображения, такого как операция передачи стиля изображения , вы можете напрямую отобразить результат на экране.

Для достижения наилучшей производительности TensorFlow Lite позволяет пользователям напрямую читать и записывать в аппаратный буфер TensorFlow и обходить копии памяти, которых можно избежать.

Предполагая, что входное изображение находится в памяти графического процессора, вы должны сначала преобразовать его в объект MTLBuffer для Metal. Вы можете связать TfLiteTensor с подготовленным пользователем MTLBuffer с помощью функции TFLGpuDelegateBindMetalBufferToTensor() . Обратите внимание, что эта функция должна вызываться после Interpreter::ModifyGraphWithDelegate() . Кроме того, выходные данные по умолчанию копируются из памяти графического процессора в память ЦП. Вы можете отключить это поведение, вызвав Interpreter::SetAllowBufferHandleOutput(true) во время инициализации.

С++

#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;
      

После отключения поведения по умолчанию для копирования вывода логического вывода из памяти графического процессора в память ЦП требуется явный вызов Interpreter::EnsureTensorDataIsReadable() для каждого выходного тензора. Этот подход также работает для квантованных моделей, но вам все равно нужно использовать буфер размера float32 с данными float32 , потому что буфер привязан к внутреннему деквантованному буферу.

Квантовые модели

Библиотеки делегатов графического процессора iOS по умолчанию поддерживают квантованные модели . Вам не нужно вносить какие-либо изменения в код, чтобы использовать квантованные модели с делегатом графического процессора. В следующем разделе объясняется, как отключить поддержку квантования для тестирования или экспериментальных целей.

Отключить поддержку квантованной модели

Следующий код показывает, как отключить поддержку квантованных моделей.

Быстрый

    var options = MetalDelegate.Options()
    options.isQuantizationEnabled = false
    let delegate = MetalDelegate(options: options)
      

Цель-C

    TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init];
    options.quantizationEnabled = false;
      

С

    TFLGpuDelegateOptions options = TFLGpuDelegateOptionsDefault();
    options.enable_quantization = false;

    TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
      

Дополнительные сведения о выполнении квантованных моделей с ускорением графического процессора см. в разделе Обзор делегата графического процессора .