شتاب‌دهی GPU با LiteRT

واحدهای پردازش گرافیکی (GPU) به دلیل توان عملیاتی موازی عظیمشان در مقایسه با CPUها، معمولاً برای شتاب‌دهی یادگیری عمیق استفاده می‌شوند. LiteRT با اجازه دادن به کاربران برای تعیین شتاب سخت‌افزاری به عنوان یک پارامتر هنگام ایجاد یک مدل کامپایل شده ( CompiledModel )، فرآیند استفاده از شتاب‌دهی GPU را ساده می‌کند.

با شتاب‌دهی GPU در LiteRT، می‌توانید بافرهای ورودی و خروجی سازگار با GPU ایجاد کنید، به کپی صفر از داده‌های خود در حافظه GPU دست یابید و وظایف را به صورت ناهمزمان اجرا کنید تا موازی‌سازی را به حداکثر برسانید.

برای مثال، پیاده‌سازی‌های LiteRT GPU، به برنامه‌های نمایشی زیر مراجعه کنید:

وابستگی به GPU را اضافه کنید

برای افزودن وابستگی به GPU به برنامه Kotlin یا C++ خود، مراحل زیر را دنبال کنید.

کاتلین

برای کاربران کاتلین، شتاب‌دهنده‌ی پردازنده‌ی گرافیکی (GPU) به صورت داخلی تعبیه شده است و نیازی به مراحل اضافی فراتر از راهنمای شروع به کار ندارد.

سی++

برای کاربران ++C، شما باید وابستگی‌های برنامه را با شتاب‌دهنده گرافیکی LiteRT بسازید. قانون cc_binary که منطق اصلی برنامه (مثلاً main.cc ) را بسته‌بندی می‌کند، به اجزای زمان اجرای زیر نیاز دارد:

  • کتابخانه مشترک LiteRT C API : ویژگی data باید شامل کتابخانه مشترک LiteRT C API ( //litert/c:litert_runtime_c_api_shared_lib ) و اجزای مخصوص GPU ( @litert_gpu//:jni/arm64-v8a/libLiteRtGpuAccelerator.so ) باشد.
  • وابستگی‌های ویژگی : ویژگی deps معمولاً شامل وابستگی‌های GLES gles_deps() است و linkopts معمولاً شامل gles_linkopts() است. هر دو برای شتاب‌دهی GPU بسیار مرتبط هستند، زیرا LiteRT اغلب از 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
)

این تنظیمات به فایل باینری کامپایل شده شما اجازه می‌دهد تا به صورت پویا بارگذاری شود و از پردازنده گرافیکی (GPU) برای استنتاج یادگیری ماشینی شتاب‌یافته استفاده کند.

استفاده از GPU با CompiledModel API

برای شروع استفاده از شتاب‌دهنده GPU، هنگام ایجاد مدل کامپایل‌شده ( CompiledModel ) پارامتر GPU را ارسال کنید. قطعه کد زیر پیاده‌سازی اولیه کل فرآیند را نشان می‌دهد:

سی++

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

کاتلین

// 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» یا «شروع با کاتلین» مراجعه کنید.

کپی صفر با شتاب‌دهی GPU

استفاده از کپی صفر، پردازنده گرافیکی (GPU) را قادر می‌سازد تا بدون نیاز به کپی کردن صریح داده‌ها توسط CPU، مستقیماً به داده‌ها در حافظه خود دسترسی پیدا کند. با عدم کپی کردن داده‌ها به و از حافظه CPU، کپی صفر می‌تواند تأخیر انتها به انتها را به میزان قابل توجهی کاهش دهد.

کد زیر نمونه‌ای از پیاده‌سازی Zero-Copy GPU با OpenGL ، یک API برای رندر کردن گرافیک‌های برداری، است. این کد تصاویر را در قالب بافر 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() ، به شما امکان می‌دهند استنتاج GPU را زمان‌بندی کنید و در عین حال به انجام سایر وظایف با استفاده از CPU یا NPU ادامه دهید. در خطوط لوله پیچیده، GPU اغلب به صورت غیرهمزمان در کنار CPU یا NPU استفاده می‌شود.

قطعه کد زیر بر اساس کد ارائه شده در مثال شتاب‌دهی GPU با کپی صفر ساخته شده است. این کد از هر دو CPU و GPU به صورت ناهمزمان استفاده می‌کند و یک Event LiteRT را به بافر ورودی متصل می‌کند. Event LiteRT مسئول مدیریت انواع مختلف اولیه‌های همگام‌سازی است و کد زیر یک شیء رویداد LiteRT مدیریت‌شده از نوع LiteRtEventTypeEglSyncFence ایجاد می‌کند. این شیء Event تضمین می‌کند که تا زمانی که GPU کار خود را تمام نکرده است، از بافر ورودی چیزی نخوانیم. همه این کارها بدون دخالت 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));

مدل‌های پشتیبانی‌شده

LiteRT از شتاب‌دهی GPU با مدل‌های زیر پشتیبانی می‌کند. نتایج بنچمارک بر اساس آزمایش‌های انجام شده روی دستگاه Samsung Galaxy S24 است.

