LiteRT ile GPU hızlandırma

Grafik işleme birimleri (GPU'lar), CPU'lara kıyasla büyük paralel işleme kapasiteleri nedeniyle derin öğrenme hızlandırması için yaygın olarak kullanılır. LiteRT, derlenmiş bir model (CompiledModel) oluştururken kullanıcıların donanım hızlandırmayı parametre olarak belirtmesine olanak tanıyarak GPU hızlandırmayı kullanma sürecini basitleştirir.

LiteRT'nin GPU hızlandırması sayesinde GPU dostu giriş ve çıkış arabellekleri oluşturabilir, GPU belleğindeki verilerinizle sıfır kopya elde edebilir ve paralelliği en üst düzeye çıkarmak için görevleri eşzamansız olarak yürütebilirsiniz.

LiteRT GPU'nun örnek uygulamaları için aşağıdaki demo uygulamalarına bakın:

GPU bağımlılığı ekleme

Kotlin veya C++ uygulamanıza GPU bağımlılığı eklemek için aşağıdaki adımları uygulayın.

Kotlin

Kotlin kullanıcıları için GPU hızlandırıcı yerleşiktir ve Başlangıç kılavuzunda belirtilen adımlar dışında ek adım gerektirmez.

C++

C++ kullanıcıları, uygulamanın bağımlılıklarını LiteRT GPU hızlandırmasıyla oluşturmalıdır. Temel uygulama mantığını paketleyen cc_binary kuralı (ör. main.cc) için aşağıdaki çalışma zamanı bileşenleri gerekir:

  • LiteRT C API paylaşılan kitaplığı: data özelliği, LiteRT C API paylaşılan kitaplığını (//litert/c:litert_runtime_c_api_shared_lib) ve GPU'ya özel bileşenleri (@litert_gpu//:jni/arm64-v8a/libLiteRtGpuAccelerator.so) içermelidir.
  • Özellik bağımlılıkları: deps özelliği genellikle GLES bağımlılıklarını gles_deps(), linkopts özelliği ise genellikle gles_linkopts() bağımlılıklarını içerir. LiteRT genellikle Android'de OpenGLES kullandığından her ikisi de GPU hızlandırma için son derece önemlidir.
  • Model dosyaları ve diğer öğeler: data özelliği aracılığıyla eklenir.

Aşağıda bir cc_binary kuralı örneği verilmiştir:

cc_binary(
    name = "your_application",
    srcs = [
        "main.cc",
    ],
    data = [
        ...
        # litert c api shared library
        "//litert/c:litert_runtime_c_api_shared_lib",
        # GPU accelerator shared library
        "@litert_gpu//:jni/arm64-v8a/libLiteRtGpuAccelerator.so",
    ],
    linkopts = select({
        "@org_tensorflow//tensorflow:android": ["-landroid"],
        "//conditions:default": [],
    }) + gles_linkopts(), # gles link options
    deps = [
        ...
        "//litert/cc:litert_tensor_buffer", # litert cc library
        ...
    ] + gles_deps(), # gles dependencies
)

Bu kurulum, derlenmiş ikilinizin hızlandırılmış makine öğrenimi çıkarımı için GPU'yu dinamik olarak yüklemesine ve kullanmasına olanak tanır.

CompiledModel API ile GPU kullanma

GPU hızlandırıcıyı kullanmaya başlamak için Derlenmiş Model'i (CompiledModel) oluştururken GPU parametresini iletin. Aşağıdaki kod snippet'inde tüm sürecin temel bir uygulaması gösterilmektedir:

C++

// 1. Load model
LITERT_ASSIGN_OR_RETURN(auto model, Model::CreateFromFile("mymodel.tflite"));

// 2. Create a compiled model targeting GPU
LITERT_ASSIGN_OR_RETURN(auto env, Environment::Create({}));
LITERT_ASSIGN_OR_RETURN(auto compiled_model, CompiledModel::Create(env, model, kLiteRtHwAcceleratorGpu));

// 3. Prepare input/output buffers
LITERT_ASSIGN_OR_RETURN(auto input_buffers, compiled_model.CreateInputBuffers());
LITERT_ASSIGN_OR_RETURN(auto output_buffers, compiled_model.CreateOutputBuffers());

// 4. Fill input data (if you have CPU-based data)
input_buffers[0].Write<float>(absl::MakeConstSpan(cpu_data, data_size));

// 5. Execute
compiled_model.Run(input_buffers, output_buffers);

// 6. Access model output
std::vector<float> data(output_data_size);
output_buffers.Read<float>(absl::MakeSpan(data));

Kotlin

// Load model and initialize runtime
val  model =
    CompiledModel.create(
        context.assets,
        "mymodel.tflite",
        CompiledModel.Options(Accelerator.GPU),
        env,
    )

// Preallocate input/output buffers
val inputBuffers = model.createInputBuffers()
val outputBuffers = model.createOutputBuffers()

// Fill the first input
inputBuffers[0].writeFloat(FloatArray(data_size) { data_value /* your data */ })

// Invoke
model.run(inputBuffers, outputBuffers)

// Read the output
val outputFloatArray = outputBuffers[0].readFloat()

Daha fazla bilgi için C++ ile Başlarken veya Kotlin ile Başlarken kılavuzlarına bakın.

GPU hızlandırmasıyla sıfır kopyalama

Sıfır kopyalama, CPU'nun bu verileri açıkça kopyalamasına gerek kalmadan bir GPU'nun kendi belleğindeki verilere doğrudan erişmesini sağlar. Verileri CPU belleğine ve CPU belleğinden kopyalamayarak sıfır kopyalama, uçtan uca gecikmeyi önemli ölçüde azaltabilir.

Aşağıdaki kod, vektör grafiklerin oluşturulması için kullanılan bir API olan OpenGL ile Sıfır Kopyalı GPU'nun örnek bir uygulamasıdır. Kod, OpenGL arabellek biçimindeki görüntüleri doğrudan LiteRT'ye iletir:

// Suppose you have an OpenGL buffer consisting of:
// target (GLenum), id (GLuint), size_bytes (size_t), and offset (size_t)
// Load model and compile for GPU
LITERT_ASSIGN_OR_RETURN(auto model, Model::CreateFromFile("mymodel.tflite"));
LITERT_ASSIGN_OR_RETURN(auto env, Environment::Create({}));
LITERT_ASSIGN_OR_RETURN(auto compiled_model,
    CompiledModel::Create(env, model, kLiteRtHwAcceleratorGpu));

// Create a TensorBuffer that wraps the OpenGL buffer.
LITERT_ASSIGN_OR_RETURN(auto tensor_type, model.GetInputTensorType("input_tensor_name"));
LITERT_ASSIGN_OR_RETURN(auto gl_input_buffer, TensorBuffer::CreateFromGlBuffer(env,
    tensor_type, opengl_buffer.target, opengl_buffer.id, opengl_buffer.size_bytes, opengl_buffer.offset));
std::vector<TensorBuffer> input_buffers{gl_input_buffer};
LITERT_ASSIGN_OR_RETURN(auto output_buffers, compiled_model.CreateOutputBuffers());

// Execute
compiled_model.Run(input_buffers, output_buffers);

// If your output is also GPU-backed, you can fetch an OpenCL buffer or re-wrap it as an OpenGL buffer:
LITERT_ASSIGN_OR_RETURN(auto out_cl_buffer, output_buffers[0].GetOpenClBuffer());

Eşzamansız yürütme

LiteRT'nin RunAsync() gibi eşzamansız yöntemleri, GPU çıkarımını planlamanıza olanak tanırken CPU veya NPU kullanarak diğer görevlere devam etmenizi sağlar. Karmaşık işlem hatlarında GPU genellikle CPU veya NPU'larla birlikte eşzamansız olarak kullanılır.

Aşağıdaki kod snippet'i, Zero-copy GPU acceleration örneğinde sağlanan kodu temel alır. Kod, hem CPU hem de GPU'yu eşzamansız olarak kullanır ve giriş arabelleğine bir LiteRT Event ekler. LiteRT Event farklı senkronizasyon temel öğelerini yönetmekten sorumludur ve aşağıdaki kod, LiteRtEventTypeEglSyncFence türünde yönetilen bir LiteRT Event nesnesi oluşturur. Bu Event nesnesi, GPU işlemi tamamlanana kadar giriş arabelleğinden okuma yapmamamızı sağlar. Tüm bu işlemler CPU kullanılmadan yapılır.

LITERT_ASSIGN_OR_RETURN(auto env, Environment::Create({}));
LITERT_ASSIGN_OR_RETURN(auto compiled_model,
    CompiledModel::Create(env, model, kLiteRtHwAcceleratorGpu));

// 1. Prepare input buffer (OpenGL buffer)
LITERT_ASSIGN_OR_RETURN(auto gl_input,
    TensorBuffer::CreateFromGlBuffer(env, tensor_type, opengl_tex));
std::vector<TensorBuffer> inputs{gl_input};
LITERT_ASSIGN_OR_RETURN(auto outputs, compiled_model.CreateOutputBuffers());

// 2. If the GL buffer is in use, create and set an event object to synchronize with the GPU.
LITERT_ASSIGN_OR_RETURN(auto input_event,
    Event::CreateManagedEvent(env, LiteRtEventTypeEglSyncFence));
inputs[0].SetEvent(std::move(input_event));

// 3. Kick off the GPU inference
compiled_model.RunAsync(inputs, outputs);

// 4. Meanwhile, do other CPU work...
// CPU Stays busy ..

// 5. Access model output
std::vector<float> data(output_data_size);
outputs[0].Read<float>(absl::MakeSpan(data));

Desteklenen modeller

LiteRT, aşağıdaki modellerde GPU hızlandırmayı destekler. Karşılaştırma testinin sonuçları, Samsung Galaxy S24 cihazda yapılan testlere dayanmaktadır.

Model LiteRT GPU Hızlandırma LiteRT GPU (ms)
hf_mms_300m Tam yetki verilmiş 19,6
hf_mobilevit_small Tam yetki verilmiş 8.7
hf_mobilevit_small_e2e Tam yetki verilmiş 8.0
hf_wav2vec2_base_960h Tam yetki verilmiş 9.1
hf_wav2vec2_base_960h_dynamic Tam yetki verilmiş 9,8
isnet Tam yetki verilmiş 43,1
timm_efficientnet Tam yetki verilmiş 3,7
timm_nfnet Tam yetki verilmiş 9.7
timm_regnety_120 Tam yetki verilmiş 12.1
torchaudio_deepspeech Tam yetki verilmiş 4,6
torchaudio_wav2letter Tam yetki verilmiş 4.8
torchvision_alexnet Tam yetki verilmiş 3.3
torchvision_deeplabv3_mobilenet_v3_large Tam yetki verilmiş 5.7
torchvision_deeplabv3_resnet101 Tam yetki verilmiş 35.1
torchvision_deeplabv3_resnet50 Tam yetki verilmiş 24,5
torchvision_densenet121 Tam yetki verilmiş 13,9
torchvision_efficientnet_b0 Tam yetki verilmiş 3.6
torchvision_efficientnet_b1 Tam yetki verilmiş 4,7
torchvision_efficientnet_b2 Tam yetki verilmiş 5,0
torchvision_efficientnet_b3 Tam yetki verilmiş 6.1
torchvision_efficientnet_b4 Tam yetki verilmiş 7.6
torchvision_efficientnet_b5 Tam yetki verilmiş 8.6
torchvision_efficientnet_b6 Tam yetki verilmiş 11.2
torchvision_efficientnet_b7 Tam yetki verilmiş 14.7
torchvision_fcn_resnet50 Tam yetki verilmiş 19,9
torchvision_googlenet Tam yetki verilmiş 3,9
torchvision_inception_v3 Tam yetki verilmiş 8.6
torchvision_lraspp_mobilenet_v3_large Tam yetki verilmiş 3.3
torchvision_mnasnet0_5 Tam yetki verilmiş 2.4
torchvision_mobilenet_v2 Tam yetki verilmiş 2.8
torchvision_mobilenet_v3_large Tam yetki verilmiş 2.8
torchvision_mobilenet_v3_small Tam yetki verilmiş 2.3
torchvision_resnet152 Tam yetki verilmiş 15,0
torchvision_resnet18 Tam yetki verilmiş 4,3
torchvision_resnet50 Tam yetki verilmiş 6.9
torchvision_squeezenet1_0 Tam yetki verilmiş 2.9
torchvision_squeezenet1_1 Tam yetki verilmiş 2.5
torchvision_vgg16 Tam yetki verilmiş 13.4
torchvision_wide_resnet101_2 Tam yetki verilmiş 25,0
torchvision_wide_resnet50_2 Tam yetki verilmiş 13.4
u2net_full Tam yetki verilmiş 98,3
u2net_lite Tam yetki verilmiş 51,4
hf_distil_whisper_small_no_cache Kısmen devredildi 251,90 E£
hf_distilbert Kısmen devredildi 13.7
hf_tinyroberta_squad2 Kısmen devredildi 17.1
hf_tinyroberta_squad2_dynamic_batch Kısmen devredildi 52.1
snapml_StyleTransferNet Kısmen devredildi 40,9
timm_efficientformer_l1 Kısmen devredildi 17,6
timm_efficientformerv2_s0 Kısmen devredildi 16.1
timm_pvt_v2_b1 Kısmen devredildi 73,5
timm_pvt_v2_b3 Kısmen devredildi 246,70 E£
timm_resnest14d Kısmen devredildi 88,9
torchaudio_conformer Kısmen devredildi 21,5
torchvision_convnext_tiny Kısmen devredildi 8.2
torchvision_maxvit_t Kısmen devredildi 194,0
torchvision_shufflenet_v2 Kısmen devredildi 9.5
torchvision_swin_tiny Kısmen devredildi 164,4
torchvision_video_resnet2plus1d_18 Kısmen devredildi 6832,0
torchvision_video_swin3d_tiny Kısmen devredildi 2617,8
yolox_tiny Kısmen devredildi 11.2