מעבדים גרפיים (GPU) משמשים בדרך כלל להאצת למידה עמוקה, בגלל התפוקה המקבילית הגדולה שלהם בהשוואה למעבדים מרכזיים (CPU). LiteRT מפשטת את תהליך השימוש בהאצת GPU בכך שהיא מאפשרת למשתמשים לציין את האצת החומרה כפרמטר בעת יצירת מודל מהודר (CompiledModel).
בעזרת האצת ה-GPU של LiteRT, אתם יכולים ליצור מאגרי קלט ופלט שמתאימים ל-GPU, להשיג אפס עותקים של הנתונים בזיכרון ה-GPU ולהריץ משימות באופן אסינכרוני כדי למקסם את המקביליות.
שנתחיל?
למודלים קלאסיים של ML, אפשר לעיין באפליקציות ההדגמה הבאות.
- אפליקציית Kotlin לפילוח תמונות: הסקת מסקנות ב-CPU/GPU/NPU.
- אפליקציית C++ לפילוח תמונות: הסקת מסקנות במעבד, במעבד גרפי או במעבד עצבי עם ביצוע אסינכרוני.
למודלים של AI גנרטיבי, אפשר לעיין בהדגמות ובמדריך הבאים:
- EmbeddingGemma semantic similarity C++ App: הסקת מסקנות ב-CPU/GPU/NPU.
- מדריך בנושא הפעלת מודלי שפה גדולים באמצעות LiteRT-LM
הוספת תלות ב-GPU
כדי להוסיף תלות ב-GPU לאפליקציית Kotlin או C++:
Kotlin
משתמשי Kotlin יכולים להשתמש במאיץ ה-GPU המובנה, ולא נדרשים שלבים נוספים מעבר לאלה שמפורטים במדריך תחילת העבודה.
C++
משתמשי C++ צריכים לבנות את התלות של האפליקציה עם האצת GPU של LiteRT. הכלל cc_binary שאורז את הלוגיקה המרכזית של האפליקציה (למשל, main.cc) דורש את רכיבי זמן הריצה הבאים:
- LiteRT C API shared library: המאפיין
dataצריך לכלול את הספרייה המשותפת של LiteRT C API (//litert/c:litert_runtime_c_api_shared_lib) ואת הרכיבים הספציפיים ל-GPU (litert_gpu_accelerator_prebuilts). - תלות בין מאפיינים: המאפיין
depsכולל בדרך כלל תלות ב-GLESgles_deps(), והמאפייןlinkoptsכולל בדרך כלל אתgles_linkopts(). שניהם רלוונטיים מאוד להאצת GPU, כי LiteRT משתמש לעיתים קרובות ב-OpenGLES ב-Android. - קבצים של מודלים ונכסים אחרים: נכללים באמצעות המאפיין
data.
דוגמה לכלל cc_binary:
load("//litert/build_common:special_rule.bzl", "litert_gpu_accelerator_prebuilts")
cc_binary(
name = "your_application",
srcs = [
"main.cc",
],
data = [
...
# litert c api shared library
"//litert/c:litert_runtime_c_api_shared_lib",
] + litert_gpu_accelerator_prebuilts(),
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 מוכנים מראש
מאיץ ה-GPU החדש LiteRT עדיין לא זמין בקוד פתוח. אבל יש רכיבים מוכנים מראש. למשתמשי Kotlin, חבילת ה-Maven של LiteRT כבר מכילה GPU Accelerators. משתמשי C++ SDK צריכים להוריד אותו בנפרד באמצעות הקישור הזה.
ב-Bazel, אפשר להשתמש בכלל הבא כדי להוסיף תלות ליעד.
cpp
load("//litert/build_common:special_rule.bzl", "litert_gpu_accelerator_prebuilts")
שימוש ב-GPU עם CompiledModel API
כדי להתחיל להשתמש בהאצת GPU, מעבירים את הפרמטר GPU כשיוצרים את המודל המהודר (CompiledModel). קטע הקוד הבא מציג הטמעה בסיסית של התהליך כולו:
C++
// 1. Create a compiled model targeting GPU
LITERT_ASSIGN_OR_RETURN(auto env, Environment::Create({}));
LITERT_ASSIGN_OR_RETURN(auto compiled_model, CompiledModel::Create(env, "mymodel.tflite", kLiteRtHwAcceleratorGpu));
// 2. Prepare input/output buffers
LITERT_ASSIGN_OR_RETURN(auto input_buffers, compiled_model.CreateInputBuffers());
LITERT_ASSIGN_OR_RETURN(auto output_buffers, compiled_model.CreateOutputBuffers());
// 3. Fill input data (if you have CPU-based data)
input_buffers[0].Write<float>(absl::MakeConstSpan(cpu_data, data_size));
// 4. Execute
compiled_model.Run(input_buffers, output_buffers);
// 5. 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.
העתקה ללא שימוש ב-GPU
שימוש בשיטת העתקה ללא העברה מאפשר ליחידת GPU לגשת לנתונים ישירות בזיכרון שלה, בלי שה-CPU יצטרך להעתיק את הנתונים באופן מפורש. היעדר העתקה של נתונים לזיכרון המעבד וממנו מאפשר לצמצם משמעותית את זמן האחזור מקצה לקצה.
הקוד הבא הוא דוגמה להטמעה של 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 env, Environment::Create({}));
LITERT_ASSIGN_OR_RETURN(auto compiled_model,
CompiledModel::Create(env, "mymodel.tflite", 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 תוך כדי המשך ביצוע משימות אחרות באמצעות המעבד או ה-NPU. בצינורות מורכבים, לעיתים קרובות נעשה שימוש ב-GPU באופן אסינכרוני לצד CPU או NPU.
קטע הקוד הבא מבוסס על הקוד שמופיע בדוגמה של האצת GPU ללא העתקה. הקוד משתמש במעבד (CPU) ובמעבד גרפי (GPU) באופן אסינכרוני, ומצרף LiteRT Event למאגר הקלט. LiteRT Event אחראי לניהול סוגים שונים של פרימיטיבים של סנכרון, והקוד הבא יוצר אובייקט LiteRT Event מנוהל מסוג LiteRtEventTypeEglSyncFence. אובייקט Event הזה מבטיח שלא נקרא ממאגר הקלט עד שה-GPU יסיים את הפעולה. כל הפעולות האלה מתבצעות בלי מעורבות של המעבד.
LITERT_ASSIGN_OR_RETURN(auto env, Environment::Create({}));
LITERT_ASSIGN_OR_RETURN(auto compiled_model,
CompiledModel::Create(env, "mymodel.tflite", 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 backend הבא לכל פלטפורמה.
| פלטפורמה | קצה עורפי |
|---|---|
| Android | OpenCL + OpenGL |
| Linux | WebGPU (Vulkan) |
| macOS | מטאל |
| Windows | WebGPU (Direct3D) |
| Android | OpenCL + OpenGL |
מודלים נתמכים
LiteRT תומך בהאצת GPU עם הדגמים הבאים. תוצאות ההשוואה מבוססות על בדיקות שבוצעו במכשיר Samsung Galaxy S24.
| מודל | האצת GPU ב-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 |