blob: 2b3c9af436e9b7814b14a5efc01e40e02f44de18 [file] [edit]
/*
* Copyright 2025 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "common/sync_driver.h"
#include <algorithm>
#include <cstdint>
#include <limits>
#include <map>
#include <memory>
#include <span> // NOLINT(build/include_order) - C++20 header is not recognized yet
#include <string>
#include <utility>
#include <vector>
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/interpreter_builder.h"
#include "tensorflow/lite/kernels/register.h"
namespace tflite::cros {
namespace {
constexpr char kSignatureKey[] = "serving_default";
} // namespace
std::unique_ptr<SyncDriver> SyncDriver::Create(
TfLiteDelegatePtr delegate,
std::unique_ptr<FlatBufferModel> model) {
ops::builtin::BuiltinOpResolver resolver;
InterpreterBuilder builder(*model, resolver);
builder.AddDelegate(delegate.get());
std::unique_ptr<Interpreter> interpreter;
if (builder(&interpreter) != kTfLiteOk) {
return nullptr;
}
SignatureRunner* runner = interpreter->GetSignatureRunner(kSignatureKey);
if (runner == nullptr) {
return nullptr;
}
return std::unique_ptr<SyncDriver>(new SyncDriver(
std::move(delegate), std::move(model), std::move(interpreter), runner));
}
TfLiteStatus SyncDriver::SetInputTensorData(const std::string& name,
std::span<const uint8_t> data) {
auto it = input_buffer_map_.find(name);
if (it == input_buffer_map_.end()) {
return kTfLiteError;
}
auto& buffer = it->second;
memcpy(buffer.get(), data.data(), data.size());
return kTfLiteOk;
}
void SyncDriver::SetInputTensorBuffer(const std::string& name,
std::shared_ptr<uint8_t[]> buffer) {
input_buffer_map_.insert_or_assign(name, std::move(buffer));
}
void SyncDriver::SetOutputTensorBuffer(const std::string& name,
std::shared_ptr<uint8_t[]> buffer) {
output_buffer_map_.insert_or_assign(name, std::move(buffer));
}
TfLiteStatus SyncDriver::Invoke() {
for (const auto& [name, buffer] : input_buffer_map_) {
const TfLiteTensor* tensor = runner_->input_tensor(name.c_str());
if (tensor == nullptr) {
return kTfLiteError;
}
TfLiteCustomAllocation allocation = {.data = buffer.get(),
.bytes = tensor->bytes};
TfLiteStatus status =
runner_->SetCustomAllocationForInputTensor(name.c_str(), allocation);
if (status != kTfLiteOk) {
return kTfLiteError;
}
}
for (const auto& [name, buffer] : output_buffer_map_) {
const TfLiteTensor* tensor = runner_->output_tensor(name.c_str());
if (tensor == nullptr) {
return kTfLiteError;
}
TfLiteCustomAllocation allocation = {.data = buffer.get(),
.bytes = tensor->bytes};
TfLiteStatus status =
runner_->SetCustomAllocationForOutputTensor(name.c_str(), allocation);
if (status != kTfLiteOk) {
return kTfLiteError;
}
}
return runner_->Invoke();
}
std::vector<uint8_t> SyncDriver::GetOutputTensorData(const std::string& name) {
const TfLiteTensor* output = runner_->output_tensor(name.c_str());
if (output == nullptr) {
return {};
}
std::vector<uint8_t> data(output->bytes);
memcpy(data.data(), output->data.data, output->bytes);
return data;
}
SyncDriver::SyncDriver(TfLiteDelegatePtr delegate,
std::unique_ptr<FlatBufferModel> model,
std::unique_ptr<Interpreter> interpreter,
tflite::SignatureRunner* runner)
: delegate_(std::move(delegate)),
model_(std::move(model)),
interpreter_(std::move(interpreter)),
runner_(runner) {}
TfLiteStatus SyncDriver::AllocateBuffers() {
return runner_->AllocateTensors();
}
} // namespace tflite::cros