iOS용 GPU 가속 위임

그래픽 처리 장치 (GPU)를 사용하여 머신러닝 (ML) 모델을 실행하면 모델의 성능과 ML 지원 애플리케이션의 사용자 환경을 크게 개선할 수 있습니다. iOS 기기에서는 대리자를 통해 모델의 GPU 가속 실행을 사용할 수 있습니다. 위임은 TensorFlow Lite용 하드웨어 드라이버 역할을 하므로 GPU 프로세서에서 모델 코드를 실행할 수 있습니다.

이 페이지에서는 iOS 앱에서 TensorFlow Lite 모델에 GPU 가속을 사용 설정하는 방법을 설명합니다. 권장사항 및 고급 기술을 포함하여 TensorFlow Lite용 GPU 대리자를 사용하는 방법에 대한 자세한 내용은 GPU 대리자 페이지를 참조하세요.

인터프리터 API와 함께 GPU 사용

TensorFlow Lite Translateer API는 머신러닝 애플리케이션을 빌드하기 위한 범용 API 모음을 제공합니다. 다음 안내에서는 iOS 앱에 GPU 지원을 추가하는 방법을 설명합니다. 이 가이드에서는 TensorFlow Lite로 ML 모델을 성공적으로 실행할 수 있는 iOS 앱이 이미 있다고 가정합니다.

GPU 지원을 포함하도록 Podfile 수정

TensorFlow Lite 2.3.0 출시 버전부터는 바이너리 크기를 줄이기 위해 GPU 대리자가 포드에서 제외됩니다. TensorFlowLiteSwift 포드의 하위 사양을 지정하여 포함할 수 있습니다.

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

OR

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

또한 버전 2.4.0 이상에서 사용 가능한 Objective-C 또는 C API를 사용하려면 TensorFlowLiteObjC 또는 TensorFlowLiteC를 사용할 수 있습니다.

GPU 위임 초기화 및 사용

