LiteRT के साथ जीपीयू ऐक्सेलरेटेड

ग्राफ़िक्स प्रोसेसिंग यूनिट (जीपीयू) का इस्तेमाल आम तौर पर डीप लर्निंग को बेहतर बनाने के लिए किया जाता है. ऐसा इसलिए, क्योंकि सीपीयू की तुलना में जीपीयू की पैरलल थ्रूपुट क्षमता बहुत ज़्यादा होती है. LiteRT, GPU ऐक्सेलरेटेड कंप्यूटिंग का इस्तेमाल करने की प्रोसेस को आसान बनाता है. इसके लिए, यह उपयोगकर्ताओं को कंपाइल किया गया मॉडल (CompiledModel) बनाते समय, हार्डवेयर ऐक्सेलरेटेड कंप्यूटिंग को पैरामीटर के तौर पर सेट करने की अनुमति देता है.

LiteRT के जीपीयू ऐक्सेलरेटर की मदद से, जीपीयू के साथ काम करने वाले इनपुट और आउटपुट बफ़र बनाए जा सकते हैं. साथ ही, जीपीयू मेमोरी में मौजूद डेटा को बिना कॉपी किए इस्तेमाल किया जा सकता है. इसके अलावा, टास्क को एसिंक्रोनस तरीके से पूरा किया जा सकता है, ताकि पैरललिज़्म को ज़्यादा से ज़्यादा किया जा सके.

LiteRT GPU को लागू करने के उदाहरणों के लिए, यहां दिए गए डेमो ऐप्लिकेशन देखें:

जीपीयू डिपेंडेंसी जोड़ना

अपने Kotlin या C++ ऐप्लिकेशन में GPU डिपेंडेंसी जोड़ने के लिए, यह तरीका अपनाएं.

Kotlin

Kotlin का इस्तेमाल करने वाले लोगों के लिए, GPU ऐक्सिलरेटर पहले से मौजूद होता है. इसके लिए, शुरू करें गाइड में दिए गए चरणों के अलावा, कोई और चरण पूरा करने की ज़रूरत नहीं होती.

C++

C++ का इस्तेमाल करने वाले लोगों को, LiteRT की मदद से ऐप्लिकेशन की डिपेंडेंसी बनानी होंगी. इसके लिए, GPU ऐक्सेलरेटेड सुविधा का इस्तेमाल करना होगा. cc_binary नियम, ऐप्लिकेशन की मुख्य लॉजिक को पैकेज करता है. उदाहरण के लिए, main.cc) के लिए, रनटाइम के इन कॉम्पोनेंट की ज़रूरत होती है:

  • LiteRT C API की शेयर की गई लाइब्रेरी: data एट्रिब्यूट में, LiteRT C API की शेयर की गई लाइब्रेरी (//litert/c:litert_runtime_c_api_shared_lib) और जीपीयू के हिसाब से कॉम्पोनेंट (@litert_gpu//:jni/arm64-v8a/libLiteRtGpuAccelerator.so) शामिल होने चाहिए.
  • एट्रिब्यूट की निर्भरताएं: आम तौर पर, deps एट्रिब्यूट में GLES की निर्भरताएं gles_deps() शामिल होती हैं. साथ ही, linkopts एट्रिब्यूट में आम तौर पर gles_linkopts() शामिल होता है. ये दोनों, GPU ऐक्सेलरेट करने के लिए बहुत ज़रूरी हैं. ऐसा इसलिए, क्योंकि LiteRT अक्सर Android पर OpenGLES का इस्तेमाल करता है.
  • मॉडल फ़ाइलें और अन्य ऐसेट: इन्हें data एट्रिब्यूट के ज़रिए शामिल किया जाता है.

यहां 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
)

इस सेटअप की मदद से, कंपाइल किए गए बाइनरी को डाइनैमिक तरीके से लोड किया जा सकता है. साथ ही, मशीन लर्निंग के अनुमान को बेहतर बनाने के लिए, जीपीयू का इस्तेमाल किया जा सकता है.

CompiledModel API के साथ GPU का इस्तेमाल करना

जीपीयू ऐक्सेलरेटर का इस्तेमाल शुरू करने के लिए, कंपाइल किया गया मॉडल (CompiledModel) बनाते समय, जीपीयू पैरामीटर पास करें. इस कोड स्निपेट में, पूरी प्रोसेस का बुनियादी तरीका दिखाया गया है:

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

