Delegat do akceleracji GPU w przypadku iOS

Korzystanie z procesorów graficznych (GPU) do uruchamiania modeli systemów uczących się może znacząco poprawić wydajność modelu i wygodę użytkowników Twoich aplikacji obsługujących ML. Na urządzeniach z iOS możesz włączyć Przyspieszone przez GPU wykonywanie modeli za pomocą przekazanie dostępu. Przedstawiciele działają jako sterowniki sprzętowe LiteRT, które umożliwia uruchamianie kodu modelu na procesorach GPU.

Na tej stronie dowiesz się, jak włączyć akcelerację GPU w modelach LiteRT w Aplikacje na iOS. Aby dowiedzieć się więcej o korzystaniu z przekazywania GPU w przypadku LiteRT, w tym sprawdzonych metod i zaawansowanych technik, zawiera artykuł GPU .

Używanie GPU z interfejsem Interpreter API

Tłumacz literatury LiteRT API udostępnia zestaw ogólnych do tworzenia aplikacji do systemów uczących się. Poniżej instrukcje dodawania obsługi GPU do aplikacji na iOS. Ten przewodnik zakłada, że masz już aplikację na iOS, która może wykonać model ML dzięki LiteRT.

Zmodyfikuj plik Podfile, aby obsługiwał GPU

Od wersji LiteRT 2.3.0 dostęp do GPU jest wykluczony z poda, aby zmniejszyć rozmiar pliku binarnego. Możesz je uwzględnić, określając podspecyfikacja poda TensorFlowLiteSwift:

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

LUB

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

Możesz też użyć TensorFlowLiteObjC lub TensorFlowLiteC, jeśli chcesz używać Objective-C (dostępny w wersji 2.4.0 i nowszych) lub C API.

Inicjowanie i używanie przekazywania dostępu do GPU

Możesz używać przedstawicieli GPU za pomocą tłumacza języka tłumaczonego przy użyciu LiteRT API z wieloma programami, języki. Zalecamy używanie języków Swift i Objective-C, ale możesz też używać C++ C: Jeśli korzystasz z wersji LiteRT wcześniej, użycie języka C jest wymagane niż 2,4. Poniższe przykłady kodu pokazują, jak używać przedstawiciela z każdym tych języków.

Swift

import TensorFlowLite

// Load model ...

// Initialize LiteRT 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 (przed 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);
      

Uwagi na temat użycia języka interfejsu GPU API

  • Wersje LiteRT wcześniejsze niż 2.4.0 mogą używać interfejsu C API tylko w przypadku Objective-C.
  • Interfejs API C++ jest dostępny tylko wtedy, gdy korzystasz z bazel lub kompilowania TensorFlow Lite dla siebie. Interfejsu API C++ nie można używać z CocoaPods.
  • Jeśli używasz LiteRT z delegatem GPU w C++, pobierz GPU przekazać dostęp za pomocą funkcji TFLGpuDelegateCreate(), a następnie przekazać ją do Interpreter::ModifyGraphWithDelegate(), zamiast dzwonić Interpreter::AllocateTensors()

Kompilowanie i testowanie w trybie wydania

Zmień na kompilację wersji z odpowiednimi ustawieniami akceleratora Metal API na aby zwiększyć skuteczność i przeprowadzić testy końcowe. W tej sekcji wyjaśniamy, jak włączyć kompilację wersji i skonfigurować ustawienie przyspieszania metalu.

Aby przejść na kompilację wersji:

  1. Aby zmienić ustawienia kompilacji, wybierz Produkt > Schemat > Edytuj schemat... a następnie Uruchom.
  2. Na karcie Informacje zmień Konfigurację kompilacji na Wersja i odznacz Debuguj plik wykonywalny. Konfiguruję
wersja produkcyjna
  3. Kliknij kartę Options (Opcje) i zmień GPU Frame Capture na Disabled (Wyłączone). i Walidacja interfejsu Metal API na Wyłączona.
    Konfiguracja metalu
