From 716e3d9359b0c1225f83c2c499f4ec54aef6ca86 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=D0=98=D0=B2=D0=B0=D0=BD=20=D0=98=D0=B2=D0=B0=D0=BD=D0=BE?= =?utf8?q?=D0=B2=D0=B8=D1=87=20=D0=9A=D1=83=D0=BB=D0=B0=D0=B3=D0=B8=D0=BD/?= =?utf8?q?AI=20Tools=20Lab=20/SRR/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84?= =?utf8?q?=EC=9E=90?= Date: Wed, 21 Nov 2018 21:19:24 +0300 Subject: [PATCH] [nnc][utils][model_generator] Add converter from tree to tflite. (#2230) Implemented converter from randomly generated Tree representation to TFLite model. Signed-off-by: i-kulagin i.kulagin@samsung.com --- .../tflite_model_generator/ModelGenerator.cpp | 22 +-- .../tflite_model_generator/RandomModelBuilder.h | 53 +++---- .../TFLiteRandomModelBuilder.cpp | 159 +++++++++++---------- .../TFLiteRandomModelBuilder.h | 30 ++-- 4 files changed, 136 insertions(+), 128 deletions(-) diff --git a/contrib/nnc/utils/tflite_model_generator/ModelGenerator.cpp b/contrib/nnc/utils/tflite_model_generator/ModelGenerator.cpp index a6392d5..99ceac4 100644 --- a/contrib/nnc/utils/tflite_model_generator/ModelGenerator.cpp +++ b/contrib/nnc/utils/tflite_model_generator/ModelGenerator.cpp @@ -16,32 +16,24 @@ #include #include +#include + +#include "Tree.h" #include "RandomModelBuilder.h" #include "TFLiteRandomModelBuilder.h" using namespace modelgen; - -static constexpr int maxNumLayers = 20; +using namespace treebuilder; int main(int argc, const char* argv[]) { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution intRand(1, maxNumLayers); + std::unique_ptr tree_builder(new TreeBuilder); + auto tree = tree_builder->buildTree(); std::unique_ptr builder(new TFLiteRandomModelBuilder); - - if (builder->addInput()) { - std::cout << "Input was added" << std::endl; - } - - auto n_layers = intRand(gen); - for (int i = 0; i < n_layers; i ++) { - builder->addLayer(); - } + builder->convertTreeToModel(tree.get()); std::unique_ptr saver = builder->createModelSaver(); - saver->saveModel(); return 0; diff --git a/contrib/nnc/utils/tflite_model_generator/RandomModelBuilder.h b/contrib/nnc/utils/tflite_model_generator/RandomModelBuilder.h index aa9ce3c..0fff191 100644 --- a/contrib/nnc/utils/tflite_model_generator/RandomModelBuilder.h +++ b/contrib/nnc/utils/tflite_model_generator/RandomModelBuilder.h @@ -55,30 +55,18 @@ public: std::numeric_limits::max()), intRand(static_cast(OpCodes::opFirst), static_cast(OpCodes::opLast)), - operatorCounts{0}, - opCreators{ - [this](int input_tensor_id) { createLayerCONV_2D(input_tensor_id);}, - } {}; + operatorCounts{0} { + opCreators[static_cast(OpCodes::opConv2d)] = + [this](treebuilder::Tree* t, treebuilder::Operation* op) { + createLayerCONV_2D(t, op); + }; + }; virtual ~RandomModelBuilder() = default; - /** - * @brief createLayerXXX are creator for operators. - * @param input_tensor_id is id of input tensor. - */ - virtual void createLayerCONV_2D(int input_tensor_id) = 0; + virtual void convertTreeToModel(treebuilder::Tree* t) = 0; /** - * @brief addInput does add input tensor to model. - * @return status of adding. - */ - virtual bool addInput() = 0; - /** - * @brief addLayer does add a new layer to model. - * @return status of adding. - */ - virtual bool addLayer() = 0; - /** * @brief getModelSaver does create unique_ptr to ModelSaver. * @return unique_ptr to ModelSaver. */ @@ -92,20 +80,35 @@ protected: /** * @brief operatorCounts this array contains amount of used operators in generated model. - * @details For example: operatorCounts[Op_CONV_2D] -- amount of used 2D convolution operators. + * @details For example: operatorCounts[OpCodes::opConv2d] -- amount of used 2D convolution operators. */ int operatorCounts[static_cast(OpCodes::opCount)]; /** * @brief opCreators this array contains a lambda with call of method * for building specified operator. - * @details This array are used for convenient creation random operators, - * like follow: opCreators[rand()%OpCodes::OpCnt] - * For example: opCreators[Op_CONV_2D](0) -- will lead to call createLayerCONV_2D method. + * @details This array is used for convenient creation random operators, + * like follow: opCreators[OpCodes::opCount] + * For example: opCreators[OpCodes::opConv2d](0) -- will lead to call createLayerCONV_2D method. */ - std::function opCreators[static_cast(OpCodes::opCount)]; -}; + std::function + opCreators[static_cast(OpCodes::opCount)]; + /** + * @Brief createInput does add input tensor to model. + */ + virtual void createInput(treebuilder::Tree* t) = 0; + /** + * @brief addOperator does add a new layer to model. + */ + virtual void addOperator(treebuilder::Tree* t, treebuilder::Operation* op) = 0; + + /** + * @brief createLayerXXX are creator for operators. + * @param input_tensor_id is id of input tensor. + */ + virtual void createLayerCONV_2D(treebuilder::Tree*, treebuilder::Operation*) = 0; +}; } // namespace modelgen #endif // RANDOM_MODELBUILDER_H diff --git a/contrib/nnc/utils/tflite_model_generator/TFLiteRandomModelBuilder.cpp b/contrib/nnc/utils/tflite_model_generator/TFLiteRandomModelBuilder.cpp index 7a2d3f3..f098cfa 100644 --- a/contrib/nnc/utils/tflite_model_generator/TFLiteRandomModelBuilder.cpp +++ b/contrib/nnc/utils/tflite_model_generator/TFLiteRandomModelBuilder.cpp @@ -55,81 +55,69 @@ TFLiteRandomModelBuilder::TFLiteRandomModelBuilder() : RandomModelBuilder(), std::fill_n(_mapOperatorCode, static_cast(OpCodes::opCount), notInitialized); } -std::unique_ptr - TFLiteRandomModelBuilder::createEmptyTensor(const std::vector& shape, - const char* name) { - auto tensor_ptr = std::unique_ptr(new TensorT); +void TFLiteRandomModelBuilder::convertTreeToModel(treebuilder::Tree* t) { + createInput(t); - tensor_ptr->type = tflite::TensorType_FLOAT32; - tensor_ptr->name = name; - tensor_ptr->shape = shape; - tensor_ptr->buffer = static_cast(_model->buffers.size()); - _model->buffers.push_back(std::unique_ptr(new BufferT)); + for (auto& op : t->opList) { + addOperator(t, op.get()); + } +} - return tensor_ptr; +std::unique_ptr TFLiteRandomModelBuilder::createModelSaver() { + return std::unique_ptr(new TFLiteModelSaver(std::move(_model))); } -std::unique_ptr - TFLiteRandomModelBuilder::createTensorWthBuffer(const std::vector& shape, - const char* name) { - auto tensor_ptr = createEmptyTensor(shape, name); +/** + * @todo Add support several inputs. + */ +void TFLiteRandomModelBuilder::createInput(treebuilder::Tree* t) { + assert(_model->subgraphs.empty() && "Subgraph is already created"); - size_t buffer_size = 1; - for (auto s : shape) { - buffer_size *= s; - } - buffer_size *= sizeof(float); + std::unique_ptr subgraph(new SubGraphT); + subgraph->inputs.push_back(0); + subgraph->outputs.push_back(0); - _model->buffers[tensor_ptr->buffer]->data.resize(buffer_size); + subgraph->tensors.push_back(createEmptyTensor(t->inputShapeTree, "input")); + _operandTree2tensor.push_back(0); // it is same as: push_pack(subgraph->tensors.size() - 1); - for (size_t i = 0; i < buffer_size; i += sizeof(float)) { - float val = floatRand(gen); - memcpy(_model->buffers[tensor_ptr->buffer]->data.data() + i, &val, sizeof(float)); - } - return tensor_ptr; + _model->subgraphs.push_back(std::move(subgraph)); + _model->description = "Random tflite model"; + _model->version = 3; } -std::unique_ptr TFLiteRandomModelBuilder::createEmptyLayer(int opcode) { - auto operator_ptr = std::unique_ptr(new OperatorT); - auto opcode_id = _mapOperatorCode[opcode]; - auto tflite_opcode = internalOpCode2TFLiteOpCode[opcode]; +void TFLiteRandomModelBuilder::addOperator(treebuilder::Tree* t, treebuilder::Operation* op) { + assert(!_model->subgraphs.empty() && "Subgraph is not created"); - if (opcode_id == notInitialized) { - auto opCodePtr = std::unique_ptr(new OperatorCodeT); - opCodePtr->builtin_code = tflite_opcode; - opCodePtr->custom_code = tflite::EnumNamesBuiltinOperator()[tflite_opcode]; - opcode_id = _model->operator_codes.size(); - _model->operator_codes.push_back(std::move(opCodePtr)); - _mapOperatorCode[opcode] = opcode_id; - } - operator_ptr->opcode_index = opcode_id; - operatorCounts[opcode]++; - - return operator_ptr; + std::cout << "Add operator [" << opNames[static_cast(op->opcode)] << "] on the level [ " + << op->levelOwner << " ]" << std::endl; + opCreators[static_cast(op->opcode)](t, op); + _model->subgraphs[0]->outputs[0] = (*_model->subgraphs[0]->operators.rbegin())->outputs[0]; } -void TFLiteRandomModelBuilder::createLayerCONV_2D(int input_tensor_id) { +void TFLiteRandomModelBuilder::createLayerCONV_2D(treebuilder::Tree* t, + treebuilder::Operation* op) { std::string output_name(opNames[static_cast(OpCodes::opConv2d)]); output_name += "_" + std::to_string(operatorCounts[static_cast(OpCodes::opConv2d)]); - auto operator_ptr = createEmptyLayer(static_cast(OpCodes::opConv2d)); + auto operator_ptr = createEmptyOperator(op); - // @todo Random tensor's shape. - auto out_tensor_ptr = createEmptyTensor(_model->subgraphs[0]->tensors[input_tensor_id]->shape, - output_name.c_str()); - auto kernel_ptr = createTensorWthBuffer({3, 1, 1, 3}, "Kernel"); - auto bias_ptr = createTensorWthBuffer({3}, "bias"); + auto out_tensor_ptr = createEmptyTensor(op->outputShape, output_name.c_str()); + auto kernel_ptr = createTensorWthBuffer(op->kernelShape, "Kernel"); + auto bias_ptr = createTensorWthBuffer({op->outputShape[3]}, "bias"); - operator_ptr->inputs.push_back(input_tensor_id); + auto input_tensor_id = op->levelOwner == 0 ? _operandTree2tensor[0] : + _operandTree2tensor[t->inputCnt + op->inputs[0]]; + operator_ptr->inputs.push_back(input_tensor_id); operator_ptr->inputs.push_back(static_cast(_model->subgraphs[0]->tensors.size())); _model->subgraphs[0]->tensors.push_back(std::move(kernel_ptr)); operator_ptr->inputs.push_back(static_cast(_model->subgraphs[0]->tensors.size())); _model->subgraphs[0]->tensors.push_back(std::move(bias_ptr)); - operator_ptr->outputs.push_back(static_cast(_model->subgraphs[0]->tensors.size())); + auto output_tensor_id = static_cast(_model->subgraphs[0]->tensors.size()); + _operandTree2tensor.push_back(output_tensor_id); + operator_ptr->outputs.push_back(output_tensor_id); _model->subgraphs[0]->tensors.push_back(std::move(out_tensor_ptr)); - // @todo Random activation function. operator_ptr->builtin_options.Set(tflite::Conv2DOptionsT()); auto conv2D_opt = operator_ptr->builtin_options.AsConv2DOptions(); conv2D_opt->stride_w = conv2D_opt->stride_h = 1; @@ -139,43 +127,58 @@ void TFLiteRandomModelBuilder::createLayerCONV_2D(int input_tensor_id) { _model->subgraphs[0]->operators.push_back(std::move(operator_ptr)); } -bool TFLiteRandomModelBuilder::addInput() { - if (!_model->subgraphs.empty()) { - return false; - } - - std::unique_ptr subgraph(new SubGraphT); - subgraph->inputs.push_back(static_cast(subgraph->tensors.size())); - subgraph->outputs.push_back(static_cast(subgraph->tensors.size())); - subgraph->tensors.push_back(createEmptyTensor({1, 224, 224, 3}, "input")); +std::unique_ptr +TFLiteRandomModelBuilder::createEmptyTensor(const std::vector& shape, + const char* name) { + auto tensor_ptr = std::unique_ptr(new TensorT); - _model->subgraphs.push_back(std::move(subgraph)); - _model->description = "Random tflite model"; - _model->version = 3; + tensor_ptr->type = tflite::TensorType_FLOAT32; + tensor_ptr->name = name; + tensor_ptr->shape = shape; + tensor_ptr->buffer = static_cast(_model->buffers.size()); + _model->buffers.push_back(std::unique_ptr(new BufferT)); - return true; + return tensor_ptr; } -bool TFLiteRandomModelBuilder::addLayer() { +std::unique_ptr +TFLiteRandomModelBuilder::createTensorWthBuffer(const std::vector& shape, + const char* name) { + auto tensor_ptr = createEmptyTensor(shape, name); - if (_model->subgraphs.empty()) { - return false; + size_t buffer_size = 1; + for (auto s : shape) { + buffer_size *= s; } + buffer_size *= sizeof(float); - auto input_id = - _model->subgraphs[0]->operators.size() == 0 ? _model->subgraphs[0]->inputs[0] : - _model->subgraphs[0]->operators[_model->subgraphs[0]->operators.size() - 1]->outputs[0]; + _model->buffers[tensor_ptr->buffer]->data.resize(buffer_size); + + for (size_t i = 0; i < buffer_size; i += sizeof(float)) { + float val = floatRand(gen); + memcpy(_model->buffers[tensor_ptr->buffer]->data.data() + i, &val, sizeof(float)); + } + return tensor_ptr; +} - auto op_id = intRand(gen); +std::unique_ptr +TFLiteRandomModelBuilder::createEmptyOperator(treebuilder::Operation* op) { + auto operator_ptr = std::unique_ptr(new OperatorT); + auto opcode_id = _mapOperatorCode[static_cast(op->opcode)]; + auto tflite_opcode = internalOpCode2TFLiteOpCode[static_cast(op->opcode)]; - std::cout << "Add layer: " << opNames[op_id] << std::endl; - opCreators[op_id](input_id); - _model->subgraphs[0]->outputs[0] = (*_model->subgraphs[0]->operators.rbegin())->outputs[0]; + if (opcode_id == notInitialized) { + auto opcode_ptr = std::unique_ptr(new OperatorCodeT); + opcode_ptr->builtin_code = tflite_opcode; + opcode_ptr->custom_code = tflite::EnumNamesBuiltinOperator()[tflite_opcode]; + opcode_id = static_cast(_model->operator_codes.size()); + _model->operator_codes.push_back(std::move(opcode_ptr)); + _mapOperatorCode[static_cast(op->opcode)] = opcode_id; + } + operator_ptr->opcode_index = static_cast(opcode_id); + operatorCounts[static_cast(op->opcode)]++; - return true; + return operator_ptr; } -std::unique_ptr TFLiteRandomModelBuilder::createModelSaver() { - return std::unique_ptr(new TFLiteModelSaver(std::move(_model))); -} } // namespace modelgen diff --git a/contrib/nnc/utils/tflite_model_generator/TFLiteRandomModelBuilder.h b/contrib/nnc/utils/tflite_model_generator/TFLiteRandomModelBuilder.h index 3670bc7..c617cd5 100644 --- a/contrib/nnc/utils/tflite_model_generator/TFLiteRandomModelBuilder.h +++ b/contrib/nnc/utils/tflite_model_generator/TFLiteRandomModelBuilder.h @@ -20,6 +20,7 @@ #include #include +#include "Tree.h" #include "RandomModelBuilder.h" #include "schema_generated.h" @@ -35,10 +36,9 @@ public: TFLiteModelSaver() = default; ~TFLiteModelSaver() override = default; - TFLiteModelSaver(std::unique_ptr &&m) : ModelSaver(), _model(std::move(m)) {} + TFLiteModelSaver(std::unique_ptr&& m) : ModelSaver(), _model(std::move(m)) {} void saveModel() override; - private: flatbuffers::FlatBufferBuilder _flatBufferBuilder; std::unique_ptr _model; @@ -53,13 +53,16 @@ public: TFLiteRandomModelBuilder(); ~TFLiteRandomModelBuilder() override = default; - void createLayerCONV_2D(int input_tensor_id) override; - - bool addInput() override; - bool addLayer() override; + void convertTreeToModel(treebuilder::Tree* t) override; std::unique_ptr createModelSaver() override; - +protected: + void createInput(treebuilder::Tree* t) override; + void addOperator(treebuilder::Tree* t, treebuilder::Operation* op) override; + /** + * Operations: + */ + void createLayerCONV_2D(treebuilder::Tree* t, treebuilder::Operation* op) override; private: /** * @brief createEmptyTensor does create tensor without buffer @@ -80,19 +83,26 @@ private: std::unique_ptr createTensorWthBuffer(const std::vector& shape, const char* name); /** - * @brief createEmptyLayer does create operator without tensors and + * @brief createEmptyOperator does create operator without tensors and * add operator to operators array of SubGraphT * @param opcode is operator's code. * @return unique_ptr to created operator. */ - std::unique_ptr createEmptyLayer(int opcode); + std::unique_ptr createEmptyOperator(treebuilder::Operation* op); std::unique_ptr _model; + + /** + * @details This vector contains a index of tensor (in subgraph tflite vector) + * for output operand of tree's node `i`. + */ + std::vector _operandTree2tensor; + /** * @brief mapOperatorCode contains indexes to operator_codes array in ModelT. */ long _mapOperatorCode[static_cast(OpCodes::opCount)]; }; -} // namespace modegGen +} // namespace modelgen #endif // TFLITEBUILDER_H -- 2.7.4