다양한 프로그래밍 언어와 함께 TensorFlow Lite Translateer API와 함께 GPU 대리자를 사용할 수 있습니다. Swift 및 Objective-C를 사용하는 것이 좋지만 C++ 및 C를 사용할 수도 있습니다. TensorFlow Lite 2.4 이전 버전을 사용하는 경우 C를 사용해야 합니다. 다음 코드 예에서는 이러한 각 언어에서 대리자를 사용하는 방법을 간략하게 설명합니다.

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

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 (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 이전 버전은 Objective-C용 C API만 사용할 수 있습니다.
  • C++ API는 bazel을 사용하거나 TensorFlow Lite를 직접 빌드하는 경우에만 사용할 수 있습니다. C++ API는 CocoaPods와 함께 사용할 수 없습니다.
  • C++로 GPU 대리자와 함께 TensorFlow Lite를 사용하는 경우 Interpreter::AllocateTensors()를 호출하는 대신 TFLGpuDelegateCreate() 함수를 통해 GPU 대리자를 가져온 다음 Interpreter::ModifyGraphWithDelegate()에 전달합니다.

출시 모드로 빌드 및 테스트

성능을 높이고 최종 테스트를 진행하려면 적절한 Metal API 가속기 설정을 사용하여 출시 빌드로 변경하세요. 이 섹션에서는 출시 빌드를 사용 설정하고 메탈 가속 설정을 구성하는 방법을 설명합니다.

출시 빌드로 변경하려면 다음 단계를 따르세요.

  1. Product(제품) > Scheme(스키마) > Edit Scheme...(스키마 수정...)을 선택한 다음 Run(실행)을 선택하여 빌드 설정을 수정합니다.
  2. Info 탭에서 Build ConfigurationRelease로 변경하고 Debug executable을 선택 해제합니다. 출시 설정
  3. Options(옵션) 탭을 클릭하고 GPU Frame Capture(GPU 프레임 캡처)Disabled(사용 중지됨)로, Metal API Validation(Metal API 유효성 검사)Disabled(사용 중지됨)로 변경합니다.
    메탈 옵션 설정
  4. 64비트 아키텍처에서 출시 전용 빌드를 선택해야 합니다. Project navigator > tflite_camera_example > PROJECT > your_project_name > Build Settings에서 Build Active Architecture Only > ReleaseYes로 설정합니다. 출시 옵션을 설정하고

고급 GPU 지원

이 섹션에서는 위임 옵션, 입력 및 출력 버퍼, 양자화 모델 사용을 포함하여 iOS용 GPU 대리자의 고급 사용법을 설명합니다.

iOS용 위임 옵션

GPU 대리자의 생성자는 Swift API, Objective-C API, C API 옵션의 struct를 허용합니다. nullptr (C API) 또는 아무것도 초기화하지 않으면 (Objective-C 및 Swift API) 기본 옵션이 설정됩니다 (위의 기본 사용 예에 설명되어 있음).

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

C++ API를 사용한 입력/출력 버퍼

GPU에서 계산하려면 GPU에서 데이터를 사용할 수 있어야 합니다. 이 요구사항은 메모리 복사를 실행해야 함을 의미합니다. 시간이 오래 걸릴 수 있으므로 가능하면 데이터가 CPU/GPU 메모리 경계를 넘지 않도록 해야 합니다. 일반적으로 이러한 교차는 불가피하지만, 일부 특수한 경우에는 둘 중 어느 하나를 생략할 수 있습니다.

네트워크 입력이 GPU 메모리에 이미 로드된 이미지 (예: 카메라 피드가 포함된 GPU 텍스처)인 경우 CPU 메모리에 들어가지 않아도 GPU 메모리에 계속 남아 있을 수 있습니다. 마찬가지로 네트워크 출력이 이미지 스타일 전송 작업과 같이 렌더링 가능한 이미지 형식인 경우 결과를 화면에 직접 표시할 수 있습니다.

최상의 성능을 달성하기 위해 TensorFlow Lite에서는 사용자가 TensorFlow 하드웨어 버퍼에서 직접 읽고 쓰고 피할 수 없는 메모리 사본을 우회할 수 있습니다.

이미지 입력이 GPU 메모리에 있다고 가정하면 먼저 이를 메탈용 MTLBuffer 객체로 변환해야 합니다. TFLGpuDelegateBindMetalBufferToTensor() 함수를 사용하여 TfLiteTensor를 사용자가 준비한 MTLBuffer에 연결할 수 있습니다. 이 함수는 Interpreter::ModifyGraphWithDelegate() 이후에 호출되어야 합니다. 또한 추론 출력은 기본적으로 GPU 메모리에서 CPU 메모리로 복사됩니다. 초기화 중에 Interpreter::SetAllowBufferHandleOutput(true)를 호출하여 이 동작을 끌 수 있습니다.

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;
      

기본 동작이 사용 중지된 후 GPU 메모리에서 CPU 메모리로 추론 출력을 복사하려면 각 출력 텐서에 대해 Interpreter::EnsureTensorDataIsReadable()를 명시적으로 호출해야 합니다. 이 접근 방식은 양자화 모델에도 적합하지만, 버퍼가 내부 비양자화 버퍼에 결합되므로 float32 데이터가 포함된 float32 크기의 버퍼를 계속 사용해야 합니다.

양자화 모델

iOS GPU 대리자 라이브러리는 기본적으로 양자화된 모델을 지원합니다. GPU 대리자를 통해 양자화 모델을 사용하기 위해 코드를 변경할 필요는 없습니다. 다음 섹션에서는 테스트 또는 실험 목적으로 양자화 지원을 사용 중지하는 방법을 설명합니다.

양자화 모델 지원 사용 중지

다음 코드는 양자화 모델에 대한 지원을 사용 중지하는 방법을 보여줍니다.

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

GPU 가속으로 양자화 모델을 실행하는 방법에 관한 자세한 내용은 GPU 대리자 개요를 참고하세요.