Delegasi akselerasi GPU untuk iOS

Menggunakan unit pemrosesan grafis (GPU) untuk menjalankan model machine learning (ML) dapat meningkatkan performa model dan pengalaman pengguna aplikasi Anda secara signifikan pada aplikasi berkemampuan ML. Di perangkat iOS, Anda dapat mengaktifkan penggunaan eksekusi model yang dipercepat GPU menggunakan delegasi. Delegasi bertindak sebagai driver hardware untuk TensorFlow Lite, sehingga Anda dapat menjalankan kode model pada prosesor GPU.

Halaman ini menjelaskan cara mengaktifkan akselerasi GPU untuk model TensorFlow Lite di aplikasi iOS. Untuk mengetahui informasi selengkapnya tentang penggunaan delegasi GPU untuk TensorFlow Lite, termasuk praktik terbaik dan teknik lanjutan, lihat halaman Delegasi GPU.

Menggunakan GPU dengan Interpreter API

Interpreter API TensorFlow Lite menyediakan sekumpulan API tujuan umum untuk mem-build aplikasi machine learning. Petunjuk berikut akan memandu Anda dalam menambahkan dukungan GPU ke aplikasi iOS. Panduan ini mengasumsikan bahwa Anda sudah memiliki aplikasi iOS yang dapat menjalankan model ML dengan TensorFlow Lite.

Ubah Podfile untuk menyertakan dukungan GPU

Mulai rilis TensorFlow Lite 2.3.0, delegasi GPU dikecualikan dari pod untuk mengurangi ukuran biner. Anda dapat menyertakannya dengan menentukan subspesifikasi untuk pod TensorFlowLiteSwift:

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

ATAU

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

Anda juga dapat menggunakan TensorFlowLiteObjC atau TensorFlowLiteC jika ingin menggunakan Objective-C, yang tersedia untuk versi 2.4.0 dan yang lebih tinggi, atau C API.

Melakukan inisialisasi dan menggunakan delegasi GPU

Anda dapat menggunakan delegasi GPU dengan Interpreter API TensorFlow Lite dengan sejumlah bahasa pemrograman. Swift dan Objective-C direkomendasikan, tetapi Anda juga dapat menggunakan C++ dan C. Penggunaan C diperlukan jika Anda menggunakan versi TensorFlow Lite yang lebih lama dari 2.4. Contoh kode berikut menguraikan cara menggunakan delegasi dengan setiap bahasa ini.

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 (sebelum 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);
      

Catatan penggunaan bahasa GPU API

  • Versi TensorFlow Lite sebelum 2.4.0 hanya dapat menggunakan C API untuk Objective-C.
  • C++ API hanya tersedia saat Anda menggunakan bazel atau mem-build TensorFlow Lite sendiri. C++ API tidak dapat digunakan dengan CocoaPods.
  • Saat menggunakan TensorFlow Lite dengan delegasi GPU dengan C++, dapatkan delegasi GPU melalui fungsi TFLGpuDelegateCreate(), lalu teruskan ke Interpreter::ModifyGraphWithDelegate(), bukan memanggil Interpreter::AllocateTensors().

Membangun dan menguji dengan mode rilis

Beralihlah ke build rilis dengan setelan akselerator Metal API yang sesuai untuk mendapatkan performa yang lebih baik dan untuk pengujian akhir. Bagian ini menjelaskan cara mengaktifkan build rilis dan mengonfigurasi setelan untuk akselerasi Metal.

Untuk beralih ke build rilis:

  1. Edit setelan build dengan memilih Product > Scheme > Edit Scheme... lalu memilih Run.
  2. Pada tab Info, ubah Build Configuration menjadi Release, lalu hapus centang Debug executable. menyiapkan rilis
  3. Klik tab Options, lalu ubah GPU Frame Capture ke Disabled dan Metal API Validation ke Disabled.
    menyiapkan pilihan logam
  4. Pastikan untuk memilih Build khusus rilis pada arsitektur 64-bit. Di bagian Project navigator > tflite_camera_example > PROJECT > your_project_name > Build Settings tetapkan Build Active Architecture Only > Release ke Yes. menyiapkan opsi
rilis

Dukungan GPU lanjutan

Bagian ini membahas penggunaan lanjutan delegasi GPU untuk iOS, termasuk opsi delegasi, buffer input dan output, serta penggunaan model terkuantisasi.

Opsi Delegasi untuk iOS

Konstruktor untuk delegasi GPU menerima opsi struct di Swift API, Objective-C API, dan C API. Meneruskan nullptr (C API) atau tidak sama sekali (Objective-C dan Swift API) ke penginisialisasi akan menetapkan opsi default (yang dijelaskan dalam contoh Penggunaan Dasar di atas).

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);
      

Buffer Input/Output menggunakan C++ API

Komputasi di GPU mengharuskan data tersedia untuk GPU. Persyaratan ini sering kali berarti Anda harus melakukan penyalinan memori. Sebaiknya jangan data Anda melewati batas memori CPU/GPU jika memungkinkan, karena hal ini dapat memakan banyak waktu. Biasanya, persimpangan seperti itu tidak dapat dihindari, tetapi dalam beberapa kasus khusus, salah satunya dapat dihilangkan.

Jika input jaringan adalah gambar yang sudah dimuat di memori GPU (misalnya, tekstur GPU yang berisi feed kamera), input tersebut dapat tetap berada di memori GPU tanpa pernah memasuki memori CPU. Demikian pula, jika output jaringan berupa gambar yang dapat dirender, seperti operasi transfer gaya gambar, Anda dapat langsung menampilkan hasilnya di layar.

Untuk mencapai performa terbaik, TensorFlow Lite memungkinkan pengguna untuk langsung membaca dari dan menulis ke buffer hardware TensorFlow dan mengabaikan salinan memori yang dapat dihindari.

Dengan asumsi input gambar berada dalam memori GPU, Anda harus terlebih dahulu mengonversinya menjadi objek MTLBuffer untuk Metal. Anda dapat mengaitkan TfLiteTensor ke MTLBuffer yang disiapkan pengguna dengan fungsi TFLGpuDelegateBindMetalBufferToTensor(). Perhatikan bahwa fungsi ini harus dipanggil setelah Interpreter::ModifyGraphWithDelegate(). Selain itu, output inferensi, secara default, disalin dari memori GPU ke memori CPU. Anda dapat menonaktifkan perilaku ini dengan memanggil Interpreter::SetAllowBufferHandleOutput(true) selama inisialisasi.

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;
      

Setelah perilaku default dinonaktifkan, penyalinan output inferensi dari memori GPU ke memori CPU memerlukan panggilan eksplisit ke Interpreter::EnsureTensorDataIsReadable() untuk setiap tensor output. Pendekatan ini juga berfungsi untuk model terkuantisasi, tetapi Anda masih perlu menggunakan buffer berukuran float32 dengan data float32, karena buffer terikat dengan buffer de-kuantisasi internal.

Model terkuantisasi

Library delegasi GPU iOS mendukung model terkuantisasi secara default. Anda tidak perlu membuat perubahan kode untuk menggunakan model terkuantisasi dengan delegasi GPU. Bagian berikut menjelaskan cara menonaktifkan dukungan terkuantisasi untuk tujuan pengujian atau eksperimental.

Menonaktifkan dukungan model terkuantisasi

Kode berikut menunjukkan cara menonaktifkan dukungan untuk model terkuantisasi.

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);
      

Untuk mengetahui informasi selengkapnya tentang menjalankan model terkuantisasi dengan akselerasi GPU, lihat ringkasan delegasi GPU.