Merge pull request #14782 from PaddlePaddle/revert-14398-imperative
Revert "Imperative"revert-14782-revert-14398-imperative
commit
9588648318
@ -1,3 +0,0 @@
|
|||||||
cc_library(layer SRCS layer.cc DEPS proto_desc operator)
|
|
||||||
cc_library(tracer SRCS tracer.cc DEPS proto_desc)
|
|
||||||
cc_library(engine SRCS engine.cc)
|
|
@ -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.
|
|
||||||
|
|
||||||
#include "paddle/fluid/imperative/engine.h"
|
|
||||||
|
|
||||||
#include <mutex> // NOLINT
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "glog/logging.h"
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace imperative {
|
|
||||||
|
|
||||||
static std::once_flag init_engine;
|
|
||||||
static Engine* engine;
|
|
||||||
|
|
||||||
class DummyEngine : public Engine {
|
|
||||||
public:
|
|
||||||
void Enqueue(Runnable* runnable) override {
|
|
||||||
queued_runnables_.push_back(runnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Size() const override { return queued_runnables_.size(); }
|
|
||||||
|
|
||||||
void Sync() override {
|
|
||||||
for (Runnable* l : queued_runnables_) {
|
|
||||||
LOG(INFO) << "running " << reinterpret_cast<void*>(l);
|
|
||||||
}
|
|
||||||
queued_runnables_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<Runnable*> queued_runnables_;
|
|
||||||
};
|
|
||||||
|
|
||||||
Engine* GetEngine() {
|
|
||||||
std::call_once(init_engine, []() { engine = new DummyEngine(); });
|
|
||||||
return engine;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace imperative
|
|
||||||
} // namespace paddle
|
|
@ -1,39 +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.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace imperative {
|
|
||||||
|
|
||||||
struct Runnable {};
|
|
||||||
|
|
||||||
class Engine {
|
|
||||||
public:
|
|
||||||
virtual ~Engine() {}
|
|
||||||
|
|
||||||
virtual void Enqueue(Runnable* runnable) = 0;
|
|
||||||
|
|
||||||
virtual size_t Size() const = 0;
|
|
||||||
|
|
||||||
virtual void Sync() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
Engine* GetEngine();
|
|
||||||
|
|
||||||
} // namespace imperative
|
|
||||||
} // namespace paddle
|
|
@ -1,221 +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/imperative/layer.h"
|
|
||||||
#include <deque>
|
|
||||||
#include <limits>
|
|
||||||
#include <map>
|
|
||||||
#include <random>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "paddle/fluid/framework/lod_tensor.h"
|
|
||||||
#include "paddle/fluid/framework/op_registry.h"
|
|
||||||
#include "paddle/fluid/string/printf.h"
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace imperative {
|
|
||||||
|
|
||||||
using framework::Variable;
|
|
||||||
|
|
||||||
void AddTo(Variable* src, Variable* dst) {
|
|
||||||
framework::LoDTensor* dst_tensor = dst->GetMutable<framework::LoDTensor>();
|
|
||||||
framework::LoDTensor* src_tensor = src->GetMutable<framework::LoDTensor>();
|
|
||||||
PADDLE_ENFORCE(dst_tensor->numel() == src_tensor->numel(), "%lld vs %lld",
|
|
||||||
dst_tensor->numel(), src_tensor->numel());
|
|
||||||
float* dst_data = dst_tensor->mutable_data<float>(platform::CPUPlace());
|
|
||||||
const float* src_data = src_tensor->data<float>();
|
|
||||||
for (size_t i = 0; i < src_tensor->numel(); ++i) {
|
|
||||||
dst_data[i] += src_data[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Autograd {
|
|
||||||
public:
|
|
||||||
explicit Autograd(framework::Scope* scope) : scope_(scope) {}
|
|
||||||
|
|
||||||
void RunBackward(VarBase* var) {
|
|
||||||
PADDLE_ENFORCE(var->pre_op_->op_desc_);
|
|
||||||
// TODO(panyx0718): Only create for vars that "require_grad"
|
|
||||||
(*var->pre_op_->output_vars_)[var->pre_op_out_idx_]->grads_ = var->grads_;
|
|
||||||
|
|
||||||
std::deque<OpBase*> ready;
|
|
||||||
ready.push_back(var->pre_op_);
|
|
||||||
|
|
||||||
std::map<OpBase*, int> dep_counts = ComputeDepCounts(var->pre_op_);
|
|
||||||
|
|
||||||
while (!ready.empty()) {
|
|
||||||
OpBase* ready_op = ready.front();
|
|
||||||
ready.pop_front();
|
|
||||||
std::vector<Variable*> input_grads = ready_op->ApplyGrad(scope_);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < input_grads.size(); ++i) {
|
|
||||||
if (!input_grads[i]) continue;
|
|
||||||
OpBase* pre_op = ready_op->pre_ops_->at(i);
|
|
||||||
if (!pre_op) continue;
|
|
||||||
|
|
||||||
dep_counts[pre_op] -= 1;
|
|
||||||
PADDLE_ENFORCE(dep_counts[pre_op] >= 0);
|
|
||||||
bool pre_op_ready = dep_counts[pre_op] == 0;
|
|
||||||
if (pre_op_ready) {
|
|
||||||
ready.push_back(pre_op);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::map<OpBase*, int> ComputeDepCounts(OpBase* op) {
|
|
||||||
std::map<OpBase*, int> ret;
|
|
||||||
|
|
||||||
std::deque<OpBase*> queue;
|
|
||||||
queue.push_back(op);
|
|
||||||
std::unordered_set<OpBase*> visited;
|
|
||||||
visited.insert(op);
|
|
||||||
while (!queue.empty()) {
|
|
||||||
OpBase* candidate = queue.front();
|
|
||||||
queue.pop_front();
|
|
||||||
for (OpBase* pre_op : *(candidate->pre_ops_)) {
|
|
||||||
if (!pre_op) continue;
|
|
||||||
if (visited.find(pre_op) == visited.end()) {
|
|
||||||
visited.insert(pre_op);
|
|
||||||
queue.push_back(pre_op);
|
|
||||||
}
|
|
||||||
ret[pre_op] += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
framework::Scope* scope_;
|
|
||||||
};
|
|
||||||
|
|
||||||
framework::Variable* CreateVariable(const std::string& name,
|
|
||||||
const framework::DDim& dim, float val,
|
|
||||||
framework::Scope* scope,
|
|
||||||
bool random_name = true) {
|
|
||||||
std::string varname = name;
|
|
||||||
if (random_name) {
|
|
||||||
std::mt19937 rng;
|
|
||||||
rng.seed(std::random_device()());
|
|
||||||
std::uniform_int_distribution<std::mt19937::result_type> dist6(
|
|
||||||
1, std::numeric_limits<int>::max());
|
|
||||||
int id = dist6(rng);
|
|
||||||
varname = string::Sprintf("%s@%d", varname, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
VLOG(3) << "creating var " << varname;
|
|
||||||
framework::Variable* var = scope->Var(varname);
|
|
||||||
framework::LoDTensor* tensor = var->GetMutable<framework::LoDTensor>();
|
|
||||||
|
|
||||||
float* data = tensor->mutable_data<float>(dim, platform::CPUPlace());
|
|
||||||
std::fill(data, data + tensor->numel(), val);
|
|
||||||
return var;
|
|
||||||
}
|
|
||||||
|
|
||||||
framework::LoDTensor& VarBase::Grad() {
|
|
||||||
VLOG(3) << "get var grad " << var_desc_->Name();
|
|
||||||
return *grads_->GetMutable<framework::LoDTensor>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VarBase::ApplyGrad(framework::Scope* scope, Variable* grad) {
|
|
||||||
VLOG(3) << "apply var grad " << var_desc_->Name() << " "
|
|
||||||
<< grad->Get<framework::LoDTensor>().data<float>()[0];
|
|
||||||
if (!grads_) {
|
|
||||||
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();
|
|
||||||
|
|
||||||
for (const std::string& grad_invar : grad_op_desc_->InputArgumentNames()) {
|
|
||||||
if (grad_to_var_->find(grad_invar) == grad_to_var_->end()) {
|
|
||||||
// grad op inputs can be forward inputs, so not in grad_to_var.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
VLOG(3) << "op grad in var " << grad_invar;
|
|
||||||
block_->FindRecursiveOrCreateVar(grad_invar);
|
|
||||||
framework::Variable* var = scope->Var(grad_invar);
|
|
||||||
const std::string& invar = grad_to_var_->at(grad_invar);
|
|
||||||
for (VarBase* varbase : *output_vars_) {
|
|
||||||
// Use the accumulated grads_ by sharing the input with grads_.
|
|
||||||
if (varbase->var_desc_->Name() == invar) {
|
|
||||||
var->GetMutable<framework::LoDTensor>()->ShareDataWith(
|
|
||||||
varbase->grads_->Get<framework::LoDTensor>());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const std::string& outvar : grad_op_desc_->OutputArgumentNames()) {
|
|
||||||
VLOG(3) << "grad outvar " << outvar;
|
|
||||||
block_->FindRecursiveOrCreateVar(outvar);
|
|
||||||
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_);
|
|
||||||
std::unique_ptr<framework::OperatorBase> opbase =
|
|
||||||
framework::OpRegistry::CreateOp(*grad_op_desc_);
|
|
||||||
|
|
||||||
opbase->Run(*scope, platform::CPUPlace());
|
|
||||||
|
|
||||||
// `ret` matches exactly with `input_vars_` of forward op.
|
|
||||||
std::vector<Variable*> ret;
|
|
||||||
for (size_t i = 0; i < input_vars_->size(); ++i) {
|
|
||||||
bool found = false;
|
|
||||||
for (const std::string& outvar : grad_op_desc_->OutputArgumentNames()) {
|
|
||||||
Variable* var = scope->FindVar(outvar);
|
|
||||||
VarBase* origin_var = (*input_vars_)[i];
|
|
||||||
std::string orig_var = grad_to_var_->at(outvar);
|
|
||||||
PADDLE_ENFORCE(origin_var->var_desc_->Name() == orig_var);
|
|
||||||
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 ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VarBase::RunBackward(framework::Scope* scope) {
|
|
||||||
grads_ = CreateVariable(framework::GradVarName(var_desc_->Name()),
|
|
||||||
var_->Get<framework::LoDTensor>().dims(), 1.0, scope,
|
|
||||||
false);
|
|
||||||
if (!pre_op_) return;
|
|
||||||
Autograd(scope).RunBackward(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace imperative
|
|
||||||
} // namespace paddle
|
|
@ -1,102 +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.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include "paddle/fluid/framework/op_desc.h"
|
|
||||||
#include "paddle/fluid/framework/operator.h"
|
|
||||||
#include "paddle/fluid/framework/scope.h"
|
|
||||||
#include "paddle/fluid/framework/var_desc.h"
|
|
||||||
#include "paddle/fluid/platform/enforce.h"
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace imperative {
|
|
||||||
|
|
||||||
class OpBase;
|
|
||||||
|
|
||||||
class VarBase {
|
|
||||||
public:
|
|
||||||
VarBase()
|
|
||||||
: pre_op_(nullptr),
|
|
||||||
pre_op_out_idx_(-1),
|
|
||||||
var_desc_(nullptr),
|
|
||||||
var_(nullptr),
|
|
||||||
grads_(nullptr) {}
|
|
||||||
|
|
||||||
virtual ~VarBase() {}
|
|
||||||
|
|
||||||
void ApplyGrad(framework::Scope* scope, framework::Variable* grad);
|
|
||||||
|
|
||||||
void RunBackward(framework::Scope* scope);
|
|
||||||
|
|
||||||
framework::LoDTensor& Grad();
|
|
||||||
|
|
||||||
OpBase* pre_op_;
|
|
||||||
int pre_op_out_idx_;
|
|
||||||
|
|
||||||
framework::VarDesc* var_desc_;
|
|
||||||
framework::Variable* var_;
|
|
||||||
framework::Variable* grads_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class OpBase {
|
|
||||||
public:
|
|
||||||
OpBase()
|
|
||||||
: input_vars_(new std::vector<VarBase*>()),
|
|
||||||
output_vars_(new std::vector<VarBase*>()),
|
|
||||||
pre_ops_(new std::vector<OpBase*>()),
|
|
||||||
pre_ops_out_idx_(new std::vector<int>()),
|
|
||||||
op_desc_(nullptr),
|
|
||||||
grad_op_desc_(nullptr) {}
|
|
||||||
|
|
||||||
virtual ~OpBase() {
|
|
||||||
delete input_vars_;
|
|
||||||
delete output_vars_;
|
|
||||||
|
|
||||||
delete pre_ops_;
|
|
||||||
delete pre_ops_out_idx_;
|
|
||||||
|
|
||||||
if (grad_op_desc_) delete grad_op_desc_;
|
|
||||||
if (grad_to_var_) delete grad_to_var_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<framework::Variable*> ApplyGrad(framework::Scope* scope);
|
|
||||||
|
|
||||||
std::vector<VarBase*>* input_vars_;
|
|
||||||
std::vector<VarBase*>* output_vars_;
|
|
||||||
std::vector<OpBase*>* pre_ops_;
|
|
||||||
std::vector<int>* pre_ops_out_idx_;
|
|
||||||
framework::OpDesc* op_desc_;
|
|
||||||
|
|
||||||
framework::OpDesc* grad_op_desc_;
|
|
||||||
std::unordered_map<std::string, std::string>* grad_to_var_;
|
|
||||||
framework::BlockDesc* block_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Layer {
|
|
||||||
public:
|
|
||||||
virtual ~Layer() {}
|
|
||||||
|
|
||||||
virtual std::vector<VarBase> Forward(const std::vector<VarBase>& inputs) {
|
|
||||||
std::vector<VarBase> vars;
|
|
||||||
return vars;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void Backward() { LOG(ERROR) << "To support customize"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace imperative
|
|
||||||
} // namespace paddle
|
|
@ -1,19 +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/imperative/tracer.h"
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace imperative {} // namespace imperative
|
|
||||||
} // namespace paddle
|
|
@ -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.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "paddle/fluid/framework/op_desc.h"
|
|
||||||
#include "paddle/fluid/framework/op_registry.h"
|
|
||||||
#include "paddle/fluid/framework/scope.h"
|
|
||||||
#include "paddle/fluid/imperative/engine.h"
|
|
||||||
#include "paddle/fluid/imperative/layer.h"
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace imperative {
|
|
||||||
|
|
||||||
void CreateGradOp(const framework::OpDesc& op_desc,
|
|
||||||
const std::unordered_set<std::string>& no_grad_set,
|
|
||||||
const std::vector<framework::BlockDesc*>& grad_sub_block,
|
|
||||||
framework::OpDesc** grad_op_desc,
|
|
||||||
std::unordered_map<std::string, std::string>* grad_to_var) {
|
|
||||||
std::vector<std::unique_ptr<framework::OpDesc>> grad_op_descs =
|
|
||||||
framework::OpInfoMap::Instance()
|
|
||||||
.Get(op_desc.Type())
|
|
||||||
.GradOpMaker()(op_desc, no_grad_set, grad_to_var, grad_sub_block);
|
|
||||||
PADDLE_ENFORCE(grad_op_descs.size() == 1, "Only support 1 grad op now.");
|
|
||||||
// TODO(panyx0718): Leak?
|
|
||||||
*grad_op_desc = grad_op_descs[0].release();
|
|
||||||
}
|
|
||||||
|
|
||||||
class Tracer {
|
|
||||||
public:
|
|
||||||
explicit Tracer(framework::BlockDesc* root_block) : root_block_(root_block) {
|
|
||||||
root_scope_ = new framework::Scope();
|
|
||||||
scopes_[root_block_] = root_scope_;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~Tracer() { delete root_scope_; }
|
|
||||||
|
|
||||||
void Trace(OpBase* op, const std::vector<VarBase*>& inputs,
|
|
||||||
const std::vector<VarBase*>& outputs,
|
|
||||||
framework::BlockDesc* block) {
|
|
||||||
framework::Scope* scope = GetScope(block);
|
|
||||||
framework::OpDesc* op_desc = op->op_desc_;
|
|
||||||
VLOG(3) << "tracer tracing " << op_desc->Type();
|
|
||||||
op_desc->InferShape(*block);
|
|
||||||
op_desc->InferVarType(block);
|
|
||||||
std::unique_ptr<framework::OperatorBase> op_base =
|
|
||||||
framework::OpRegistry::CreateOp(*op_desc);
|
|
||||||
|
|
||||||
*op->input_vars_ = inputs;
|
|
||||||
for (VarBase* input : inputs) {
|
|
||||||
const std::string vname = input->var_desc_->Name();
|
|
||||||
framework::Variable* var = scope->Var(vname);
|
|
||||||
input->var_ = var;
|
|
||||||
if (!var->IsInitialized()) {
|
|
||||||
framework::VarDesc* var_desc = block->FindVar(vname);
|
|
||||||
if (var_desc->GetType() == framework::proto::VarType::LOD_TENSOR) {
|
|
||||||
var->GetMutable<framework::LoDTensor>();
|
|
||||||
} else {
|
|
||||||
LOG(ERROR) << "tracer doesn't support yet";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (input->pre_op_) {
|
|
||||||
op->pre_ops_->push_back(input->pre_op_);
|
|
||||||
op->pre_ops_out_idx_->push_back(input->pre_op_out_idx_);
|
|
||||||
} else {
|
|
||||||
op->pre_ops_->push_back(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*op->output_vars_ = outputs;
|
|
||||||
for (size_t i = 0; i < outputs.size(); ++i) {
|
|
||||||
const std::string vname = outputs[i]->var_desc_->Name();
|
|
||||||
framework::Variable* var = scope->Var(vname);
|
|
||||||
if (!var->IsInitialized()) {
|
|
||||||
framework::VarDesc* var_desc = block->FindVar(vname);
|
|
||||||
if (var_desc->GetType() == framework::proto::VarType::LOD_TENSOR) {
|
|
||||||
var->GetMutable<framework::LoDTensor>();
|
|
||||||
} else {
|
|
||||||
LOG(ERROR) << "tracer doesn't support yet";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outputs[i]->var_ = var;
|
|
||||||
outputs[i]->pre_op_ = op;
|
|
||||||
outputs[i]->pre_op_out_idx_ = i;
|
|
||||||
}
|
|
||||||
op_base->Run(*scope, platform::CPUPlace());
|
|
||||||
framework::OpDesc* grad_op_desc;
|
|
||||||
auto grad_to_var = new std::unordered_map<std::string, std::string>();
|
|
||||||
CreateGradOp(*op_desc, {}, {block}, &grad_op_desc, grad_to_var);
|
|
||||||
op->grad_op_desc_ = grad_op_desc;
|
|
||||||
op->grad_to_var_ = grad_to_var;
|
|
||||||
op->block_ = block;
|
|
||||||
}
|
|
||||||
|
|
||||||
framework::Scope* GetScope(framework::BlockDesc* block) {
|
|
||||||
if (scopes_.find(block) != scopes_.end()) {
|
|
||||||
return scopes_.at(block);
|
|
||||||
}
|
|
||||||
framework::BlockDesc* parent_block = block->ParentBlock();
|
|
||||||
PADDLE_ENFORCE(scopes_.find(parent_block) != scopes_.end());
|
|
||||||
framework::Scope* scope = &scopes_[parent_block]->NewScope();
|
|
||||||
scopes_[block] = scope;
|
|
||||||
return scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::map<framework::BlockDesc*, framework::Scope*> scopes_;
|
|
||||||
framework::BlockDesc* root_block_;
|
|
||||||
framework::Scope* root_scope_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace imperative
|
|
||||||
} // namespace paddle
|
|
@ -1,36 +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/pybind/imperative.h"
|
|
||||||
#include "paddle/fluid/framework/block_desc.h"
|
|
||||||
#include "paddle/fluid/framework/scope.h"
|
|
||||||
#include "paddle/fluid/imperative/tracer.h"
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace pybind {
|
|
||||||
|
|
||||||
// Bind Methods
|
|
||||||
void BindTracer(pybind11::module *m) {
|
|
||||||
pybind11::class_<imperative::Tracer>(*m, "Tracer", "")
|
|
||||||
.def("__init__",
|
|
||||||
[](imperative::Tracer &self, framework::BlockDesc *root_block) {
|
|
||||||
new (&self) imperative::Tracer(root_block);
|
|
||||||
})
|
|
||||||
.def("trace", &imperative::Tracer::Trace)
|
|
||||||
.def("get_scope", &imperative::Tracer::GetScope,
|
|
||||||
pybind11::return_value_policy::reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace pybind
|
|
||||||
} // namespace paddle
|
|
@ -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. */
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
#include <vector>
|
|
||||||
#include "paddle/fluid/imperative/layer.h"
|
|
||||||
#include "pybind11/pybind11.h"
|
|
||||||
#include "pybind11/stl.h"
|
|
||||||
|
|
||||||
namespace paddle {
|
|
||||||
namespace pybind {
|
|
||||||
|
|
||||||
class PyLayer : public imperative::Layer {
|
|
||||||
public:
|
|
||||||
using imperative::Layer::Layer; // Inherit constructors
|
|
||||||
|
|
||||||
std::vector<imperative::VarBase> Forward(
|
|
||||||
const std::vector<imperative::VarBase>& inputs) override {
|
|
||||||
PYBIND11_OVERLOAD(std::vector<imperative::VarBase>, Layer, Forward,
|
|
||||||
inputs); // NOLINT
|
|
||||||
}
|
|
||||||
|
|
||||||
void Backward() override {
|
|
||||||
PYBIND11_OVERLOAD(void, Layer, Backward, ); // NOLINT
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class PyOpBase : public imperative::OpBase {
|
|
||||||
public:
|
|
||||||
using imperative::OpBase::OpBase; // Inherit constructors
|
|
||||||
};
|
|
||||||
|
|
||||||
class PyVarBase : public imperative::VarBase {
|
|
||||||
public:
|
|
||||||
using imperative::VarBase::VarBase; // Inherit constructors
|
|
||||||
};
|
|
||||||
|
|
||||||
void BindTracer(pybind11::module* m);
|
|
||||||
|
|
||||||
} // namespace pybind
|
|
||||||
} // namespace paddle
|
|
@ -1,25 +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.
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
from . import base
|
|
||||||
from .base import *
|
|
||||||
|
|
||||||
from . import layers
|
|
||||||
from .layers import *
|
|
||||||
|
|
||||||
__all__ = []
|
|
||||||
__all__ += layers.__all__
|
|
||||||
__all__ += base.__all__
|
|
@ -1,56 +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 contextlib
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
from paddle.fluid import core
|
|
||||||
from paddle.fluid import framework
|
|
||||||
|
|
||||||
__all__ = ['enabled', 'guard', 'to_variable']
|
|
||||||
|
|
||||||
|
|
||||||
def enabled():
|
|
||||||
return framework._in_imperative_mode()
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def guard():
|
|
||||||
train = framework.Program()
|
|
||||||
startup = framework.Program()
|
|
||||||
tracer = core.Tracer(train.current_block().desc)
|
|
||||||
with framework.program_guard(train, startup):
|
|
||||||
with framework.unique_name.guard():
|
|
||||||
with framework._imperative_guard(tracer):
|
|
||||||
yield
|
|
||||||
|
|
||||||
|
|
||||||
def to_variable(value, block=None):
|
|
||||||
if isinstance(value, np.ndarray):
|
|
||||||
if not block:
|
|
||||||
block = framework.default_main_program().current_block()
|
|
||||||
py_var = framework.Variable(
|
|
||||||
block,
|
|
||||||
type=core.VarDesc.VarType.LOD_TENSOR,
|
|
||||||
name=None,
|
|
||||||
shape=value.shape,
|
|
||||||
dtype=value.dtype)
|
|
||||||
scope = framework._imperative_tracer().get_scope(block.desc)
|
|
||||||
var = scope.var(py_var.name)
|
|
||||||
tensor = var.get_tensor()
|
|
||||||
tensor.set(value, core.CPUPlace())
|
|
||||||
return py_var
|
|
||||||
elif isinstance(value, framework.Variable):
|
|
||||||
return value
|
|
||||||
else:
|
|
||||||
raise ValueError("Unsupported type %s" % type(value))
|
|
@ -1,44 +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 contextlib
|
|
||||||
import sys
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
from paddle.fluid import core
|
|
||||||
from paddle.fluid import framework
|
|
||||||
from paddle.fluid.imperative import base
|
|
||||||
|
|
||||||
__all__ = ['PyLayer']
|
|
||||||
|
|
||||||
|
|
||||||
class PyLayer(core.Layer):
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __call__(self, inputs):
|
|
||||||
# TODO(panyx0718): Support declarative mode as well.
|
|
||||||
assert base.enabled()
|
|
||||||
if not isinstance(inputs, list) and not isinstance(inputs, tuple):
|
|
||||||
inputs = [inputs]
|
|
||||||
|
|
||||||
var_inputs = []
|
|
||||||
for x in inputs:
|
|
||||||
py_var = base.to_variable(x)
|
|
||||||
var_inputs.append(py_var)
|
|
||||||
outputs = self.forward(var_inputs)
|
|
||||||
return outputs
|
|
||||||
|
|
||||||
def forward(self, inputs):
|
|
||||||
return []
|
|
@ -1,52 +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 unittest
|
|
||||||
import sys
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
import paddle.fluid as fluid
|
|
||||||
from paddle.fluid import core
|
|
||||||
|
|
||||||
|
|
||||||
class MyLayer(fluid.imperative.PyLayer):
|
|
||||||
def __init__(self):
|
|
||||||
super(MyLayer, self).__init__()
|
|
||||||
|
|
||||||
def forward(self, inputs):
|
|
||||||
x = fluid.layers.relu(inputs[0])
|
|
||||||
self._x_for_debug = x
|
|
||||||
return [fluid.layers.elementwise_mul(x, x)]
|
|
||||||
|
|
||||||
|
|
||||||
class TestImperative(unittest.TestCase):
|
|
||||||
def test_layer(self):
|
|
||||||
with fluid.imperative.guard():
|
|
||||||
cl = core.Layer()
|
|
||||||
cl.forward([])
|
|
||||||
l = fluid.imperative.PyLayer()
|
|
||||||
l.forward([])
|
|
||||||
|
|
||||||
def test_layer_in_out(self):
|
|
||||||
with fluid.imperative.guard():
|
|
||||||
l = MyLayer()
|
|
||||||
x = l(np.array([1.0, 2.0, -1.0], dtype=np.float32))[0]
|
|
||||||
self.assertIsNotNone(x)
|
|
||||||
sys.stderr.write("%s output: %s\n" % (x, x._numpy()))
|
|
||||||
x._backward()
|
|
||||||
sys.stderr.write("grad %s\n" % l._x_for_debug._gradient())
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
Loading…
Reference in new issue