Tăng tốc GPU bằng LiteRT

Đơn vị xử lý đồ hoạ (GPU) thường được dùng để tăng tốc học sâu do có thông lượng song song lớn so với CPU. LiteRT đơn giản hoá quy trình sử dụng tính năng tăng tốc GPU bằng cách cho phép người dùng chỉ định tính năng tăng tốc phần cứng làm tham số khi tạo Mô hình đã biên dịch (CompiledModel).

Với tính năng tăng tốc GPU của LiteRT, bạn có thể tạo các vùng đệm đầu vào và đầu ra thân thiện với GPU, đạt được khả năng sao chép bằng 0 với dữ liệu trong bộ nhớ GPU và thực thi các tác vụ không đồng bộ để tối đa hoá khả năng xử lý song song.

Để biết ví dụ về cách triển khai GPU LiteRT, hãy tham khảo các ứng dụng minh hoạ sau:

Thêm phần phụ thuộc GPU

Hãy làm theo các bước sau để thêm phần phụ thuộc GPU vào ứng dụng Kotlin hoặc C++.

Kotlin

Đối với người dùng Kotlin, trình tăng tốc GPU được tích hợp sẵn và không yêu cầu các bước bổ sung ngoài hướng dẫn Bắt đầu.

C++

Đối với người dùng C++, bạn phải tạo các phần phụ thuộc của ứng dụng bằng tính năng tăng tốc GPU LiteRT. Quy tắc cc_binary đóng gói logic ứng dụng cốt lõi (ví dụ: main.cc) yêu cầu các thành phần thời gian chạy sau:

  • Thư viện dùng chung LiteRT C API: thuộc tính data phải bao gồm thư viện dùng chung LiteRT C API (//litert/c:litert_runtime_c_api_shared_lib) và các thành phần dành riêng cho GPU (@litert_gpu//:jni/arm64-v8a/libLiteRtGpuAccelerator.so).
  • Phần phụ thuộc của thuộc tính: Thuộc tính deps thường bao gồm các phần phụ thuộc GLES gles_deps()linkopts thường bao gồm gles_linkopts(). Cả hai đều rất phù hợp để tăng tốc GPU, vì LiteRT thường sử dụng OpenGLES trên Android.
  • Tệp mô hình và các thành phần khác: Được thêm thông qua thuộc tính data.

Sau đây là ví dụ về một quy tắc 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
)

Chế độ thiết lập này cho phép tệp nhị phân đã biên dịch của bạn tải và sử dụng GPU một cách linh hoạt để suy luận học máy được tăng tốc.

Sử dụng GPU với CompiledModel API

Để bắt đầu sử dụng trình tăng tốc GPU, hãy truyền tham số GPU khi tạo Mô hình đã biên dịch (CompiledModel). Đoạn mã sau đây cho thấy một cách triển khai cơ bản của toàn bộ quy trình:

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()

Để biết thêm thông tin, hãy xem hướng dẫn Bắt đầu sử dụng C++ hoặc Bắt đầu sử dụng Kotlin.

Sao chép bằng 0 với tính năng tăng tốc GPU

Việc sử dụng tính năng sao chép bằng 0 cho phép GPU truy cập trực tiếp vào dữ liệu trong bộ nhớ riêng mà không cần CPU sao chép dữ liệu đó một cách rõ ràng. Bằng cách không sao chép dữ liệu đến và đi từ bộ nhớ CPU, tính năng sao chép bằng 0 có thể giảm đáng kể độ trễ từ đầu đến cuối.

Đoạn mã sau đây là một ví dụ về việc triển khai GPU Zero-Copy bằng OpenGL, một API để kết xuất đồ hoạ vectơ. Đoạn mã này truyền trực tiếp hình ảnh ở định dạng bộ đệm OpenGL đến 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());

Thực thi không đồng bộ

Các phương thức không đồng bộ của LiteRT, chẳng hạn như RunAsync(), cho phép bạn lên lịch suy luận GPU trong khi tiếp tục các tác vụ khác bằng CPU hoặc NPU. Trong các quy trình phức tạp, GPU thường được dùng không đồng bộ cùng với CPU hoặc NPU.

Đoạn mã sau đây dựa trên mã được cung cấp trong ví dụ về tăng tốc GPU sao chép bằng 0. Mã này sử dụng cả CPU và GPU không đồng bộ, đồng thời đính kèm một Event LiteRT vào vùng đệm đầu vào. LiteRT Event chịu trách nhiệm quản lý các loại nguyên tắc đồng bộ hoá khác nhau và mã sau đây tạo một đối tượng LiteRT Event được quản lý thuộc loại LiteRtEventTypeEglSyncFence. Đối tượng Event này đảm bảo rằng chúng ta không đọc từ vùng đệm đầu vào cho đến khi GPU hoàn tất. Tất cả những việc này đều được thực hiện mà không cần đến 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));

Mô hình được hỗ trợ

LiteRT hỗ trợ tính năng tăng tốc GPU với các mô hình sau. Kết quả đo điểm chuẩn dựa trên các kiểm thử được chạy trên thiết bị Samsung Galaxy S24.

