blob: eb0f273a6601b6860ab77a763773cfcca97023c8 [file] [edit]
/*
* Copyright 2024 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef COMMON_SIMPLE_MODEL_BUILDER_H_
#define COMMON_SIMPLE_MODEL_BUILDER_H_
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include "tensorflow/lite/builtin_ops.h"
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/model_builder.h"
namespace tflite::cros {
// A helper class to simplify the model building process so we don't need to
// manipulate raw FlatBuffer types. This class is thread-compatible.
class SimpleModelBuilder {
public:
static constexpr char kSignatureKey[] = "serving_default";
struct TensorArgs {
// TODO(shik): Generate SignatureDef using the tensor names. It's not
// supported by the ModelWriter we are using now so we have to do it
// ourselves.
std::string name;
TfLiteType type = kTfLiteNoType;
std::vector<int> shape;
// Index of buffer returned by AddBuffer() for constant data.
// The 0-th buffer is a sentinel empty buffer per TFLite schema, which means
// no buffer.
int buffer = 0;
// TODO(shik): Support quantizations.
};
template <typename T>
struct OperatorArgs {
TfLiteBuiltinOperator op;
// Input/Output tensor indices.
// TODO(shik): Support intermediates tensors. It's not exposed by
// Interpreter API we have to use Subgraph API directly in implementation.
std::vector<int> inputs;
std::vector<int> outputs;
// The corresponding params for the given operator. For example, it should
// be TfLiteAddParams for kTfLiteBuiltinAdd. See
// tensorflow/lite/core/c/builtin_op_data.h for their names.
T params;
};
SimpleModelBuilder();
// Copyable and movable.
SimpleModelBuilder(const SimpleModelBuilder& other) = default;
SimpleModelBuilder& operator=(const SimpleModelBuilder& other) = default;
SimpleModelBuilder(SimpleModelBuilder&& other) = default;
SimpleModelBuilder& operator=(SimpleModelBuilder&& other) = default;
// Adds an input tensor. Returns the tensor index.
int AddInput(const TensorArgs& args);
// Adds an output tensor. Returns the tensor index.
int AddOutput(const TensorArgs& args);
// Adds an internal tensor. Returns the tensor index.
int AddInternalTensor(const TensorArgs& args);
// Adds a buffer with data. Returns the buffer index.
int AddBuffer(std::vector<uint8_t> data);
// Adds an operator node in the graph.
template <typename T = std::monostate>
void AddOperator(const OperatorArgs<T>& args) {
std::vector<uint8_t> params(sizeof(T));
memcpy(params.data(), &args.params, params.size());
operators_.push_back({
.op = args.op,
.inputs = args.inputs,
.outputs = args.outputs,
.params = std::move(params),
});
}
// Builds the model. This can be called multiple times.
std::unique_ptr<FlatBufferModel> Build() const;
// Save the model to the given path. This can be called multiple times and can
// be called without first calling Build().
void SaveTo(const std::string& path) const;
private:
int next_tensor_index_ = 0;
// The added tensors stored as vectors of (tensor_index, tensor_args) pair.
std::vector<std::pair<int, TensorArgs>> inputs_;
std::vector<std::pair<int, TensorArgs>> outputs_;
std::vector<std::pair<int, TensorArgs>> internal_tensors_;
// The added buffers. The first one will be an empty vector to match TFLite
// schema.
std::vector<std::vector<uint8_t>> buffers_;
// The added operators with params converted to owned bytes.
std::vector<OperatorArgs<std::vector<uint8_t>>> operators_;
};
} // namespace tflite::cros
#endif // COMMON_SIMPLE_MODEL_BUILDER_H_