forked from PaddlePaddle/Paddle
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add piano graph executor (PaddlePaddle#36)
* add piano graph executor * change VarType_Type to VarType::Type * add single test script * complete some test script * add enforce at convert vartype * fix some bug and merge meta op PR change * fix VarType2NoteType bug * improve and perfect test script * use vector instead of unordered_set * perfect topo sort by @wzzju 's review advise * fix get var data type problem * fix print string not c-string bug * perfect PianoGraphExecutor class structure by @wzzju 's review advise * optimize vartype utils by wzzju 's advice * fix some potential problem
- Loading branch information
Showing
8 changed files
with
640 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
paddle/fluid/compiler/paddle2piano/piano_graph_executor.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
/* Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. */ | ||
|
||
#include "paddle/fluid/compiler/paddle2piano/piano_graph_executor.h" | ||
|
||
#include <memory> | ||
#include <queue> | ||
#include <unordered_map> | ||
#include <unordered_set> | ||
|
||
#include "paddle/fluid/compiler/paddle2piano/piano_op_kernel_context.h" | ||
#include "paddle/fluid/compiler/paddle2piano/vartype_utils.h" | ||
#include "paddle/fluid/compiler/piano/symbolization/meta_op.h" | ||
#include "paddle/fluid/platform/enforce.h" | ||
|
||
namespace paddle { | ||
namespace piano { | ||
|
||
using framework::ir::Node; | ||
using GraphNodeVec = PianoGraphExecutor::GraphNodeVec; | ||
|
||
std::unique_ptr<PianoScope> PianoGraphExecutor::CreateInputOperand( | ||
symbolization::NoteBuilder* builder) const { | ||
std::unique_ptr<PianoScope> scope = std::make_unique<PianoScope>(); | ||
for (int64_t id = 0; id < cluster_inputs_.size(); ++id) { | ||
auto* node = cluster_inputs_.at(id); | ||
PADDLE_ENFORCE_EQ(node->IsVar(), true, | ||
platform::errors::InvalidArgument( | ||
"Cluster Sub-Graph Input should be var")); | ||
|
||
const auto& var_name = node->Name(); | ||
|
||
// create operand shape | ||
const auto& var_shape = node->Var()->GetShape(); | ||
const auto& var_type = utils::GetVarDataType(node->Var()); | ||
|
||
// convert framework vartype to piano note type | ||
note::ElementTypeProto element_type = utils::VarType2NoteType(var_type); | ||
Shape operand_shape(element_type, var_shape); | ||
|
||
// create Operand | ||
symbolization::Operand op = | ||
symbolization::Parameter(builder, id, operand_shape, var_name); | ||
|
||
// store into PianoScope | ||
scope->SetOperand(var_name, op); | ||
} | ||
return scope; | ||
} | ||
|
||
GraphNodeVec PianoGraphExecutor::SortInternalCluster() const { | ||
GraphNodeVec cluster_sorted; | ||
std::unordered_set<Node*> cluster_set(cluster_.cbegin(), cluster_.cend()); | ||
|
||
std::unordered_map<Node*, size_t> indegree; | ||
std::unordered_map<Node*, std::unordered_map<Node*, size_t>> adj_list; | ||
std::queue<Node*> topo_queue; | ||
|
||
// record all op's input op and output op | ||
for (auto* n : cluster_) { | ||
PADDLE_ENFORCE_EQ(n->IsOp(), true, | ||
platform::errors::PreconditionNotMet( | ||
"Cluster's node all should be op node")); | ||
PADDLE_ENFORCE_EQ(PianoOpRegistry::IsPianoOp(n->Name()), true, | ||
platform::errors::PreconditionNotMet( | ||
"Cluster's op all should be piano op")); | ||
// the op's input is var | ||
for (auto* in_var : n->inputs) { | ||
// the var's input is op | ||
for (auto* in_op : in_var->inputs) { | ||
if (cluster_set.find(in_op) != cluster_set.end()) { | ||
++indegree[n]; | ||
++adj_list[in_op][n]; | ||
} | ||
} | ||
} | ||
} | ||
|
||
// find topology entrance | ||
for (auto* n : cluster_) { | ||
if (indegree[n] == 0) { | ||
topo_queue.push(n); | ||
} | ||
} | ||
|
||
// topological sorting | ||
while (!topo_queue.empty()) { | ||
auto* cur_op = topo_queue.front(); | ||
topo_queue.pop(); | ||
|
||
cluster_sorted.emplace_back(cur_op); | ||
for (const auto& adj_pair : adj_list[cur_op]) { | ||
// decrease output op's in-degree | ||
indegree.at(adj_pair.first) -= adj_pair.second; | ||
|
||
// if empty, push into queue | ||
if (indegree.at(adj_pair.first) == 0) { | ||
topo_queue.push(adj_pair.first); | ||
} | ||
} | ||
} | ||
|
||
PADDLE_ENFORCE_EQ(cluster_sorted.size(), cluster_.size(), | ||
platform::errors::PreconditionNotMet( | ||
"Cluster Sub-Graph shouldn't contain cycle.")); | ||
return cluster_sorted; | ||
} | ||
|
||
void PianoGraphExecutor::RunCompile(const GraphNodeVec& cluster, | ||
PianoScope* scope, | ||
symbolization::NoteBuilder* builder) const { | ||
for (auto* n : cluster) { | ||
const auto& op_name = n->Name(); | ||
const auto* op_desc = n->Op(); | ||
|
||
const auto& op_kernel_map = PianoOpRegistry::AllPianoOpKernels(op_name); | ||
// TODO(jiangcheng05): how to distinguish library's kernel, like cudnn? | ||
op_kernel_map.at("PLAIN")(PianoOpKernelContext(op_desc, scope, builder)); | ||
} | ||
} | ||
|
||
note::ModuleProto PianoGraphExecutor::operator()() const { | ||
// Step1: create unique NoteBuilder | ||
std::string builder_name = "NoteBuilderOfGraph_"; | ||
builder_name.append(std::to_string(graph_id_)); | ||
|
||
symbolization::NoteBuilder builder(builder_name); | ||
|
||
// Step2: create graph's input operand | ||
auto scope = CreateInputOperand(&builder); | ||
|
||
// Step3: topo sort graph | ||
// rvalue references avoid useless copy | ||
const auto& cluster_sorted = SortInternalCluster(); | ||
|
||
// Step4: get PianoOpKernel and run compile | ||
RunCompile(cluster_sorted, scope.get(), &builder); | ||
|
||
// Step5: build and return module | ||
return builder.Build(); | ||
} | ||
|
||
} // namespace piano | ||
} // namespace paddle |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. */ | ||
|
||
#pragma once | ||
|
||
#include <vector> | ||
|
||
#include "paddle/fluid/compiler/paddle2piano/piano_scope.h" | ||
#include "paddle/fluid/compiler/piano/note/note.pb.h" | ||
#include "paddle/fluid/compiler/piano/symbolization/note_builder.h" | ||
#include "paddle/fluid/framework/ir/node.h" | ||
|
||
namespace paddle { | ||
namespace piano { | ||
|
||
// An executor accept sub-graph which is generated by PianoCompilePass, | ||
// run each op's PianoOpKernel, finally return the graph's ModuleProto. | ||
// | ||
// Parameter: | ||
// 1. graph_id: the unique graph id, used for generating unique notebuilder name | ||
// 2. cluster: a vector which contains all graph op, non-topological-sorting. | ||
// 3. cluster_inputs: a vector which contains all graph's input var, the var's | ||
// input are outside op, the output are inside op | ||
// 4. cluster_outputs: a vector which contains all graph's output var, the var's | ||
// input are inside op, the output are outside op | ||
// 5. cluster_internals: a vector which contains all graph's internal var, the | ||
// var's input and output are inside op | ||
// | ||
// Example: | ||
// -------------------------> op3 -> var4 -> | ||
// / / | ||
// -> var1 -> op1 -> var2 -> op2 -> var3 | ||
// | ||
// cluster: [op1, op2, op3] | ||
// cluster_inputs: [var1] | ||
// cluster_outputs: [var4] | ||
// cluster_internals: [var2, var3] | ||
// | ||
// Describe: | ||
// The executor consisted by the following step: | ||
// 1. create a NoteBuilder, it's name is unique for each graph | ||
// 2. create PianoScope, initially, scope only consist graph's input var and its | ||
// operand | ||
// 3. topological sorting graph | ||
// 4. create PianoOpKernelContext and run each op's PianoOpKernel | ||
// 5. run NoteBuilder's Build function to generate graph's ModuleProto | ||
class PianoGraphExecutor { | ||
public: | ||
using GraphNodeVec = std::vector<framework::ir::Node*>; | ||
|
||
PianoGraphExecutor(int64_t graph_id, const GraphNodeVec& cluster, | ||
const GraphNodeVec& cluster_inputs, | ||
const GraphNodeVec& cluster_outputs, | ||
const GraphNodeVec& cluster_internals) | ||
: graph_id_(graph_id), | ||
cluster_(cluster), | ||
cluster_inputs_(cluster_inputs), | ||
cluster_outputs_(cluster_outputs), | ||
cluster_internals_(cluster_internals) {} | ||
|
||
note::ModuleProto operator()() const; | ||
|
||
private: | ||
const int64_t graph_id_; | ||
const GraphNodeVec& cluster_; | ||
const GraphNodeVec& cluster_inputs_; | ||
const GraphNodeVec& cluster_outputs_; | ||
const GraphNodeVec& cluster_internals_; | ||
|
||
// create graph's input operand from cluster_inputs_ | ||
// why return std::unique_ptr ? PianoScope DISABLE_COPY_AND_ASSIGN | ||
std::unique_ptr<PianoScope> CreateInputOperand( | ||
symbolization::NoteBuilder* builder) const; | ||
|
||
// run PianoOpKernel's Compile | ||
void RunCompile(const GraphNodeVec& cluster, PianoScope* scope, | ||
symbolization::NoteBuilder* builder) const; | ||
|
||
// topologic sorting graph node | ||
GraphNodeVec SortInternalCluster() const; | ||
}; | ||
|
||
} // namespace piano | ||
} // namespace paddle |
Oops, something went wrong.