[neurun] Revise graph partitioning code (#4510)
author김용섭/On-Device Lab(SR)/Engineer/삼성전자 <yons.kim@samsung.com>
Wed, 27 Feb 2019 07:17:54 +0000 (16:17 +0900)
committer오형석/On-Device Lab(SR)/Staff Engineer/삼성전자 <hseok82.oh@samsung.com>
Wed, 27 Feb 2019 07:17:54 +0000 (16:17 +0900)
* [neurun] Revise graph partitioning code

- Move graph paritionining code from Linear to Graph.
- Handle Subgraphs as like LowerInfo until Execution

* Add skipped code to fix failed test

* Change the access specifier of partition method from public to private

Signed-off-by: Yongseop Kim <yons.kim@samsung.com>
runtimes/neurun/src/compiler/Compiler.cc
runtimes/neurun/src/exec/Executor.h
runtimes/neurun/src/exec/ExecutorBase.cc
runtimes/neurun/src/exec/ExecutorBase.h
runtimes/neurun/src/graph/Graph.cc
runtimes/neurun/src/graph/Graph.h
runtimes/neurun/src/linear/Linear.cc
runtimes/neurun/src/linear/Linear.h

index 03bb7c6..82a9b90 100644 (file)
@@ -66,7 +66,7 @@ void Compiler::compile(void)
 
   dot_dumper.dumpIfNeeded("after_lower");
 
-  // linearize with subgraphs
+  // linearize
   auto linear = _model->linearize();
   _state = State::LINEARIZED;
 
@@ -118,8 +118,8 @@ void Compiler::compile(void)
    * Code generation phase finished
    ********************************/
   auto plan = std::make_shared<Plan>(operand_context, operation_sequence);
-  _executor =
-      std::make_shared<exec::Executor>(_model->shareModel(), linear->releaseLowerInfo(), plan);
+  _executor = std::make_shared<exec::Executor>(_model->shareModel(), linear->releaseSubgraphSet(),
+                                               linear->releaseLowerInfo(), plan);
   _state = State::COMPILED;
 }
 
index 00b60ac..5555beb 100644 (file)
@@ -40,9 +40,10 @@ public:
    * @param[in] plan  Execution plan generated by compiled result
    */
   Executor(const std::shared_ptr<const model::Model> &model,
+           std::unique_ptr<std::vector<std::unique_ptr<model::operation::Subgraph>>> subg_set,
            std::unique_ptr<graph::LowerInfoMap> lower_info,
            const std::shared_ptr<const neurun::compiler::Plan> &plan)
-      : ExecutorBase{model, std::move(lower_info)}, _plan{plan}
+      : ExecutorBase{model, std::move(subg_set), std::move(lower_info)}, _plan{plan}
   {
   }
 