opcje
  4. Pamiętaj, aby wybrać tryb Tylko wersje wykorzystujący architekturę 64-bitową. Poniżej Nawigator projektów > tflite_camera_example > PROJEKT > nazwa_projektu > Ustawienia kompilacji ustawione na Twórz tylko aktywną architekturę > Zwolnij: Tak. konfigurowanie wersji
opcje

Zaawansowana obsługa GPU

W tej sekcji omawiamy zaawansowane zastosowania przekazywania GPU w iOS, w tym: delegowania opcji, buforów wejściowych i wyjściowych oraz korzystanie z modeli kwantyzowanych.

Opcje przekazywania dostępu w systemie iOS

Konstruktor dla delegata GPU akceptuje struct opcji w Swift API Objective-C API, i C . przekazanie nullptr (C API) lub brak danych (Objective-C i Swift API) do inicjator ustawia opcje domyślne (które są objaśnione w sekcji Podstawowe użycie powyżej).

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

Bufory wejściowe/wyjściowe z użyciem interfejsu API C++

Obliczanie w GPU wymaga, aby dane były dostępne dla GPU. Ten wymaga często kopii z pamięci. Należy unikać dane mogą przekraczać granice pamięci procesora/GPU, ponieważ może to zająć przez dłuższy czas. Zwykle takie przekroczenie jest nieuniknione, ale w niektórych w szczególnych przypadkach, jeden lub drugi może zostać pominięty.

Jeśli danymi wejściowymi sieci jest obraz wczytany już w pamięci GPU (na np. teksturę GPU zawierającą kanał aparatu), może pozostać w pamięci GPU bez dostępu do pamięci procesora. Podobnie, jeśli dane wyjściowe sieci są rodzaj możliwego do renderowania obrazu, np. styl obrazu przenieś możesz wyświetlić wynik bezpośrednio na ekranie.

Aby uzyskać najlepszą wydajność, LiteRT umożliwia użytkownikom bezpośredni odczyt z bufora sprzętowego TensorFlow i zapis w nim oraz omijanie kopii wspomnień, których można uniknąć.

Zakładając, że dane wejściowe obrazu są zapisane w pamięci GPU, musisz najpierw przekonwertować je na Obiekt MTLBuffer dla Metal. TfLiteTensor możesz powiązać z przygotowane przez użytkownika MTLBuffer za pomocą tagu TFLGpuDelegateBindMetalBufferToTensor() . Pamiętaj, że ta funkcja musi zostać wywołana po Interpreter::ModifyGraphWithDelegate() Dodatkowo dane wyjściowe wnioskowania to: kopiowana z pamięci GPU do pamięci procesora. Możesz wyłączyć tę funkcję dzwoniąc pod numer Interpreter::SetAllowBufferHandleOutput(true) w trakcie jego zainicjowanie.

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;
      

Po wyłączeniu domyślnego działania kopiuję dane wyjściowe wnioskowania z GPU pamięć do pamięci procesora wymaga jawnego wywołania funkcji Interpreter::EnsureTensorDataIsReadable() dla każdego tensora wyjściowego. Ten sprawdza się też w przypadku modeli kwantowych, ale nadal musisz zastosować bufor o rozmiarze float32 z danymi float32, wewnętrzny bufor zdekwantyzowany.

Modele kwantowe

Biblioteki delegowania GPU w iOS domyślnie obsługują modele kwantowe. Ty nie wprowadzenia zmian w kodzie, aby można było używać skwantyzowanych modeli z delegacją GPU. poniżej dowiesz się, jak wyłączyć kwantyzowaną obsługę testów lub do celów eksperymentalnych.

Wyłącz obsługę modeli kwantowych

Ten kod pokazuje, jak wyłączyć obsługę modeli kwantyzowanych.

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

Więcej informacji o uruchamianiu modeli kwantowych z akceleracją GPU znajdziesz w artykule Omówienie przekazywania dostępu do GPU.