From: Efimov Alexander/AI Tools Lab/./Samsung Electronics Date: Sun, 15 Jul 2018 06:47:30 +0000 (+0300) Subject: C++ code generator (#604) X-Git-Tag: nncc_backup~2421 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=81910b22bd59874735183fa857efe2304f352f7a;p=platform%2Fcore%2Fml%2Fnnfw.git C++ code generator (#604) Implementation of C++ *.cpp file generator Signed-off-by: Efimov Alexander --- diff --git a/contrib/nnc/libs/backend/soft/include/cpp_operations.def b/contrib/nnc/libs/backend/soft/include/cpp_operations.def new file mode 100644 index 0000000..cd6cab7 --- /dev/null +++ b/contrib/nnc/libs/backend/soft/include/cpp_operations.def @@ -0,0 +1 @@ +S() diff --git a/contrib/nnc/libs/backend/soft/src/generator.cpp b/contrib/nnc/libs/backend/soft/src/generator.cpp index a58e1fc..a0d041e 100644 --- a/contrib/nnc/libs/backend/soft/src/generator.cpp +++ b/contrib/nnc/libs/backend/soft/src/generator.cpp @@ -5,12 +5,13 @@ #include #include #include -#include #include #include #include #include +#include +#include using namespace std; using namespace nncc::contrib; @@ -195,6 +196,10 @@ CPPCodeGenerator CPPCodeGenerator::create(const std::string &headerFile, static const char *cpp_header_types = #include "cpp_header_types.def" ; + + static const char *cpp_operations = + #include "cpp_operations.def" + ; #undef S void CPPCodeGenerator::materializeHeader(ostream &out, const ModelAnalyzer &ma) @@ -225,9 +230,134 @@ void CPPCodeGenerator::materializeHeader(ostream &out, const ModelAnalyzer &ma) out << "};\n"; } +// print allocation of temporary tensors +static void printTmpTensors(ostream &out, const ModelAnalyzer::OpDescr &op) +{ + for (const ModelAnalyzer::TensorDescription &td: op._outputs) + { + if (td._isNNOutput) + continue; + out << " Tensor " << td._name << ";\n"; + } +} + +// generate function output arguments +static void gatherOperationCallOutputs(const ModelAnalyzer::OpDescr &op, vector &args) +{ + for (const ModelAnalyzer::TensorDescription &td: op._outputs) + { + const string &tensorName = td._name; + if (td._isNNOutput) + args.push_back("*" + tensorName); + else + args.push_back(tensorName); + } +} + +// generate function input arguments +static void gatherOperationCallInputs(const ModelAnalyzer::OpDescr &op, map &node2Descr, vector &args) +{ + for (const INode::IODescriptor &d: op._node->getPrevNodes()) + { + size_t idx = d.index; + INode *node = d.node; + assert(node2Descr.find(node) != node2Descr.end()); + const ModelAnalyzer::OpDescr &descr = *node2Descr[node]; + const ModelAnalyzer::TensorDescription &tDescr = descr._outputs[idx]; + const string &tensorName = tDescr._name; + if (tDescr._isNNOutput) + args.push_back("*" + tensorName); + else + args.push_back(tensorName); + } +} + +// print operation call arguments +static void printOperationArgs(ostream &out, const vector &args) +{ + bool insertComma = false; + for (const string &arg: args) + { + if (insertComma) + out << ", "; + insertComma = true; + out << arg; + } +} + +// generate inference sequence +static void materializeCPPInferenceSequence(ostream &out, const ModelAnalyzer &ma) +{ + using OpDescr = ModelAnalyzer::OpDescr; + map node2Descr; + for (const ModelAnalyzer::OpDescr &op: ma.getInferenceSequence()) + { + node2Descr.insert(pair(op._node, &op)); + using Type = OpDescr::Type; + using TensorDescription = ModelAnalyzer::TensorDescription; + if (op._type == Type::IN) + continue; + // create temporary tensors + printTmpTensors(out, op); + // materialize call + out << " " << op._opName << "("; + const auto &prevNodes = op._node->getPrevNodes(); + const auto &outTensors = op._outputs; + vector args; + args.reserve(prevNodes.size() + outTensors.size() + 1); + // gather output arguments + gatherOperationCallOutputs(op, args); + // parameters offset + args.push_back(to_string(op._paramStartOffset)); + // gather input arguments + gatherOperationCallInputs(op, node2Descr, args); + // put arguments into stream + printOperationArgs(out, args); + out << ");\n"; + } +} + +// TODO think about better string formatting to make code more readable void CPPCodeGenerator::materializeCode(ostream &out, const ModelAnalyzer &ma) { - // TODO emit C++ code to out stream + string className = ma.getModelName() + "Model"; + out << cpp_operations; + + // gen NN constructor + out << className << "::" << className << "(const string ¶metersPath)\n" + "{\n" + " readParameters(_parameters, parametersPath, " << + ma.getFormatVersion() << ", " << ma.getModelHash() << ");" + "}\n"; + + // gen input setters + for (const string &inName: ma.getInputs()) + { + out << "void " << className << "::set_" << inName << "(const Tensor& t)\n" + "{\n" + " _" << inName << " = t;" + "}\n"; + } + + // gen output getters + for (const string &outName: ma.getOutputs()) + { + out << "shared_ptr " << className <<"::get_" << outName << "()\n" + "{\n" + " return _" << outName << ";" + "}\n"; + } + out << "void " << className << "::doInference()\n" + "{\n"; + for (const string &outName: ma.getOutputs()) + { + out << " _" << outName << ".reset(new Tensor());\n"; + } + + // gen inference sequence + materializeCPPInferenceSequence(out, ma); + out << "}"; } } // namespace soft