Delegasi akselerasi GPU untuk iOS

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

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

Gunakan GPU dengan Interpreter API

TensorFlow Lite Interpreter API menyediakan serangkaian API tujuan umum untuk membangun aplikasi pembelajaran mesin. Petunjuk berikut memandu Anda dalam menambahkan dukungan GPU ke aplikasi iOS. Panduan ini mengasumsikan Anda sudah memiliki aplikasi iOS yang berhasil menjalankan model ML dengan TensorFlow Lite.

Ubah Podfile untuk menyertakan dukungan GPU

Dimulai dengan 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 lebih tinggi, atau C API.

Inisialisasi dan gunakan delegasi GPU

Anda dapat menggunakan delegasi GPU dengan TensorFlow Lite Interpreter API dengan sejumlah bahasa pemrograman. Swift dan Objective-C direkomendasikan, namun Anda juga dapat menggunakan C++ dan C. Penggunaan C diperlukan jika Anda menggunakan versi TensorFlow Lite sebelum 2.4. Contoh kode berikut menguraikan cara menggunakan delegasi dengan masing-masing bahasa tersebut.

Cepat

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

Tujuan-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 membuat 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() , alih-alih memanggil Interpreter::AllocateTensors() .

Bangun dan uji dengan mode rilis

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

Untuk mengubah ke versi rilis:

  1. Edit pengaturan build dengan memilih Product > Scheme > Edit Scheme... lalu pilih Run .
  2. Pada tab Info , ubah Build Configuration menjadi Release dan hapus centang Debug executable .menyiapkan rilis
  3. Klik tab Opsi dan ubah GPU Frame Capture menjadi Disabled dan Metal API Validation menjadi Disabled .
    menyiapkan opsi logam
  4. Pastikan untuk memilih Rilis-saja yang dibangun pada arsitektur 64-bit. Di bawah Project navigator > tflite_camera_example > PROJECT > your_project_name > Build Settings atur Build Active Architecture Only > Release ke Yes . menyiapkan opsi rilis

Dukungan GPU tingkat lanjut

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

Opsi Delegasi untuk iOS

Konstruktor untuk delegasi GPU menerima struct opsi 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 menyetel opsi default (yang dijelaskan dalam contoh Penggunaan Dasar di atas).

Cepat

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

Tujuan-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 pada GPU mengharuskan data tersedia untuk GPU. Persyaratan ini sering kali berarti Anda harus melakukan penyalinan memori. Anda harus menghindari data Anda melewati batas memori CPU/GPU jika memungkinkan, karena ini dapat memakan banyak waktu. Biasanya, penyeberangan seperti itu tidak dapat dihindari, tetapi dalam beberapa kasus khusus, salah satu hal tersebut dapat dihilangkan.

Jika masukan jaringan adalah gambar yang sudah dimuat di memori GPU (misalnya, tekstur GPU yang berisi umpan kamera), maka masukan tersebut dapat tetap berada di memori GPU tanpa pernah masuk ke memori CPU. Demikian pula, jika keluaran jaringan berupa gambar yang dapat dirender, misalnya operasi transfer gaya gambar , Anda dapat langsung menampilkan hasilnya di layar.

Untuk mencapai performa terbaik, TensorFlow Lite memungkinkan pengguna membaca dan menulis secara langsung ke buffering perangkat keras TensorFlow dan mengabaikan salinan memori yang dapat dihindari.

Dengan asumsi input gambar ada di 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, menyalin keluaran inferensi dari memori GPU ke memori CPU memerlukan panggilan eksplisit ke Interpreter::EnsureTensorDataIsReadable() untuk setiap tensor keluaran. Pendekatan ini juga berfungsi untuk model terkuantisasi, tetapi Anda masih perlu menggunakan buffer berukuran float32 dengan data float32 , karena buffer terikat ke buffer internal yang tidak terkuantisasi.

Model terkuantisasi

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

Nonaktifkan dukungan model terkuantisasi

Kode berikut menunjukkan cara menonaktifkan dukungan untuk model terkuantisasi.

Cepat

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

Tujuan-C

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

C

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

    TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
      

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