Generate unified setter and getter (#1284)
authorEfimov Alexander/AI Tools Lab/./Samsung Electronics <a.efimov@samsung.com>
Tue, 4 Sep 2018 14:36:05 +0000 (17:36 +0300)
committerРоман Михайлович Русяев/AI Tools Lab /SRR/Staff Engineer/삼성전자 <r.rusyaev@samsung.com>
Tue, 4 Sep 2018 14:36:05 +0000 (17:36 +0300)
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 <a.efimov@samsung.com>
contrib/nnc/plugin/soft_backend/cpp_generator.cpp
contrib/nnc/plugin/soft_backend/cpp_generator.h
contrib/nnc/plugin/soft_backend/model_analyzer.cpp
contrib/nnc/plugin/soft_backend/model_analyzer.h
contrib/nnc/unittests/soft_backend/generator.cpp

index cc4896e..1dbff0a 100644 (file)
@@ -76,13 +76,21 @@ void CPPCodeGenerator::materializeHeader(ostream &out, const ModelAnalyzer &ma)
          "  " << className << "(const std::string &parametersPath);\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<Tensor> getOutput();\n";
+  }
+  for (const size_t outId: ma.getNamedTensors())
   {
     const string &tName = _formattedTensors[outId];
     out << "  std::shared_ptr<Tensor> 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<Tensor> " << 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<Tensor> " << 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<Tensor> " << 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";
index 0143102..6448b98 100644 (file)
@@ -25,6 +25,8 @@ protected:
   void gatherOperationArguments(const ModelAnalyzer &ma,
                                 const std::vector<size_t> &argIds,
                                 std::vector<std::string> &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;
 };
index deb2821..4971ab6 100644 (file)
@@ -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<size_t> nodeInputs;
   for (const ADT::INode::IODescriptor &d: node->getPrevNodes())
index d9eafa5..2a9ba14 100644 (file)
@@ -74,6 +74,11 @@ public:
     return _inputs;
   }
 
+  const std::vector<size_t> &getNamedTensors() const
+  {
+    return _named_tensors;
+  }
+
   const std::vector<size_t> &getOutputs() const
   {
     return _outputs;
@@ -108,6 +113,7 @@ private:
   std::list<OpDescr> _inferenceSequence;
   size_t _allocatedTensors = 0;
   std::vector<size_t> _inputs;
+  std::vector<size_t> _named_tensors;
   std::vector<size_t> _outputs;
   std::vector<TensorDescription> _tensors;
   std::map<const ADT::INode *, OpDescr *> _nodeToDescr;
index 5584b06..005c756 100644 (file)
@@ -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<ops::VariableOp>("input");
+  INode *input = g.create<ops::VariableOp>("input");
+  input->getOperation()->setOutputShape(0, data::Shape({1,2,3,4}));
+  INode *output = g.create<ops::ReluOp>("output");
+  output->connectInputTo(0, input->getOutput(0));
 
   // test that generator creates output dir and files
   if (isFileExists(TEST_DIR))