ज़्यादा जानकारी के लिए, C++ का इस्तेमाल शुरू करना या Kotlin का इस्तेमाल शुरू करना गाइड देखें.

जीपीयू ऐक्सेलरेटेड रेंडरिंग के साथ ज़ीरो-कॉपी

ज़ेरो-कॉपी का इस्तेमाल करने पर, जीपीयू अपने मेमोरी में मौजूद डेटा को सीधे तौर पर ऐक्सेस कर सकता है. इसके लिए, सीपीयू को उस डेटा को कॉपी करने की ज़रूरत नहीं होती. सीपीयू मेमोरी में डेटा कॉपी न करने की वजह से, ज़ीरो-कॉपी से एंड-टू-एंड लेटेंसी को काफ़ी हद तक कम किया जा सकता है.

यहां दिया गया कोड, OpenGL के साथ Zero-Copy GPU को लागू करने का उदाहरण है. OpenGL, वेक्टर ग्राफ़िक रेंडर करने के लिए एक एपीआई है. यह कोड, OpenGL बफ़र फ़ॉर्मैट में मौजूद इमेज को सीधे 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());

एसिंक्रोनस एक्ज़ीक्यूशन

LiteRT के एसिंक्रोनस तरीके, जैसे कि RunAsync(), आपको सीपीयू या एनपीयू का इस्तेमाल करके अन्य टास्क जारी रखते हुए, जीपीयू इन्फ़रेंस को शेड्यूल करने की सुविधा देते हैं. मुश्किल पाइपलाइन में, सीपीयू या एनपीयू के साथ-साथ जीपीयू का इस्तेमाल अक्सर एसिंक्रोनस तरीके से किया जाता है.

नीचे दिया गया कोड स्निपेट, ज़ीरो-कॉपी जीपीयू ऐक्सेलरेटेड के उदाहरण में दिए गए कोड पर आधारित है. यह कोड, सीपीयू और जीपीयू, दोनों का इस्तेमाल एसिंक्रोनस तरीके से करता है. साथ ही, इनपुट बफ़र में LiteRT Event अटैच करता है. LiteRT Event अलग-अलग तरह के सिंक्रनाइज़ेशन प्रिमिटिव को मैनेज करता है. साथ ही, यहां दिया गया कोड LiteRtEventTypeEglSyncFence टाइप का मैनेज किया गया LiteRT इवेंट ऑब्जेक्ट बनाता है. यह Event ऑब्जेक्ट यह पक्का करता है कि जब तक जीपीयू का काम पूरा नहीं हो जाता, तब तक हम इनपुट बफ़र से डेटा न पढ़ें. यह सब सीपीयू के बिना किया जाता है.

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

इन मॉडल के साथ काम करता है

LiteRT, इन मॉडल के साथ जीपीयू ऐक्सेलरेट करने की सुविधा देता है. बेंचमार्क के नतीजे, Samsung Galaxy S24 डिवाइस पर किए गए टेस्ट के आधार पर दिए गए हैं.

