ML Topluluk Günü 9 Kasım! TensorFlow, JAX güncellemeler için bize katılın ve daha fazla bilgi edinin

GPU'da TensorFlow Lite

TensorFlow Lite , birkaç donanım hızlandırıcıyı destekler. Bu belge, Android'de (OpenCL veya OpenGL ES 3.1 ve üstü gerekir) ve iOS'ta (iOS 8 veya üstü gerekir) TensorFlow Lite delege API'leri kullanılarak GPU arka ucunun nasıl kullanılacağını açıklar.

GPU hızlandırmanın faydaları

Hız

GPU'lar, büyük ölçüde paralelleştirilebilir iş yükleri için yüksek verim sağlayacak şekilde tasarlanmıştır. Bu nedenle, her biri kolaylıkla daha küçük iş yüklerine bölünebilen ve paralel olarak yürütülebilen bazı giriş tensör (ler) i üzerinde çalışan çok sayıda operatörden oluşan derin sinir ağları için çok uygundurlar. Bu paralellik tipik olarak daha düşük gecikmeyle sonuçlanır. En iyi senaryoda, GPU üzerindeki çıkarım, daha önce mümkün olmayan gerçek zamanlı uygulamalara uygun hale gelmek için yeterince hızlı çalışabilir.

Doğruluk

GPU'lar hesaplamalarını 16 bit veya 32 bit kayan nokta sayılarıyla yapar ve (CPU'lardan farklı olarak) optimum performans için niceleme gerektirmez. Düşük doğruluk, modelleriniz için nicemlemeyi kabul edilemez hale getirdiyse, sinir ağınızı bir GPU'da çalıştırmak bu sorunu ortadan kaldırabilir.

Enerji verimliliği

GPU çıkarımıyla gelen bir diğer avantaj, güç verimliliğidir. Bir GPU, hesaplamaları çok verimli ve optimize edilmiş bir şekilde gerçekleştirir, daha az güç tüketir ve bir CPU'da çalıştırılan aynı görevden daha az ısı üretir.

Desteklenen operasyonlar

GPU'da TensorFlow Lite, 16 bit ve 32 bit kayan nokta hassasiyetinde aşağıdaki işlemleri destekler:

  • ADD
  • AVERAGE_POOL_2D
  • CONCATENATION
  • CONV_2D
  • DEPTHWISE_CONV_2D v1-2
  • EXP
  • FULLY_CONNECTED
  • LOGISTIC
  • LSTM v2 (Basic LSTM only)
  • MAX_POOL_2D
  • MAXIMUM
  • MINIMUM
  • MUL
  • PAD
  • PRELU
  • RELU
  • RELU6
  • RESHAPE
  • RESIZE_BILINEAR v1-3
  • SOFTMAX
  • STRIDED_SLICE
  • SUB
  • TRANSPOSE_CONV

Varsayılan olarak, tüm işlemler yalnızca sürüm 1'de desteklenir. Deneysel niceleme desteğini etkinleştirmek, uygun sürümlere izin verir; örneğin, ADD v2.

Temel kullanım

Android Studio ML Model Binding veya TensorFlow Lite Interpreter kullanıyor olmanıza bağlı olarak Android'de model hızlandırmayı çağırmanın iki yolu vardır.

TensorFlow Lite Interpreter aracılığıyla Android

Mevcut dependencies bloğundaki mevcut tensorflow-lite paketinin yanına tensorflow-lite-gpu paketini tensorflow-lite .

dependencies {
    ...
    implementation 'org.tensorflow:tensorflow-lite:2.3.0'
    implementation 'org.tensorflow:tensorflow-lite-gpu:2.3.0'
}

Sonra birlikte GPU üzerinde TensorFlow Lite çalıştırmak TfLiteDelegate . Java'da, GpuDelegate Interpreter.Options aracılığıyla belirtebilirsiniz.

Kotlin

    import org.tensorflow.lite.Interpreter
    import org.tensorflow.lite.gpu.CompatibilityList
    import org.tensorflow.lite.gpu.GpuDelegate

    val compatList = CompatibilityList()

    val options = Interpreter.Options().apply{
        if(compatList.isDelegateSupportedOnThisDevice){
            // if the device has a supported GPU, add the GPU delegate
            val delegateOptions = compatList.bestOptionsForThisDevice
            this.addDelegate(GpuDelegate(delegateOptions))
        } else {
            // if the GPU is not supported, run on 4 threads
            this.setNumThreads(4)
        }
    }

    val interpreter = Interpreter(model, options)

    // Run inference
    writeToInput(input)
    interpreter.run(input, output)
    readFromOutput(output)
      

