iOS 適用的 GPU 加速委派

使用圖形處理器 (GPU) 執行機器學習 (ML) 模型 可大幅改善模型成效和使用者體驗 您的機器學習應用程式在 iOS 裝置上,您可以啟用 透過 GPU 加速執行模型 委派代表。委派代表擔任下列硬體的驅動程式 LiteRT 可讓您在 GPU 處理器上執行模型的程式碼。

本頁面說明如何在以下位置啟用 LiteRT 模型的 GPU 加速功能: iOS 應用程式。如要進一步瞭解 LiteRT 適用的 GPU 委派功能, 包括最佳做法和進階技術,請參閱 GPU 資源 委派代表

將 GPU 與 解譯 er API 搭配使用

LiteRT 翻譯工具 API 提供了一組 以建構機器學習應用程式下列 操作說明,引導您為 iOS 應用程式新增 GPU 支援。本指南 假設您已有可成功執行機器學習模型的 iOS 應用程式 。

修改 Podfile 以納入 GPU 支援

從 LiteRT 2.3.0 版開始,系統會排除 GPU 委派 縮減二進位檔的大小如要納入這類目標對象,請指定 TensorFlowLiteSwift Pod 的子規格:

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

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

您也可以使用 TensorFlowLiteObjCTensorFlowLiteC Objective-C (適用於 2.4.0 版及更新版本),或 C API。

初始化及使用 GPU 委派

您可以透過 LiteRT 解譯器使用 GPU 委派功能 包含多種程式設計的 API 語言。建議使用 Swift 和 Objective-C,但您也可以使用 C++ 和 C:如果您使用的是舊版 LiteRT,則必須使用 C 而非 2.4以下程式碼範例概略說明如何使用委派功能

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 (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 語言使用注意事項

  • 2.4.0 以下版本的 LiteRT 只能用於將 C API 用於 Objective-C:
  • 只有在使用 bazel 或建構 TensorFlow 時,才能使用 C++ API 輕而易舉C++ API 無法與 CocoaPods 搭配使用。
  • 將 LiteRT 與 C++ 委派搭配使用時,取得 GPU 透過 TFLGpuDelegateCreate() 函式委派,然後再傳遞至 Interpreter::ModifyGraphWithDelegate(),不再撥打電話 Interpreter::AllocateTensors()

使用發布模式建構及測試

改用適當的 Metal API 加速器設定的發布子版本: 成效更佳並進行最終測試本節說明如何 啟用發布子版本並設定「金屬加速」功能的設定。

如要變更為發布子版本,請按照下列步驟操作:

  1. 選取 產品 >,編輯建構設定配置 >編輯配置... 然後選取「執行」
  2. 在「Info」分頁中,將「Build Configuration」變更為「Release」,然後 取消勾選「偵錯執行檔」設定。
版本
  3. 按一下「Options」分頁標籤,然後將「GPU Frame Capture」變更為「Disabled」。 和「Metal API Validation」設為「Disabled」
    設定金屬。
選項
  4. 請務必選取採用 64 位元架構的「僅限發布版本」。低於 專案導覽工具 >tflite_camera_example >專案 ><您的專案名稱> > 版本設定設定僅建構使用中的架構>發布可以設定版本
選項

進階 GPU 支援

本節說明 iOS 適用的 GPU 委派功能的進階用法,包括 委派選項、輸入和輸出緩衝區,以及量化模型的使用。

iOS 的委派選項

GPU 委派的建構函式接受 Swift 中的 struct 選項 API Objective-C API, 和 C API 來建構應用程式。 將 nullptr (C API) 傳遞至 Initializer 會設定預設選項 (如需基本使用說明,請前往 範例)。

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 紋理),這類紋理可保留在 GPU 記憶體中 不必進入 CPU 記憶體同樣地,如果網路輸出位於 圖片的可轉譯格式,例如圖片樣式 轉移 作業,即可直接在畫面上顯示結果。

為達到最佳效能,LRT 能讓使用者 直接讀取和寫入 TensorFlow 硬體緩衝區,並略過 避免產生記憶體的副本

假設圖片輸入內容位於 GPU 記憶體中,您必須先將輸入內容轉換為 MTLBuffer 物件 (金屬)。您可以將 TfLiteTensor 與 運用 TFLGpuDelegateBindMetalBufferToTensor() 為使用者提供預先準備的 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 的推論輸出內容 需要明確呼叫 每個輸出張量的 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 委派總覽。