मॉडल LiteRT में जीपीयू का इस्तेमाल करके प्रोसेस को तेज़ करना LiteRT GPU (ms)
hf_mms_300m पूरी तरह से डेलिगेट किया गया 19.6
hf_mobilevit_small पूरी तरह से डेलिगेट किया गया 8.7
hf_mobilevit_small_e2e पूरी तरह से डेलिगेट किया गया 8.0
hf_wav2vec2_base_960h पूरी तरह से डेलिगेट किया गया 9.1
hf_wav2vec2_base_960h_dynamic पूरी तरह से डेलिगेट किया गया 9.8
isnet पूरी तरह से डेलिगेट किया गया 43.1
timm_efficientnet पूरी तरह से डेलिगेट किया गया 3.7
timm_nfnet पूरी तरह से डेलिगेट किया गया 9.7
timm_regnety_120 पूरी तरह से डेलिगेट किया गया 12.1
torchaudio_deepspeech पूरी तरह से डेलिगेट किया गया 4.6
torchaudio_wav2letter पूरी तरह से डेलिगेट किया गया 4.8
torchvision_alexnet पूरी तरह से डेलिगेट किया गया 3.3
torchvision_deeplabv3_mobilenet_v3_large पूरी तरह से डेलिगेट किया गया 5.7
torchvision_deeplabv3_resnet101 पूरी तरह से डेलिगेट किया गया 35.1
torchvision_deeplabv3_resnet50 पूरी तरह से डेलिगेट किया गया 24.5
torchvision_densenet121 पूरी तरह से डेलिगेट किया गया 13.9
torchvision_efficientnet_b0 पूरी तरह से डेलिगेट किया गया 3.6
torchvision_efficientnet_b1 पूरी तरह से डेलिगेट किया गया 4.7
torchvision_efficientnet_b2 पूरी तरह से डेलिगेट किया गया 5.0
torchvision_efficientnet_b3 पूरी तरह से डेलिगेट किया गया 6.1
torchvision_efficientnet_b4 पूरी तरह से डेलिगेट किया गया 7.6
torchvision_efficientnet_b5 पूरी तरह से डेलिगेट किया गया 8.6
torchvision_efficientnet_b6 पूरी तरह से डेलिगेट किया गया 11.2
torchvision_efficientnet_b7 पूरी तरह से डेलिगेट किया गया 14.7
torchvision_fcn_resnet50 पूरी तरह से डेलिगेट किया गया 19.9
torchvision_googlenet पूरी तरह से डेलिगेट किया गया 3.9
torchvision_inception_v3 पूरी तरह से डेलिगेट किया गया 8.6
torchvision_lraspp_mobilenet_v3_large पूरी तरह से डेलिगेट किया गया 3.3
torchvision_mnasnet0_5 पूरी तरह से डेलिगेट किया गया 2.4
torchvision_mobilenet_v2 पूरी तरह से डेलिगेट किया गया 2.8
torchvision_mobilenet_v3_large पूरी तरह से डेलिगेट किया गया 2.8
torchvision_mobilenet_v3_small पूरी तरह से डेलिगेट किया गया 2.3
torchvision_resnet152 पूरी तरह से डेलिगेट किया गया 15.0
torchvision_resnet18 पूरी तरह से डेलिगेट किया गया 4.3
torchvision_resnet50 पूरी तरह से डेलिगेट किया गया 6.9
torchvision_squeezenet1_0 पूरी तरह से डेलिगेट किया गया 2.9
torchvision_squeezenet1_1 पूरी तरह से डेलिगेट किया गया 2.5
torchvision_vgg16 पूरी तरह से डेलिगेट किया गया 13.4
torchvision_wide_resnet101_2 पूरी तरह से डेलिगेट किया गया 25.0
torchvision_wide_resnet50_2 पूरी तरह से डेलिगेट किया गया 13.4
u2net_full पूरी तरह से डेलिगेट किया गया 98.3
u2net_lite पूरी तरह से डेलिगेट किया गया 51.4
hf_distil_whisper_small_no_cache कुछ ही अधिकारों को सौंपा गया है 251.9
hf_distilbert कुछ ही अधिकारों को सौंपा गया है 13.7
hf_tinyroberta_squad2 कुछ ही अधिकारों को सौंपा गया है 17.1
hf_tinyroberta_squad2_dynamic_batch कुछ ही अधिकारों को सौंपा गया है 52.1
snapml_StyleTransferNet कुछ ही अधिकारों को सौंपा गया है 40.9
timm_efficientformer_l1 कुछ ही अधिकारों को सौंपा गया है 17.6
timm_efficientformerv2_s0 कुछ ही अधिकारों को सौंपा गया है 16.1
timm_pvt_v2_b1 कुछ ही अधिकारों को सौंपा गया है 73.5
timm_pvt_v2_b3 कुछ ही अधिकारों को सौंपा गया है 246.7
timm_resnest14d कुछ ही अधिकारों को सौंपा गया है 88.9
torchaudio_conformer कुछ ही अधिकारों को सौंपा गया है 21.5
torchvision_convnext_tiny कुछ ही अधिकारों को सौंपा गया है 8.2
torchvision_maxvit_t कुछ ही अधिकारों को सौंपा गया है 194.0
torchvision_shufflenet_v2 कुछ ही अधिकारों को सौंपा गया है 9.5
torchvision_swin_tiny कुछ ही अधिकारों को सौंपा गया है 164.4
torchvision_video_resnet2plus1d_18 कुछ ही अधिकारों को सौंपा गया है 6832.0
torchvision_video_swin3d_tiny कुछ ही अधिकारों को सौंपा गया है 2617.8
yolox_tiny कुछ ही अधिकारों को सौंपा गया है 11.2