Mô hình Tính năng tăng tốc GPU LiteRT GPU LiteRT (mili giây)
hf_mms_300m Được uỷ quyền hoàn toàn 19,6
hf_mobilevit_small Được uỷ quyền hoàn toàn 8.7
hf_mobilevit_small_e2e Được uỷ quyền hoàn toàn 8.0
hf_wav2vec2_base_960h Được uỷ quyền hoàn toàn 9.1
hf_wav2vec2_base_960h_dynamic Được uỷ quyền hoàn toàn 9,8
isnet Được uỷ quyền hoàn toàn 43,1
timm_efficientnet Được uỷ quyền hoàn toàn 3.7
timm_nfnet Được uỷ quyền hoàn toàn 9.7
timm_regnety_120 Được uỷ quyền hoàn toàn 12.1
torchaudio_deepspeech Được uỷ quyền hoàn toàn 4,6
torchaudio_wav2letter Được uỷ quyền hoàn toàn 4.8
torchvision_alexnet Được uỷ quyền hoàn toàn 3.3
torchvision_deeplabv3_mobilenet_v3_large Được uỷ quyền hoàn toàn 5.7
torchvision_deeplabv3_resnet101 Được uỷ quyền hoàn toàn 35,1
torchvision_deeplabv3_resnet50 Được uỷ quyền hoàn toàn 24,5
torchvision_densenet121 Được uỷ quyền hoàn toàn 13,9
torchvision_efficientnet_b0 Được uỷ quyền hoàn toàn 3.6
torchvision_efficientnet_b1 Được uỷ quyền hoàn toàn 4,7
torchvision_efficientnet_b2 Được uỷ quyền hoàn toàn 5
torchvision_efficientnet_b3 Được uỷ quyền hoàn toàn 6.1
torchvision_efficientnet_b4 Được uỷ quyền hoàn toàn 7.6
torchvision_efficientnet_b5 Được uỷ quyền hoàn toàn 8.6
torchvision_efficientnet_b6 Được uỷ quyền hoàn toàn 11.2
torchvision_efficientnet_b7 Được uỷ quyền hoàn toàn 14,7
torchvision_fcn_resnet50 Được uỷ quyền hoàn toàn 19,9
torchvision_googlenet Được uỷ quyền hoàn toàn 3,9
torchvision_inception_v3 Được uỷ quyền hoàn toàn 8.6
torchvision_lraspp_mobilenet_v3_large Được uỷ quyền hoàn toàn 3.3
torchvision_mnasnet0_5 Được uỷ quyền hoàn toàn 2.4
torchvision_mobilenet_v2 Được uỷ quyền hoàn toàn 2.8
torchvision_mobilenet_v3_large Được uỷ quyền hoàn toàn 2.8
torchvision_mobilenet_v3_small Được uỷ quyền hoàn toàn 2.3
torchvision_resnet152 Được uỷ quyền hoàn toàn 15
torchvision_resnet18 Được uỷ quyền hoàn toàn 4,3
torchvision_resnet50 Được uỷ quyền hoàn toàn 6.9
torchvision_squeezenet1_0 Được uỷ quyền hoàn toàn 2.9
torchvision_squeezenet1_1 Được uỷ quyền hoàn toàn 2.5
torchvision_vgg16 Được uỷ quyền hoàn toàn 13,4
torchvision_wide_resnet101_2 Được uỷ quyền hoàn toàn 25,0
torchvision_wide_resnet50_2 Được uỷ quyền hoàn toàn 13,4
u2net_full Được uỷ quyền hoàn toàn 98,3
u2net_lite Được uỷ quyền hoàn toàn 51,4
hf_distil_whisper_small_no_cache Được uỷ quyền một phần 251,9
hf_distilbert Được uỷ quyền một phần 13.7
hf_tinyroberta_squad2 Được uỷ quyền một phần 17,1
hf_tinyroberta_squad2_dynamic_batch Được uỷ quyền một phần 52,1
snapml_StyleTransferNet Được uỷ quyền một phần 40,9
timm_efficientformer_l1 Được uỷ quyền một phần 17,6
timm_efficientformerv2_s0 Được uỷ quyền một phần 16,1
timm_pvt_v2_b1 Được uỷ quyền một phần 73,5
timm_pvt_v2_b3 Được uỷ quyền một phần 246,7
timm_resnest14d Được uỷ quyền một phần 88,9
torchaudio_conformer Được uỷ quyền một phần 21,5
torchvision_convnext_tiny Được uỷ quyền một phần 8.2
torchvision_maxvit_t Được uỷ quyền một phần 194,0
torchvision_shufflenet_v2 Được uỷ quyền một phần 9.5
torchvision_swin_tiny Được uỷ quyền một phần 164,4
torchvision_video_resnet2plus1d_18 Được uỷ quyền một phần 6832.0
torchvision_video_swin3d_tiny Được uỷ quyền một phần 2617,8
yolox_tiny Được uỷ quyền một phần 11.2