Java

    import org.tensorflow.lite.Interpreter;
    import org.tensorflow.lite.gpu.CompatibilityList;
    import org.tensorflow.lite.gpu.GpuDelegate;

    // Initialize interpreter with GPU delegate
    Interpreter.Options options = new Interpreter.Options();
    CompatibilityList compatList = CompatibilityList();

    if(compatList.isDelegateSupportedOnThisDevice()){
        // if the device has a supported GPU, add the GPU delegate
        GpuDelegate.Options delegateOptions = compatList.getBestOptionsForThisDevice();
        GpuDelegate gpuDelegate = new GpuDelegate(delegateOptions);
        options.addDelegate(gpuDelegate);
    } else {
        // if the GPU is not supported, run on 4 threads
        options.setNumThreads(4);
    }

    Interpreter interpreter = new Interpreter(model, options);

    // Run inference
    writeToInput(input);
    interpreter.run(input, output);
    readFromOutput(output);
      

Android (C / C ++)

Android'de TensorFlow Lite GPU'nun C / C ++ kullanımı için GPU temsilcisi TfLiteGpuDelegateV2Create() ile oluşturulabilir ve TfLiteGpuDelegateV2Create() ile yok TfLiteGpuDelegateV2Delete() .

0f Александd1900

Özel seçeneklerle bir temsilci örneği oluşturmak için TfLiteGpuDelegateOptionsV2 bir göz atın. Varsayılan seçenekleri TfLiteGpuDelegateOptionsV2Default() ile TfLiteGpuDelegateOptionsV2Default() ve ardından gerektiği gibi değiştirebilirsiniz.

Android C / C ++ için TFLite GPU, Bazel derleme sistemini kullanır. Temsilci, örneğin aşağıdaki komut kullanılarak oluşturulabilir:

bazel build -c opt --config android_arm64 tensorflow/lite/delegates/gpu:delegate                           # for static library
bazel build -c opt --config android_arm64 tensorflow/lite/delegates/gpu:libtensorflowlite_gpu_delegate.so  # for dynamic library

iOS (C ++)

TensorFlow Lite'ı GPU'da kullanmak için, GPU temsilcisini TFLGpuDelegateCreate() aracılığıyla TFLGpuDelegateCreate() ve ardından Interpreter::ModifyGraphWithDelegate() Interpreter::AllocateTensors() çağırmak yerine).

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

// NEW: 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);

Gelişmiş kullanım

İOS için Temsilci Seçenekleri

GPU temsilcisi için oluşturucu bir seçenekler struct kabul eder. ( Swift API , Objective-C API , C API )

nullptr (C API) veya hiçbir şey (Objective-C ve Swift API) geçirmek, varsayılan seçenekleri (yukarıdaki Temel Kullanım örneğinde açıklanan) ayarlar.

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

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

nullptr veya varsayılan oluşturucular kullanmak uygun olsa da, gelecekte varsayılan değerler değiştirilirse beklenmedik davranışlardan kaçınmak için seçenekleri açıkça ayarlamanızı öneririz.

GPU'da nicelleştirilmiş modeller çalıştırma

Bu bölüm, GPU temsilcisinin 8 bitlik nicelleştirilmiş modelleri nasıl hızlandırdığını açıklar. Bu, aşağıdakiler dahil tüm niceleme çeşitlerini içerir:

Performansı optimize etmek için kayan nokta giriş ve çıkış tensörlerine sahip modelleri kullanın.

Bu nasıl çalışıyor?

GPU arka ucu yalnızca kayan noktalı yürütmeyi desteklediğinden, nicelleştirilmiş modelleri orijinal modelin 'kayan nokta görünümünü' vererek çalıştırıyoruz. Yüksek düzeyde, bu aşağıdaki adımları gerektirir:

  • Sabit tensörler (ağırlıklar / önyargılar gibi) bir kez GPU belleğine çözülür. Bu, temsilci TFLite Yorumlayıcısına başvurduğunda gerçekleşir.

  • GPU programına girişler ve çıkışlar , 8 bitlik nicemlenmişse, her bir çıkarım için nicemden arındırılır ve nicelendirilir (sırasıyla). Bu işlem, TFLite'ın optimize edilmiş çekirdekleri kullanılarak CPU'da yapılır.

  • GPU programı, işlemler arasına niceleme simülatörleri ekleyerek nicelenmiş davranışı taklit edecek şekilde değiştirilir. Bu, işlemlerin etkinleştirmelerin niceleme sırasında öğrenilen sınırları takip etmesini beklediği modeller için gereklidir.

