API-ja LiteRT CompiledModel është e disponueshme në C++, duke u dhënë zhvilluesve kontroll të hollësishëm mbi alokimin e memories dhe zhvillimin e nivelit të ulët. Për një shembull, shihni Aplikacionin C++ të Segmentimit të Imazheve .
Udhëzuesi i mëposhtëm tregon konkluzionin bazë të CPU-së të API-t CompiledModel Kotlin. Shihni udhëzuesin mbi përshpejtimin e GPU-së dhe përshpejtimin e NPU-së për veçoritë e përparuara të përshpejtimit.
Shto varësi ndërtimi
Zgjidhni rrugën që i përshtatet projektit tuaj:
Përdorni bibliotekën e parapërgatitur (ndër-platforma) : Përdorni bibliotekën e parapërgatitur LiteRT për konfigurim të menjëhershëm. Shikoni se si të përdorni bibliotekën e parapërgatitur C++ nga paketa LiteRT Maven në Android , ose shkarkoni/integroni skedarin binar të parapërgatitur C++ në Android, iOS, macOS, Linux dhe Windows .
Ndërto nga burimi (ndër-platforma) : Ndërto nga burimi me CMake për kontroll të plotë dhe mbështetje për shumë platforma (Android, iOS, macOS, Linux, Windows). Shih detajet në këtë udhëzues .
Përfundim bazë
Ky seksion tregon se si kryhet përfundimi bazë.
Krijo mjedisin
Objekti Environment ofron një mjedis ekzekutimi që përfshin komponentë të tillë si shtegu i plugin-it të kompajlerit dhe kontekstet e GPU-së. Environment kërkohet kur krijohen CompiledModel dhe TensorBuffer . Kodi i mëposhtëm krijon një Environment për ekzekutimin e CPU-së dhe GPU-së pa asnjë opsion:
LITERT_ASSIGN_OR_RETURN(auto env, Environment::Create({}));
Krijo CompiledModel
Pasi të keni marrë një model LiteRT, ose ta keni konvertuar një model në formatin .tflite , inicializoni kohën e ekzekutimit me skedarin e modelit duke përdorur API- CompiledModel . Mund të specifikoni përshpejtimin e harduerit në këtë pikë ( kLiteRtHwAcceleratorCpu ose kLiteRtHwAcceleratorGpu ):
LITERT_ASSIGN_OR_RETURN(auto compiled_model,
CompiledModel::Create(env, model, kLiteRtHwAcceleratorCpu));
Krijo bufera hyrëse dhe dalëse
Krijoni strukturat e nevojshme të të dhënave (buferat) për të mbajtur të dhënat hyrëse që do t'i ushqeni modelit për përfundim, dhe të dhënat dalëse që modeli prodhon pas ekzekutimit të përfundimit.
LITERT_ASSIGN_OR_RETURN(auto input_buffers, compiled_model.CreateInputBuffers());
LITERT_ASSIGN_OR_RETURN(auto output_buffers, compiled_model.CreateOutputBuffers());
Nëse përdorni memorien e CPU-së, plotësoni të dhënat hyrëse duke shkruar të dhëna direkt në memorjen e parë të hyrjes.
input_buffers[0].Write<float>(absl::MakeConstSpan(input_data, input_size));
Thirrni modelin
Duke siguruar buffer-at e hyrjes dhe daljes, ekzekutoni Modelin e Kompiluar me modelin dhe përshpejtimin e harduerit të specifikuar në hapat e mëparshëm.
compiled_model.Run(input_buffers, output_buffers);
Merrni Rezultatet
Merrni rezultatet duke lexuar drejtpërdrejti daljen e modelit nga memoria.
std::vector<float> data(output_data_size);
output_buffers[0].Read<float>(absl::MakeSpan(data));
// ... process output data
Konceptet dhe përbërësit kryesorë
Referojuni seksioneve të mëposhtme për informacion mbi konceptet dhe komponentët kryesorë të API-t LiteRT CompiledModel .
Trajtimi i Gabimeve
LiteRT përdor litert::Expected për të kthyer vlera ose për të përhapur gabimet në një mënyrë të ngjashme me absl::StatusOr ose std::expected . Mund ta kontrolloni manualisht vetë për gabimin.
Për lehtësi, LiteRT ofron makrot e mëposhtme:
LITERT_ASSIGN_OR_RETURN(lhs, expr)ia cakton rezultatin eexprlhsnëse nuk prodhon gabim dhe përndryshe e kthen gabimin.Do të zgjerohet në diçka si fragmenti i mëposhtëm.
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)bën të njëjtën gjë siLITERT_ASSIGN_OR_RETURNpor e ndërpret programin në rast gabimi.LITERT_RETURN_IF_ERROR(expr)kthenexprnëse vlerësimi i saj prodhon një gabim.LITERT_ABORT_IF_ERROR(expr)bën të njëjtën gjë siLITERT_RETURN_IF_ERRORpor e ndërpret programin në rast gabimi.
Për më shumë informacion mbi makrot LiteRT, shihni litert_macros.h .
Tamponi i Tensorit (TensorBuffer)
LiteRT ofron mbështetje të integruar për ndërveprimin e buffer-it I/O, duke përdorur API-në Tensor Buffer ( TensorBuffer ) për të trajtuar rrjedhën e të dhënave brenda dhe jashtë modelit të kompajluar. API-ja Tensor Buffer ofron mundësinë për të shkruar ( Write<T>() ) dhe lexuar ( Read<T>() ), si dhe për të bllokuar memorien e CPU-së.
Për një pamje më të plotë se si zbatohet API-ja TensorBuffer , shihni kodin burimor për littert_tensor_buffer.h .
Kërkesat e hyrjes/daljes së modelit të pyetjes
Kërkesat për ndarjen e një Tensor Buffer ( TensorBuffer ) zakonisht specifikohen nga përshpejtuesi i harduerit. Buffer-at për hyrjet dhe daljet mund të kenë kërkesa në lidhje me shtrirjen, hapat e buffer-it dhe llojin e memories. Mund të përdorni funksione ndihmëse si CreateInputBuffers për të trajtuar automatikisht këto kërkesa.
Fragmenti i mëposhtëm i kodit të thjeshtuar tregon se si mund të merrni kërkesat e buffer-it për të dhënat hyrëse:
LITERT_ASSIGN_OR_RETURN(auto reqs, compiled_model.GetInputBufferRequirements(signature_index, input_index));
Për një pamje më të plotë se si zbatohet API-ja TensorBufferRequirements , shihni kodin burimor për littert_tensor_buffer_requirements.h .
Krijo Bufera Tensorësh të Menaxhuar (TensorBuffers)
Fragmenti i mëposhtëm i thjeshtuar i kodit tregon se si të krijoni Bufera Tensor të Menaxhuar, ku API-ja TensorBuffer ndan buferat përkatës:
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));
Krijo Tampona Tensor me kopje zero
Për të mbështjellë një buffer ekzistues si një Tensor Buffer (zero-kopje), përdorni fragmentin e mëposhtëm të kodit:
// 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));
Leximi dhe shkrimi nga Tensor Buffer
Fragmenti i mëposhtëm tregon se si mund të lexoni nga një buffer hyrës dhe të shkruani në një buffer dalës:
// 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 */
}
I avancuar: Ndërveprimi i bufferit zero-kopje për llojet e specializuara të bufferit të harduerit
Disa lloje të caktuara të buffer-ave, siç është AHardwareBuffer , lejojnë ndërveprimin me lloje të tjera të buffer-ave. Për shembull, një buffer OpenGL mund të krijohet nga një AHardwareBuffer me kopje zero. Fragmenti i mëposhtëm i kodit tregon një shembull:
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());
Buferat OpenCL mund të krijohen gjithashtu nga AHardwareBuffer :
LITERT_ASSIGN_OR_RETURN(auto cl_buffer, tensor_buffer_ahwb.GetOpenClMemory());
Në pajisjet mobile që mbështesin ndërveprimin midis OpenCL dhe OpenGL, buffer-at CL mund të krijohen nga buffer-at GL:
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());
Shembuj implementimesh
Referojuni implementimeve të mëposhtme të LiteRT në C++.
Inferenca Bazë (CPU)
Më poshtë është një version i shkurtuar i fragmenteve të kodit nga seksioni "Fillimi" . Është implementimi më i thjeshtë i inferencës me 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));
Zero-kopje me memorien pritëse
API-ja LiteRT CompiledModel zvogëlon fërkimin e tubacioneve të nxjerrjes së përfundimeve, veçanërisht kur merret me backend-e të shumëfishta harduerike dhe rrjedha zero-kopje. Fragmenti i mëposhtëm i kodit përdor metodën CreateFromHostMemory kur krijon buffer-in e hyrjes, i cili përdor zero-kopje me memorien pritëse.
// 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);