Đại biểu tăng tốc GPU cho iOS

Việc sử dụng bộ xử lý đồ họa (GPU) để chạy các mô hình máy học (ML) của bạn có thể cải thiện đáng kể hiệu suất của mô hình và trải nghiệm người dùng của các ứng dụng hỗ trợ ML của bạn. Trên thiết bị iOS, bạn có thể cho phép sử dụng tính năng thực thi được tăng tốc GPU cho các mô hình của mình bằng cách sử dụng đại biểu . Các đại biểu đóng vai trò là trình điều khiển phần cứng cho TensorFlow Lite, cho phép bạn chạy mã của mô hình trên bộ xử lý GPU.

Trang này mô tả cách bật khả năng tăng tốc GPU cho các mẫu TensorFlow Lite trong ứng dụng iOS. Để biết thêm thông tin về cách sử dụng đại biểu GPU cho TensorFlow Lite, bao gồm các phương pháp hay nhất và kỹ thuật nâng cao, hãy xem trang đại biểu GPU .

Sử dụng GPU với API thông dịch

API trình thông dịch TensorFlow Lite cung cấp một bộ API có mục đích chung để xây dựng các ứng dụng máy học. Các hướng dẫn sau sẽ hướng dẫn bạn cách thêm hỗ trợ GPU vào ứng dụng iOS. Hướng dẫn này giả định rằng bạn đã có ứng dụng iOS có thể thực thi thành công mô hình ML với TensorFlow Lite.

Sửa đổi Podfile để bao gồm hỗ trợ GPU

Bắt đầu với bản phát hành TensorFlow Lite 2.3.0, đại biểu GPU bị loại khỏi nhóm để giảm kích thước nhị phân. Bạn có thể bao gồm chúng bằng cách chỉ định thông số phụ cho nhóm TensorFlowLiteSwift :

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

HOẶC

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

Bạn cũng có thể sử dụng TensorFlowLiteObjC hoặc TensorFlowLiteC nếu bạn muốn sử dụng Objective-C, có sẵn cho các phiên bản 2.4.0 trở lên hoặc API C.

Khởi tạo và sử dụng đại biểu GPU

Bạn có thể sử dụng đại biểu GPU với API trình thông dịch TensorFlow Lite với một số ngôn ngữ lập trình. Nên sử dụng Swift và Objective-C, nhưng bạn cũng có thể sử dụng C++ và C. Cần sử dụng C nếu bạn đang sử dụng phiên bản TensorFlow Lite cũ hơn 2.4. Các ví dụ về mã sau đây phác thảo cách sử dụng đại biểu với từng ngôn ngữ này.

Nhanh

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

Mục tiêu-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 (trướ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);
      

Ghi chú sử dụng ngôn ngữ GPU API

  • Các phiên bản TensorFlow Lite trước 2.4.0 chỉ có thể sử dụng API C cho Objective-C.
  • API C++ chỉ khả dụng khi bạn đang sử dụng bazel hoặc tự mình xây dựng TensorFlow Lite. Không thể sử dụng API C++ với CocoaPods.
  • Khi sử dụng TensorFlow Lite với đại biểu GPU bằng C++, hãy nhận đại biểu GPU thông qua hàm TFLGpuDelegateCreate() rồi chuyển nó tới Interpreter::ModifyGraphWithDelegate() , thay vì gọi Interpreter::AllocateTensors() .

Xây dựng và thử nghiệm với chế độ phát hành

Thay đổi sang bản phát hành có cài đặt trình tăng tốc API Metal thích hợp để có hiệu suất tốt hơn và cho thử nghiệm cuối cùng. Phần này giải thích cách bật cài đặt cấu hình và xây dựng bản phát hành cho khả năng tăng tốc Metal.

Để thay đổi sang bản phát hành:

  1. Chỉnh sửa cài đặt bản dựng bằng cách chọn Sản phẩm > Lược đồ > Chỉnh sửa lược đồ... rồi chọn Chạy .
  2. Trên tab Thông tin , thay đổi Cấu hình bản dựng thành Bản phát hành và bỏ chọn Gỡ lỗi thực thi .thiết lập phát hành
  3. Nhấp vào tab Tùy chọn và thay đổi GPU Frame Capture thành Đã tắtXác thực API kim loại thành Đã tắt .
    thiết lập các tùy chọn kim loại
  4. Đảm bảo chọn Bản dựng chỉ phát hành trên kiến ​​trúc 64 bit. Trong Trình điều hướng dự án > tflite_máy ảnh_example > DỰ ÁN > your_project_name > Cài đặt bản dựng được đặt Chỉ xây dựng kiến ​​trúc hoạt động > Phát hành thành .thiết lập tùy chọn phát hành