Bu özellik, temsilci seçenekleri kullanılarak aşağıdaki şekilde etkinleştirilebilir:

Android

Android API'leri, nicelleştirilmiş modelleri varsayılan olarak destekler. Devre dışı bırakmak için aşağıdakileri yapın:

C ++ API

TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
options.experimental_flags = TFLITE_GPU_EXPERIMENTAL_FLAGS_NONE;

auto* delegate = TfLiteGpuDelegateV2Create(options);
if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;

Java API

GpuDelegate delegate = new GpuDelegate(new GpuDelegate.Options().setQuantizedModelsAllowed(false));

Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);

iOS

iOS API'leri, varsayılan olarak nicelleştirilmiş modelleri destekler. Devre dışı bırakmak için aşağıdakileri yapın:

Swift

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

Amaç-C

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

C

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

    TfLiteDelegate* delegate = TFLGpuDelegateCreate(options);
      

Giriş / Çıkış Tamponları (yalnızca iOS, C ++ API)

GPU'da hesaplama yapmak için, verilerin GPU'da kullanılabilir hale getirilmesi gerekir. Bu genellikle bir bellek kopyası yapmayı gerektirir. Önemli miktarda zaman alabileceğinden, mümkünse CPU / GPU bellek sınırını geçmemek istenir. Genellikle böyle bir geçiş kaçınılmazdır, ancak bazı özel durumlarda biri veya diğeri ihmal edilebilir.

Ağın girişi GPU belleğine önceden yüklenmiş bir görüntü ise (örneğin, kamera beslemesini içeren bir GPU dokusu), CPU belleğine hiç girmeden GPU belleğinde kalabilir. Benzer şekilde, ağın çıktısı işlenebilir bir görüntü biçimindeyse (örneğin, görüntü stili aktarımı ) doğrudan ekranda görüntülenebilir.

En iyi performansı elde etmek için TensorFlow Lite, kullanıcıların TensorFlow donanım tamponundan doğrudan okumasını ve yazmasını ve önlenebilir bellek kopyalarını atlamasını mümkün kılar.

Görüntü girişinin GPU belleğinde olduğunu varsayarsak, önce Metal için bir MTLBuffer nesnesine dönüştürülmesi gerekir. Bir TfLiteTensor ile kullanıcı tarafından hazırlanmış bir MTLBuffer TFLGpuDelegateBindMetalBufferToTensor() ile TFLGpuDelegateBindMetalBufferToTensor() . TFLGpuDelegateBindMetalBufferToTensor() Interpreter::ModifyGraphWithDelegate() sonra çağrılması gerektiğini unutmayın. Ek olarak, çıkarım çıkışı varsayılan olarak GPU belleğinden CPU belleğine kopyalanır. Bu davranış, başlatma sırasında Interpreter::SetAllowBufferHandleOutput(true) çağrılarak kapatılabilir.

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

Ipuçları ve Püf noktaları

  • CPU üzerinde önemsiz olan bazı işlemler, bir GPU'da yüksek maliyetli olabilir. Bu tür bir işlemin bir sınıfı, çeşitli yeniden şekillendirme işlemleri biçimlerini içerir ( BATCH_TO_SPACE , SPACE_TO_BATCH , SPACE_TO_DEPTH ve benzer işlemler dahil). Bu işlemler gerekli değilse (örneğin, ağ mimarına sistem hakkında karar vermesine yardımcı olmak için eklenmişlerse ancak çıktıyı başka şekilde etkilemiyorlarsa), performans için bunları kaldırmaya değer.

  • Bir GPU'da tensör verileri 4 kanala bölünür. Bu durumda, şekilli bir tensör bir hesaplama [B, H, W, 5] şekilli bir tensör ile yaklaşık olarak aynı gerçekleştirecek [B, H, W, 8] , ama daha kötü [B, H, W, 4] .

    • Örneğin, kamera donanımı RGBA'da görüntü çerçevelerini destekliyorsa, bu 4 kanallı girişi beslemek önemli ölçüde daha hızlıdır, çünkü bir bellek kopyası (3 kanallı RGB'den 4 kanallı RGBX'e) önlenebilir.
  • En iyi performans için, sınıflandırıcınızı mobil cihazlar için optimize edilmiş ağ mimarisiyle yeniden eğitmekten çekinmeyin. Bu, cihaz üzerinde çıkarım için optimizasyonun önemli bir parçasıdır.