Akselerasi GPU dengan LiteRT

Unit Pemrosesan Grafis (GPU) umumnya digunakan untuk akselerasi deep learning karena throughput paralelnya yang sangat besar dibandingkan dengan CPU. LiteRT menyederhanakan proses penggunaan akselerasi GPU dengan memungkinkan pengguna menentukan akselerasi hardware sebagai parameter saat membuat Model yang Dikompilasi (CompiledModel).

Dengan akselerasi GPU LiteRT, Anda dapat membuat buffer input dan output yang kompatibel dengan GPU, mencapai penyalinan nol dengan data Anda di memori GPU, dan menjalankan tugas secara asinkron untuk memaksimalkan paralelisme.

Untuk contoh penerapan GPU LiteRT, lihat aplikasi demo berikut:

Menambahkan dependensi GPU

Gunakan langkah-langkah berikut untuk menambahkan dependensi GPU ke aplikasi Kotlin atau C++ Anda.

Kotlin

Untuk pengguna Kotlin, akselerator GPU sudah tersedia dan tidak memerlukan langkah tambahan di luar panduan Mulai.

C++

Untuk pengguna C++, Anda harus membuat dependensi aplikasi dengan akselerasi GPU LiteRT. Aturan cc_binary yang mengemas logika aplikasi inti (misalnya, main.cc) memerlukan komponen runtime berikut:

  • Library bersama LiteRT C API: atribut data harus menyertakan library bersama LiteRT C API (//litert/c:litert_runtime_c_api_shared_lib) dan komponen khusus GPU (@litert_gpu//:jni/arm64-v8a/libLiteRtGpuAccelerator.so).
  • Dependensi atribut: Atribut deps biasanya mencakup dependensi GLES gles_deps(), dan linkopts biasanya mencakup gles_linkopts(). Keduanya sangat relevan untuk akselerasi GPU, karena LiteRT sering menggunakan OpenGLES di Android.
  • File model dan aset lainnya: Disertakan melalui atribut data.

Berikut adalah contoh aturan cc_binary:

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
)

Penyiapan ini memungkinkan biner yang dikompilasi Anda memuat dan menggunakan GPU secara dinamis untuk inferensi machine learning yang dipercepat.

Menggunakan GPU dengan CompiledModel API

Untuk mulai menggunakan akselerator GPU, teruskan parameter GPU saat membuat Model yang Dikompilasi (CompiledModel). Cuplikan kode berikut menunjukkan implementasi dasar dari seluruh proses:

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

Untuk mengetahui informasi selengkapnya, lihat panduan Mulai Menggunakan C++ atau Mulai Menggunakan Kotlin.

Tanpa salinan dengan akselerasi GPU

Penggunaan salinan nol memungkinkan GPU mengakses data secara langsung di memorinya sendiri tanpa perlu CPU menyalin data tersebut secara eksplisit. Dengan tidak menyalin data ke dan dari memori CPU, salinan nol dapat mengurangi latensi end-to-end secara signifikan.

Kode berikut adalah contoh penerapan GPU Zero-Copy dengan OpenGL, API untuk merender grafik vektor. Kode meneruskan gambar dalam format buffer OpenGL langsung ke LiteRT:

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

Eksekusi asinkron

Metode asinkron LiteRT, seperti RunAsync(), memungkinkan Anda menjadwalkan inferensi GPU sambil melanjutkan tugas lain menggunakan CPU atau NPU. Dalam pipeline yang kompleks, GPU sering digunakan secara asinkron bersama CPU atau NPU.

Cuplikan kode berikut dibuat berdasarkan kode yang diberikan dalam contoh Akselerasi GPU salinan nol. Kode menggunakan CPU dan GPU secara asinkron dan melampirkan Event LiteRT ke buffer input. LiteRT Event bertanggung jawab untuk mengelola berbagai jenis primitif sinkronisasi, dan kode berikut membuat objek Peristiwa LiteRT terkelola berjenis LiteRtEventTypeEglSyncFence. Objek Event ini memastikan bahwa kita tidak membaca dari buffer input hingga GPU selesai. Semua ini dilakukan tanpa melibatkan CPU.

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

Model yang didukung

LiteRT mendukung akselerasi GPU dengan model berikut. Hasil benchmark didasarkan pada pengujian yang dijalankan di perangkat Samsung Galaxy S24.

