dot_dumper.dumpIfNeeded("after_lower");
- // linearize with subgraphs
+ // linearize
auto linear = _model->linearize();
_state = State::LINEARIZED;
* 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;
}
* @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}
{
}
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());
#include "graph/LowerInfoMap.h"
#include "backend/interface/IConfig.h"
#include "compiler/TensorInfo.h"
+#include "model/operation/Subgraph.h"
namespace neurun
{
{
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;
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;
{
assert(_phase == Phase::MODEL);
+ partition();
+
// Lower
{
// operand::LowerInfo holder
{
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);
_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
#include "model/operation/Node.h"
#include "model/Model.h"
#include "graph/LowerInfoMap.h"
+#include "model/operation/Subgraph.h"
namespace neurun
{
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();
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
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
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
}
{
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;
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;
};