From 683b8b09963922c9914fe013f9eab0d229632cb0 Mon Sep 17 00:00:00 2001 From: "Efimov Alexander/AI Tools Lab/./Samsung Electronics" Date: Tue, 4 Sep 2018 17:36:05 +0300 Subject: [PATCH] Generate unified setter and getter (#1284) Generate unified setter and getter for single input/output nets to artifact. This setter and getter has fixed declaration for all nets with single input and output Signed-off-by: Efimov Alexander --- contrib/nnc/plugin/soft_backend/cpp_generator.cpp | 60 +++++++++++++++++----- contrib/nnc/plugin/soft_backend/cpp_generator.h | 2 + contrib/nnc/plugin/soft_backend/model_analyzer.cpp | 9 +++- contrib/nnc/plugin/soft_backend/model_analyzer.h | 6 +++ contrib/nnc/unittests/soft_backend/generator.cpp | 7 ++- 5 files changed, 68 insertions(+), 16 deletions(-) diff --git a/contrib/nnc/plugin/soft_backend/cpp_generator.cpp b/contrib/nnc/plugin/soft_backend/cpp_generator.cpp index cc4896e..1dbff0a 100644 --- a/contrib/nnc/plugin/soft_backend/cpp_generator.cpp +++ b/contrib/nnc/plugin/soft_backend/cpp_generator.cpp @@ -76,13 +76,21 @@ void CPPCodeGenerator::materializeHeader(ostream &out, const ModelAnalyzer &ma) " " << className << "(const std::string ¶metersPath);\n" " ~" << className << "();\n"; // generate input setters + if (ma.getInputs().size() == 1) + { + out << " void setInput(const Tensor &inputs);\n"; + } for (const size_t inId: ma.getInputs()) { const string &tName = _formattedTensors[inId]; out << " void set" << tName << "(const Tensor& t);\n"; } // generate output getters - for (const size_t outId: ma.getOutputs()) + if (ma.getOutputs().size() == 1) + { + out << " std::shared_ptr getOutput();\n"; + } + for (const size_t outId: ma.getNamedTensors()) { const string &tName = _formattedTensors[outId]; out << " std::shared_ptr get" << tName << "();\n"; @@ -98,7 +106,7 @@ void CPPCodeGenerator::materializeHeader(ostream &out, const ModelAnalyzer &ma) const string &tName = _formattedTensors[inId]; out << " Tensor " << tName << ";\n"; } - for (const size_t outId: ma.getOutputs()) + for (const size_t outId: ma.getNamedTensors()) { const string &tName = _formattedTensors[outId]; out << " std::shared_ptr " << tName << ";\n"; @@ -156,6 +164,22 @@ void CPPCodeGenerator::gatherOperationArguments(const ModelAnalyzer &ma, } } +void CPPCodeGenerator::printSetter(ostream &out, const string &className, const string &setterName, const string &varName) +{ + out << "void " << className << "::set" << setterName << "(const Tensor& t)\n" + "{\n" + " " << varName << " = t;\n" + "}\n\n"; +} + +void CPPCodeGenerator::printGetter(ostream &out, const string &className, const string &getterName, const string &varName) +{ + out << "shared_ptr " << className <<"::get" << getterName << "()\n" + "{\n" + " return " << varName << ";\n" + "}\n\n"; +} + // generate inference sequence void CPPCodeGenerator::materializeInferenceSequence(ostream &out, const ModelAnalyzer &ma) { @@ -220,28 +244,36 @@ void CPPCodeGenerator::materializeCode(ostream &out, const ModelAnalyzer &ma, co "{\n" " releaseParameters(_parameters, _paramSize);\n" "}\n\n"; - // gen input setters - for (size_t inId: ma.getInputs()) + // generate input setters + // generate main setter if network has only one + const auto &inputs = ma.getInputs(); + if (inputs.size() == 1) + { + const string &inName = _formattedTensors[inputs[0]]; + printSetter(out, className, "Input", inName); + } + // generate setters by names + for (size_t inId: inputs) { const string &inName = _formattedTensors[inId]; - out << "void " << className << "::set" << inName << "(const Tensor& t)\n" - "{\n" - " " << inName << " = t;\n" - "}\n\n"; + printSetter(out, className, inName, inName); } // gen output getters - for (size_t outId: ma.getOutputs()) + // generate main getter if network has only one + if (ma.getOutputs().size() == 1) + { + const string outName = _formattedTensors[ma.getOutputs()[0]]; + printGetter(out, className, "Output", outName); + } + for (size_t outId: ma.getNamedTensors()) { const string &outName = _formattedTensors[outId]; - out << "shared_ptr " << className <<"::get" << outName << "()\n" - "{\n" - " return " << outName << ";\n" - "}\n\n"; + printGetter(out, className, outName, outName); } out << "void " << className << "::doInference()\n" "{\n"; - for (size_t outId: ma.getOutputs()) + for (size_t outId: ma.getNamedTensors()) { const string &outName = _formattedTensors[outId]; out << " " << outName << ".reset(new Tensor());\n"; diff --git a/contrib/nnc/plugin/soft_backend/cpp_generator.h b/contrib/nnc/plugin/soft_backend/cpp_generator.h index 0143102..6448b98 100644 --- a/contrib/nnc/plugin/soft_backend/cpp_generator.h +++ b/contrib/nnc/plugin/soft_backend/cpp_generator.h @@ -25,6 +25,8 @@ protected: void gatherOperationArguments(const ModelAnalyzer &ma, const std::vector &argIds, std::vector &args); + void printSetter(std::ostream &out, const std::string &className, const std::string &setterName, const std::string &varName); + void printGetter(std::ostream &out, const std::string &className, const std::string &setterName, const std::string &varName); void materializeInferenceSequence(std::ostream &out, const ModelAnalyzer &ma); void materializeCode(std::ostream &out, const ModelAnalyzer &ma, const Serializer &s) override; }; diff --git a/contrib/nnc/plugin/soft_backend/model_analyzer.cpp b/contrib/nnc/plugin/soft_backend/model_analyzer.cpp index deb2821..4971ab6 100644 --- a/contrib/nnc/plugin/soft_backend/model_analyzer.cpp +++ b/contrib/nnc/plugin/soft_backend/model_analyzer.cpp @@ -50,7 +50,7 @@ void ModelAnalyzer::addOpDescr(ADT::INode *node, const string &opName) { // process output node nodeTid = allocateTensor(name, false, true); - _outputs.push_back(nodeTid); + _named_tensors.push_back(nodeTid); type = OpDescr::Type::OUT; } else @@ -60,6 +60,13 @@ void ModelAnalyzer::addOpDescr(ADT::INode *node, const string &opName) } assert(nodeTid != INVALID_TENSOR_ID); nodeOutputs.push_back(nodeTid); + // process node outputs + // consider node as output if it has no consumers + if (node->getNextNodes().empty()) + { + assert(type == OpDescr::Type::OUT); + _outputs.push_back(nodeTid); + } // process node inputs vector nodeInputs; for (const ADT::INode::IODescriptor &d: node->getPrevNodes()) diff --git a/contrib/nnc/plugin/soft_backend/model_analyzer.h b/contrib/nnc/plugin/soft_backend/model_analyzer.h index d9eafa5..2a9ba14 100644 --- a/contrib/nnc/plugin/soft_backend/model_analyzer.h +++ b/contrib/nnc/plugin/soft_backend/model_analyzer.h @@ -74,6 +74,11 @@ public: return _inputs; } + const std::vector &getNamedTensors() const + { + return _named_tensors; + } + const std::vector &getOutputs() const { return _outputs; @@ -108,6 +113,7 @@ private: std::list _inferenceSequence; size_t _allocatedTensors = 0; std::vector _inputs; + std::vector _named_tensors; std::vector _outputs; std::vector _tensors; std::map _nodeToDescr; diff --git a/contrib/nnc/unittests/soft_backend/generator.cpp b/contrib/nnc/unittests/soft_backend/generator.cpp index 5584b06..005c756 100644 --- a/contrib/nnc/unittests/soft_backend/generator.cpp +++ b/contrib/nnc/unittests/soft_backend/generator.cpp @@ -1,4 +1,5 @@ #include "cpp_generator.h" +#include "core/modelIR/operations/relu_op.h" #include "support/PluginException.h" @@ -16,6 +17,7 @@ using namespace std; using namespace nncc::contrib; using namespace nncc::contrib::backend::soft; +using namespace nncc::contrib::core; using namespace nncc::contrib::core::IR::model; static bool isFileExists(const string &path) @@ -70,7 +72,10 @@ TEST(Generator, check_generator_call) clopt::CommandLine::getParser()->parseCommandLine(argc, argv, false); nncc::contrib::core::IR::model::Graph g; - g.create("input"); + INode *input = g.create("input"); + input->getOperation()->setOutputShape(0, data::Shape({1,2,3,4})); + INode *output = g.create("output"); + output->connectInputTo(0, input->getOutput(0)); // test that generator creates output dir and files if (isFileExists(TEST_DIR)) -- 2.7.4