LiteRT Next API'leri C++'da kullanılabilir ve Android geliştiricilerine Kotlin API'lerine kıyasla bellek ayırma ve düşük düzey geliştirme üzerinde daha fazla kontrol sunabilir.
C++'ta LiteRT Next uygulaması örneği için C++ demo ile asenkron segmentasyon bölümüne bakın.
Başlayın
Android uygulamanıza LiteRT Next'i eklemek için aşağıdaki adımları uygulayın.
Derleme yapılandırmasını güncelleme
Bazel'i kullanarak GPU, NPU ve CPU hızlandırması için LiteRT ile C++ uygulaması oluşturmak, gerekli tüm bileşenlerin derlendiğinden, bağlandığından ve paketlendiğinden emin olmak amacıyla bir cc_binary
kuralı tanımlamayı içerir. Aşağıdaki örnek kurulum, uygulamanızın GPU, NPU ve CPU hızlandırıcıları dinamik olarak seçmesine veya kullanmasına olanak tanır.
Bazel derleme yapılandırmanızdaki temel bileşenler şunlardır:
cc_binary
Kuralı: Bu, C++ yürütülebilir hedefinizi (ör.name = "your_application_name"
).srcs
Özelliği: Uygulamanızın C++ kaynak dosyalarını (ör.main.cc
ve diğer.cc
veya.h
dosyaları).data
Özelliği (Çalışma Zamanı Bağımlılıkları): Bu, uygulamanızın çalışma zamanında yüklediği paylaşılan kitaplıkları ve öğeleri paketlemek için çok önemlidir.- LiteRT Core Runtime: Ana LiteRT C API paylaşılan kitaplığı (ör.
//litert/c:litert_runtime_c_api_shared_lib
). - Gönderim Kitaplıkları: LiteRT'nin donanım sürücüleriyle (ör.
//litert/vendors/qualcomm/dispatch:dispatch_api_so
). - GPU Arka Uç Kitaplıkları: GPU hızlandırması için paylaşılan kitaplıklar (ör.
"@litert_gpu//:jni/arm64-v8a/libLiteRtGpuAccelerator.so
). - NPU Arka Uç Kitaplıkları: NPU hızlandırması için özel paylaşılan kitaplıklar (ör.Qualcomm'un QNN HTP kitaplıkları (ör.
@qairt//:lib/aarch64-android/libQnnHtp.so
,@qairt//:lib/hexagon-v79/unsigned/libQnnHtpV79Skel.so
). - Model Dosyaları ve Öğeleri: Eğitilmiş model dosyalarınız, test resimleriniz, gölgelendiricileriniz veya çalışma zamanında ihtiyaç duyulan diğer veriler (ör.
:model_files
,:shader_files
).
- LiteRT Core Runtime: Ana LiteRT C API paylaşılan kitaplığı (ör.
deps
Özelliği (Derleme Zamanında Bağımlılıklar): Bu özellik, kodunuzun derlenmesi için gereken kitaplıkları listeler.- LiteRT API'leri ve Yardımcı Programları: Tensör tamponları (ör.
//litert/cc:litert_tensor_buffer
). - Grafik Kitaplıkları (GPU için): GPU hızlandırıcı bunları kullanıyorsa grafik API'leriyle ilgili bağımlılar (ör.
gles_deps()
).
- LiteRT API'leri ve Yardımcı Programları: Tensör tamponları (ör.
linkopts
Özelliği: Bağlayıcıya iletilen seçenekleri belirtir.Bu seçenekler, sistem kitaplıklarına (ör. Android derlemeleri için-landroid
veyagles_linkopts()
içeren GLES kitaplıkları).
Aşağıda, cc_binary
kuralına örnek verilmiştir:
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",
# NPU accelerator shared library
"//litert/vendors/qualcomm/dispatch:dispatch_api_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
)
Modeli yükleme
Bir LiteRT modeli elde ettikten veya bir modeli .tflite
biçimine dönüştürdükten sonra Model
nesnesi oluşturarak modeli yükleyin.
LITERT_ASSIGN_OR_RETURN(auto model, Model::CreateFromFile("mymodel.tflite"));
Ortamı oluşturma
Environment
nesnesi, derleyici eklentisinin yolu ve GPU bağlamları gibi bileşenleri içeren bir çalışma zamanı ortamı sağlar. CompiledModel
ve TensorBuffer
oluştururken Environment
gereklidir. Aşağıdaki kod, CPU ve GPU yürütme için herhangi bir seçenek olmadan bir Environment
oluşturur:
LITERT_ASSIGN_OR_RETURN(auto env, Environment::Create({}));
Derlenmiş modeli oluşturma
CompiledModel
API'yi kullanarak yeni oluşturulan Model
nesnesi ile çalışma zamanını başlatın. Bu noktada donanım hızlandırmayı belirtebilirsiniz (kLiteRtHwAcceleratorCpu
veya kLiteRtHwAcceleratorGpu
):
LITERT_ASSIGN_OR_RETURN(auto compiled_model,
CompiledModel::Create(env, model, kLiteRtHwAcceleratorCpu));
Giriş ve Çıkış Arabellekleri Oluşturma
Tahmin için modele aktaracağınız giriş verilerini ve modelin tahmin çalıştırdıktan sonra ürettiği çıkış verilerini tutacak gerekli veri yapılarını (arabellekler) oluşturun.
LITERT_ASSIGN_OR_RETURN(auto input_buffers, compiled_model.CreateInputBuffers());
LITERT_ASSIGN_OR_RETURN(auto output_buffers, compiled_model.CreateOutputBuffers());
CPU belleği kullanıyorsanız verileri doğrudan ilk giriş arabelleğine yazarak girişleri doldurun.
input_buffers[0].Write<float>(absl::MakeConstSpan(input_data, input_size));
Modeli çağırma
Giriş ve çıkış arabelleklerini sağlayarak, derlenmiş modeli önceki adımlarda belirtilen model ve donanım hızlandırmasıyla çalıştırın.
compiled_model.Run(input_buffers, output_buffers);
Çıkışları alma
Model çıkışını doğrudan bellekten okuyarak çıkışları alın.
std::vector<float> data(output_data_size);
output_buffers[0].Read<float>(absl::MakeSpan(data));
// ... process output data
Temel kavramlar ve bileşenler
LiteRT Next API'lerinin temel kavramları ve bileşenleri hakkında bilgi edinmek için aşağıdaki bölümlere bakın.
Hata İşleme
LiteRT, absl::StatusOr
veya std::expected
'ye benzer bir şekilde değerleri döndürmek ya da hataları yaymak için litert::Expected
'ü kullanır. Hatayı manuel olarak kontrol edebilirsiniz.
Kolaylık sağlamak amacıyla LiteRT aşağıdaki makroları sağlar:
LITERT_ASSIGN_OR_RETURN(lhs, expr)
, hata oluşturmazsaexpr
sonucunulhs
'ye atar, aksi takdirde hatayı döndürür.Aşağıdaki snippet'e benzer bir şekilde genişler.
auto maybe_model = Model::CreateFromFile("mymodel.tflite"); if (!maybe_model) { return maybe_model.Error(); } auto model = std::move(maybe_model.Value());
LITERT_ASSIGN_OR_ABORT(lhs, expr)
,LITERT_ASSIGN_OR_RETURN
ile aynı işlemi yapar ancak hata durumunda programı durdurur.Değerlendirmesi hata döndürürse
LITERT_RETURN_IF_ERROR(expr)
,expr
değerini döndürür.LITERT_ABORT_IF_ERROR(expr)
,LITERT_RETURN_IF_ERROR
ile aynı işlemi yapar ancak hata durumunda programı durdurur.
LiteRT makroları hakkında daha fazla bilgi için litert_macros.h
sayfasına bakın.
Derlenmiş Model (CompiledModel)
Derlenmiş Model API'si (CompiledModel
), model yükleme, donanım hızlandırma uygulama, çalışma zamanını örnekleme, giriş ve çıkış arabellekleri oluşturma ve çıkarım çalıştırma işlemlerinden sorumludur.
Aşağıdaki basitleştirilmiş kod snippet'inde, Derlenmiş Model API'nin bir LiteRT modelini (.tflite
) ve hedef donanım hızlandırıcıyı (GPU) nasıl alıp çıkarım yapmaya hazır bir derlenmiş model oluşturduğu gösterilmektedir.
// Load model and initialize runtime
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, kLiteRtHwAcceleratorCpu));
Aşağıdaki basitleştirilmiş kod snippet'inde, Derlenmiş Model API'sinin nasıl giriş ve çıkış arabelleği aldığı ve derlenmiş modelle çıkarım yürüttüğü gösterilmektedir.
// 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 */ };
LITERT_RETURN_IF_ERROR(
input_buffers[0].Write<float>(absl::MakeConstSpan(input_values, /*size*/)));
// Invoke
LITERT_RETURN_IF_ERROR(compiled_model.Run(input_buffers, output_buffers));
// Read the output
std::vector<float> data(output_data_size);
LITERT_RETURN_IF_ERROR(
output_buffers[0].Read<float>(absl::MakeSpan(data)));
CompiledModel
API'nin nasıl uygulandığına dair daha kapsamlı bir görünüm için litert_compiled_model.h kaynak koduna bakın.
Tensor Tamponu (TensorBuffer)
LiteRT Next, derlenmiş modele gelen ve modelden çıkan veri akışını işlemek için TensorFlow Buffer API'yi (TensorBuffer
) kullanarak G/Ç arabelleği birlikte çalışabilirliği için yerleşik destek sağlar. Tensor Buffer API, yazma (Write<T>()
) ve okuma (Read<T>()
) ve CPU belleğini kilitleme olanağı sunar.
TensorBuffer
API'nin nasıl uygulandığına dair daha kapsamlı bir görünüm için litert_tensor_buffer.h kaynak koduna bakın.
Sorgu modeli giriş/çıkış şartları
Bir Tensor Tamponu (TensorBuffer
) ayırma koşulları genellikle donanım hızlandırıcı tarafından belirtilir. Giriş ve çıkışlar için arabellekler, hizalama, arabellek adımlar ve bellek türü ile ilgili koşullara sahip olabilir. Bu koşulları otomatik olarak işlemek için CreateInputBuffers
gibi yardımcı işlevleri kullanabilirsiniz.
Aşağıdaki basitleştirilmiş kod snippet'inde, giriş verileri için arabelleğe alma koşullarını nasıl alabileceğiniz gösterilmektedir:
LITERT_ASSIGN_OR_RETURN(auto reqs, compiled_model.GetInputBufferRequirements(signature_index, input_index));
TensorBufferRequirements
API'nin nasıl uygulandığına dair daha kapsamlı bir görünüm için litert_tensor_buffer_requirements.h dosyasının kaynak koduna bakın.
Yönetilen Tensor Tamponları (TensorBuffers) oluşturma
Aşağıdaki basitleştirilmiş kod snippet'inde, TensorBuffer
API'nin ilgili tamponları ayırdığı Managed TensorBuffers'ın nasıl oluşturulacağı gösterilmektedir:
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));
Kopyasız Tensor Tamponları oluşturma
Mevcut bir arabelleği Tensor arabelleği olarak sarmalamak için (sıfır kopyalama) aşağıdaki kod snippet'ini kullanın:
// 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 arabelleğinden okuma ve yazma
Aşağıdaki snippet'te, giriş arabelleğinden nasıl veri okuyabileceğiniz ve çıkış arabelleğine nasıl veri yazabileceğiniz gösterilmektedir:
// 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 */
}
Gelişmiş: Özel donanım arabellek türleri için sıfır kopyalama arabellek birlikte çalışabilirliği
AHardwareBuffer
gibi belirli arabellek türleri, diğer arabellek türleriyle birlikte çalışabilirlik sağlar. Örneğin, sıfır kopyalama ile bir AHardwareBuffer
'ten OpenGL arabelleği oluşturulabilir. Aşağıdaki kod snippet'inde bir örnek gösterilmektedir:
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());
OpenCL arabellekleri AHardwareBuffer
'den de oluşturulabilir:
LITERT_ASSIGN_OR_RETURN(auto cl_buffer, tensor_buffer_ahwb.GetOpenClMemory());
OpenCL ile OpenGL arasındaki birlikte çalışabilirliği destekleyen mobil cihazlarda GL arabelleklerinden CL arabellekleri oluşturulabilir:
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());
Örnek uygulamalar
C++'da LiteRT Next'in aşağıdaki uygulamalarını inceleyin.
Temel Çıkarma (CPU)
Aşağıda, Başlayın bölümündeki kod snippet'lerinin sıkıştırılmış bir sürümü bulunmaktadır. LiteRT Next ile çıkarım yapmanın en basit uygulamasıdır.
// Load model and initialize runtime
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,
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));
Ana Makine Belleği ile Kopyasız Aktarım
LiteRT Next Compiled Model API, özellikle birden fazla donanım arka ucu ve sıfır kopyalama akışıyla çalışırken çıkarım ardışık düzenlerinin sürtünmesini azaltır. Aşağıdaki kod snippet'inde, ana makine belleğiyle sıfır kopyalama kullanan giriş arabelleği oluştururken CreateFromHostMemory
yöntemi kullanılmaktadır.
// 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 model1, Model::CreateFromFile("model1.tflite"));
LITERT_ASSIGN_OR_RETURN(auto compiled_model1, CompiledModel::Create(env, model1, 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 model2, Model::CreateFromFile("model2.tflite"));
LITERT_ASSIGN_OR_RETURN(auto compiled_model2, CompiledModel::Create(env, model2, 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);