تسريع وحدة معالجة الرسومات باستخدام LiteRT Next

تُستخدَم وحدات معالجة الرسومات (GPU) عادةً لتسريع التعلم العميق بسبب معدل نقل البيانات المتوازي الهائل مقارنةً بوحدات المعالجة المركزية. تعمل أداة LiteRT Next على تبسيط عملية استخدام ميزة تسريع وحدة معالجة الرسومات من خلال السماح للمستخدمين بتحديد ميزة تسريع الأجهزة كمَعلمة عند إنشاء نموذج مجمَّع (CompiledModel). وتستخدم أداة LiteRT Next أيضًا عملية جديدة ومحسّنة لتنفيذ ميزة تسريع وحدة معالجة الرسومات، وهي ميزة لا تقدّمها أداة LiteRT.

باستخدام ميزة تسريع وحدة معالجة الرسومات في LiteRT Next، يمكنك إنشاء مخازن ذاكرة مؤقتة للدخل والخرج متوافقة مع وحدة معالجة الرسومات، وتحقيق ميزة "عدم إجراء أي نسخ" لبياناتك في ذاكرة وحدة معالجة الرسومات، وتنفيذ tasks بشكل غير متزامن لزيادة التوازي إلى أقصى حد.

للحصول على أمثلة على عمليات تنفيذ LiteRT Next مع ميزة دعم وحدة معالجة الرسومات، يُرجى الرجوع إلى التطبيقات التجريبية التالية:

إضافة الاعتماد على وحدة معالجة الرسومات

اتّبِع الخطوات التالية لإضافة الاعتماد على وحدة معالجة الرسومات إلى تطبيقك المكتوب بلغة Kotlin أو C++.

Kotlin

بالنسبة إلى مستخدمي Kotlin، يكون مسرع وحدة معالجة الرسومات مضمّنًا ولا يتطلّب سوى خطوات إضافية خارج دليل البدء.

C++‎

بالنسبة إلى مستخدمي C++، يجب إنشاء ملفات الاعتماد للتطبيق باستخدام LiteRT تسريع وحدة معالجة الرسومات. قاعدة 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_deps() لـ GLES، وتتضمّن سمة linkopts عادةًgles_linkopts(). يرتبط كلاهما بشكل كبير بتسريع وحدة معالجة الرسومات، لأنّه غالبًا ما يستخدم LiteRT OpenGLES على Android.
  • ملفات النماذج ومواد العرض الأخرى: يتم تضمينها من خلال السمة 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). يعرض مقتطف الرمز التالي تنفيذًا أساسيًا للعملية بأكملها:

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.

مسرّع LiteRT Next لوحدة معالجة الرسومات

تم تحسين أداة تسريع وحدة معالجة الرسومات الجديدة، المتوفّرة فقط مع LiteRT Next، للتعامل مع مهام الذكاء الاصطناعي بكفاءة أكبر من الإصدارات السابقة، مثل عمليات ضرب المصفوفات الكبيرة وذاكرة التخزين المؤقت KV للنماذج اللغوية الكبيرة. يقدّم مسرِّع وحدة معالجة الرسومات LiteRT Next التحسينات التالية مقارنةً بإصدار LiteRT:

  • تغطية موسّعة لمشغّلي الشبكات: يمكنك التعامل مع الشبكات العصبية الأكبر والأكثر تعقيدًا.
  • إمكانية التشغيل التفاعلي الأفضل للذاكرة المؤقتة: يمكنك تفعيل الاستخدام المباشر لذاكرات التخزين المؤقت لوحدة معالجة الرسومات لمعالجة لقطات الكاميرا أو مواد النسيج ثنائية الأبعاد أو حالات LLM الكبيرة.
  • إتاحة التنفيذ غير المتزامن: يمكنك تداخل المعالجة المُسبقة باستخدام وحدة المعالجة المركزية مع الاستنتاج باستخدام وحدة معالجة الرسومات.

ميزة "النسخ بدون نقل البيانات" مع تسريع وحدة معالجة الرسومات

من خلال استخدام تقنية "النسخ بدون نقل البيانات"، يمكن لوحدة معالجة الرسومات الوصول إلى البيانات مباشرةً في ذاكرتها الخاصة بدون الحاجة إلى أن تنسخ وحدة المعالجة المركزية هذه البيانات صراحةً. من خلال عدم نسخ البيانات إلى ذاكرة وحدة المعالجة المركزية وإزالتها منها، يمكن أن تقلل تقنية "النسخ بدون نقل البيانات" بشكل كبير من وقت الاستجابة من البداية إلى النهاية.

الرمز البرمجي التالي هو مثال على تنفيذ ميزة "وحدة معالجة الرسومات بدون نسخ" باستخدام OpenGL، وهي واجهة برمجة تطبيقات لعرض الرسومات المتجهة. تُرسِل العبارة البرمجية الصور بتنسيق مخزن OpenGL مباشرةً إلى LiteRT Next:

// 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()، جدولة الاستنتاج باستخدام وحدة معالجة الرسومات أثناء مواصلة المهام الأخرى باستخدام وحدة المعالجة المركزية أو وحدة المعالجة العصبية. في مسارات المعالجة المعقدة، غالبًا ما يتم استخدام وحدة معالجة الرسومات بشكل غير متزامن إلى جانب وحدة المعالجة المركزية أو وحدات المعالجة العصبية.

يستند مقتطف التعليمات البرمجية التالي إلى الرمز المقدَّم في مثال تسريع GPU بتقنية "النسخ بدون نقل البيانات". يستخدم الرمز البرمجي كلّ من وحدة المعالجة المركزية ووحدة معالجة الرسومات بشكل غير متزامن ويُرفِق Event LiteRT بوحدة تخزين مؤقت للدخل. ‫LiteRT Event هي المسؤولة عن إدارة أنواع مختلفة من العناصر الأساسية للتزامن، وينشئ الرمز البرمجي التالي عنصر حدث LiteRT مُدارًا من النوع LiteRtEventTypeEglSyncFence. يضمن عنصر 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 Next مع ميزة تسريع وحدة معالجة الرسومات في الطُرز التالية. تستند نتائج قياس الأداء إلى الاختبارات التي تم إجراؤها على جهاز Samsung Galaxy S24.

النموذج تسريع LiteRT باستخدام وحدة معالجة الرسومات LiteRT GPU (ms)
hf_mms_300m مفوض بالكامل 19.6
hf_mobilevit_small مفوض بالكامل 8.7
hf_mobilevit_small_e2e مفوض بالكامل من نظام التشغيل Android
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
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