Model Akselerasi GPU LiteRT GPU LiteRT (ms)
hf_mms_300m Didelegasikan sepenuhnya 19,6
hf_mobilevit_small Didelegasikan sepenuhnya 8.7
hf_mobilevit_small_e2e Didelegasikan sepenuhnya 8.0
hf_wav2vec2_base_960h Didelegasikan sepenuhnya 9.1
hf_wav2vec2_base_960h_dynamic Didelegasikan sepenuhnya 9.8
isnet Didelegasikan sepenuhnya 43.1
timm_efficientnet Didelegasikan sepenuhnya 3.7
timm_nfnet Didelegasikan sepenuhnya 9.7
timm_regnety_120 Didelegasikan sepenuhnya 12.1
torchaudio_deepspeech Didelegasikan sepenuhnya 4,6
torchaudio_wav2letter Didelegasikan sepenuhnya 4,8
torchvision_alexnet Didelegasikan sepenuhnya 3.3
torchvision_deeplabv3_mobilenet_v3_large Didelegasikan sepenuhnya 5.7
torchvision_deeplabv3_resnet101 Didelegasikan sepenuhnya 35.1
torchvision_deeplabv3_resnet50 Didelegasikan sepenuhnya 24,5
torchvision_densenet121 Didelegasikan sepenuhnya 13,9
torchvision_efficientnet_b0 Didelegasikan sepenuhnya 3,6
torchvision_efficientnet_b1 Didelegasikan sepenuhnya 4,7
torchvision_efficientnet_b2 Didelegasikan sepenuhnya 5,0
torchvision_efficientnet_b3 Didelegasikan sepenuhnya 6.1
torchvision_efficientnet_b4 Didelegasikan sepenuhnya 7.6
torchvision_efficientnet_b5 Didelegasikan sepenuhnya 8.6
torchvision_efficientnet_b6 Didelegasikan sepenuhnya 11.2
torchvision_efficientnet_b7 Didelegasikan sepenuhnya 14.7
torchvision_fcn_resnet50 Didelegasikan sepenuhnya 19,9
torchvision_googlenet Didelegasikan sepenuhnya 3,9
torchvision_inception_v3 Didelegasikan sepenuhnya 8.6
torchvision_lraspp_mobilenet_v3_large Didelegasikan sepenuhnya 3.3
torchvision_mnasnet0_5 Didelegasikan sepenuhnya 2,4
torchvision_mobilenet_v2 Didelegasikan sepenuhnya 2.8
torchvision_mobilenet_v3_large Didelegasikan sepenuhnya 2.8
torchvision_mobilenet_v3_small Didelegasikan sepenuhnya 2.3
torchvision_resnet152 Didelegasikan sepenuhnya 15,0
torchvision_resnet18 Didelegasikan sepenuhnya 4.3
torchvision_resnet50 Didelegasikan sepenuhnya 6.9
torchvision_squeezenet1_0 Didelegasikan sepenuhnya 2.9
torchvision_squeezenet1_1 Didelegasikan sepenuhnya 2,5
torchvision_vgg16 Didelegasikan sepenuhnya 13.4
torchvision_wide_resnet101_2 Didelegasikan sepenuhnya 25,0
torchvision_wide_resnet50_2 Didelegasikan sepenuhnya 13.4
u2net_full Didelegasikan sepenuhnya 98,3
u2net_lite Didelegasikan sepenuhnya 51,4
hf_distil_whisper_small_no_cache Didelegasikan sebagian 251,9
hf_distilbert Didelegasikan sebagian 13.7
hf_tinyroberta_squad2 Didelegasikan sebagian 17.1
hf_tinyroberta_squad2_dynamic_batch Didelegasikan sebagian 52.1
snapml_StyleTransferNet Didelegasikan sebagian 40,9
timm_efficientformer_l1 Didelegasikan sebagian 17,6
timm_efficientformerv2_s0 Didelegasikan sebagian 16.1
timm_pvt_v2_b1 Didelegasikan sebagian 73,5
timm_pvt_v2_b3 Didelegasikan sebagian 246,7
timm_resnest14d Didelegasikan sebagian 88,9
torchaudio_conformer Didelegasikan sebagian 21,5
torchvision_convnext_tiny Didelegasikan sebagian 8.2
torchvision_maxvit_t Didelegasikan sebagian 194,0
torchvision_shufflenet_v2 Didelegasikan sebagian 9.5
torchvision_swin_tiny Didelegasikan sebagian 164,4
torchvision_video_resnet2plus1d_18 Didelegasikan sebagian 6832.0
torchvision_video_swin3d_tiny Didelegasikan sebagian 2617,8
yolox_tiny Didelegasikan sebagian 11.2