מעבדים גרפיים (GPU) משמשים בדרך כלל להאצת למידה עמוקה, בגלל התפוקה המקבילית הגבוהה שלהם בהשוואה למעבדים מרכזיים (CPU). LiteRT מפשטת את תהליך השימוש בהאצת GPU בכך שהיא מאפשרת למשתמשים לציין את האצת החומרה כפרמטר בעת יצירת מודל מהודר (CompiledModel).
בעזרת האצת ה-GPU של LiteRT, אתם יכולים ליצור מאגרי קלט ופלט שמתאימים ל-GPU, להשיג אפס עותקים של הנתונים בזיכרון ה-GPU ולהריץ משימות באופן אסינכרוני כדי למקסם את המקביליות.
דוגמאות להטמעה של LiteRT GPU אפשר למצוא באפליקציות ההדגמה הבאות:
הוספת תלות ב-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//:jni/arm64-v8a/libLiteRtGpuAccelerator.so). - תלות בין מאפיינים: המאפיין
depsכולל בדרך כלל תלות ב-GLESgles_deps(), והמאפייןlinkoptsכולל בדרך כלל אתgles_linkopts(). שניהם רלוונטיים מאוד להאצת GPU, כי 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
)
ההגדרה הזו מאפשרת לבינארי המהודר לטעון באופן דינמי את ה-GPU ולהשתמש בו כדי להסיק מסקנות מנתונים באמצעות למידת מכונה מואצת.
שימוש ב-GPU עם CompiledModel API
כדי להתחיל להשתמש בהאצת GPU, מעבירים את פרמטר ה-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.
העתקה ללא שימוש ב-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 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 תוך כדי המשך ביצוע משימות אחרות באמצעות המעבד או ה-NPU. בצינורות מורכבים, לעיתים קרובות נעשה שימוש ב-GPU באופן אסינכרוני לצד CPU או NPU.
קטע הקוד הבא מבוסס על הקוד שמופיע בדוגמה של האצת GPU ללא העתקה. הקוד משתמש ב-CPU וב-GPU באופן אסינכרוני ומצרף LiteRT Event למאגר הקלט. LiteRT Event אחראי לניהול סוגים שונים של פרימיטיבים של סנכרון, והקוד הבא יוצר אובייקט LiteRT מנוהל מסוג LiteRtEventTypeEglSyncFence. אובייקט Event הזה מבטיח שלא נקרא ממאגר הקלט עד שה-GPU יסיים את הפעולה. כל הפעולות האלה מתבצעות בלי להשתמש במעבד.
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.
| מודל | האצת 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 |