หน่วยประมวลผลกราฟิก (GPU) มักใช้สำหรับการเร่งการเรียนรู้เชิงลึกเนื่องจากมีอัตราผ่านข้อมูลแบบขนานจำนวนมากเมื่อเทียบกับ CPU LiteRT Next ลดความซับซ้อนในการใช้การเร่งความเร็วด้วย GPU โดยอนุญาตให้ผู้ใช้ระบุการเร่งความเร็วด้วยฮาร์ดแวร์เป็นพารามิเตอร์เมื่อสร้างรูปแบบที่คอมไพล์แล้ว (CompiledModel
) นอกจากนี้ LiteRT Next ยังใช้การใช้งานการเร่งความเร็วด้วย GPU รูปแบบใหม่ที่ได้รับการปรับปรุง ซึ่ง LiteRT ไม่มีให้บริการ
การใช้การเร่งด้วย GPU ของ LiteRT Next ช่วยให้คุณสร้างบัฟเฟอร์อินพุตและเอาต์พุตที่เหมาะกับ GPU, ใช้การคัดลอกข้อมูลไปยังหน่วยความจำ GPU โดยไม่ต้องคัดลอกข้อมูล และดำเนินการแบบไม่พร้อมกันเพื่อเพิ่มการทำงานแบบขนานให้สูงสุด
ดูตัวอย่างการใช้งาน LiteRT Next ที่รองรับ GPU ได้จากแอปพลิเคชันเดโมต่อไปนี้
เพิ่มการพึ่งพา GPU
ทําตามขั้นตอนต่อไปนี้เพื่อเพิ่มการพึ่งพา GPU ในแอปพลิเคชัน Kotlin หรือ C++
Kotlin
สำหรับผู้ใช้ Kotlin โปรแกรมเร่งความเร็ว GPU จะติดตั้งมาในตัวอยู่แล้วและไม่จำเป็นต้องทำตามขั้นตอนเพิ่มเติมนอกเหนือจากคำแนะนำเริ่มต้นใช้งาน
C++
สําหรับผู้ใช้ C++ คุณต้องสร้างทรัพยากร Dependency ของแอปพลิเคชันด้วย LiteRT ที่เร่งด้วย GPU กฎ cc_binary
ที่แพ็กเกจตรรกะหลักของแอปพลิเคชัน (เช่น main.cc
) ต้องใช้คอมโพเนนต์รันไทม์ต่อไปนี้
- ไลบรารีที่แชร์ของ LiteRT C API: แอตทริบิวต์
data
ต้องมีไฟล์ LiteRT C API shared library (//litert/c:litert_runtime_c_api_shared_lib
) และคอมโพเนนต์เฉพาะ GPU (@litert_gpu//:jni/arm64-v8a/libLiteRtGpuAccelerator.so
) - การพึ่งพาแอตทริบิวต์: โดยทั่วไปแอตทริบิวต์
deps
จะมี GLES และlinkopts
โดยทั่วไปจะมีgles_linkopts()
gles_deps()
ทั้ง 2 รายการมีความเกี่ยวข้องอย่างมากกับการเร่งความเร็ว 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 ให้ส่งพารามิเตอร์ 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 รุ่น LiteRT Next
ตัวเร่ง GPU ใหม่ซึ่งใช้ได้กับ LiteRT Next เท่านั้นได้รับการเพิ่มประสิทธิภาพให้จัดการปริมาณงาน AI เช่น การคูณเมทริกซ์ขนาดใหญ่และแคช KV สําหรับ LLM ได้อย่างมีประสิทธิภาพมากกว่าเวอร์ชันก่อนหน้า ตัวเร่ง GPU LiteRT Next มีการปรับปรุงที่สำคัญต่อไปนี้เมื่อเทียบกับเวอร์ชัน LiteRT
- การครอบคลุมผู้ให้บริการแบบขยาย: จัดการเครือข่ายประสาทที่ใหญ่ขึ้นและซับซ้อนมากขึ้น
- ความสามารถในการทำงานร่วมกันของบัฟเฟอร์ที่ดีขึ้น: เปิดใช้การใช้บัฟเฟอร์ GPU โดยตรงสำหรับเฟรมกล้อง พื้นผิว 2 มิติ หรือสถานะ LLM ขนาดใหญ่
- การรองรับการดำเนินการแบบไม่พร้อมกัน: ซ้อนการจัดเตรียมข้อมูลเบื้องต้นของ CPU กับการอนุมานของ GPU
การคัดลอกข้อมูลแบบไม่ใช้พื้นที่เก็บข้อมูลด้วยระบบเร่งการทำงานของ GPU
การใช้การคัดลอกข้อมูลแบบ 0 ช่วยให้ GPU สามารถเข้าถึงข้อมูลในหน่วยความจำของตนเองได้โดยตรงโดยไม่ต้องให้ CPU คัดลอกข้อมูลดังกล่าวอย่างชัดแจ้ง การไม่คัดลอกข้อมูลจากและไปยังหน่วยความจําของ CPU จะช่วยให้การคัดลอกข้อมูลแบบไม่ใช้พื้นที่เก็บข้อมูล (Zero-Copy) ลดเวลาในการตอบสนองจากต้นทางถึงปลายทางได้อย่างมาก
โค้ดต่อไปนี้เป็นตัวอย่างการใช้งาน GPU แบบไม่คัดลอกข้อมูลกับ OpenGL ซึ่งเป็น API สำหรับการเรนเดอร์กราฟิกเวกเตอร์ โค้ดจะส่งรูปภาพในรูปแบบบัฟเฟอร์ 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 ได้ในขณะที่ทำงานอื่นๆ ต่อไปโดยใช้ CPU หรือ NPU ในไปป์ไลน์ที่ซับซ้อน มักจะใช้ GPU แบบไม่พร้อมกันควบคู่ไปกับ CPU หรือ NPU
ข้อมูลโค้ดต่อไปนี้จะต่อยอดจากโค้ดที่ให้ไว้ในตัวอย่างการเร่งความเร็ว GPU แบบไม่คัดลอก โค้ดใช้ทั้ง CPU และ GPU แบบไม่พร้อมกัน และแนบ LiteRT Event
ไปยังบัฟเฟอร์อินพุต LiteRT Event
มีหน้าที่จัดการพรอมิเตอการซิงค์ประเภทต่างๆ และโค้ดต่อไปนี้จะสร้างออบเจ็กต์เหตุการณ์ 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 Next รองรับการเร่งด้วย 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 |