Hỗ trợ GPU nâng cao

Phần này bao gồm các cách sử dụng nâng cao của GPU delegate cho iOS, bao gồm các tùy chọn ủy quyền, bộ đệm đầu vào và đầu ra cũng như việc sử dụng các mô hình lượng tử hóa.

Tùy chọn đại biểu cho iOS

Hàm tạo cho đại biểu GPU chấp nhận struct tùy chọn trong Swift API , Objective-C APIC API . Truyền nullptr (API C) hoặc không có gì (API Objective-C và Swift) cho trình khởi tạo sẽ đặt các tùy chọn mặc định (được giải thích trong ví dụ Sử dụng cơ bản ở trên).

Nhanh

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

Mục tiêu-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);
      

Bộ đệm đầu vào/đầu ra sử dụng API C++

Tính toán trên GPU yêu cầu dữ liệu phải có sẵn cho GPU. Yêu cầu này thường có nghĩa là bạn phải thực hiện sao chép bộ nhớ. Bạn nên tránh để dữ liệu của mình vượt qua ranh giới bộ nhớ CPU/GPU nếu có thể, vì việc này có thể tiêu tốn một lượng thời gian đáng kể. Thông thường, việc vượt biển như vậy là không thể tránh khỏi, nhưng trong một số trường hợp đặc biệt, có thể bỏ qua cái này hoặc cái kia.

Nếu đầu vào của mạng là hình ảnh đã được tải trong bộ nhớ GPU (ví dụ: kết cấu GPU chứa nguồn cấp dữ liệu máy ảnh), thì hình ảnh đó có thể ở trong bộ nhớ GPU mà không cần vào bộ nhớ CPU. Tương tự, nếu đầu ra của mạng ở dạng hình ảnh có thể hiển thị, chẳng hạn như thao tác chuyển kiểu hình ảnh , bạn có thể hiển thị trực tiếp kết quả trên màn hình.

Để đạt được hiệu suất tốt nhất, TensorFlow Lite giúp người dùng có thể đọc và ghi trực tiếp vào bộ đệm phần cứng TensorFlow và bỏ qua các bản sao bộ nhớ có thể tránh được.

Giả sử hình ảnh đầu vào nằm trong bộ nhớ GPU, trước tiên bạn phải chuyển đổi nó thành đối tượng MTLBuffer cho Metal. Bạn có thể liên kết TfLiteTensor với MTLBuffer do người dùng chuẩn bị bằng hàm TFLGpuDelegateBindMetalBufferToTensor() . Lưu ý rằng hàm này phải được gọi sau Interpreter::ModifyGraphWithDelegate() . Ngoài ra, theo mặc định, đầu ra suy luận được sao chép từ bộ nhớ GPU sang bộ nhớ CPU. Bạn có thể tắt hành vi này bằng cách gọi Interpreter::SetAllowBufferHandleOutput(true) trong quá trình khởi tạo.

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;
      

Sau khi tắt hành vi mặc định, việc sao chép đầu ra suy luận từ bộ nhớ GPU sang bộ nhớ CPU sẽ yêu cầu lệnh gọi rõ ràng tới Interpreter::EnsureTensorDataIsReadable() cho mỗi tensor đầu ra. Cách tiếp cận này cũng hiệu quả với các mô hình lượng tử hóa, nhưng bạn vẫn cần sử dụng bộ đệm có kích thước float32 với dữ liệu float32 , vì bộ đệm được liên kết với bộ đệm khử lượng tử hóa bên trong.

Mô hình lượng tử hóa

Theo mặc định, thư viện đại biểu GPU iOS hỗ trợ các mô hình lượng tử hóa . Bạn không cần thực hiện bất kỳ thay đổi mã nào để sử dụng các mô hình lượng tử hóa với đại biểu GPU. Phần sau đây giải thích cách tắt hỗ trợ lượng tử hóa cho mục đích thử nghiệm hoặc thử nghiệm.

Tắt hỗ trợ mô hình lượng tử hóa

Đoạn mã sau cho biết cách tắt hỗ trợ cho các mô hình lượng tử hóa.

Nhanh

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

Mục tiêu-C

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

C

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

    TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
      

Để biết thêm thông tin về cách chạy các mô hình lượng tử hóa với khả năng tăng tốc GPU, hãy xem tổng quan về đại biểu GPU .