مدل شتاب‌دهنده گرافیکی LiteRT پردازنده گرافیکی LiteRT (میلی‌ثانیه)
hf_mms_300m کاملاً تفویض اختیار شده ۱۹.۶
hf_mobilevit_small کاملاً تفویض اختیار شده ۸.۷
hf_mobilevit_small_e2e کاملاً تفویض اختیار شده ۸.۰
hf_wav2vec2_base_960h کاملاً تفویض اختیار شده ۹.۱
hf_wav2vec2_base_960h_dynamic کاملاً تفویض اختیار شده ۹.۸
ایزنت کاملاً تفویض اختیار شده ۴۳.۱
timm_efficientnet کاملاً تفویض اختیار شده ۳.۷
تیم_ان_اف_نت کاملاً تفویض اختیار شده ۹.۷
timm_regnety_120 کاملاً تفویض اختیار شده ۱۲.۱
torchaudio_deepspeech کاملاً تفویض اختیار شده ۴.۶
torchaudio_wav2letter کاملاً تفویض اختیار شده ۴.۸
torchvision_alexnet کاملاً تفویض اختیار شده ۳.۳
torchvision_deeplabv3_mobilenet_v3_large کاملاً تفویض اختیار شده ۵.۷
torchvision_deeplabv3_resnet101 کاملاً تفویض اختیار شده ۳۵.۱
torchvision_deeplabv3_resnet50 کاملاً تفویض اختیار شده ۲۴.۵
torchvision_densenet121 کاملاً تفویض اختیار شده ۱۳.۹
torchvision_efficientnet_b0 کاملاً تفویض اختیار شده ۳.۶
torchvision_efficientnet_b1 کاملاً تفویض اختیار شده ۴.۷
torchvision_efficientnet_b2 کاملاً تفویض اختیار شده ۵.۰
torchvision_efficientnet_b3 کاملاً تفویض اختیار شده ۶.۱
torchvision_efficientnet_b4 کاملاً تفویض اختیار شده ۷.۶
torchvision_efficientnet_b5 کاملاً تفویض اختیار شده ۸.۶
torchvision_efficientnet_b6 کاملاً تفویض اختیار شده ۱۱.۲
torchvision_efficientnet_b7 کاملاً تفویض اختیار شده ۱۴.۷
torchvision_fcn_resnet50 کاملاً تفویض اختیار شده ۱۹.۹
torchvision_googlenet کاملاً تفویض اختیار شده ۳.۹
torchvision_inception_v3 کاملاً تفویض اختیار شده ۸.۶
torchvision_lraspp_mobilenet_v3_large کاملاً تفویض اختیار شده ۳.۳
torchvision_mnasnet0_5 کاملاً تفویض اختیار شده ۲.۴
torchvision_mobilenet_v2 کاملاً تفویض اختیار شده ۲.۸
torchvision_mobilenet_v3_large کاملاً تفویض اختیار شده ۲.۸
torchvision_mobilenet_v3_small کاملاً تفویض اختیار شده ۲.۳
torchvision_resnet152 کاملاً تفویض اختیار شده ۱۵.۰
torchvision_resnet18 کاملاً تفویض اختیار شده ۴.۳
torchvision_resnet50 کاملاً تفویض اختیار شده ۶.۹
torchvision_squeezenet1_0 کاملاً تفویض اختیار شده ۲.۹
torchvision_squeezenet1_1 کاملاً تفویض اختیار شده ۲.۵
torchvision_vgg16 کاملاً تفویض اختیار شده ۱۳.۴
torchvision_wide_resnet101_2 کاملاً تفویض اختیار شده ۲۵.۰
torchvision_wide_resnet50_2 کاملاً تفویض اختیار شده ۱۳.۴
u2net_full کاملاً تفویض اختیار شده ۹۸.۳
u2net_lite کاملاً تفویض اختیار شده ۵۱.۴
hf_distil_whisper_small_no_cache تا حدی تفویض شده ۲۵۱.۹
hf_distilbert تا حدی تفویض شده ۱۳.۷
hf_tinyroberta_squad2 تا حدی تفویض شده ۱۷.۱
hf_tinyroberta_squad2_dynamic_batch تا حدی تفویض شده ۵۲.۱
snapml_StyleTransferNet تا حدی تفویض شده ۴۰.۹
timm_efficientformer_l1 تا حدی تفویض شده ۱۷.۶
timm_efficientformerv2_s0 تا حدی تفویض شده ۱۶.۱
timm_pvt_v2_b1 تا حدی تفویض شده ۷۳.۵
timm_pvt_v2_b3 تا حدی تفویض شده ۲۴۶.۷
timm_resnest14d تا حدی تفویض شده ۸۸.۹
torchaudio_conformer تا حدی تفویض شده ۲۱.۵
torchvision_convnext_tiny تا حدی تفویض شده ۸.۲
torchvision_maxvit_t تا حدی تفویض شده ۱۹۴.۰
torchvision_shufflenet_v2 تا حدی تفویض شده ۹.۵
torchvision_swin_tiny تا حدی تفویض شده ۱۶۴.۴
torchvision_video_resnet2plus1d_18 تا حدی تفویض شده ۶۸۳۲.۰
torchvision_video_swin3d_tiny تا حدی تفویض شده ۲۶۱۷.۸
یولوکس_تینی تا حدی تفویض شده ۱۱.۲