LiteRT CompiledModel API 以 C++ 提供,可让开发者对内存分配和低阶开发进行精细控制。如需查看示例,请参阅图像分割 C++ 应用。
以下指南展示了 CompiledModel Kotlin API 的基本 CPU 推理。如需了解高级加速功能,请参阅有关 GPU 加速和 NPU 加速的指南。
添加 build 依赖项
选择适合您项目的路径:
使用预构建库(跨平台):使用 LiteRT 预构建库可立即完成设置。了解如何在 Android 上使用 LiteRT Maven 软件包中的预构建 C++ 库,或者如何在 Android、iOS、macOS、Linux 和 Windows 上下载/集成预构建 C++ 二进制文件。
从源代码构建(跨平台):使用 CMake 从源代码构建,以实现完全控制和多平台支持(Android、iOS、macOS、Linux、Windows)。如需了解详情,请参阅本指南。
基本推理
本部分介绍如何执行基本推理。
创建环境
Environment 对象提供了一个运行时环境,其中包含编译器插件的路径和 GPU 上下文等组件。创建 CompiledModel 和 TensorBuffer 时必须提供 Environment。以下代码创建了一个 Environment,用于在 CPU 和 GPU 上执行,不带任何选项:
LITERT_ASSIGN_OR_RETURN(auto env, Environment::Create({}));
创建 CompiledModel:
获得 LiteRT 模型或将模型转换为 .tflite 格式后,使用 CompiledModel API 通过模型文件初始化运行时。您可以在此点指定硬件加速(kLiteRtHwAcceleratorCpu 或 kLiteRtHwAcceleratorGpu):
LITERT_ASSIGN_OR_RETURN(auto compiled_model,
CompiledModel::Create(env, model, kLiteRtHwAcceleratorCpu));
创建输入和输出缓冲区
创建必要的数据结构(缓冲区),以保存您将输入到模型中进行推理的输入数据,以及模型在运行推理后生成的输出数据。
LITERT_ASSIGN_OR_RETURN(auto input_buffers, compiled_model.CreateInputBuffers());
LITERT_ASSIGN_OR_RETURN(auto output_buffers, compiled_model.CreateOutputBuffers());
如果您使用的是 CPU 内存,请通过将数据直接写入第一个输入缓冲区来填充输入。
input_buffers[0].Write<float>(absl::MakeConstSpan(input_data, input_size));
调用模型
提供输入和输出缓冲区,并使用上一步中指定的模型和硬件加速来运行编译后的模型。
compiled_model.Run(input_buffers, output_buffers);
检索输出
通过直接从内存中读取模型输出来检索输出。
std::vector<float> data(output_data_size);
output_buffers[0].Read<float>(absl::MakeSpan(data));
// ... process output data
主要概念和组件
如需了解 LiteRT CompiledModel API 的主要概念和组件,请参阅以下部分。
错误处理
LiteRT 使用 litert::Expected 返回值或传播错误,方式与 absl::StatusOr 或 std::expected 类似。您可以自行手动检查是否存在此错误。
为方便起见,LiteRT 提供了以下宏:
如果
expr未产生错误,LITERT_ASSIGN_OR_RETURN(lhs, expr)会将expr的结果分配给lhs,否则会返回错误。它会展开为类似以下代码段的内容。
auto maybe_model = CompiledModel::Create(env, "mymodel.tflite", HwAccelerators::kCpu); if (!maybe_model) { return maybe_model.Error(); } auto model = std::move(maybe_model.Value());LITERT_ASSIGN_OR_ABORT(lhs, expr)与LITERT_ASSIGN_OR_RETURN执行的操作相同,但会在出现错误时中止程序。如果
LITERT_RETURN_IF_ERROR(expr)的评估结果为错误,则返回expr。LITERT_ABORT_IF_ERROR(expr)的作用与LITERT_RETURN_IF_ERROR相同,但如果出现错误,则会中止程序。
如需详细了解 LiteRT 宏,请参阅 litert_macros.h。
Tensor 缓冲区 (TensorBuffer)
LiteRT 使用 Tensor Buffer API (TensorBuffer) 来处理编译后模型的数据流入和流出,从而为 I/O 缓冲区互操作性提供内置支持。Tensor Buffer API 提供写入 (Write<T>()) 和读取 (Read<T>()) 以及锁定 CPU 内存的功能。
如需更全面地了解 TensorBuffer API 的实现方式,请参阅 litert_tensor_buffer.h 的源代码。
查询模型输入/输出要求
分配张量缓冲区 (TensorBuffer) 的要求通常由硬件加速器指定。输入和输出的缓冲区在对齐、缓冲区步长和内存类型方面可能存在要求。您可以使用 CreateInputBuffers 等辅助函数来自动处理这些要求。
以下简化的代码段演示了如何检索输入数据的缓冲区要求:
LITERT_ASSIGN_OR_RETURN(auto reqs, compiled_model.GetInputBufferRequirements(signature_index, input_index));
如需更全面地了解 TensorBufferRequirements API 的实现方式,请参阅 litert_tensor_buffer_requirements.h 的源代码。
创建受管理的 Tensor 缓冲区 (TensorBuffers)
以下简化的代码段演示了如何创建受管理的张量缓冲区,其中 TensorBuffer API 会分配相应的缓冲区:
LITERT_ASSIGN_OR_RETURN(auto tensor_buffer_cpu,
TensorBuffer::CreateManaged(env, /*buffer_type=*/kLiteRtTensorBufferTypeHostMemory,
ranked_tensor_type, buffer_size));
LITERT_ASSIGN_OR_RETURN(auto tensor_buffer_gl, TensorBuffer::CreateManaged(env,
/*buffer_type=*/kLiteRtTensorBufferTypeGlBuffer, ranked_tensor_type, buffer_size));
LITERT_ASSIGN_OR_RETURN(auto tensor_buffer_ahwb, TensorBuffer::CreateManaged(env,
/*buffer_type=*/kLiteRtTensorBufferTypeAhwb, ranked_tensor_type, buffer_size));
创建零复制张量缓冲区
如需将现有缓冲区封装为 Tensor 缓冲区(零复制),请使用以下代码段:
// Create a TensorBuffer from host memory
LITERT_ASSIGN_OR_RETURN(auto tensor_buffer_from_host,
TensorBuffer::CreateFromHostMemory(env, ranked_tensor_type,
ptr_to_host_memory, buffer_size));
// Create a TensorBuffer from GlBuffer
LITERT_ASSIGN_OR_RETURN(auto tensor_buffer_from_gl,
TensorBuffer::CreateFromGlBuffer(env, ranked_tensor_type, gl_target, gl_id,
size_bytes, offset));
// Create a TensorBuffer from AHardware Buffer
LITERT_ASSIGN_OR_RETURN(auto tensor_buffer_from_ahwb,
TensorBuffer::CreateFromAhwb(env, ranked_tensor_type, ahardware_buffer, offset));
从 Tensor 缓冲区读取和写入
以下代码段演示了如何从输入缓冲区读取数据并写入输出缓冲区:
// Example of reading to input buffer:
std::vector<float> input_tensor_data = {1,2};
LITERT_ASSIGN_OR_RETURN(auto write_success,
input_tensor_buffer.Write<float>(absl::MakeConstSpan(input_tensor_data)));
if(write_success){
/* Continue after successful write... */
}
// Example of writing to output buffer:
std::vector<float> data(total_elements);
LITERT_ASSIGN_OR_RETURN(auto read_success,
output_tensor_buffer.Read<float>(absl::MakeSpan(data)));
if(read_success){
/* Continue after successful read */
}
高级:针对专用硬件缓冲区类型的零复制缓冲区互操作
某些缓冲区类型(例如 AHardwareBuffer)允许与其他缓冲区类型进行互操作。例如,可以使用零复制从 AHardwareBuffer 创建 OpenGL 缓冲区。以下代码段展示了一个示例:
LITERT_ASSIGN_OR_RETURN(auto tensor_buffer_ahwb,
TensorBuffer::CreateManaged(env, kLiteRtTensorBufferTypeAhwb,
ranked_tensor_type, buffer_size));
// Buffer interop: Get OpenGL buffer from AHWB,
// internally creating an OpenGL buffer backed by AHWB memory.
LITERT_ASSIGN_OR_RETURN(auto gl_buffer, tensor_buffer_ahwb.GetGlBuffer());
还可以从 AHardwareBuffer 创建 OpenCL 缓冲区:
LITERT_ASSIGN_OR_RETURN(auto cl_buffer, tensor_buffer_ahwb.GetOpenClMemory());
在支持 OpenCL 和 OpenGL 之间互操作性的移动设备上,可以从 GL 缓冲区创建 CL 缓冲区:
LITERT_ASSIGN_OR_RETURN(auto tensor_buffer_from_gl,
TensorBuffer::CreateFromGlBuffer(env, ranked_tensor_type, gl_target, gl_id,
size_bytes, offset));
// Creates an OpenCL buffer from the OpenGL buffer, zero-copy.
LITERT_ASSIGN_OR_RETURN(auto cl_buffer, tensor_buffer_from_gl.GetOpenClMemory());
实现示例
请参阅以下 LiteRT 在 C++ 中的实现。
基本推理(CPU)
以下是开始使用部分中的代码段的精简版本。这是使用 LiteRT 进行推理的最简单实现。
// Load model and initialize runtime
LITERT_ASSIGN_OR_RETURN(auto env, Environment::Create({}));
LITERT_ASSIGN_OR_RETURN(auto compiled_model, CompiledModel::Create(env, "mymodel.tflite",
kLiteRtHwAcceleratorCpu));
// Preallocate input/output buffers
LITERT_ASSIGN_OR_RETURN(auto input_buffers, compiled_model.CreateInputBuffers());
LITERT_ASSIGN_OR_RETURN(auto output_buffers, compiled_model.CreateOutputBuffers());
// Fill the first input
float input_values[] = { /* your data */ };
input_buffers[0].Write<float>(absl::MakeConstSpan(input_values, /*size*/));
// Invoke
compiled_model.Run(input_buffers, output_buffers);
// Read the output
std::vector<float> data(output_data_size);
output_buffers[0].Read<float>(absl::MakeSpan(data));
使用主机内存的零复制
LiteRT CompiledModel API 可减少推理流水线的摩擦,尤其是在处理多个硬件后端和零复制流程时。以下代码段在创建输入缓冲区时使用了 CreateFromHostMemory 方法,该方法使用与主机内存的零复制。
// Define an LiteRT environment to use existing EGL display and context.
const std::vector<Environment::Option> environment_options = {
{OptionTag::EglDisplay, user_egl_display},
{OptionTag::EglContext, user_egl_context}};
LITERT_ASSIGN_OR_RETURN(auto env,
Environment::Create(absl::MakeConstSpan(environment_options)));
// Load model1 and initialize runtime.
LITERT_ASSIGN_OR_RETURN(auto compiled_model1, CompiledModel::Create(env, "model1.tflite", kLiteRtHwAcceleratorGpu));
// Prepare I/O buffers. opengl_buffer is given outside from the producer.
LITERT_ASSIGN_OR_RETURN(auto tensor_type, model.GetInputTensorType("input_name0"));
// Create an input TensorBuffer based on tensor_type that wraps the given OpenGL Buffer.
LITERT_ASSIGN_OR_RETURN(auto tensor_buffer_from_opengl,
litert::TensorBuffer::CreateFromGlBuffer(env, tensor_type, opengl_buffer));
// Create an input event and attach it to the input buffer. Internally, it creates
// and inserts a fence sync object into the current EGL command queue.
LITERT_ASSIGN_OR_RETURN(auto input_event, Event::CreateManaged(env, LiteRtEventTypeEglSyncFence));
tensor_buffer_from_opengl.SetEvent(std::move(input_event));
std::vector<TensorBuffer> input_buffers;
input_buffers.push_back(std::move(tensor_buffer_from_opengl));
// Create an output TensorBuffer of the model1. It's also used as an input of the model2.
LITERT_ASSIGN_OR_RETURN(auto intermedidate_buffers, compiled_model1.CreateOutputBuffers());
// Load model2 and initialize runtime.
LITERT_ASSIGN_OR_RETURN(auto compiled_model2, CompiledModel::Create(env, "model2.tflite", kLiteRtHwAcceleratorGpu));
LITERT_ASSIGN_OR_RETURN(auto output_buffers, compiled_model2.CreateOutputBuffers());
compiled_model1.RunAsync(input_buffers, intermedidate_buffers);
compiled_model2.RunAsync(intermedidate_buffers, output_buffers);