使用圖形處理單元 (GPU) 執行您的機器學習 (ML) 模型,可以大幅提升模型的效能,以及啟用 ML 功能的應用程式的使用者體驗。在 iOS 裝置上,您可以使用委派,啟用 GPU 加速執行模型的功能。委派作為 TensorFlow Lite 的硬體驅動程式,可讓您在 GPU 處理器上執行模型程式碼。
本頁說明如何在 iOS 應用程式中為 TensorFlow Lite 模型啟用 GPU 加速。如要進一步瞭解如何使用 TensorFlow Lite 的 GPU 委派 (包括最佳做法和進階技巧),請參閱 GPU 委派頁面。
搭配 Interpreter API 使用 GPU
TensorFlow Lite Interpreter API 提供一組通用 API,用於建構機器學習應用程式。以下操作說明將引導您將 GPU 支援新增至 iOS 應用程式。本指南假設您已具備可使用 TensorFlow Lite 成功執行 ML 模型的 iOS 應用程式。
修改 Podfile 以納入 GPU 支援
從 TensorFlow Lite 2.3.0 版本開始,GPU 委派已從 pod 中排除,以縮減二進位檔大小。您可以透過為 TensorFlowLiteSwift
pod 指定子規格來納入 GPU 委派
pod 'TensorFlowLiteSwift/Metal', '~> 0.0.1-nightly',
或
pod 'TensorFlowLiteSwift', '~> 0.0.1-nightly', :subspecs => ['Metal']
如果您想使用 Objective-C (適用於 2.4.0 和更高版本) 或 C API,也可以使用 TensorFlowLiteObjC
或 TensorFlowLiteC
。
初始化和使用 GPU 委派
您可以搭配 TensorFlow Lite Interpreter 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 語言使用注意事項
- 2.4.0 之前的 TensorFlow Lite 版本只能針對 Objective-C 使用 C API。
- C++ API 僅在您使用 bazel 或自行建構 TensorFlow Lite 時才適用。C++ API 無法與 CocoaPods 搭配使用。
- 搭配 C++ 和 GPU 委派使用 TensorFlow Lite 時,請透過
TFLGpuDelegateCreate()
函式取得 GPU 委派,然後將其傳遞至Interpreter::ModifyGraphWithDelegate()
,而不是呼叫Interpreter::AllocateTensors()
。
在發布模式中建構及測試
切換至發布版本,並使用適當的 Metal API 加速器設定,以獲得更佳效能並進行最終測試。本節說明如何啟用發布版本,以及設定 Metal 加速的設定。
切換至發布版本的方法:
- 選取「Product > Scheme > Edit Scheme...」(產品 > 結構配置 > 編輯結構配置...),然後選取「Run」(執行),即可編輯建構設定。
- 在「Info」(資訊) 標籤頁中,將「Build Configuration」(建構組態) 變更為「Release」(發布),並取消勾選「Debug executable」(偵錯執行檔)。
- 按一下「Options」(選項) 標籤頁,然後將「GPU Frame Capture」(GPU 幀率擷取) 變更為「Disabled」(停用),並將「Metal API Validation」(Metal API 驗證) 變更為「Disabled」(停用)。
- 請務必在 64 位元架構上選取僅限發布版本。在「Project navigator > tflite_camera_example > PROJECT > your_project_name > Build Settings」(專案導覽器 > tflite_camera_example > 專案 > 您的專案名稱 > 建構設定) 下,將「Build Active Architecture Only > Release」(僅建構現用架構 > 發布) 設定為「Yes」(是)。
進階 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 紋理),則圖片可以保留在 GPU 記憶體中,而無需進入 CPU 記憶體。同樣地,如果網路的輸出是可算繪圖片的形式 (例如,圖片樣式轉換作業),您可以直接在螢幕上顯示結果。
為了達到最佳效能,TensorFlow Lite 可讓使用者直接從 TensorFlow 硬體緩衝區讀取和寫入,並略過可避免的記憶體複製。
假設圖片輸入位於 GPU 記憶體中,您必須先將其轉換為 Metal 的 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 委派總覽。