index 581dce3..db982a8 100644 (file)
@@ -21,9 +21,11 @@ namespace neurun
 namespace exec
 {
 
-ExecutorBase::ExecutorBase(const std::shared_ptr<const model::Model> &model,
-                           std::unique_ptr<graph::LowerInfoMap> lower_info)
-    : _model{model}, _lower_info{std::move(lower_info)}
+ExecutorBase::ExecutorBase(
+    const std::shared_ptr<const model::Model> &model,
+    std::unique_ptr<std::vector<std::unique_ptr<model::operation::Subgraph>>> subg_set,
+    std::unique_ptr<graph::LowerInfoMap> lower_info)
+    : _model{model}, _subg_set{std::move(subg_set)}, _lower_info{std::move(lower_info)}
 {
   _sources.resize(_model->inputs.size());
   _sinks.resize(_model->outputs.size());
index e8f1740..e8d4bec 100644 (file)
@@ -24,6 +24,7 @@
 #include "graph/LowerInfoMap.h"
 #include "backend/interface/IConfig.h"
 #include "compiler/TensorInfo.h"
+#include "model/operation/Subgraph.h"
 
 namespace neurun
 {
@@ -34,6 +35,7 @@ class ExecutorBase : public IExecutor
 {
 public:
   ExecutorBase(const std::shared_ptr<const model::Model> &model,
+               std::unique_ptr<std::vector<std::unique_ptr<model::operation::Subgraph>>> subg_set,
                std::unique_ptr<graph::LowerInfoMap> lower_info);
 
   virtual ~ExecutorBase() = default;
@@ -115,6 +117,7 @@ private:
 
 protected:
   std::shared_ptr<const model::Model> _model;
+  std::unique_ptr<std::vector<std::unique_ptr<model::operation::Subgraph>>> _subg_set;
   std::unique_ptr<graph::LowerInfoMap> _lower_info;
   std::vector<std::unique_ptr<ISource>> _sources;
   std::vector<std::unique_ptr<ISink>> _sinks;
index 50acab8..9ad5759 100644 (file)
@@ -91,6 +91,8 @@ void Graph::lower(void)
 {
   assert(_phase == Phase::MODEL);
 
+  partition();
+
   // Lower
   {
     // operand::LowerInfo holder
@@ -213,7 +215,8 @@ std::unique_ptr<linear::Linear> Graph::linearize(void)
 {
   assert(_phase == Phase::MODEL);
 
-  auto linear = nnfw::cpp14::make_unique<linear::Linear>(*this, releaseLowerInfo());
+  auto linear =
+      nnfw::cpp14::make_unique<linear::Linear>(*this, releaseSubgraphSet(), releaseLowerInfo());
 
   // TODO Move the operations and operands to linear object
   return std::move(linear);
@@ -281,6 +284,99 @@ void Graph::setLowerInfo(const model::operand::Index &index,
   _lower_info_map->operand.insert(std::make_pair(index, std::move(lower_info)));
 }
 
+void Graph::partition()
+{
+  // Partition the graph into some subgraphs by topological sort while assuming that
+  // a subgraph has linear form
+  //
+  // algorithm
+  //   0. Create new subgraph
+  //   1. Add a node into current subgraph
+  //   2. Test two stuff for checking new subgraph is needed
+  //     - Current node has multiple inputs like concat?
+  //       - Does current node have two or more than previous operation?
+  //
+  //        [CONV] [CONV] [CONV]  [MAX_POOL]
+  //         |      |      |       |
+  //        [0]    [1]    [2]     [3]
+  //         \      |      |      /
+  //          [    C O N C A T   ]  # current node
+  //
+  //     - Current node is on the separated branch at the beginning?
+  //       - Does current node's input operand's uses have two or more than?
+  //
+  //       [CONV]
+  //         |
+  //        [0]----.
+  //         |     |
+  //       [CONV] [CONV]  # current node
+  //         |      |
+  //        [1]    [2]
+  //         \      /
+  //         [CONCAT]
+  //
+
+  _subg_set = nnfw::cpp14::make_unique<std::vector<std::unique_ptr<model::operation::Subgraph>>>();
+
+  {
+    std::unique_ptr<model::operation::Subgraph> subg = nullptr;
+    Graph::PostDfsConstIterator().iterate(
+        *this, [&](const model::operation::Index &index, const model::operation::Node &node) {
+
+          if (!subg)
+            subg = nnfw::cpp14::make_unique<model::operation::Subgraph>();
+
+          subg->appendOperation(index, node);
+
+          bool finish_subg = false;
+          size_t prev_op_cnt = 0;
+          for (auto input : node.getInputs())
+          {
+            const auto &operand = this->operands().at(input);
+            if (operand.getDef().list().size() > 0)
+              ++prev_op_cnt;
+
+            if (prev_op_cnt > 1 || operand.getUses().list().size() > 1)
+            {
+              finish_subg = true;
+              break;
+            }
+          }
+
+          if (finish_subg)
+          {
+            _subg_set->emplace_back(std::move(subg));
+            subg = nullptr;
+          }
+        });
+
+    // If the last subgraph leaves, append it to the subgraph set
+    if (subg && subg->operations().size() > 0)
+      _subg_set->emplace_back(std::move(subg));
+
+    // NOTE. Now these subgraph are on the reverse order
+  }
+
+  // Set input/output of each subgraph while reversing
+  std::reverse(_subg_set->begin(), _subg_set->end());
+  for (auto &subg : *_subg_set)
+  {
+    // output
+    auto it = std::begin(subg->operations());
+    subg->setOutputs((*it).node->getOutputs());
+
+    std::reverse(std::begin(subg->operations()), std::end(subg->operations()));
+
+    // input
+    it = std::begin(subg->operations());
+    subg->setInputs((*it).node->getInputs());
+  }
+
+  VERBOSE(Subgraph) << "Subgraphs" << std::endl;
+  for (const auto &subg : *_subg_set)
+    VERBOSE(Subgraph) << subg->getStr() << std::endl;
+}
+
 } // namespace graph
 } // namespace neurun
 
index 17eecf8..89e1f3a 100644 (file)
@@ -22,6 +22,7 @@
 #include "model/operation/Node.h"
 #include "model/Model.h"
 #include "graph/LowerInfoMap.h"
+#include "model/operation/Subgraph.h"
 
 namespace neurun
 {
@@ -125,6 +126,10 @@ public:
   bool isBuildingPhase(void) const { return _phase == Phase::BUILDING; }
   std::shared_ptr<const model::Model> shareModel() { return _model; }
   std::unique_ptr<graph::LowerInfoMap> releaseLowerInfo() { return std::move(_lower_info_map); }
+  std::unique_ptr<std::vector<std::unique_ptr<model::operation::Subgraph>>> releaseSubgraphSet()
+  {
+    return std::move(_subg_set);
+  }
 
 private:
   void initializeUseDef();
@@ -161,6 +166,13 @@ public:
 private:
   std::unique_ptr<compiler::BackendResolver> _backend_resolver;
   std::unique_ptr<LowerInfoMap> _lower_info_map;
+
+  // For Subgraph
+private:
+  void partition();
+
+private:
+  std::unique_ptr<std::vector<std::unique_ptr<model::operation::Subgraph>>> _subg_set;
 };
 
 } // namespace graph
index 3ff73a6..cc79cbc 100644 (file)
@@ -35,112 +35,18 @@ namespace neurun
 namespace linear
 {
 
-Linear::Linear(const graph::Graph &graph, std::unique_ptr<graph::LowerInfoMap> lower_info_map)
-    : _graph(graph), _lower_info_map(std::move(lower_info_map))
+Linear::Linear(const graph::Graph &graph,
+               std::unique_ptr<std::vector<std::unique_ptr<model::operation::Subgraph>>> subg_set,
+               std::unique_ptr<graph::LowerInfoMap> lower_info_map)
+    : _graph(graph), _subg_set(std::move(subg_set)), _lower_info_map(std::move(lower_info_map))
 {
-  assert(_lower_info_map);
-
-  // TODO: Move this code to graph
-
-  // Linearize graph with subgraphs by topological sort while assuming that
-  // a subgraph has linear form
-  //
-  // algorithm
-  //   0. Create new subgraph
-  //   1. Add a node into current subgraph
-  //   2. Test two stuff for checking new subgraph is needed
-  //   - Current node has multiple inputs like concat?
-  //     - Does current node have two or more than previous operation?
-  //
-  //  [CONV] [CONV] [CONV]  [MAX_POOL]
-  //    |      |      |       |
-  //   [0]    [1]    [2]     [3]
-  //    \      |      |      /
-  //     [    C O N C A T   ]  # current node
-  //
-  //   - Current node is on the separated branch at the beginning?
-  //     - Does current node's input operand's uses have two or more than?
-  //
-  //     [CONV]
-  //       |
-  //      [0]----.
-  //       |     |
-  //     [CONV] [CONV]  # current node
-  //       |      |
-  //      [1]    [2]
-  //       \      /
-  //       [CONCAT]
-  //
-  //   3. If needed, push current subgraph to the set and create new subgraph
-
-  auto subgraph_set =
-      nnfw::cpp14::make_unique<std::vector<std::unique_ptr<model::operation::Subgraph>>>();
+  assert(_subg_set && _lower_info_map);
+  for (const auto &subg : *_subg_set)
   {
-    std::unique_ptr<model::operation::Subgraph> subgraph = nullptr;
-    graph::Graph::PostDfsConstIterator().iterate(
-        graph, [&](const model::operation::Index &index, const model::operation::Node &node) {
-
-          if (!subgraph)
-            subgraph = nnfw::cpp14::make_unique<model::operation::Subgraph>();
-
-          subgraph->appendOperation(index, node);
-
-          bool new_subgraph = false;
-          size_t prev_op_cnt = 0;
-          for (auto input : node.getInputs())
-          {
-            const auto &operand = graph.operands().at(input);
-            if (operand.getDef().list().size() > 0)
-              ++prev_op_cnt;
-
-            if (prev_op_cnt > 1 || operand.getUses().list().size() > 1)
-            {
-              new_subgraph = true;
-              break;
-            }
-          }
-
-          if (new_subgraph)
-          {
-            subgraph_set->emplace_back(std::move(subgraph));
-            subgraph = nullptr;
-          }
-        });
-
-    // If the last subgraph leaves, append it to the subgraph set
-    if (subgraph && subgraph->operations().size() > 0)
-      subgraph_set->emplace_back(std::move(subgraph));
-
-    // NOTE. Now these subgraph are on the reverse order
-  }
-
-  // Set input/output of each subgraph while reversing
-  std::reverse(subgraph_set->begin(), subgraph_set->end());
-  for (auto &subgraph : *subgraph_set)
-  {
-    // output
-    auto it = std::begin(subgraph->operations());
-    subgraph->setOutputs((*it).node->getOutputs());
-
-    std::reverse(std::begin(subgraph->operations()), std::end(subgraph->operations()));
-
-    // input
-    it = std::begin(subgraph->operations());
-    subgraph->setInputs((*it).node->getInputs());
-  }
-
-  // Now ordered subgraphs are ready
-  for (auto &subgraph : *subgraph_set)
-  {
-    // Assume that the backend of all nodes on a subgraph are identified on the subgraph
-    const auto &first_ind = subgraph->operations()[0].index;
-    auto lower_info = getLowerInfo(first_ind);
-    _elements.emplace_back(std::move(subgraph), lower_info);
+    // Assume that the lower_infos of all nodes on a subgraph are identified on the subgraph
+    const auto &first_ind = subg->operations()[0].index;
+    _elements.emplace_back(subg.get(), getLowerInfo(first_ind));
   }
-
-  VERBOSE(LINEAR) << "Subgraphs" << std::endl;
-  for (const auto &element : _elements)
-    VERBOSE(LINEAR) << element.subgraph->getStr() << std::endl;
 }
 
 void Linear::accept(model::operation::NodeVisitor &&visitor) const
index b513db4..99b3389 100644 (file)
@@ -50,14 +50,11 @@ namespace linear
 
 struct Element
 {
-  // TODO: Change unique_ptr to ptr after Graph has Subgraphs
-  std::unique_ptr<model::operation::Subgraph> subgraph;
-
+  const model::operation::Subgraph *subgraph;
   const graph::operation::LowerInfo *lower_info;
 
-  Element(std::unique_ptr<model::operation::Subgraph> subgraph,
-          const graph::operation::LowerInfo *lower_info)
-      : subgraph{std::move(subgraph)}, lower_info{lower_info}
+  Element(const model::operation::Subgraph *subgraph, const graph::operation::LowerInfo *lower_info)
+      : subgraph{subgraph}, lower_info{lower_info}
   {
     // DO NOTHING
   }
@@ -67,7 +64,9 @@ class Linear
 {
 public:
   // TODO Change std::shared_ptr<Model> instead of Graph
-  Linear(const graph::Graph &graph, std::unique_ptr<graph::LowerInfoMap> lower_info_map);
+  Linear(const graph::Graph &graph,
+         std::unique_ptr<std::vector<std::unique_ptr<model::operation::Subgraph>>> subg_set,
+         std::unique_ptr<graph::LowerInfoMap> lower_info_map);
 
 public:
   Linear(const Linear &linear) = delete;
@@ -81,17 +80,21 @@ public:
   void iterate(const std::function<void(const Element &element)> &fn) const;
 
   std::unique_ptr<graph::LowerInfoMap> releaseLowerInfo() { return std::move(_lower_info_map); }
-
   graph::LowerInfoMap *getLowerInfo() { return _lower_info_map.get(); }
 
+  std::unique_ptr<std::vector<std::unique_ptr<model::operation::Subgraph>>> releaseSubgraphSet()
+  {
+    return std::move(_subg_set);
+  }
+
 private:
   // TODO Replace these getLowerInfo methods with ones of LowerInfoMap in the future
   const graph::operation::LowerInfo *getLowerInfo(const model::operation::Index &index) const;
-
   const graph::operand::LowerInfo *getLowerInfo(const model::operand::Index &index) const;
 
 private:
   const graph::Graph &_graph;
+  std::unique_ptr<std::vector<std::unique_ptr<model::operation::Subgraph>>> _subg_set;
   std::unique_ptr<graph::LowerInfoMap> _lower_info_map;
   std::vector<Element> _elements;
 };