圖形處理器 (GPU) 通常用於深度學習加速,因為相較於 CPU,GPU 的平行總處理量相當龐大。LiteRT Next 會在使用者建立編譯模型 (CompiledModel
) 時,允許使用者將硬體加速功能指定為參數,藉此簡化使用 GPU 加速功能的程序。LiteRT Next 也會使用全新且經過改善的 GPU 加速功能實作,而這並非 LiteRT 提供的功能。
透過 LiteRT Next 的 GPU 加速功能,您可以建立 GPU 友善的輸入和輸出緩衝區,在 GPU 記憶體中實現零複製資料,並以非同步方式執行工作,以便盡可能提高平行處理作業。
如需 LiteRT Next 支援 GPU 的實作範例,請參閱下列試用版應用程式:
新增 GPU 依附元件
請按照下列步驟,在 Kotlin 或 C++ 應用程式中新增 GPU 依附元件。
Kotlin
對於 Kotlin 使用者而言,GPU 加速器是內建的,因此除了「開始使用」指南之外,不需要額外採取任何步驟。
C++
C++ 使用者必須使用 LiteRT GPU 加速功能建構應用程式的依附元件。cc_binary
規則會封裝核心應用程式邏輯 (例如main.cc
) 需要下列執行階段元件:
- LiteRT C API 共用程式庫:
data
屬性必須包含 LiteRT C API 共用程式庫 (//litert/c:litert_runtime_c_api_shared_lib
) 和 GPU 專屬元件 (@litert_gpu//:jni/arm64-v8a/libLiteRtGpuAccelerator.so
)。 - 屬性依附元件:
deps
屬性通常包含 GLES 依附元件gles_deps()
,而linkopts
通常包含gles_linkopts()
。由於 LiteRT 通常會在 Android 上使用 OpenGLES,因此這兩者與 GPU 加速功能高度相關。 - 模型檔案和其他資產:透過
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
) 時傳遞 GPU 參數。以下程式碼片段顯示整個程序的基本實作方式:
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」指南。
LiteRT Next GPU 加速器
全新 GPU 加速器僅適用於 LiteRT Next,經過最佳化處理 AI 工作負載,例如大型矩陣相乘和 LLM 的 KV 快取,比先前版本更有效率。LiteRT Next GPU 加速器相較於 LiteRT 版本,具有下列主要改善項目:
- 擴充運算子涵蓋範圍:處理更大型、更複雜的類神經網路。
- 更佳的緩衝區互通性:啟用 GPU 緩衝區的直接使用方式,適用於相機影格、2D 紋理或大型 LLM 狀態。
- 支援非同步執行:將 CPU 預先處理作業與 GPU 推論作業重疊執行。
搭配 GPU 加速功能的零複製
使用零複製功能可讓 GPU 直接存取自身記憶體中的資料,而無需由 CPU 明確複製該資料。由於零複製不會將資料複製至 CPU 記憶體,因此可大幅降低端對端延遲時間。
以下程式碼是使用 OpenGL 實作零複製 GPU 的範例,這是用於算繪向量圖形的 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
負責管理不同類型的同步化原語,而下列程式碼會建立 LiteRtEventTypeEglSyncFence
類型的受管理 LiteRT 事件物件。這個 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 裝置上執行的測試得出。