Përshpejtimi i GPU-së me LiteRT

Njësitë e Përpunimit Grafik (GPU) përdoren zakonisht për përshpejtimin e të mësuarit të thellë për shkak të rendimentit të tyre masiv paralel krahasuar me CPU-të. LiteRT thjeshton procesin e përdorimit të përshpejtimit të GPU-së duke u lejuar përdoruesve të specifikojnë përshpejtimin e harduerit si një parametër kur krijojnë një Model të Kompiluar ( CompiledModel ).

Me përshpejtimin e GPU-së të LiteRT, ju mund të krijoni buffer-a hyrës dhe dalës miqësorë me GPU-në, të arrini zero kopje me të dhënat tuaja në memorien e GPU-së dhe të ekzekutoni detyra në mënyrë asinkrone për të maksimizuar paralelizmin.

Për shembull implementime të GPU-së LiteRT, referojuni aplikacioneve demo të mëposhtme:

Shto varësinë e GPU-së

Ndiqni hapat e mëposhtëm për të shtuar varësinë e GPU-së në aplikacionin tuaj Kotlin ose C++.

Kotlin

Për përdoruesit e Kotlin, përshpejtuesi i GPU-së është i integruar dhe nuk kërkon hapa shtesë përtej udhëzuesit "Fillimi" .

C++

Për përdoruesit e C++, duhet të ndërtoni varësitë e aplikacionit me përshpejtimin e GPU-së LiteRT. Rregulli cc_binary që paketon logjikën thelbësore të aplikacionit (p.sh., main.cc ) kërkon komponentët e mëposhtëm të kohës së ekzekutimit:

  • Biblioteka e përbashkët e LiteRT C API : atributi i data duhet të përfshijë bibliotekën e përbashkët të LiteRT C API ( //litert/c:litert_runtime_c_api_shared_lib ) dhe komponentët specifikë të GPU-së ( @litert_gpu//:jni/arm64-v8a/libLiteRtGpuAccelerator.so ).
  • Varësitë e atributeve : Atributi deps zakonisht përfshin varësitë GLES gles_deps() , dhe linkopts zakonisht përfshin gles_linkopts() . Të dyja janë shumë të rëndësishme për përshpejtimin e GPU-së, pasi LiteRT shpesh përdor OpenGLES në Android.
  • Skedarët e modelit dhe asete të tjera : Përfshihen përmes atributit të data .

Më poshtë është një shembull i një rregulli 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
)

Ky konfigurim lejon që skedari juaj binar i kompiluar të ngarkohet në mënyrë dinamike dhe të përdorë GPU-në për përfundime të përshpejtuara të të mësuarit automatik.

Përdor GPU me API- CompiledModel

Për të filluar përdorimin e përshpejtuesit të GPU-së, kaloni parametrin GPU kur krijoni Modelin e Kompiluar ( CompiledModel ). Fragmenti i mëposhtëm i kodit tregon një implementim bazë të të gjithë procesit:

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

Për më shumë informacion, shihni udhëzuesit " Filloni me C++" ose "Filloni me Kotlin" .

Zero-kopje me përshpejtim GPU

Përdorimi i kopjes zero i mundëson një GPU-je të qaset në të dhënat direkt në memorien e vet pa pasur nevojë që CPU-ja t'i kopjojë në mënyrë të qartë ato të dhëna. Duke mos kopjuar të dhëna nga dhe në memorien e CPU-së, kopja zero mund ta zvogëlojë ndjeshëm vonesën nga fillimi në fund.

Kodi i mëposhtëm është një shembull implementimi i GPU-së Zero-Copy me OpenGL , një API për renderimin e grafikës vektoriale. Kodi i kalon imazhet në formatin e bufferit OpenGL direkt te 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());

Ekzekutim asinkron

Metodat asinkrone të LiteRT, si RunAsync() , ju lejojnë të planifikoni përfundimin e GPU-së ndërsa vazhdoni detyra të tjera duke përdorur CPU-në ose NPU-në. Në tubacione komplekse, GPU-ja shpesh përdoret në mënyrë asinkrone së bashku me CPU-në ose NPU-të.

Fragmenti i mëposhtëm i kodit ndërtohet mbi kodin e dhënë në shembullin e përshpejtimit të GPU-së me kopje zero . Kodi përdor si CPU-në ashtu edhe GPU-në në mënyrë asinkrone dhe bashkëngjit një Event LiteRT në buffer-in hyrës. Event LiteRT është përgjegjëse për menaxhimin e llojeve të ndryshme të primitivave të sinkronizimit, dhe kodi i mëposhtëm krijon një objekt të menaxhuar të Ngjarjes LiteRT të tipit LiteRtEventTypeEglSyncFence . Ky objekt Event siguron që ne të mos lexojmë nga buffer-i hyrës derisa GPU-ja të ketë mbaruar. E gjithë kjo bëhet pa përfshirë CPU-në.

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

