提交 ce7e503c 编写于 作者: X Xin Pan

refactor to avoid scope.

test=develop
上级 0238a3bb
...@@ -180,6 +180,11 @@ void OperatorBase::Run(const Scope& scope, const platform::Place& place) { ...@@ -180,6 +180,11 @@ void OperatorBase::Run(const Scope& scope, const platform::Place& place) {
VLOG(3) << place << " " << DebugStringEx(&scope); VLOG(3) << place << " " << DebugStringEx(&scope);
} }
void OperatorBase::Run(const RuntimeContext& ctx,
const platform::Place& place) {
RunImpl(ctx, place);
}
bool OperatorBase::HasInputs(const std::string& name) const { bool OperatorBase::HasInputs(const std::string& name) const {
return inputs_.find(name) != inputs_.end(); return inputs_.find(name) != inputs_.end();
} }
...@@ -954,6 +959,51 @@ void OperatorWithKernel::RunImpl(const Scope& scope, ...@@ -954,6 +959,51 @@ void OperatorWithKernel::RunImpl(const Scope& scope,
} }
} }
void OperatorWithKernel::RunImpl(const RuntimeContext& ctx,
const platform::Place& place) const {
Scope scope;
platform::DeviceContextPool& pool = platform::DeviceContextPool::Instance();
auto* dev_ctx = pool.Get(place);
// check if op[type] has kernel registered.
auto& all_op_kernels = AllOpKernels();
auto kernels_iter = all_op_kernels.find(type_);
if (kernels_iter == all_op_kernels.end()) {
PADDLE_THROW(
"There are no kernels which are registered in the %s operator.", type_);
}
OpKernelMap& kernels = kernels_iter->second;
auto expected_kernel_key = this->GetExpectedKernelType(
ExecutionContext(*this, scope, *dev_ctx, ctx));
VLOG(3) << "expected_kernel_key:" << expected_kernel_key;
auto kernel_iter = kernels.find(expected_kernel_key);
#ifdef PADDLE_WITH_MKLDNN
// workaround for missing MKLDNN kernel when FLAGS_use_mkldnn env var is set
if (kernel_iter == kernels.end() &&
expected_kernel_key.library_type_ == LibraryType::kMKLDNN) {
VLOG(3) << "missing MKLDNN kernel: fallbacking to PLAIN one";
expected_kernel_key.library_type_ = LibraryType::kPlain;
expected_kernel_key.data_layout_ = DataLayout::kAnyLayout;
kernel_iter = kernels.find(expected_kernel_key);
}
#endif
if (kernel_iter == kernels.end()) {
PADDLE_THROW("op %s does not have kernel for %s", type_,
KernelTypeToString(expected_kernel_key));
}
if (!(expected_kernel_key.place_ == dev_ctx->GetPlace())) {
dev_ctx = pool.Get(expected_kernel_key.place_);
}
RuntimeInferShapeContext infer_shape_ctx(*this, scope, ctx);
this->InferShape(&infer_shape_ctx);
kernel_iter->second(ExecutionContext(*this, scope, *dev_ctx, ctx));
}
void OperatorWithKernel::TransferInplaceVarsBack( void OperatorWithKernel::TransferInplaceVarsBack(
const Scope& scope, const std::vector<std::string>& inplace_vars, const Scope& scope, const std::vector<std::string>& inplace_vars,
const Scope& transfer_scope) const { const Scope& transfer_scope) const {
...@@ -1041,12 +1091,9 @@ Scope* OperatorWithKernel::PrepareData( ...@@ -1041,12 +1091,9 @@ Scope* OperatorWithKernel::PrepareData(
proto::VarType::Type OperatorWithKernel::IndicateDataType( proto::VarType::Type OperatorWithKernel::IndicateDataType(
const ExecutionContext& ctx) const { const ExecutionContext& ctx) const {
auto& scope = ctx.scope();
int data_type = -1; int data_type = -1;
std::string last_input_name;
for (auto& input : this->inputs_) { for (auto& input : this->inputs_) {
for (auto& ipt_name : input.second) { for (const Variable* var : ctx.MultiInputVar(input.first)) {
auto* var = scope.FindVar(ipt_name);
if (var != nullptr) { if (var != nullptr) {
const Tensor* t = nullptr; const Tensor* t = nullptr;
if (var->IsType<Tensor>()) { if (var->IsType<Tensor>()) {
...@@ -1062,10 +1109,9 @@ proto::VarType::Type OperatorWithKernel::IndicateDataType( ...@@ -1062,10 +1109,9 @@ proto::VarType::Type OperatorWithKernel::IndicateDataType(
int tmp = static_cast<int>(t->type()); int tmp = static_cast<int>(t->type());
PADDLE_ENFORCE( PADDLE_ENFORCE(
tmp == data_type || data_type == -1, tmp == data_type || data_type == -1,
"DataType of Paddle Op %s must be the same. Get %s(%d) != %s(%d)", "DataType of Paddle Op %s must be the same. Get (%d) != (%d)",
Type(), last_input_name, data_type, ipt_name, tmp); Type(), data_type, tmp);
data_type = tmp; data_type = tmp;
last_input_name = ipt_name;
} }
} }
} }
......
...@@ -81,6 +81,10 @@ class RuntimeContext { ...@@ -81,6 +81,10 @@ class RuntimeContext {
RuntimeContext(const VariableNameMap& innames, RuntimeContext(const VariableNameMap& innames,
const VariableNameMap& outnames, const Scope& scope); const VariableNameMap& outnames, const Scope& scope);
RuntimeContext(const VariableValueMap& invars,
const VariableValueMap& outvars)
: inputs(invars), outputs(outvars) {}
VariableValueMap inputs; VariableValueMap inputs;
VariableValueMap outputs; VariableValueMap outputs;
}; };
...@@ -101,6 +105,7 @@ class OperatorBase { ...@@ -101,6 +105,7 @@ class OperatorBase {
/// Executor will call this interface function to Run an op. /// Executor will call this interface function to Run an op.
// The implementation should be written at RunImpl // The implementation should be written at RunImpl
void Run(const Scope& scope, const platform::Place& place); void Run(const Scope& scope, const platform::Place& place);
void Run(const RuntimeContext& ctx, const platform::Place& place);
// FIXME(typhoonzero): this is only used for recv_op to stop event_loop. // FIXME(typhoonzero): this is only used for recv_op to stop event_loop.
virtual void Stop() {} virtual void Stop() {}
...@@ -167,6 +172,9 @@ class OperatorBase { ...@@ -167,6 +172,9 @@ class OperatorBase {
void CheckAllInputOutputSet() const; void CheckAllInputOutputSet() const;
virtual void RunImpl(const Scope& scope, virtual void RunImpl(const Scope& scope,
const platform::Place& place) const = 0; const platform::Place& place) const = 0;
virtual void RunImpl(const RuntimeContext& ctx,
const platform::Place& place) const {}
}; };
class ExecutionContext { class ExecutionContext {
...@@ -458,6 +466,8 @@ class OperatorWithKernel : public OperatorBase { ...@@ -458,6 +466,8 @@ class OperatorWithKernel : public OperatorBase {
// same. // same.
proto::VarType::Type IndicateDataType(const ExecutionContext& ctx) const; proto::VarType::Type IndicateDataType(const ExecutionContext& ctx) const;
void RunImpl(const Scope& scope, const platform::Place& place) const final; void RunImpl(const Scope& scope, const platform::Place& place) const final;
void RunImpl(const RuntimeContext& ctx,
const platform::Place& place) const final;
/** /**
* Transfer data from scope to a transfered scope. If there is no data need to * Transfer data from scope to a transfered scope. If there is no data need to
......
...@@ -31,6 +31,11 @@ using framework::Variable; ...@@ -31,6 +31,11 @@ using framework::Variable;
void AddTo(Variable* src, Variable* dst) { void AddTo(Variable* src, Variable* dst) {
framework::LoDTensor* dst_tensor = dst->GetMutable<framework::LoDTensor>(); framework::LoDTensor* dst_tensor = dst->GetMutable<framework::LoDTensor>();
framework::LoDTensor* src_tensor = src->GetMutable<framework::LoDTensor>(); framework::LoDTensor* src_tensor = src->GetMutable<framework::LoDTensor>();
VLOG(3) << "apply var grad " << src_tensor->data<float>()[0] << " "
<< src_tensor->data<float>()[1] << " "
<< src_tensor->data<float>()[2];
PADDLE_ENFORCE(dst_tensor->numel() == src_tensor->numel(), "%lld vs %lld", PADDLE_ENFORCE(dst_tensor->numel() == src_tensor->numel(), "%lld vs %lld",
dst_tensor->numel(), src_tensor->numel()); dst_tensor->numel(), src_tensor->numel());
float* dst_data = dst_tensor->mutable_data<float>(platform::CPUPlace()); float* dst_data = dst_tensor->mutable_data<float>(platform::CPUPlace());
...@@ -38,16 +43,28 @@ void AddTo(Variable* src, Variable* dst) { ...@@ -38,16 +43,28 @@ void AddTo(Variable* src, Variable* dst) {
for (size_t i = 0; i < src_tensor->numel(); ++i) { for (size_t i = 0; i < src_tensor->numel(); ++i) {
dst_data[i] += src_data[i]; dst_data[i] += src_data[i];
} }
VLOG(3) << "apply var dst grad " << dst_tensor->data<float>()[0] << " "
<< dst_tensor->data<float>()[1] << " "
<< dst_tensor->data<float>()[2];
} }
class Autograd { class Autograd {
public: public:
explicit Autograd(framework::Scope* scope) : scope_(scope) {} Autograd() {}
void RunBackward(VarBase* var) { void RunBackward(VarBase* var) {
PADDLE_ENFORCE(var->pre_op_->op_desc_); PADDLE_ENFORCE(var->pre_op_->op_desc_);
// TODO(panyx0718): Only create for vars that "require_grad" // TODO(panyx0718): Only create for vars that "require_grad"
(*var->pre_op_->output_vars_)[var->pre_op_out_idx_]->grads_ = var->grads_; LOG(ERROR) << reinterpret_cast<void*>(var->grads_) << " vs "
<< reinterpret_cast<void*>(
var->pre_op_
->output_vars_[var->pre_op_out_name_]
[var->pre_op_out_idx_]
->grads_);
var->pre_op_->output_vars_[var->pre_op_out_name_][var->pre_op_out_idx_]
->grads_->GetMutable<framework::LoDTensor>()
->ShareDataWith(var->grads_->Get<framework::LoDTensor>());
std::deque<OpBase*> ready; std::deque<OpBase*> ready;
ready.push_back(var->pre_op_); ready.push_back(var->pre_op_);
...@@ -57,11 +74,15 @@ class Autograd { ...@@ -57,11 +74,15 @@ class Autograd {
while (!ready.empty()) { while (!ready.empty()) {
OpBase* ready_op = ready.front(); OpBase* ready_op = ready.front();
ready.pop_front(); ready.pop_front();
std::vector<Variable*> input_grads = ready_op->ApplyGrad(scope_); std::map<std::string, std::vector<VarBase*>> input_grads =
ready_op->ApplyGrad();
for (size_t i = 0; i < input_grads.size(); ++i) { VLOG(3) << "after apply grad";
if (!input_grads[i]) continue;
OpBase* pre_op = ready_op->pre_ops_->at(i); for (auto it : input_grads) {
const std::vector<VarBase*>& ingrads = it.second;
for (size_t i = 0; i < ingrads.size(); ++i) {
if (!ingrads[i]) continue;
OpBase* pre_op = (*ready_op->pre_ops_)[it.first][i];
if (!pre_op) continue; if (!pre_op) continue;
dep_counts[pre_op] -= 1; dep_counts[pre_op] -= 1;
...@@ -73,6 +94,7 @@ class Autograd { ...@@ -73,6 +94,7 @@ class Autograd {
} }
} }
} }
}
private: private:
std::map<OpBase*, int> ComputeDepCounts(OpBase* op) { std::map<OpBase*, int> ComputeDepCounts(OpBase* op) {
...@@ -85,7 +107,8 @@ class Autograd { ...@@ -85,7 +107,8 @@ class Autograd {
while (!queue.empty()) { while (!queue.empty()) {
OpBase* candidate = queue.front(); OpBase* candidate = queue.front();
queue.pop_front(); queue.pop_front();
for (OpBase* pre_op : *(candidate->pre_ops_)) { for (auto it : *(candidate->pre_ops_)) {
for (OpBase* pre_op : it.second) {
if (!pre_op) continue; if (!pre_op) continue;
if (visited.find(pre_op) == visited.end()) { if (visited.find(pre_op) == visited.end()) {
visited.insert(pre_op); visited.insert(pre_op);
...@@ -94,17 +117,15 @@ class Autograd { ...@@ -94,17 +117,15 @@ class Autograd {
ret[pre_op] += 1; ret[pre_op] += 1;
} }
} }
}
return ret; return ret;
} }
framework::Scope* scope_;
}; };
framework::Variable* CreateVariable(const std::string& name, void CreateVariable(const std::string& name, const framework::DDim& dim,
const framework::DDim& dim, float val, float val, bool random_name, framework::Variable* var) {
framework::Scope* scope, if (var->IsInitialized()) return;
bool random_name = true) {
std::string varname = name; std::string varname = name;
if (random_name) { if (random_name) {
std::mt19937 rng; std::mt19937 rng;
...@@ -116,12 +137,9 @@ framework::Variable* CreateVariable(const std::string& name, ...@@ -116,12 +137,9 @@ framework::Variable* CreateVariable(const std::string& name,
} }
VLOG(3) << "creating var " << varname; VLOG(3) << "creating var " << varname;
framework::Variable* var = scope->Var(varname);
framework::LoDTensor* tensor = var->GetMutable<framework::LoDTensor>(); framework::LoDTensor* tensor = var->GetMutable<framework::LoDTensor>();
float* data = tensor->mutable_data<float>(dim, platform::CPUPlace()); float* data = tensor->mutable_data<float>(dim, platform::CPUPlace());
std::fill(data, data + tensor->numel(), val); std::fill(data, data + tensor->numel(), val);
return var;
} }
framework::LoDTensor& VarBase::Grad() { framework::LoDTensor& VarBase::Grad() {
...@@ -129,94 +147,56 @@ framework::LoDTensor& VarBase::Grad() { ...@@ -129,94 +147,56 @@ framework::LoDTensor& VarBase::Grad() {
return *grads_->GetMutable<framework::LoDTensor>(); return *grads_->GetMutable<framework::LoDTensor>();
} }
void VarBase::ApplyGrad(framework::Scope* scope, Variable* grad) { std::map<std::string, std::vector<VarBase*>> OpBase::ApplyGrad() {
VLOG(3) << "apply var grad " << var_desc_->Name() << " " if (!grad_op_desc_) {
<< grad->Get<framework::LoDTensor>().data<float>()[0]; VLOG(3) << "op with no grad: " << op_desc_->Type();
if (!grads_) { return {};
grads_ = }
CreateVariable(string::Sprintf("%s@IGrad", var_desc_->Name()),
var_->Get<framework::LoDTensor>().dims(), 0.0, scope);
}
AddTo(grad, grads_);
VLOG(3) << "grad_ after apply var grad " << var_desc_->Name() << " "
<< grads_->Get<framework::LoDTensor>().data<float>()[0];
}
std::vector<Variable*> OpBase::ApplyGrad(framework::Scope* scope) {
VLOG(3) << "op grad " << grad_op_desc_->Type(); VLOG(3) << "op grad " << grad_op_desc_->Type();
for (const std::string& grad_invar : grad_op_desc_->InputArgumentNames()) { std::map<std::string, std::vector<framework::Variable*>> grad_outputs;
if (grad_to_var_->find(grad_invar) == grad_to_var_->end()) { for (auto it : grad_output_vars_) {
// grad op inputs can be forward inputs, so not in grad_to_var. auto& outputs = grad_outputs[it.first];
continue; for (size_t i = 0; i < it.second.size(); ++i) {
} outputs.push_back(new framework::Variable());
VLOG(3) << "op grad in var " << grad_invar; outputs.back()->GetMutable<framework::LoDTensor>();
block_->FindRecursiveOrCreateVar(grad_invar); /*
framework::Variable* var = scope->Var(grad_invar); auto& accum_grad_t = it.second[i]->Get<framework::LoDTensor>();
const std::string& invar = grad_to_var_->at(grad_invar); Variable* grad_var = outputs.back();
for (VarBase* varbase : *output_vars_) { float* data = grad_var->GetMutable<framework::LoDTensor>()
// Use the accumulated grads_ by sharing the input with grads_. ->mutable_data<float>(accum_grad_t.dims(), platform::CPUPlace());
if (varbase->var_desc_->Name() == invar) { std::fill(data, data + accum_grad_t.numel(), 0.0);*/
var->GetMutable<framework::LoDTensor>()->ShareDataWith(
varbase->grads_->Get<framework::LoDTensor>());
break;
}
} }
} }
for (const std::string& outvar : grad_op_desc_->OutputArgumentNames()) { framework::RuntimeContext ctx(grad_input_vars_, grad_outputs);
VLOG(3) << "grad outvar " << outvar;
block_->FindRecursiveOrCreateVar(outvar); // grad_op_desc_->InferShape(*block_);
framework::Variable* var = scope->Var(outvar);
if (!var->IsInitialized()) {
framework::VarDesc* var_desc = block_->FindVar(outvar);
if (var_desc->GetType() == framework::proto::VarType::LOD_TENSOR) {
var->GetMutable<framework::LoDTensor>();
} else {
LOG(ERROR) << "tracer doesn't support yet";
}
}
}
grad_op_desc_->InferShape(*block_);
grad_op_desc_->InferVarType(block_); grad_op_desc_->InferVarType(block_);
std::unique_ptr<framework::OperatorBase> opbase = std::unique_ptr<framework::OperatorBase> opbase =
framework::OpRegistry::CreateOp(*grad_op_desc_); framework::OpRegistry::CreateOp(*grad_op_desc_);
opbase->Run(ctx, platform::CPUPlace());
opbase->Run(*scope, platform::CPUPlace()); for (auto it : grad_output_vars_) {
auto& outputs = grad_outputs[it.first];
// `ret` matches exactly with `input_vars_` of forward op. auto& origin_outputs = it.second;
std::vector<Variable*> ret; for (size_t i = 0; i < outputs.size(); ++i) {
for (size_t i = 0; i < input_vars_->size(); ++i) { framework::Variable* orig_grad = origin_outputs[i];
bool found = false; AddTo(outputs[i], orig_grad);
VarBase* origin_var = (*input_vars_)[i]; VLOG(3) << "done add to " << grad_op_desc_->Outputs().at(it.first)[i];
for (const std::string& outvar : grad_op_desc_->OutputArgumentNames()) {
Variable* var = scope->FindVar(outvar);
std::string orig_var = grad_to_var_->at(outvar);
if (origin_var->var_desc_->Name() != orig_var) {
continue;
}
VLOG(3) << "apply grad " << outvar << " with origin " << orig_var;
origin_var->ApplyGrad(scope, var);
found = true;
ret.push_back(var);
// TODO(panyx0718): There might be another outvar with the same name.
// In that case, it doesn't matter the first one or the second one is
// used.
break;
} }
if (!found) {
ret.push_back(nullptr);
} }
} return input_vars_;
return ret;
} }
void VarBase::RunBackward(framework::Scope* scope) { void VarBase::RunBackward() {
grads_ = CreateVariable(framework::GradVarName(var_desc_->Name()), auto grads_t = grads_->GetMutable<framework::LoDTensor>();
var_->Get<framework::LoDTensor>().dims(), 1.0, scope, float* data = grads_t->mutable_data<float>(platform::CPUPlace());
false); std::fill(data, data + grads_t->numel(), 1.0);
if (!pre_op_) return; if (!pre_op_) return;
Autograd(scope).RunBackward(this); Autograd().RunBackward(this);
} }
} // namespace imperative } // namespace imperative
......
...@@ -14,11 +14,11 @@ ...@@ -14,11 +14,11 @@
#pragma once #pragma once
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include "paddle/fluid/framework/op_desc.h" #include "paddle/fluid/framework/op_desc.h"
#include "paddle/fluid/framework/operator.h" #include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/framework/scope.h"
#include "paddle/fluid/framework/var_desc.h" #include "paddle/fluid/framework/var_desc.h"
#include "paddle/fluid/platform/enforce.h" #include "paddle/fluid/platform/enforce.h"
...@@ -33,18 +33,26 @@ class VarBase { ...@@ -33,18 +33,26 @@ class VarBase {
: pre_op_(nullptr), : pre_op_(nullptr),
pre_op_out_idx_(-1), pre_op_out_idx_(-1),
var_desc_(nullptr), var_desc_(nullptr),
var_(nullptr), var_(new framework::Variable()),
grads_(nullptr) {} grads_(new framework::Variable()) {}
virtual ~VarBase() {} virtual ~VarBase() {
if (var_) {
void ApplyGrad(framework::Scope* scope, framework::Variable* grad); delete var_;
var_ = nullptr;
}
if (grads_) {
delete grads_;
grads_ = nullptr;
}
}
void RunBackward(framework::Scope* scope); void RunBackward();
framework::LoDTensor& Grad(); framework::LoDTensor& Grad();
OpBase* pre_op_; OpBase* pre_op_;
std::string pre_op_out_name_;
int pre_op_out_idx_; int pre_op_out_idx_;
framework::VarDesc* var_desc_; framework::VarDesc* var_desc_;
...@@ -55,17 +63,12 @@ class VarBase { ...@@ -55,17 +63,12 @@ class VarBase {
class OpBase { class OpBase {
public: public:
OpBase() OpBase()
: input_vars_(new std::vector<VarBase*>()), : pre_ops_(new std::map<std::string, std::vector<OpBase*>>()),
output_vars_(new std::vector<VarBase*>()), pre_ops_out_idx_(new std::map<std::string, std::vector<int>>()),
pre_ops_(new std::vector<OpBase*>()),
pre_ops_out_idx_(new std::vector<int>()),
op_desc_(nullptr), op_desc_(nullptr),
grad_op_desc_(nullptr) {} grad_op_desc_(nullptr) {}
virtual ~OpBase() { virtual ~OpBase() {
delete input_vars_;
delete output_vars_;
delete pre_ops_; delete pre_ops_;
delete pre_ops_out_idx_; delete pre_ops_out_idx_;
...@@ -73,16 +76,18 @@ class OpBase { ...@@ -73,16 +76,18 @@ class OpBase {
if (grad_to_var_) delete grad_to_var_; if (grad_to_var_) delete grad_to_var_;
} }
std::vector<framework::Variable*> ApplyGrad(framework::Scope* scope); std::map<std::string, std::vector<VarBase*>> ApplyGrad();
std::vector<VarBase*>* input_vars_; std::map<std::string, std::vector<VarBase*>> input_vars_;
std::vector<VarBase*>* output_vars_; std::map<std::string, std::vector<VarBase*>> output_vars_;
std::vector<OpBase*>* pre_ops_; std::map<std::string, std::vector<OpBase*>>* pre_ops_;
std::vector<int>* pre_ops_out_idx_; std::map<std::string, std::vector<int>>* pre_ops_out_idx_;
framework::OpDesc* op_desc_; framework::OpDesc* op_desc_;
framework::OpDesc* grad_op_desc_; framework::OpDesc* grad_op_desc_;
std::unordered_map<std::string, std::string>* grad_to_var_; std::unordered_map<std::string, std::string>* grad_to_var_;
std::map<std::string, std::vector<framework::Variable*>> grad_input_vars_;
std::map<std::string, std::vector<framework::Variable*>> grad_output_vars_;
framework::BlockDesc* block_; framework::BlockDesc* block_;
}; };
......
...@@ -41,6 +41,14 @@ void CreateGradOp(const framework::OpDesc& op_desc, ...@@ -41,6 +41,14 @@ void CreateGradOp(const framework::OpDesc& op_desc,
*grad_op_desc = grad_op_descs[0].release(); *grad_op_desc = grad_op_descs[0].release();
} }
void InitVar(framework::Variable* var, framework::Variable* grad_var) {
auto& var_t = var->Get<framework::LoDTensor>();
float* data =
grad_var->GetMutable<framework::LoDTensor>()->mutable_data<float>(
var_t.dims(), platform::CPUPlace());
std::fill(data, data + var_t.numel(), 0.0);
}
class Tracer { class Tracer {
public: public:
explicit Tracer(framework::BlockDesc* root_block, explicit Tracer(framework::BlockDesc* root_block,
...@@ -53,10 +61,13 @@ class Tracer { ...@@ -53,10 +61,13 @@ class Tracer {
virtual ~Tracer() { delete root_scope_; } virtual ~Tracer() { delete root_scope_; }
void Trace(OpBase* op, const std::vector<VarBase*>& inputs, void Trace(OpBase* op,
const std::vector<VarBase*>& outputs, const std::map<std::string, std::vector<VarBase*>>& inputs,
const std::map<std::string, std::vector<VarBase*>>& outputs,
framework::BlockDesc* block) { framework::BlockDesc* block) {
framework::Scope* scope = GetScope(block); // framework::Scope* scope = GetScope(block);
std::map<std::string, VarBase*> vars;
framework::OpDesc* op_desc = op->op_desc_; framework::OpDesc* op_desc = op->op_desc_;
VLOG(3) << "tracer tracing " << op_desc->Type(); VLOG(3) << "tracer tracing " << op_desc->Type();
op_desc->InferShape(*block); op_desc->InferShape(*block);
...@@ -64,48 +75,60 @@ class Tracer { ...@@ -64,48 +75,60 @@ class Tracer {
std::unique_ptr<framework::OperatorBase> op_base = std::unique_ptr<framework::OperatorBase> op_base =
framework::OpRegistry::CreateOp(*op_desc); framework::OpRegistry::CreateOp(*op_desc);
*op->input_vars_ = inputs; framework::VariableValueMap invars_map;
for (VarBase* input : inputs) { framework::VariableValueMap outvars_map;
const std::string vname = input->var_desc_->Name();
framework::Variable* var = scope->Var(vname); op->input_vars_ = inputs;
input->var_ = var; for (auto it : op->input_vars_) {
if (!var->IsInitialized()) { auto& invars = invars_map[it.first];
framework::VarDesc* var_desc = block->FindVar(vname); for (VarBase* inp : it.second) {
if (var_desc->GetType() == framework::proto::VarType::LOD_TENSOR) { PADDLE_ENFORCE_NOT_NULL(inp->var_, "op %s input %s nullptr",
var->GetMutable<framework::LoDTensor>(); op->op_desc_->Type(), inp->var_desc_->Name());
invars.push_back(inp->var_);
vars[inp->var_desc_->Name()] = inp;
if (inp->pre_op_) {
(*op->pre_ops_)[it.first].push_back(inp->pre_op_);
(*op->pre_ops_out_idx_)[it.first].push_back(inp->pre_op_out_idx_);
} else { } else {
LOG(ERROR) << "tracer doesn't support yet"; (*op->pre_ops_)[it.first].push_back(nullptr);
}
} }
if (input->pre_op_) { VLOG(3) << "input vname " << inp->var_desc_->Name() << " "
op->pre_ops_->push_back(input->pre_op_); << inp->var_->Get<framework::LoDTensor>().dims().size()
op->pre_ops_out_idx_->push_back(input->pre_op_out_idx_); << reinterpret_cast<void*>(inp->var_);
} else {
op->pre_ops_->push_back(nullptr);
} }
VLOG(3) << "input vname " << vname << " "
<< var->Get<framework::LoDTensor>().dims().size();
} }
*op->output_vars_ = outputs; op->output_vars_ = outputs;
for (auto it : op->output_vars_) {
auto& outvars = outvars_map[it.first];
const std::vector<VarBase*>& outputs = it.second;
for (size_t i = 0; i < outputs.size(); ++i) { for (size_t i = 0; i < outputs.size(); ++i) {
const std::string vname = outputs[i]->var_desc_->Name(); VarBase* out = outputs[i];
framework::Variable* var = scope->Var(vname); outvars.push_back(out->var_);
if (!var->IsInitialized()) { vars[out->var_desc_->Name()] = out;
framework::VarDesc* var_desc = block->FindVar(vname);
framework::VarDesc* var_desc = block->FindVar(out->var_desc_->Name());
if (var_desc->GetType() == framework::proto::VarType::LOD_TENSOR) { if (var_desc->GetType() == framework::proto::VarType::LOD_TENSOR) {
var->GetMutable<framework::LoDTensor>(); out->var_->GetMutable<framework::LoDTensor>();
} else { } else {
LOG(ERROR) << "tracer doesn't support yet"; LOG(ERROR) << "tracer doesn't support yet";
} }
out->pre_op_ = op;
out->pre_op_out_name_ = it.first;
out->pre_op_out_idx_ = i;
VLOG(3) << "output vname " << out->var_desc_->Name() << " "
<< out->var_->Get<framework::LoDTensor>().dims().size() << " "
<< reinterpret_cast<void*>(out->var_) << " "
<< out->var_->IsInitialized();
} }
outputs[i]->var_ = var;
outputs[i]->pre_op_ = op;
outputs[i]->pre_op_out_idx_ = i;
} }
VLOG(3) << "tracer running " << op_desc->Type(); VLOG(3) << "tracer running " << op_desc->Type();
op_base->Run(*scope, platform::CPUPlace()); framework::RuntimeContext ctx(invars_map, outvars_map);
op_base->Run(ctx, platform::CPUPlace());
if (block == startup_block_) { if (block == startup_block_) {
op->grad_op_desc_ = nullptr; op->grad_op_desc_ = nullptr;
op->grad_to_var_ = nullptr; op->grad_to_var_ = nullptr;
...@@ -115,6 +138,39 @@ class Tracer { ...@@ -115,6 +138,39 @@ class Tracer {
CreateGradOp(*op_desc, {}, {block}, &grad_op_desc, grad_to_var); CreateGradOp(*op_desc, {}, {block}, &grad_op_desc, grad_to_var);
op->grad_op_desc_ = grad_op_desc; op->grad_op_desc_ = grad_op_desc;
op->grad_to_var_ = grad_to_var; op->grad_to_var_ = grad_to_var;
for (auto it : grad_op_desc->Inputs()) {
auto& grad_in_vars = op->grad_input_vars_[it.first];
for (const std::string& grad_invar : it.second) {
block->FindRecursiveOrCreateVar(grad_invar);
auto var_it = op->grad_to_var_->find(grad_invar);
if (var_it == op->grad_to_var_->end()) {
auto fwd_var_it = vars.find(grad_invar);
PADDLE_ENFORCE(fwd_var_it != vars.end());
grad_in_vars.push_back(fwd_var_it->second->var_);
} else {
VarBase* var = vars[var_it->second];
if (!var->grads_->IsInitialized()) {
InitVar(var->var_, var->grads_);
}
grad_in_vars.push_back(var->grads_);
}
}
}
for (auto it : grad_op_desc->Outputs()) {
auto& grad_out_vars = op->grad_output_vars_[it.first];
for (const std::string& grad_outvar : it.second) {
block->FindRecursiveOrCreateVar(grad_outvar);
auto var_it = op->grad_to_var_->find(grad_outvar);
PADDLE_ENFORCE(var_it != op->grad_to_var_->end());
VarBase* var = vars[var_it->second];
if (!var->grads_->IsInitialized()) {
InitVar(var->var_, var->grads_);
}
LOG(ERROR) << grad_outvar << " map to " << var->var_desc_->Name();
grad_out_vars.push_back(var->grads_);
}
}
} }
op->block_ = block; op->block_ = block;
} }
......
...@@ -68,6 +68,41 @@ class FillConstantOp : public framework::OperatorBase { ...@@ -68,6 +68,41 @@ class FillConstantOp : public framework::OperatorBase {
auto &dev_ctx = *pool.Get(dev_place); auto &dev_ctx = *pool.Get(dev_place);
math::set_constant(dev_ctx, tensor, value); math::set_constant(dev_ctx, tensor, value);
} }
void RunImpl(const framework::RuntimeContext &ctx,
const platform::Place &dev_place) const override {
auto data_type =
static_cast<framework::proto::VarType::Type>(Attr<int>("dtype"));
auto value = Attr<float>("value");
auto force_cpu = Attr<bool>("force_cpu");
framework::Tensor *tensor = nullptr;
auto &out_var = *ctx.outputs.at("Out")[0];
if (out_var.IsType<framework::LoDTensor>()) {
tensor = out_var.GetMutable<framework::LoDTensor>();
tensor->Resize(framework::make_ddim(Attr<std::vector<int64_t>>("shape")));
} else if (out_var.IsType<framework::SelectedRows>()) {
tensor = out_var.GetMutable<framework::SelectedRows>()->mutable_value();
tensor->Resize(framework::make_ddim(Attr<std::vector<int64_t>>("shape")));
} else {
PADDLE_THROW(
"fill constant op's output only"
"supports SelectedRows and LoDTensor");
}
if (force_cpu) {
auto cpu = platform::CPUPlace();
tensor->mutable_data(cpu, data_type);
} else {
tensor->mutable_data(dev_place, data_type);
}
platform::DeviceContextPool &pool = platform::DeviceContextPool::Instance();
auto &dev_ctx = *pool.Get(dev_place);
math::set_constant(dev_ctx, tensor, value);
}
}; };
class FillConstantOpVarTypeInference : public framework::VarTypeInference { class FillConstantOpVarTypeInference : public framework::VarTypeInference {
......
...@@ -124,9 +124,7 @@ PYBIND11_MODULE(core, m) { ...@@ -124,9 +124,7 @@ PYBIND11_MODULE(core, m) {
py::class_<imperative::VarBase, PyVarBase>(m, "VarBase", R"DOC()DOC") py::class_<imperative::VarBase, PyVarBase>(m, "VarBase", R"DOC()DOC")
.def(py::init<>()) .def(py::init<>())
.def("_run_backward", .def("_run_backward",
[](imperative::VarBase &self, framework::Scope *scope) { [](imperative::VarBase &self) { self.RunBackward(); })
self.RunBackward(scope);
})
.def("_grad", &imperative::VarBase::Grad) .def("_grad", &imperative::VarBase::Grad)
.def_property( .def_property(
"desc", "desc",
...@@ -134,6 +132,12 @@ PYBIND11_MODULE(core, m) { ...@@ -134,6 +132,12 @@ PYBIND11_MODULE(core, m) {
[](imperative::VarBase &self, framework::VarDesc *var_desc) { [](imperative::VarBase &self, framework::VarDesc *var_desc) {
self.var_desc_ = var_desc; self.var_desc_ = var_desc;
}, },
py::return_value_policy::reference)
.def_property("var",
[](const imperative::VarBase &self) { return self.var_; },
[](imperative::VarBase &self, framework::Variable *var) {
self.var_ = var;
},
py::return_value_policy::reference); py::return_value_policy::reference);
py::class_<imperative::OpBase, PyOpBase>(m, "OpBase", R"DOC()DOC") py::class_<imperative::OpBase, PyOpBase>(m, "OpBase", R"DOC()DOC")
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
from __future__ import print_function from __future__ import print_function
import collections import collections
from collections import defaultdict
import contextlib import contextlib
import os import os
import re import re
...@@ -369,13 +370,11 @@ class Variable(object): ...@@ -369,13 +370,11 @@ class Variable(object):
self._ivar.desc = self.desc self._ivar.desc = self.desc
def _numpy(self): def _numpy(self):
scope = _imperative_tracer().get_scope(self.block.desc) tensor = self._ivar.var.get_tensor()
tensor = core.get_variable_tensor(scope, self.desc.name())
return np.array(tensor) return np.array(tensor)
def _backward(self): def _backward(self):
scope = _imperative_tracer().get_scope(self.block.desc) self._ivar._run_backward()
self._ivar._run_backward(scope)
def _gradient(self): def _gradient(self):
return np.array(self._ivar._grad()) return np.array(self._ivar._grad())
...@@ -692,20 +691,20 @@ class Operator(object): ...@@ -692,20 +691,20 @@ class Operator(object):
if _in_imperative_mode(): if _in_imperative_mode():
self.iop = core.OpBase() self.iop = core.OpBase()
self.iop.desc = self.desc self.iop.desc = self.desc
self.inputs = [] self.inputs = defaultdict(list)
if inputs is not None: if inputs is not None:
for inp in inputs.values(): for k, v in six.iteritems(inputs):
if isinstance(inp, Variable): if isinstance(v, Variable):
self.inputs.append(inp) self.inputs[k].append(v._ivar)
elif isinstance(inp, list) or isinstance(inp, tuple): elif isinstance(v, list) or isinstance(v, tuple):
self.inputs.extend(inp[:]) self.inputs[k].extend([var._ivar for var in v])
self.outputs = [] self.outputs = defaultdict(list)
if outputs is not None: if outputs is not None:
for out in outputs.values(): for k, v in six.iteritems(outputs):
if isinstance(out, Variable): if isinstance(v, Variable):
self.outputs.append(out) self.outputs[k].append(v._ivar)
elif isinstance(out, list) or isinstance(out, tuple): elif isinstance(v, list) or isinstance(v, tuple):
self.outputs.extend(out[:]) self.outputs[k].extend([var._ivar for var in v])
def _has_kernel(self, op_type): def _has_kernel(self, op_type):
return op_type not in self.OP_WITHOUT_KERNEL_SET return op_type not in self.OP_WITHOUT_KERNEL_SET
...@@ -1273,8 +1272,7 @@ class Block(object): ...@@ -1273,8 +1272,7 @@ class Block(object):
op_desc = self.desc.append_op() op_desc = self.desc.append_op()
op = Operator(block=self, desc=op_desc, *args, **kwargs) op = Operator(block=self, desc=op_desc, *args, **kwargs)
if _in_imperative_mode(): if _in_imperative_mode():
_imperative_tracer().trace(op.iop, [v._ivar for v in op.inputs], _imperative_tracer().trace(op.iop, op.inputs, op.outputs, self.desc)
[v._ivar for v in op.outputs], self.desc)
self.ops.append(op) self.ops.append(op)
return op return op
...@@ -1325,8 +1323,7 @@ class Block(object): ...@@ -1325,8 +1323,7 @@ class Block(object):
op_desc = self.desc._prepend_op() op_desc = self.desc._prepend_op()
op = Operator(self, op_desc, *args, **kwargs) op = Operator(self, op_desc, *args, **kwargs)
if _in_imperative_mode(): if _in_imperative_mode():
_imperative_tracer().trace(op.iop, [v._ivar for v in op.inputs], _imperative_tracer().trace(op.iop, op.inputs, op.outputs, self.desc)
[v._ivar for v in op.outputs], self.desc)
self.ops.insert(0, op) self.ops.insert(0, op)
return op return op
......
...@@ -46,8 +46,7 @@ def to_variable(value, block=None): ...@@ -46,8 +46,7 @@ def to_variable(value, block=None):
name=None, name=None,
shape=value.shape, shape=value.shape,
dtype=value.dtype) dtype=value.dtype)
scope = framework._imperative_tracer().get_scope(block.desc) var = py_var._ivar.var
var = scope.var(py_var.name)
tensor = var.get_tensor() tensor = var.get_tensor()
tensor.set(value, core.CPUPlace()) tensor.set(value, core.CPUPlace())
return py_var return py_var
......
...@@ -20,7 +20,7 @@ import six ...@@ -20,7 +20,7 @@ import six
import sys import sys
import numpy as np import numpy as np
from .framework import Variable, Parameter, default_main_program, default_startup_program, dtype_is_floating from .framework import Variable, Parameter, default_main_program, default_startup_program, dtype_is_floating, _in_imperative_mode
from . import unique_name from . import unique_name
from paddle.fluid.initializer import Constant, Xavier from paddle.fluid.initializer import Constant, Xavier
from paddle.fluid.imperative import base from paddle.fluid.imperative import base
...@@ -313,9 +313,18 @@ class LayerHelper(object): ...@@ -313,9 +313,18 @@ class LayerHelper(object):
param = self._create_weight_normalize(attr, shape, dtype) param = self._create_weight_normalize(attr, shape, dtype)
WeightNormParamAttr.params_with_weight_norm.append(param) WeightNormParamAttr.params_with_weight_norm.append(param)
return param return param
if _in_imperative_mode():
self.main_program.global_block().create_parameter(
dtype=dtype, shape=shape, **attr._to_kwargs())
return self.startup_program.global_block().create_parameter(
dtype=dtype,
shape=shape,
**attr._to_kwargs(with_initializer=True))
else:
self.startup_program.global_block().create_parameter( self.startup_program.global_block().create_parameter(
dtype=dtype, shape=shape, **attr._to_kwargs(with_initializer=True)) dtype=dtype,
shape=shape,
**attr._to_kwargs(with_initializer=True))
return self.main_program.global_block().create_parameter( return self.main_program.global_block().create_parameter(
dtype=dtype, shape=shape, **attr._to_kwargs()) dtype=dtype, shape=shape, **attr._to_kwargs())
......
...@@ -20,6 +20,7 @@ from __future__ import print_function ...@@ -20,6 +20,7 @@ from __future__ import print_function
import numpy as np import numpy as np
import six import six
import os import os
import sys
import inspect import inspect
from ..layer_helper import LayerHelper from ..layer_helper import LayerHelper
from ..initializer import Normal, Constant from ..initializer import Normal, Constant
...@@ -9682,6 +9683,7 @@ class FC(layers.PyLayer): ...@@ -9682,6 +9683,7 @@ class FC(layers.PyLayer):
shape=param_shape, shape=param_shape,
dtype=self._dtype, dtype=self._dtype,
is_bias=False) is_bias=False)
sys.stderr.write('created w: %s\n' % self._w.name)
def forward(self, inputs): def forward(self, inputs):
tmp = self._helper.create_variable_for_type_inference(self._dtype) tmp = self._helper.create_variable_for_type_inference(self._dtype)
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import sys
import contextlib import contextlib
import unittest import unittest
import numpy as np import numpy as np
...@@ -38,7 +39,9 @@ class MyLayer(fluid.imperative.PyLayer): ...@@ -38,7 +39,9 @@ class MyLayer(fluid.imperative.PyLayer):
def forward(self, inputs): def forward(self, inputs):
x = fluid.layers.relu(inputs[0]) x = fluid.layers.relu(inputs[0])
self._x_for_debug = x self._x_for_debug = x
return [fluid.layers.elementwise_mul(x, x)] x = fluid.layers.elementwise_mul(x, x)
x = fluid.layers.reduce_sum(x)
return [x]
class MLP(fluid.imperative.PyLayer): class MLP(fluid.imperative.PyLayer):
...@@ -79,10 +82,12 @@ class TestImperative(unittest.TestCase): ...@@ -79,10 +82,12 @@ class TestImperative(unittest.TestCase):
with new_program_scope(): with new_program_scope():
inp = fluid.layers.data( inp = fluid.layers.data(
name="inp", shape=[3], append_batch_size=False) name="inp", shape=[3], append_batch_size=False)
l = MyLayer() x = fluid.layers.relu(inp)
x = l(inp)[0] x_for_debug = x
x = fluid.layers.elementwise_mul(x, x)
x = fluid.layers.reduce_sum(x)
param_grads = fluid.backward.append_backward( param_grads = fluid.backward.append_backward(
x, parameter_list=[l._x_for_debug.name])[0] x, parameter_list=[x_for_debug.name])[0]
exe = fluid.Executor(fluid.CPUPlace()) exe = fluid.Executor(fluid.CPUPlace())
static_out, static_grad = exe.run( static_out, static_grad = exe.run(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册