نماینده شتاب پردازنده گرافیکی برای iOS

استفاده از واحدهای پردازش گرافیکی (GPU) برای اجرای مدل‌های یادگیری ماشینی (ML) می‌تواند عملکرد مدل شما و تجربه کاربری برنامه‌های دارای ML را به طور چشمگیری بهبود بخشد. در دستگاه‌های iOS، می‌توانید استفاده از مدل‌های خود را با سرعت GPU با استفاده از یک نماینده فعال کنید. نمایندگان به عنوان درایورهای سخت افزاری برای TensorFlow Lite عمل می کنند و به شما امکان می دهند کد مدل خود را روی پردازنده های گرافیکی اجرا کنید.

این صفحه نحوه فعال کردن شتاب GPU را برای مدل‌های TensorFlow Lite در برنامه‌های iOS توضیح می‌دهد. برای اطلاعات بیشتر درباره استفاده از نماینده GPU برای TensorFlow Lite، از جمله بهترین شیوه‌ها و تکنیک‌های پیشرفته، به صفحه نمایندگان GPU مراجعه کنید.

از GPU با Interpreter API استفاده کنید

TensorFlow Lite Interpreter API مجموعه‌ای از APIهای عمومی را برای ساخت برنامه‌های یادگیری ماشین ارائه می‌کند. دستورالعمل های زیر شما را از طریق افزودن پشتیبانی GPU به یک برنامه iOS راهنمایی می کند. این راهنما فرض می کند که شما قبلاً یک برنامه iOS دارید که می تواند یک مدل ML را با TensorFlow Lite با موفقیت اجرا کند.

فایل Podfile را طوری تغییر دهید که پشتیبانی از GPU را شامل شود

با شروع انتشار TensorFlow Lite 2.3.0، نماینده GPU از پاد حذف می شود تا اندازه باینری کاهش یابد. می توانید آنها را با تعیین یک زیرمجموعه برای غلاف TensorFlowLiteSwift اضافه کنید:

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

می‌توانید از نماینده GPU با TensorFlow Lite Interpreter API با تعدادی از زبان‌های برنامه‌نویسی استفاده کنید. Swift و Objective-C توصیه می‌شوند، اما می‌توانید از C++ و C نیز استفاده کنید. اگر از نسخه‌ای از TensorFlow Lite زودتر از 2.4 استفاده می‌کنید، استفاده از C ضروری است. مثال‌های کد زیر نحوه استفاده از نماینده را با هر یک از این زبان‌ها شرح می‌دهند.

سریع

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

هدف-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 فقط می‌توانند از C API برای Objective-C استفاده کنند.
  • C++ API فقط زمانی در دسترس است که از bazel استفاده می‌کنید یا خودتان TensorFlow Lite را می‌سازید. C++ API را نمی توان با CocoaPods استفاده کرد.
  • هنگام استفاده از TensorFlow Lite با نماینده GPU با C++، نماینده GPU را از طریق تابع TFLGpuDelegateCreate() دریافت کنید و سپس به جای فراخوانی Interpreter::ModifyGraphWithDelegate() Interpreter::AllocateTensors() ارسال کنید.

ساخت و تست با حالت انتشار

برای دستیابی به عملکرد بهتر و برای آزمایش نهایی، به نسخه نسخه با تنظیمات شتاب دهنده مناسب Metal API تغییر دهید. این بخش نحوه فعال کردن ساخت انتشار و پیکربندی تنظیمات شتاب فلزی را توضیح می‌دهد.

برای تغییر به نسخه انتشار:

  1. تنظیمات ساخت را با انتخاب Product > Scheme > Edit Scheme... و سپس انتخاب Run ویرایش کنید.
  2. در تب اطلاعات ، Build Configuration را به Release تغییر دهید و تیک Debug executable را بردارید.راه اندازی انتشار
  3. روی تب Options کلیک کنید و GPU Frame Capture را به Disabled و Metal API Validation را به Disabled تغییر دهید.
    راه اندازی گزینه های فلزی
  4. مطمئن شوید که ساخت‌های Release-Only بر اساس معماری 64 بیتی را انتخاب کنید. در Project Navigator > tflite_camera_example > PROJECT > your_project_name > Build Settings را تنظیم کنید Build Active Architecture Only > Release را روی Yes قرار دهید. راه اندازی گزینه های انتشار

پشتیبانی از GPU پیشرفته

این بخش کاربردهای پیشرفته نماینده GPU برای iOS، از جمله گزینه‌های نمایندگی، بافرهای ورودی و خروجی و استفاده از مدل‌های کوانتیزه را پوشش می‌دهد.

Delegate Options برای iOS

سازنده برای نماینده GPU struct از گزینه‌ها را در Swift API ، Objective-C API و C API می‌پذیرد. ارسال nullptr (C API) یا هیچ (Objective-C و 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()
      

هدف-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];
      

سی

// 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 برای Metal تبدیل کنید. می توانید یک TfLiteTensor را به یک MTLBuffer آماده شده توسط کاربر با تابع TFLGpuDelegateBindMetalBufferToTensor() مرتبط کنید. توجه داشته باشید که این تابع باید بعد از 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 نیازی به تغییر کد ندارید. بخش زیر نحوه غیرفعال کردن پشتیبانی کوانتیزه شده برای اهداف آزمایشی یا آزمایشی را توضیح می دهد.

پشتیبانی از مدل کوانتیزه را غیرفعال کنید

کد زیر نحوه غیرفعال کردن پشتیبانی از مدل های کوانتیزه را نشان می دهد.

سریع

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

هدف-C

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

سی

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

    TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
      

برای اطلاعات بیشتر در مورد اجرای مدل های کوانتیزه شده با شتاب GPU، به نمای کلی نماینده GPU مراجعه کنید.