Tăng tốc GPU bằng LiteRT Next

Đơn vị xử lý đồ hoạ (GPU) thường được dùng để tăng tốc học sâu do có băng thông song song khổng lồ so với CPU. LiteRT Next đơ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). LiteRT Next cũng sử dụng phương thức triển khai tăng tốc GPU mới và cải tiến mà LiteRT không cung cấp.

Với tính năng tăng tốc GPU của LiteRT Next, bạn có thể tạo vùng đệm đầu vào và đầu ra phù hợp với GPU, đạt được tính năng không sao chép 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á tính song song.

Để biết ví dụ về cách triển khai LiteRT Next có hỗ trợ GPU, 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 thêm bước nào 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 API LiteRT C: thuộc tính data phải bao gồm thư viện dùng chung API LiteRT C (//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 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 có liên quan chặt chẽ đến tính năng 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 đưa vào thông qua thuộc tính data.

Sau đây là ví dụ về 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 động để tăng tốc suy luận học máy.

Bắt đầu

Để 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 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 với C++ hoặc Bắt đầu với Kotlin.

Trình tăng tốc GPU LiteRT Next

Trình tăng tốc GPU mới (chỉ có trong LiteRT Next) được tối ưu hoá để xử lý khối lượng công việc AI, chẳng hạn như phép nhân ma trận lớn và bộ nhớ đệm KV cho LLM, hiệu quả hơn so với các phiên bản trước. Trình tăng tốc GPU LiteRT Next có các điểm cải tiến chính sau đây so với phiên bản LiteRT:

  • Mở rộng phạm vi hoạt động của toán tử: Xử lý các mạng nơron lớn hơn và phức tạp hơn.
  • Khả năng tương tác tốt hơn của bộ đệm: Cho phép sử dụng trực tiếp bộ đệm GPU cho khung máy ảnh, hoạ tiết 2D hoặc trạng thái LLM lớn.
  • Hỗ trợ thực thi không đồng bộ: Lồng ghép quá trình xử lý trước của CPU với suy luận GPU.

Không sao chép với tính năng tăng tốc GPU

Việc sử dụng tính năng không sao chép cho phép GPU truy cập trực tiếp vào dữ liệu trong bộ nhớ của chính GPU 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 vào và từ bộ nhớ CPU, tính năng không sao chép có thể làm giảm đáng kể độ trễ toàn bộ.

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

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 dự đoá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 sử 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 không sao chép. Mã này sử dụng cả CPU và GPU một cách không đồng bộ và đính kèm Event LiteRT vào vùng đệm đầu vào. LiteRT Event chịu trách nhiệm quản lý nhiều loại nguyên hàm đồng bộ hoá và mã sau đây sẽ 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ả việc này đượ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 Next 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 thử nghiệm chạy trên thiết bị Samsung Galaxy S24.

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