remove net op and cond_op (#9663)
* remove net op and cond_op * fix cpplint * fix dependency * delete backward_test; fix compile * disable batch_norm backward * rm test_net.py * make batchnorm test independent of backward.cc * make test_layer_norm_op independent of backward.cc * make test_layer_norm_op independent of backward.cc * delete unused code * clean upwangkuiyi-patch-2
parent
8d3ce01f36
commit
b26f505002
File diff suppressed because it is too large
Load Diff
@ -1,235 +0,0 @@
|
|||||||
/* Copyright (c) 2016 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/operators/cond_op.h"
|
|
||||||
#include "paddle/fluid/operators/gather.h"
|
|
||||||
#include "paddle/fluid/operators/scatter.h"
|
|
||||||
#include "paddle/fluid/platform/device_context.h"
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace operators {
|
|
||||||
|
|
||||||
using Scope = framework::Scope;
|
|
||||||
using Variable = framework::Variable;
|
|
||||||
using Tensor = framework::Tensor;
|
|
||||||
using LoDTensor = framework::LoDTensor;
|
|
||||||
using DDim = framework::DDim;
|
|
||||||
|
|
||||||
framework::Scope& CondOp::AddSubScope(const Scope& scope) const {
|
|
||||||
auto sub_scopes_var = scope.FindVar("SubScopes");
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(sub_scopes_var,
|
|
||||||
"Output(SubScopes) of CondOp should not be null.");
|
|
||||||
auto sub_scopes = sub_scopes_var->GetMutable<std::vector<Scope*>>();
|
|
||||||
auto& sub_scope = scope.NewScope();
|
|
||||||
sub_scopes->push_back(&sub_scope);
|
|
||||||
return sub_scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<framework::Scope*>& CondOp::GetSubScopes(
|
|
||||||
const framework::Scope& scope) const {
|
|
||||||
auto sub_scopes_var = scope.FindVar("SubScopes");
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(sub_scopes_var,
|
|
||||||
"Output(SubScopes) of CondOp should not be null.");
|
|
||||||
return *sub_scopes_var->GetMutable<std::vector<framework::Scope*>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
LoDTensor& CondOp::AddIndexTensor(const Scope& scope) const {
|
|
||||||
auto index_tensors_var = scope.FindVar("IndexTensors");
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(index_tensors_var,
|
|
||||||
"Output(IndexTensors) of CondOp should not be null.");
|
|
||||||
auto& index_tensors =
|
|
||||||
*index_tensors_var->GetMutable<std::vector<LoDTensor>>();
|
|
||||||
index_tensors.push_back(LoDTensor());
|
|
||||||
return index_tensors.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<framework::LoDTensor>& CondOp::GetIndexTensors(
|
|
||||||
const framework::Scope& scope) const {
|
|
||||||
auto* index_tensors_var = scope.FindVar("IndexTensors");
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(index_tensors_var,
|
|
||||||
"Output(IndexTensors) of CondOp should not be null.");
|
|
||||||
return *index_tensors_var->GetMutable<std::vector<framework::LoDTensor>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CondOp::PrepareDataForSubnet(
|
|
||||||
const framework::Scope& scope,
|
|
||||||
const platform::DeviceContext& dev_ctx) const {
|
|
||||||
PADDLE_ENFORCE(!Inputs("Xs").empty(), "Inputs(Xs) of CondOp can't be empty.");
|
|
||||||
|
|
||||||
for (int i = 0; i < BRANCH_NUM; ++i) {
|
|
||||||
// Create two sub scopes for true and false branches
|
|
||||||
// sub_scopes[0] for the true branch
|
|
||||||
// sub_scopes[1] for the false branch
|
|
||||||
AddSubScope(scope);
|
|
||||||
// Create two tensors for true and false indices:
|
|
||||||
// index_tensors[0] for the true branch
|
|
||||||
// index_tensors[1] for the false branch
|
|
||||||
AddIndexTensor(scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
Variable* cond_var = scope.FindVar(Input("Cond"));
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(cond_var,
|
|
||||||
"Input(Cond) of CondOp should not be null.");
|
|
||||||
const LoDTensor* cond = cond_var->GetMutable<LoDTensor>();
|
|
||||||
|
|
||||||
// get the true/false index at runtime according to cond tensor
|
|
||||||
// index_vectors[0]: vector<int>, contains all index for cond[i] == true
|
|
||||||
// index_vectors[1]: vector<int>, contains all index for cond[i] == false
|
|
||||||
std::vector<std::vector<int>> index_vectors;
|
|
||||||
index_vectors.resize(BRANCH_NUM);
|
|
||||||
|
|
||||||
const int* cond_data = cond->data<int>();
|
|
||||||
for (int i = 0; i < cond->dims()[0]; ++i) {
|
|
||||||
if (cond_data[i])
|
|
||||||
index_vectors[TRUE_BRANCH].push_back(i);
|
|
||||||
else
|
|
||||||
index_vectors[FALSE_BRANCH].push_back(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// put index_vectors[0] and index_vectors[1] into two tensors:
|
|
||||||
// index_tensors[0] and index_tensors[1]
|
|
||||||
std::vector<framework::LoDTensor>& index_tensors = GetIndexTensors(scope);
|
|
||||||
std::vector<framework::Scope*>& sub_scopes = GetSubScopes(scope);
|
|
||||||
|
|
||||||
for (int i = 0; i < BRANCH_NUM; ++i) {
|
|
||||||
DDim dim = {static_cast<int64_t>(index_vectors[i].size())};
|
|
||||||
int* index_tensor_data_ptr =
|
|
||||||
index_tensors[i].mutable_data<int>(dim, platform::CPUPlace());
|
|
||||||
memcpy(index_tensor_data_ptr, index_vectors[i].data(),
|
|
||||||
dim[0] * sizeof(int));
|
|
||||||
}
|
|
||||||
|
|
||||||
// create input in subscopes according to index_vectors
|
|
||||||
for (auto& input : Inputs("Xs")) {
|
|
||||||
Variable* var_parent = scope.FindVar(input);
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(var_parent);
|
|
||||||
const auto* tensor_parent = &var_parent->Get<LoDTensor>();
|
|
||||||
|
|
||||||
for (int i = 0; i < BRANCH_NUM; ++i) {
|
|
||||||
Variable* var_child = sub_scopes[i]->FindVar(input);
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(var_child);
|
|
||||||
auto* tensor_child = var_child->GetMutable<LoDTensor>();
|
|
||||||
|
|
||||||
// Resize child
|
|
||||||
DDim dim = tensor_parent->dims();
|
|
||||||
dim[0] = index_tensors[i].dims()[0];
|
|
||||||
tensor_child->mutable_data<float>(dim, platform::CPUPlace());
|
|
||||||
|
|
||||||
CPUGather<float>(dev_ctx, *tensor_parent, index_tensors[i], tensor_child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create output_tensors in subscope for sub_net
|
|
||||||
for (int i = 0; i < BRANCH_NUM; ++i) {
|
|
||||||
for (auto& output : (*sub_net_op_[i]).Outputs()) {
|
|
||||||
for (auto& var_name : output.second) {
|
|
||||||
sub_scopes[i]->Var(var_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CondOp::MergeDataFromSubnet(const framework::Scope& scope,
|
|
||||||
const platform::DeviceContext& dev_ctx) const {
|
|
||||||
std::vector<framework::Scope*>& sub_scopes = GetSubScopes(scope);
|
|
||||||
const std::vector<framework::LoDTensor>& index_tensors =
|
|
||||||
GetIndexTensors(scope);
|
|
||||||
|
|
||||||
// Infer the output dim, out_dim[0] = true_dim[0] + false_dim[0]
|
|
||||||
PADDLE_ENFORCE(!Outputs("Outs").empty(),
|
|
||||||
"Outputs(Outs) of CondOp can't be empty.");
|
|
||||||
for (auto& output : Outputs("Outs")) {
|
|
||||||
const LoDTensor* tensor_t_out =
|
|
||||||
&sub_scopes[TRUE_BRANCH]->FindVar(output)->Get<LoDTensor>();
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(tensor_t_out, "True output should not be NULL");
|
|
||||||
const LoDTensor* tensor_f_out =
|
|
||||||
&sub_scopes[FALSE_BRANCH]->FindVar(output)->Get<LoDTensor>();
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(tensor_f_out, "False output should not be NULL");
|
|
||||||
|
|
||||||
auto* var_out = scope.FindVar(output);
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(var_out, "Output not found");
|
|
||||||
LoDTensor* tensor_out = var_out->GetMutable<LoDTensor>();
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(tensor_t_out,
|
|
||||||
"True output tensor should not be NULL");
|
|
||||||
|
|
||||||
DDim true_dim = tensor_t_out->dims();
|
|
||||||
DDim false_dim = tensor_f_out->dims();
|
|
||||||
true_dim[0] = 0;
|
|
||||||
false_dim[0] = 0;
|
|
||||||
PADDLE_ENFORCE_EQ(true_dim, false_dim,
|
|
||||||
"Outputs not of the same shape except the first dim");
|
|
||||||
|
|
||||||
DDim out_dim = tensor_t_out->dims();
|
|
||||||
out_dim[0] = tensor_t_out->dims()[0] + tensor_f_out->dims()[0];
|
|
||||||
tensor_out->Resize(out_dim);
|
|
||||||
tensor_out->mutable_data<float>(platform::CPUPlace());
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge output results:
|
|
||||||
// output_tensor = true_output_tensor + false_output_tensor
|
|
||||||
for (auto& output : Outputs("Outs")) {
|
|
||||||
Variable* var_parent = scope.FindVar(output);
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(var_parent);
|
|
||||||
auto* tensor_parent = var_parent->GetMutable<LoDTensor>();
|
|
||||||
|
|
||||||
for (int i = 0; i < BRANCH_NUM; ++i) {
|
|
||||||
Variable* var_child = sub_scopes[i]->FindVar(output);
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(var_child);
|
|
||||||
auto* tensor_child = &var_child->Get<LoDTensor>();
|
|
||||||
ScatterAssign<float>(dev_ctx, *tensor_child, index_tensors[i],
|
|
||||||
tensor_parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CondOp::RunImpl(const Scope& scope, const platform::Place& place) const {
|
|
||||||
// get device context from pool
|
|
||||||
platform::DeviceContextPool& pool = platform::DeviceContextPool::Instance();
|
|
||||||
auto& dev_ctx = *pool.Get(place);
|
|
||||||
|
|
||||||
PrepareDataForSubnet(scope, dev_ctx);
|
|
||||||
std::vector<framework::Scope*>& sub_scopes = GetSubScopes(scope);
|
|
||||||
for (int i = 0; i < BRANCH_NUM; ++i) {
|
|
||||||
sub_net_op_[i]->Run(*sub_scopes[i], place);
|
|
||||||
}
|
|
||||||
MergeDataFromSubnet(scope, dev_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
class CondOpProtoAndCheckerMaker : public framework::OpProtoAndCheckerMaker {
|
|
||||||
public:
|
|
||||||
CondOpProtoAndCheckerMaker(OpProto* proto, OpAttrChecker* op_checker)
|
|
||||||
: OpProtoAndCheckerMaker(proto, op_checker) {
|
|
||||||
AddInput("Cond", "The condition, which is a bool vector");
|
|
||||||
AddInput("Xs", "Inputs of Subnets").AsDuplicable();
|
|
||||||
AddOutput("Outs", "Outputs of Cond_Op after merge").AsDuplicable();
|
|
||||||
|
|
||||||
AddOutput("SubScopes", "sub scopes for true and false branches");
|
|
||||||
AddOutput("IndexTensors", "Index Tensors contains indices for true/false");
|
|
||||||
|
|
||||||
AddComment(R"DOC(
|
|
||||||
Sample Dependent Conditional Operator.
|
|
||||||
|
|
||||||
Given Cond[i] as a 1/0 vector to indicate true/false:
|
|
||||||
Out[i] = subnet_true[i], if Cond[i] == true
|
|
||||||
Out[i] = subnet_false[i], if Cond[i] == false
|
|
||||||
|
|
||||||
)DOC");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace operators
|
|
||||||
} // namespace paddle
|
|
||||||
|
|
||||||
REGISTER_OP_WITHOUT_GRADIENT(cond, paddle::operators::CondOp,
|
|
||||||
paddle::operators::CondOpProtoAndCheckerMaker);
|
|
@ -1,96 +0,0 @@
|
|||||||
/* Copyright (c) 2016 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 <string>
|
|
||||||
#include <vector>
|
|
||||||
#include "glog/logging.h"
|
|
||||||
#include "paddle/fluid/framework/ddim.h"
|
|
||||||
#include "paddle/fluid/framework/eigen.h"
|
|
||||||
#include "paddle/fluid/framework/operator.h"
|
|
||||||
#include "paddle/fluid/framework/tensor.h"
|
|
||||||
#include "paddle/fluid/operators/net_op.h"
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace operators {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief CondOp is a dynamic if-else Operator
|
|
||||||
*
|
|
||||||
* It has a input tensor named cond indicating which netop each instance will
|
|
||||||
* run.
|
|
||||||
*
|
|
||||||
* if cond == 1, it will run true_net, which is a NetOp.
|
|
||||||
*
|
|
||||||
* if cond == 0, it will run false_net, which is another NetOp.
|
|
||||||
*/
|
|
||||||
class CondOp : public framework::OperatorBase {
|
|
||||||
public:
|
|
||||||
CondOp(const std::string& type, const framework::VariableNameMap& inputs,
|
|
||||||
const framework::VariableNameMap& outputs,
|
|
||||||
const framework::AttributeMap& attrs)
|
|
||||||
: OperatorBase(type, inputs, outputs, attrs) {
|
|
||||||
sub_net_op_.resize(BRANCH_NUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
CondOp(const CondOp& o)
|
|
||||||
: framework::OperatorBase(
|
|
||||||
static_cast<const framework::OperatorBase&>(o)) {
|
|
||||||
// TODO(yuyang18): Implement copy ctor well.
|
|
||||||
PADDLE_THROW("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
framework::Scope& AddSubScope(const framework::Scope& scope) const;
|
|
||||||
std::vector<framework::Scope*>& GetSubScopes(
|
|
||||||
const framework::Scope& scope) const;
|
|
||||||
|
|
||||||
framework::LoDTensor& AddIndexTensor(const framework::Scope& scope) const;
|
|
||||||
std::vector<framework::LoDTensor>& GetIndexTensors(
|
|
||||||
const framework::Scope& scope) const;
|
|
||||||
|
|
||||||
void PrepareDataForSubnet(const framework::Scope& scope,
|
|
||||||
const platform::DeviceContext& dev_ctx) const;
|
|
||||||
void MergeDataFromSubnet(const framework::Scope& scope,
|
|
||||||
const platform::DeviceContext& dev_ctx) const;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set True Block
|
|
||||||
*/
|
|
||||||
void set_truenet(std::unique_ptr<OperatorBase>&& net) {
|
|
||||||
sub_net_op_[TRUE_BRANCH] = std::move(net);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set False Block
|
|
||||||
*/
|
|
||||||
void set_falsenet(std::unique_ptr<OperatorBase>&& net) {
|
|
||||||
sub_net_op_[FALSE_BRANCH] = std::move(net);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RunImpl(const framework::Scope& scope,
|
|
||||||
const platform::Place& place) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const int TRUE_BRANCH = 0;
|
|
||||||
const int FALSE_BRANCH = 1;
|
|
||||||
const int BRANCH_NUM = 2;
|
|
||||||
|
|
||||||
// sub_net_op_[0]: subnet_t
|
|
||||||
// sub_net_op_[1]: subnet_f
|
|
||||||
std::vector<std::unique_ptr<framework::OperatorBase>> sub_net_op_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace operators
|
|
||||||
} // namespace paddle
|
|
@ -1,103 +0,0 @@
|
|||||||
// Copyright (c) 2018 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/operators/net_op.h"
|
|
||||||
#include <set>
|
|
||||||
#include "paddle/fluid/framework/op_registry.h"
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace operators {
|
|
||||||
|
|
||||||
const char NetOp::kAll[] = "all";
|
|
||||||
|
|
||||||
void NetOp::CompleteAddOp(bool calc) {
|
|
||||||
add_op_done_ = true;
|
|
||||||
if (!calc) return;
|
|
||||||
std::set<std::string> input_set;
|
|
||||||
std::set<std::string> output_set;
|
|
||||||
for (auto& op : ops_) {
|
|
||||||
for (auto& ipt : op->Inputs()) {
|
|
||||||
for (auto& var_name : ipt.second) {
|
|
||||||
// If input variable has been in output set, then it will be
|
|
||||||
// added into intermediate_outputs_. Otherwise, it will be
|
|
||||||
// added into input set.
|
|
||||||
if (Contains(output_set, var_name)) {
|
|
||||||
intermediate_outputs_.insert(var_name);
|
|
||||||
} else {
|
|
||||||
input_set.insert(var_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& opt : op->Outputs()) {
|
|
||||||
for (auto& var_name : opt.second) {
|
|
||||||
output_set.insert(var_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto& inputs = inputs_[kAll];
|
|
||||||
inputs.reserve(input_set.size());
|
|
||||||
std::copy(input_set.begin(), input_set.end(), std::back_inserter(inputs));
|
|
||||||
auto& outputs = outputs_[kAll];
|
|
||||||
outputs.reserve(output_set.size());
|
|
||||||
std::copy(output_set.begin(), output_set.end(), std::back_inserter(outputs));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string NetOp::DebugStringEx(const framework::Scope* scope) const {
|
|
||||||
std::ostringstream os;
|
|
||||||
os << OperatorBase::DebugStringEx(scope) << std::endl;
|
|
||||||
for (auto& op : ops_) {
|
|
||||||
std::istringstream is(op->DebugStringEx(scope));
|
|
||||||
for (std::string line; std::getline(is, line);) {
|
|
||||||
os << " " << line << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return os.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NetOp::IsNetOp() const { return true; }
|
|
||||||
|
|
||||||
std::vector<std::string> NetOp::OutputVars(bool has_intermediate) const {
|
|
||||||
std::vector<std::string> all;
|
|
||||||
for (auto& pair : this->outputs_) {
|
|
||||||
for (auto& var_name : pair.second) {
|
|
||||||
all.push_back(var_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (has_intermediate) {
|
|
||||||
return all;
|
|
||||||
}
|
|
||||||
std::vector<std::string> ret_val;
|
|
||||||
for (auto& each : all) {
|
|
||||||
if (!Contains(intermediate_outputs_, each)) {
|
|
||||||
ret_val.push_back(each);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetOp::NetOp(const std::string& type, const framework::VariableNameMap& inputs,
|
|
||||||
const framework::VariableNameMap& outputs,
|
|
||||||
const framework::AttributeMap& attrs)
|
|
||||||
: framework::OperatorBase(type, inputs, outputs, attrs) {}
|
|
||||||
|
|
||||||
std::unique_ptr<framework::OperatorBase> NetOp::Clone() const {
|
|
||||||
PADDLE_ENFORCE(
|
|
||||||
add_op_done_,
|
|
||||||
"Must clone a sealed NetOp, invoke Net::CompleteAddOp before clone");
|
|
||||||
return std::unique_ptr<OperatorBase>(new NetOp(*this));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace operators
|
|
||||||
} // namespace paddle
|
|
@ -1,130 +0,0 @@
|
|||||||
/* Copyright (c) 2016 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 <set>
|
|
||||||
#include "paddle/fluid/framework/framework.pb.h"
|
|
||||||
#include "paddle/fluid/framework/op_registry.h"
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace operators {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Network is also a type of Operator
|
|
||||||
*
|
|
||||||
* It will manage the operators it has.
|
|
||||||
*
|
|
||||||
* Network is the container and controller of a set of operators.
|
|
||||||
|
|
||||||
* A network object knows all Operators belonging to this network. Variables,
|
|
||||||
* which are inputs and outputs of these operators, are created and managed by a
|
|
||||||
* hierarchy of Scope objects.
|
|
||||||
*
|
|
||||||
* This is the base class of network, all the networks should implement the APIs
|
|
||||||
* it defines.
|
|
||||||
*/
|
|
||||||
class NetOp : public framework::OperatorBase {
|
|
||||||
public:
|
|
||||||
static const char kAll[];
|
|
||||||
NetOp()
|
|
||||||
: framework::OperatorBase("plain_net", framework::VariableNameMap{},
|
|
||||||
framework::VariableNameMap{},
|
|
||||||
framework::AttributeMap{}) {}
|
|
||||||
|
|
||||||
NetOp(const std::string& type, const framework::VariableNameMap& inputs,
|
|
||||||
const framework::VariableNameMap& outputs,
|
|
||||||
const framework::AttributeMap& attrs);
|
|
||||||
|
|
||||||
NetOp(const NetOp& o) : framework::OperatorBase(o.type_, {}, {}, o.attrs_) {
|
|
||||||
this->ops_.reserve(o.ops_.size());
|
|
||||||
std::transform(
|
|
||||||
o.ops_.begin(), o.ops_.end(), std::back_inserter(this->ops_),
|
|
||||||
[](const std::unique_ptr<framework::OperatorBase>& op) {
|
|
||||||
return std::unique_ptr<framework::OperatorBase>(op->Clone());
|
|
||||||
});
|
|
||||||
this->CompleteAddOp();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SupportGPU() const override {
|
|
||||||
for (auto& op : ops_) {
|
|
||||||
if (!op->SupportGPU()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppendOp(const framework::OperatorBase& op) { AppendOp(op.Clone()); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Add an operator by ptr
|
|
||||||
*/
|
|
||||||
void AppendOp(std::unique_ptr<framework::OperatorBase> op) {
|
|
||||||
PADDLE_ENFORCE(!add_op_done_,
|
|
||||||
"Cannot AppendOp when this network is sealed");
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(op, "Cannot Insert Null op");
|
|
||||||
ops_.push_back(std::move(op));
|
|
||||||
}
|
|
||||||
|
|
||||||
void InsertOp(size_t pos, std::unique_ptr<framework::OperatorBase> op) {
|
|
||||||
PADDLE_ENFORCE(!add_op_done_,
|
|
||||||
"Cannot InsertOp when this network is sealed");
|
|
||||||
PADDLE_ENFORCE_NOT_NULL(op, "Cannot Insert Null op");
|
|
||||||
PADDLE_ENFORCE_LE(pos, ops_.size(), "Out of range");
|
|
||||||
ops_.insert(ops_.begin() + pos, std::move(op));
|
|
||||||
}
|
|
||||||
|
|
||||||
void InsertOp(size_t pos, const framework::OperatorBase& op) {
|
|
||||||
InsertOp(pos, op.Clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CompleteAddOp(bool calculate = true);
|
|
||||||
|
|
||||||
std::string DebugStringEx(
|
|
||||||
const framework::Scope* scope = nullptr) const override;
|
|
||||||
|
|
||||||
bool IsNetOp() const override;
|
|
||||||
std::vector<std::string> OutputVars(bool has_intermediate) const override;
|
|
||||||
|
|
||||||
std::unique_ptr<framework::OperatorBase> Clone() const override;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<framework::OperatorBase>> ops_;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* @brief Run the network.
|
|
||||||
*
|
|
||||||
* Run all the operators with the `scope`, if no scope is provided, default
|
|
||||||
* scope will be used instead. If no OpContext is provicded, default context
|
|
||||||
* will be used.
|
|
||||||
*/
|
|
||||||
void RunImpl(const framework::Scope& scope,
|
|
||||||
const platform::Place& place) const override {
|
|
||||||
for (auto& op : ops_) {
|
|
||||||
op->Run(scope, place);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool add_op_done_{false};
|
|
||||||
std::set<std::string> intermediate_outputs_;
|
|
||||||
|
|
||||||
template <typename T, typename KeyType>
|
|
||||||
static bool Contains(T container, KeyType key) {
|
|
||||||
return container.find(key) != container.end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace operators
|
|
||||||
} // namespace paddle
|
|
@ -1,103 +0,0 @@
|
|||||||
// Copyright (c) 2018 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/operators/net_op.h"
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace operators {
|
|
||||||
using Scope = framework::Scope;
|
|
||||||
using DeviceContext = platform::DeviceContext;
|
|
||||||
|
|
||||||
static int run_cnt = 0;
|
|
||||||
|
|
||||||
class TestOp : public framework::OperatorBase {
|
|
||||||
public:
|
|
||||||
using framework::OperatorBase::OperatorBase;
|
|
||||||
DEFINE_OP_CLONE_METHOD(TestOp);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RunImpl(const Scope& scope,
|
|
||||||
const platform::Place& place) const override {
|
|
||||||
++run_cnt;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void AssertSameVectorWithoutOrder(const std::vector<T>& expected,
|
|
||||||
const std::vector<T>& actual) {
|
|
||||||
ASSERT_EQ(expected.size(), actual.size());
|
|
||||||
std::unordered_set<T> expected_set;
|
|
||||||
for (auto& tmp : expected) {
|
|
||||||
expected_set.insert(tmp);
|
|
||||||
}
|
|
||||||
for (auto& act : actual) {
|
|
||||||
ASSERT_NE(expected_set.end(), expected_set.find(act));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(OpKernel, all) {
|
|
||||||
auto net = std::make_shared<NetOp>();
|
|
||||||
ASSERT_NE(net, nullptr);
|
|
||||||
|
|
||||||
net->AppendOp(std::unique_ptr<TestOp>(
|
|
||||||
new TestOp("test", {{"X", {"x"}}, {"W", {"w1"}}, {"b", {"b1"}}},
|
|
||||||
{{"Out", {"y"}}}, framework::AttributeMap{})));
|
|
||||||
net->AppendOp(std::unique_ptr<TestOp>(
|
|
||||||
new TestOp("test", {{"X", {"y"}}, {"W", {"w2"}}, {"b", {"b2"}}},
|
|
||||||
{{"Out", {"z"}}}, framework::AttributeMap{})));
|
|
||||||
|
|
||||||
net->CompleteAddOp();
|
|
||||||
AssertSameVectorWithoutOrder({"x", "w1", "b1", "w2", "b2"},
|
|
||||||
net->Inputs(NetOp::kAll));
|
|
||||||
AssertSameVectorWithoutOrder({"y", "z"}, net->Outputs(NetOp::kAll));
|
|
||||||
|
|
||||||
auto final_outs = net->OutputVars(false);
|
|
||||||
|
|
||||||
ASSERT_EQ(final_outs.size(), 1UL);
|
|
||||||
ASSERT_EQ(final_outs[0], "z");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(NetOp, insert_op) {
|
|
||||||
NetOp net;
|
|
||||||
auto op1 = std::unique_ptr<framework::NOP>(
|
|
||||||
new framework::NOP("empty", {{"X", {"x"}}, {"W", {"w1"}}, {"b", {"b1"}}},
|
|
||||||
{{"Out", {"y"}}}, framework::AttributeMap{}));
|
|
||||||
net.AppendOp(*op1);
|
|
||||||
net.InsertOp(0, *op1);
|
|
||||||
ASSERT_EQ(2UL, net.ops_.size());
|
|
||||||
net.InsertOp(2, std::move(op1));
|
|
||||||
ASSERT_EQ(3UL, net.ops_.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(NetOp, Clone) {
|
|
||||||
NetOp net;
|
|
||||||
net.AppendOp(std::unique_ptr<framework::NOP>(new framework::NOP{
|
|
||||||
"empty", framework::VariableNameMap{}, framework::VariableNameMap{},
|
|
||||||
framework::AttributeMap{}}));
|
|
||||||
net.AppendOp(std::unique_ptr<framework::NOP>(new framework::NOP{
|
|
||||||
"empty2", framework::VariableNameMap{}, framework::VariableNameMap{},
|
|
||||||
framework::AttributeMap{}}));
|
|
||||||
net.CompleteAddOp(true);
|
|
||||||
auto new_net_op = net.Clone();
|
|
||||||
ASSERT_NE(new_net_op, nullptr);
|
|
||||||
ASSERT_TRUE(new_net_op->IsNetOp());
|
|
||||||
auto* new_net = static_cast<NetOp*>(new_net_op.get());
|
|
||||||
ASSERT_EQ(2UL, new_net->ops_.size());
|
|
||||||
ASSERT_EQ(new_net->ops_[0]->Type(), "empty");
|
|
||||||
ASSERT_EQ(new_net->ops_[1]->Type(), "empty2");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace operators
|
|
||||||
} // namespace paddle
|
|
File diff suppressed because it is too large
Load Diff
@ -1,128 +0,0 @@
|
|||||||
# Copyright (c) 2018 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.
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import paddle.fluid.core as core
|
|
||||||
import unittest
|
|
||||||
import numpy as np
|
|
||||||
from paddle.fluid.op import Operator, CondOp
|
|
||||||
|
|
||||||
|
|
||||||
class PySimpleCond(object):
|
|
||||||
'''
|
|
||||||
A simple implementation of dynamic if-else based on numpy
|
|
||||||
'''
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
array = [1] * 10
|
|
||||||
for i in range(1, 10, 2):
|
|
||||||
array[i] = 0
|
|
||||||
self.cond = np.array(array)
|
|
||||||
self.x = np.ones(shape=(10, 1)).astype("float32")
|
|
||||||
|
|
||||||
def forward(self):
|
|
||||||
self.index_t = np.where(self.cond == 1)
|
|
||||||
self.index_f = np.where(self.cond == 0)
|
|
||||||
y_t = self.x[self.index_t]
|
|
||||||
y_f = self.x[self.index_f]
|
|
||||||
y_t = y_t * 2.
|
|
||||||
y_f = y_f * (-2.)
|
|
||||||
output = np.zeros(shape=(10, 1))
|
|
||||||
output[self.index_t] = y_t
|
|
||||||
output[self.index_f] = y_f
|
|
||||||
return output
|
|
||||||
|
|
||||||
|
|
||||||
class PySimpleCondTest(unittest.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.condnn = PySimpleCond()
|
|
||||||
|
|
||||||
def test_forward(self):
|
|
||||||
output = self.condnn.forward()
|
|
||||||
|
|
||||||
|
|
||||||
def create_tensor(scope, name, shape, np_data):
|
|
||||||
tensor = scope.var(name).get_tensor()
|
|
||||||
tensor.set_dims(shape)
|
|
||||||
tensor.set(np_data, core.CPUPlace())
|
|
||||||
return tensor
|
|
||||||
|
|
||||||
|
|
||||||
class TestCondOp(unittest.TestCase):
|
|
||||||
'''
|
|
||||||
Test CondOp
|
|
||||||
|
|
||||||
equation:
|
|
||||||
cond = [True, False, True, False, ...]
|
|
||||||
y[index_t] = x[index_t] * 2.
|
|
||||||
y[index_f] = x[index_f] * -2.
|
|
||||||
outputs:
|
|
||||||
y
|
|
||||||
'''
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.py_cond = PySimpleCond()
|
|
||||||
|
|
||||||
def forward(self):
|
|
||||||
self.scope = core.Scope()
|
|
||||||
self.create_global_variables()
|
|
||||||
self.create_cond_op()
|
|
||||||
self.create_sub_net()
|
|
||||||
self.condop.run(self.scope, core.CPUPlace())
|
|
||||||
return np.array(self.scope.find_var("Out").get_tensor())
|
|
||||||
|
|
||||||
def create_global_variables(self):
|
|
||||||
x_np_data = self.py_cond.x
|
|
||||||
create_tensor(self.scope, "X", [10, 1], x_np_data)
|
|
||||||
cond_np_data = self.py_cond.cond.astype("int32")
|
|
||||||
create_tensor(self.scope, "cond", [10, 1], cond_np_data)
|
|
||||||
self.scope.var("SubScopes")
|
|
||||||
self.scope.var("IndexTensors")
|
|
||||||
self.scope.var("Out")
|
|
||||||
|
|
||||||
def create_cond_op(self):
|
|
||||||
self.condop = CondOp(
|
|
||||||
Cond="cond",
|
|
||||||
Xs=["X"],
|
|
||||||
Outs=["Out"],
|
|
||||||
SubScopes="SubScopes",
|
|
||||||
IndexTensors="IndexTensors")
|
|
||||||
|
|
||||||
def create_sub_net(self):
|
|
||||||
truenet = core.Net.create()
|
|
||||||
scale_op_t = Operator("scale", X='X', Out='Out', scale=2.)
|
|
||||||
truenet.append_op(scale_op_t)
|
|
||||||
truenet.complete_add_op(True)
|
|
||||||
self.condop.set_truenet(truenet)
|
|
||||||
|
|
||||||
falsenet = core.Net.create()
|
|
||||||
scale_op_t = Operator("scale", X='X', Out='Out', scale=-2.)
|
|
||||||
falsenet.append_op(scale_op_t)
|
|
||||||
falsenet.complete_add_op(True)
|
|
||||||
self.condop.set_falsenet(falsenet)
|
|
||||||
|
|
||||||
def test_forward(self):
|
|
||||||
print 'test cond op forward'
|
|
||||||
pd_output = self.forward()
|
|
||||||
py_output = self.py_cond.forward()
|
|
||||||
print 'pd_output', pd_output
|
|
||||||
print
|
|
||||||
print 'py_output', py_output
|
|
||||||
self.assertEqual(pd_output.shape, py_output.shape)
|
|
||||||
print 'test passed'
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
File diff suppressed because it is too large
Load Diff
@ -1,53 +0,0 @@
|
|||||||
# Copyright (c) 2018 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.
|
|
||||||
|
|
||||||
import paddle.fluid.core as core
|
|
||||||
from paddle.fluid.op import Operator
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
|
|
||||||
def fc(X, W, Y):
|
|
||||||
ret_v = core.Net.create()
|
|
||||||
|
|
||||||
ret_v.append_op(Operator("mul", X="X", Y="W", Out="pre_activation"))
|
|
||||||
ret_v.append_op(Operator("sigmoid", X="pre_activation", Out=Y))
|
|
||||||
ret_v.complete_add_op(True)
|
|
||||||
return ret_v
|
|
||||||
|
|
||||||
|
|
||||||
class TestNet(unittest.TestCase):
|
|
||||||
def test_net_all(self):
|
|
||||||
net = core.Net.create()
|
|
||||||
op1 = Operator("sum", X=["X", "Y"], Out="Out")
|
|
||||||
net.append_op(op1)
|
|
||||||
|
|
||||||
net2 = core.Net.create()
|
|
||||||
net2.append_op(fc(X="X", W="w", Y="fc.out"))
|
|
||||||
net2.complete_add_op(True)
|
|
||||||
net.append_op(net2)
|
|
||||||
net.complete_add_op(True)
|
|
||||||
|
|
||||||
expected = '''
|
|
||||||
Op(plain_net), inputs:{all[W, X, Y]}, outputs:{all[Out, fc.out, pre_activation]}.
|
|
||||||
Op(sum), inputs:{X[X, Y]}, outputs:{Out[Out]}.
|
|
||||||
Op(plain_net), inputs:{all[W, X]}, outputs:{all[fc.out, pre_activation]}.
|
|
||||||
Op(plain_net), inputs:{all[W, X]}, outputs:{all[fc.out, pre_activation]}.
|
|
||||||
Op(mul), inputs:{X[X], Y[W]}, outputs:{Out[pre_activation]}.
|
|
||||||
Op(sigmoid), inputs:{X[pre_activation]}, outputs:{Out[fc.out]}.
|
|
||||||
'''
|
|
||||||
self.assertEqual(expected, "\n" + str(net))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
unittest.main()
|
|
Loading…
Reference in new issue