Графические процессоры (GPU) широко используются для ускорения глубокого обучения благодаря их огромной параллельной пропускной способности по сравнению с центральными процессорами (CPU). LiteRT упрощает процесс использования аппаратного ускорения GPU, позволяя пользователям указывать аппаратное ускорение в качестве параметра при создании скомпилированной модели ( CompiledModel ).
Благодаря ускорению на графическом процессоре в LiteRT вы можете создавать удобные для графического процессора входные и выходные буферы, обеспечивать копирование данных в памяти графического процессора без копирования и выполнять задачи асинхронно для максимального параллелизма.
Примеры реализации LiteRT GPU можно найти в следующих демонстрационных приложениях:
Добавить зависимость от графического процессора.
Выполните следующие шаги, чтобы добавить зависимость от графического процессора в ваше приложение на Kotlin или C++.
Котлин
Для пользователей Kotlin графический ускоритель встроен и не требует дополнительных действий, помимо тех, что описаны в руководстве по началу работы .
C++
Пользователям C++ необходимо собрать зависимости приложения с использованием ускорения LiteRT GPU. Правило cc_binary , которое упаковывает основную логику приложения (например, main.cc ), требует наличия следующих компонентов среды выполнения:
- Библиотека LiteRT C API : атрибут
dataдолжен включать библиотеку LiteRT C API (//litert/c:litert_runtime_c_api_shared_lib) и компоненты, специфичные для графического процессора (@litert_gpu//:jni/arm64-v8a/libLiteRtGpuAccelerator.so). - Атрибут dependencies : Атрибут
depsобычно включает зависимости GLESgles_deps(), аlinkoptsобычно включаетgles_linkopts(). Оба атрибута очень важны для ускорения работы 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
)
Такая настройка позволяет скомпилированному исполняемому файлу динамически загружать и использовать графический процессор для ускорения выполнения вычислений в рамках машинного обучения.
Использование графического процессора с API CompiledModel
Для начала использования графического ускорителя передайте параметр 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));
Котлин
// 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» .
Копирование без копирования с ускорением на графическом процессоре
Использование технологии «нулевого копирования» позволяет графическому процессору получать доступ к данным непосредственно в собственной памяти без необходимости явного копирования этих данных центральным процессором. Благодаря отсутствию копирования данных в память центрального процессора и из неё, технология «нулевого копирования» может значительно снизить сквозную задержку.
Приведённый ниже код представляет собой пример реализации технологии Zero-Copy GPU с использованием OpenGL , API для рендеринга векторной графики. Код передаёт изображения в формате буфера OpenGL непосредственно в 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());
Асинхронное выполнение
Асинхронные методы LiteRT, такие как RunAsync() , позволяют планировать выполнение задач на графическом процессоре, продолжая при этом другие задачи на центральном процессоре или нейронном процессоре. В сложных конвейерах графический процессор часто используется асинхронно наряду с центральным процессором или нейронным процессором.
Приведенный ниже фрагмент кода основан на коде, представленном в примере ускорения GPU без копирования . Код использует как CPU, так и GPU асинхронно и прикрепляет Event LiteRT к входному буферу. Event LiteRT отвечает за управление различными типами примитивов синхронизации, и следующий код создает управляемый объект события 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 поддерживает ускорение графического процессора на следующих моделях. Результаты бенчмарков основаны на тестах, проведенных на устройстве Samsung Galaxy S24.
| Модель | Ускорение LiteRT на графическом процессоре | LiteRT GPU (мс) |
|---|---|---|
| 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 |
| интернет | Полностью делегировано | 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 |