使用图形处理单元 (GPU) 运行机器学习 (ML) 模型可以显著提高模型的性能和支持机器学习的应用的用户体验。在 iOS 设备上,您可以使用代理来启用由 GPU 加速执行的模型。委托可充当 TensorFlow Lite 的硬件驱动程序,可让您在 GPU 处理器上运行模型的代码。
本页面介绍如何在 iOS 应用中为 TensorFlow Lite 模型启用 GPU 加速。如需详细了解如何为 TensorFlow Lite 使用 GPU 代理,包括最佳实践和高级技术,请参阅 GPU 代理页面。
将 GPU 与 Explainer API 搭配使用
TensorFlow Lite Explainer API 提供了一组用于构建机器学习应用的通用 API。以下说明将指导您向 iOS 应用添加 GPU 支持。本指南假定您已经有一个可以使用 TensorFlow Lite 成功执行机器学习模型的 iOS 应用。
修改 Podfile 以支持 GPU
从 TensorFlow Lite 2.3.0 版本开始,GPU 代理已从 Pod 中排除,以缩减二进制文件的大小。您可以通过为 TensorFlowLiteSwift
pod 指定子规范来包含这些规范:
pod 'TensorFlowLiteSwift/Metal', '~> 0.0.1-nightly',
OR
pod 'TensorFlowLiteSwift', '~> 0.0.1-nightly', :subspecs => ['Metal']
如果您想使用 Objective-C(适用于版本 2.4.0 及更高版本)或 C API,则也可以使用 TensorFlowLiteObjC
或 TensorFlowLiteC
。
初始化和使用 GPU 代理
您可以将 GPU 代理与多种编程语言的 TensorFlow Lite Explainer API 搭配使用。建议使用 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。
- 只有在您使用 bazel 或自行构建 TensorFlow Lite 时,才能使用 C++ API。C++ API 无法与 CocoaPods 搭配使用。
- 将 TensorFlow Lite 与 GPU 委托 (C++) 搭配使用时,请通过
TFLGpuDelegateCreate()
函数获取 GPU 委托,然后将其传递给Interpreter::ModifyGraphWithDelegate()
,而不是调用Interpreter::AllocateTensors()
。
在发布模式下进行构建和测试
更改为具有适当 Metal API 加速器设置的发布 build,以获得更好的性能并进行最终测试。本部分介绍如何启用发布 build 以及配置 Metal 加速设置。
如需更改为发布 build,请执行以下操作:
- 修改构建设置,方法是依次选择 Product > Scheme > Edit Scheme...,然后选择 Run。
- 在 Info 标签页上,将 Build Configuration 更改为 Release,然后取消选中 Debug executable。
- 点击 Options 标签页,然后将 GPU Frame Capture 更改为 Disabled,将 Metal API Validation 更改为 Disabled。
- 请务必选择基于 64 位架构的“仅限发布”build。在 Project navgator > tflite_camera_example > PROJECT > your_project_name > Build Settings 下,将 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 代理概览。