Modelet e mbështetura

LiteRT mbështet përshpejtimin e GPU-së me modelet e mëposhtme. Rezultatet e krahasimit bazohen në testet e kryera në një pajisje Samsung Galaxy S24.

Model Përshpejtimi i GPU-së LiteRT GPU LiteRT (ms)
hf_mms_300m Deleguar plotësisht 19.6
hf_mobilevit_small Deleguar plotësisht 8.7
hf_mobilevit_small_e2e Deleguar plotësisht 8.0
hf_wav2vec2_base_960h Deleguar plotësisht 9.1
hf_wav2vec2_base_960h_dynamic Deleguar plotësisht 9.8
isnet Deleguar plotësisht 43.1
timm_efficientnet Deleguar plotësisht 3.7
timm_nfnet Deleguar plotësisht 9.7
timm_regnety_120 Deleguar plotësisht 12.1
torchaudio_deepspeech Deleguar plotësisht 4.6
torchaudio_wav2letter Deleguar plotësisht 4.8
torchvision_alexnet Deleguar plotësisht 3.3
torchvision_deeplabv3_mobilenet_v3_large Deleguar plotësisht 5.7
torchvision_deeplabv3_resnet101 Deleguar plotësisht 35.1
torchvision_deeplabv3_resnet50 Deleguar plotësisht 24.5
torchvision_densenet121 Deleguar plotësisht 13.9
torchvision_efficientnet_b0 Deleguar plotësisht 3.6
torchvision_efficientnet_b1 Deleguar plotësisht 4.7
torchvision_efficientnet_b2 Deleguar plotësisht 5.0
torchvision_efficientnet_b3 Deleguar plotësisht 6.1
torchvision_efficientnet_b4 Deleguar plotësisht 7.6
torchvision_efficientnet_b5 Deleguar plotësisht 8.6
torchvision_efficientnet_b6 Deleguar plotësisht 11.2
torchvision_efficientnet_b7 Deleguar plotësisht 14.7
torchvision_fcn_resnet50 Deleguar plotësisht 19.9
torchvision_googlenet Deleguar plotësisht 3.9
torchvision_inception_v3 Deleguar plotësisht 8.6
torchvision_lraspp_mobilenet_v3_large Deleguar plotësisht 3.3
torchvision_mnasnet0_5 Deleguar plotësisht 2.4
torchvision_mobilenet_v2 Deleguar plotësisht 2.8
torchvision_mobilenet_v3_large Deleguar plotësisht 2.8
torchvision_mobilenet_v3_small Deleguar plotësisht 2.3
torchvision_resnet152 Deleguar plotësisht 15.0
torchvision_resnet18 Deleguar plotësisht 4.3
torchvision_resnet50 Plotësisht i deleguar 6.9
torchvision_squeezenet1_0 Deleguar plotësisht 2.9
torchvision_squeezenet1_1 Deleguar plotësisht 2.5
torchvision_vgg16 Deleguar plotësisht 13.4
torchvision_wide_resnet101_2 Deleguar plotësisht 25.0
torchvision_wide_resnet50_2 Deleguar plotësisht 13.4
u2net_full Deleguar plotësisht 98.3
u2net_lite Deleguar plotësisht 51.4
hf_distil_whisper_small_no_cache Pjesërisht i deleguar 251.9
hf_distilbert Pjesërisht i deleguar 13.7
hf_tinyroberta_squad2 Pjesërisht i deleguar 17.1
hf_tinyroberta_squad2_dynamic_batch Pjesërisht i deleguar 52.1
snapml_StyleTransferNet Pjesërisht i deleguar 40.9
timm_efficientformer_l1 Pjesërisht i deleguar 17.6
timm_efficientformerv2_s0 Pjesërisht i deleguar 16.1
timm_pvt_v2_b1 Pjesërisht i deleguar 73.5
timm_pvt_v2_b3 Pjesërisht i deleguar 246.7
timm_resnest14d Pjesërisht i deleguar 88.9
torchaudio_conformer Pjesërisht i deleguar 21.5
torchvision_convnext_tiny Pjesërisht i deleguar 8.2
torchvision_maxvit_t Pjesërisht i deleguar 194.0
torchvision_shufflenet_v2 Pjesërisht i deleguar 9.5
torchvision_swin_tiny Pjesërisht i deleguar 164.4
torchvision_video_resnet2plus1d_18 Pjesërisht i deleguar 6832.0
torchvision_video_swin3d_tiny Pjesërisht i deleguar 2617.8
yolox_tiny Pjesërisht i deleguar 11.2