GradMaker for dygraph (#19706)

* refactor dygraph,test=develop

* fix failed unittest,test=develop

* polish code,test=develop

* check windows ci error,test=develop
try to fix windows ci error by np.allclose,test=develop

* polish vlog and profiler, test=develop

* try to fix preceding ops order,test=develop

* test transformer in windows ci, test=develop

* use python c-api to speed up tracer.trace,test=develop

* test=develop, fix docker with paddle nccl problem

* test=develop, add ut for debug string and gradient_accumulator

* test=develop, add tests for layer/gradient_accumulator/prepared_op

* test=develop, fix complie error for test_prepared_op

* test=develop, add more ut for dygraph

* test=develop, create API.spec for dygraph api change

* optimize grad maker; test=develop

* optimize grad maker

* test

* grad make optim; test=develop

* fix unittest bugs; test=develop

* add dygraph grad op maker and split_op

* grad op maker refactor; test=develop

* add dygraph grad maker; test=develop

* fix op deformable_conv_v1_op bug; test=develop

* fix deformable_conv prroi pool bugs;

* fix new op grad op maker bug; test=develop

* fix split by ref bug; test=develop

* fix dygraph auto prune bug; test=develop

* fix test_trace bug; test=develop

* fix fused emb seq pool bug; test=develop

* remove useless code in op_desc file; test=develop

* remove useless code, StrVarBaseNode; test=develop

* fix review issues; test=develop

* fix rank_loss grad maker; test=develop

* remove flag in VarBase; test=develop

* fix distributed_notify_op compile bug ; test=develop

* fix reshape op double grad; test=develop

* fix expand as op; test=develop

* add impertive type_defs.h for demo_train; test=develop

* fix inference lib cmake; test=develop

* fix inference lib; test=develop

* fix infernce_lib; test=develop

* fix inference cmake; test=develop

* fix inference lib; test=develop

* fix inference lib; test=develop

* remove condition dygraph grad maker, modify local name; test=develop

* fix split grad maker bug; test=develop

* fix pyramid_op bug; test=develop

* change travis time out limit; test=develop

* restore travis; test=develop

* change timeout limit; test=develop
yaoxuefeng
hong 5 years ago committed by GitHub
parent b741761098
commit 8c4573a3cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -20,6 +20,7 @@ before_install:
- |
function timeout() { perl -e 'alarm shift; exec @ARGV' "$@"; }
script:
- "travis_wait 30 sleep 1800 &"
- |
# 43min timeout
paddle/scripts/paddle_docker_build.sh ${JOB}

@ -191,6 +191,13 @@ copy(fluid_lib_dist
${src_dir}/${module}/ir/*.h ${src_dir}/${module}/fleet/*.h
DSTS ${dst_dir}/${module} ${dst_dir}/${module}/details ${dst_dir}/${module} ${dst_dir}/${module} ${dst_dir}/${module} ${dst_dir}/${module}/ir/memory_optimize_pass ${dst_dir}/${module}/ir ${dst_dir}/${module}/fleet)
set(module "imperative")
copy(fluid_lib_dist
SRCS ${src_dir}/${module}/type_defs.h ${src_dir}/${module}/dygraph_grad_maker.h ${src_dir}/${module}/layer.h ${src_dir}/${module}/flags.h
DSTS ${dst_dir}/${module}/ ${dst_dir}/${module}/ ${dst_dir}/${module}/ ${dst_dir}/${module}/
)
set(module "operators")
copy(fluid_lib_dist
SRCS ${src_dir}/${module}/reader/blocking_queue.h

@ -27,6 +27,8 @@ limitations under the License. */
#include "paddle/fluid/framework/op_proto_maker.h"
#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/framework/var_type_inference.h"
#include "paddle/fluid/imperative/dygraph_grad_maker.h"
#include "paddle/fluid/imperative/type_defs.h"
namespace paddle {
namespace framework {
@ -40,6 +42,7 @@ enum OpInfoFillType {
kShapeInference = 4,
kInplaceOpInference = 5,
kNoNeedBufferVarsInference = 6,
kGradOpBaseMaker = 7,
kUnknown = -1
};
@ -54,6 +57,7 @@ using OpRegistryClasses = std::tuple< // NOLINT
TypePair<OperatorBase, kOperator>, // NOLINT
TypePair<OpProtoAndCheckerMaker, kOpProtoAndCheckerMaker>, // NOLINT
TypePair<GradOpDescMakerBase, kGradOpDescMaker>, // NOLINT
TypePair<imperative::GradOpBaseMakerBase, kGradOpBaseMaker>, // NOLINT
TypePair<VarTypeInference, kVarTypeInference>, // NOLINT
TypePair<InferShapeBase, kShapeInference>, // NOLINT
TypePair<InplaceOpInference, kInplaceOpInference>, // NOLINT
@ -186,8 +190,21 @@ struct OpInfoFiller<T, kGradOpDescMaker> {
};
info->use_default_grad_op_desc_maker_ =
std::is_base_of<DefaultGradOpDescMaker<true>, T>::value ||
std::is_base_of<DefaultGradOpDescMaker<false>, T>::value;
std::is_base_of<DefaultGradOpMaker<OpDesc, true>, T>::value ||
std::is_base_of<DefaultGradOpMaker<OpDesc, false>, T>::value;
}
};
template <typename T>
struct OpInfoFiller<T, kGradOpBaseMaker> {
void operator()(const char* op_type, OpInfo* info) const {
info->dygraph_grad_op_maker_ = [](
const imperative::OpBase* fw_op_base,
const imperative::NameVarBaseMap& var_base_map_in,
const imperative::NameVarBaseMap& var_base_map_out) {
T maker(fw_op_base, var_base_map_in, var_base_map_out);
return maker();
};
}
};

@ -21,6 +21,9 @@ limitations under the License. */
#include <vector>
#include "paddle/fluid/framework/op_desc.h"
#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/imperative/dygraph_grad_maker.h"
#include "paddle/fluid/imperative/layer.h"
#include "paddle/fluid/imperative/type_defs.h"
namespace paddle {
namespace framework {
@ -97,6 +100,8 @@ class GradOpDescMakerBase {
return ret_val;
}
std::vector<std::string> Empty() const { return {}; }
std::vector<std::string> InputNames() const {
return this->fwd_op_.InputNames();
}
@ -132,7 +137,9 @@ class GradOpDescMakerBase {
std::string ForwardOpType() const { return this->fwd_op_.Type(); }
protected:
const OpDesc& ForwardOp() const { return fwd_op_; }
bool HasInput(const std::string& name) const {
return (fwd_op_.Inputs().count(name) > 0);
}
private:
const OpDesc& fwd_op_;
@ -143,11 +150,24 @@ class GradOpDescMakerBase {
std::vector<BlockDesc*> grad_block_;
};
class SingleGradOpDescMaker : public GradOpDescMakerBase {
template <typename T>
class SingleGradOpMaker {
public:
std::vector<std::unique_ptr<T>> operator()() const {
PADDLE_ENFORCE(false, "should not call this function");
return {};
}
protected:
virtual std::unique_ptr<T> Apply() const = 0;
};
template <>
class SingleGradOpMaker<OpDesc> : public GradOpDescMakerBase {
public:
using GradOpDescMakerBase::GradOpDescMakerBase;
std::vector<std::unique_ptr<OpDesc>> operator()() const final {
std::vector<std::unique_ptr<OpDesc>> operator()() const {
std::vector<std::unique_ptr<OpDesc>> retv;
retv.emplace_back(this->Apply());
return retv;
@ -157,14 +177,32 @@ class SingleGradOpDescMaker : public GradOpDescMakerBase {
virtual std::unique_ptr<OpDesc> Apply() const = 0;
};
template <bool DropEmptyIG = true>
class DefaultGradOpDescMaker final : public SingleGradOpDescMaker {
template <>
class SingleGradOpMaker<imperative::OpBase>
: public imperative::GradOpBaseMakerBase {
public:
using GradOpBaseMakerBase::GradOpBaseMakerBase;
public:
using SingleGradOpDescMaker::SingleGradOpDescMaker;
std::vector<std::unique_ptr<imperative::OpBase>> operator()() const {
std::vector<std::unique_ptr<imperative::OpBase>> retv;
retv.emplace_back(this->Apply());
return retv;
}
protected:
std::unique_ptr<OpDesc> Apply() const final {
auto* grad = new OpDesc();
virtual std::unique_ptr<imperative::OpBase> Apply() const = 0;
};
template <typename T, bool DropEmptyIG = true>
class DefaultGradOpMaker final : public SingleGradOpMaker<T> {
public:
using SingleGradOpMaker<T>::SingleGradOpMaker;
protected:
std::unique_ptr<T> Apply() const final {
auto* grad = new T();
grad->SetType(this->ForwardOpType() + "_grad");
for (auto& input_param : this->InputNames()) {
@ -180,15 +218,35 @@ class DefaultGradOpDescMaker final : public SingleGradOpDescMaker {
grad->SetAttrMap(this->Attrs());
return std::unique_ptr<OpDesc>(grad);
return std::unique_ptr<T>(grad);
}
};
class EmptyGradOpMaker final : public GradOpDescMakerBase {
template <typename T>
class EmptyGradOpMaker {
public:
virtual std::vector<std::unique_ptr<T>> operator()()
const final { /* NOLINT */
return {};
}
};
template <>
class EmptyGradOpMaker<OpDesc> final : public GradOpDescMakerBase {
public:
using GradOpDescMakerBase::GradOpDescMakerBase;
std::vector<std::unique_ptr<OpDesc>> operator()() const final { return {}; }
};
template <>
class EmptyGradOpMaker<imperative::OpBase> final
: public imperative::GradOpBaseMakerBase {
public:
using GradOpBaseMakerBase::GradOpBaseMakerBase;
std::vector<std::unique_ptr<imperative::OpBase>> operator()() const final {
return {};
}
};
} // namespace framework
} // namespace paddle

@ -18,6 +18,7 @@
#include "paddle/fluid/platform/place.h"
#include "paddle/fluid/framework/op_proto_maker.h"
#include "paddle/fluid/imperative/type_defs.h"
namespace paddle {
namespace framework {

@ -15,6 +15,7 @@
#include "paddle/fluid/framework/ir/mkldnn/cpu_quantize_pass.h"
#include <gtest/gtest.h>
#include "paddle/fluid/framework/naive_executor.h"
#include "paddle/fluid/imperative/type_defs.h"
#include "paddle/fluid/platform/place.h"
namespace paddle {
@ -29,6 +30,7 @@ void SetOp(ProgramDesc* prog, const std::string& type, const std::string& name,
op->SetType(type);
op->SetAttr("use_mkldnn", use_mkldnn);
op->SetAttr("name", name);
if (type == "conv2d") {
op->SetInput("Input", {inputs[0]});
op->SetInput("Filter", {inputs[1]});

@ -16,6 +16,7 @@ limitations under the License. */
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "paddle/fluid/framework/attribute.h"
#include "paddle/fluid/framework/type_defs.h"

@ -42,6 +42,7 @@ struct OpInfo {
InferShapeFN infer_shape_;
InferInplaceOpFN infer_inplace_;
InferNoNeedBufferVarsFN infer_no_need_buffer_vars_;
DygraphGradOpMakerFN dygraph_grad_op_maker_;
// NOTE(zjl): this flag is added to check whether
// the grad maker is the default one.
@ -81,6 +82,24 @@ struct OpInfo {
// some op has no grad_op_maker, add check before use GradOpMaker()
bool HasGradOpMaker() const { return grad_op_maker_ != nullptr; }
const DygraphGradOpMakerFN& DygraphGradOpMaker() const {
// Normally, proto_ should not be null, except some special operators, such
// as LeaklyReluDoubleGrad op.
std::string type = proto_ ? proto_->type() : "unknown";
PADDLE_ENFORCE_NOT_NULL(
dygraph_grad_op_maker_,
"Operator %s's DygraphGradOpMaker has not been "
"registered.\nPlease check whether %s_op has "
"grad_op.\nIf not, please set stop_gradient to True "
"for its input and output variables using var.stop_gradient=True.",
type.c_str(), type.c_str());
return dygraph_grad_op_maker_;
}
bool HasDygraphGradOpMaker() const {
return dygraph_grad_op_maker_ != nullptr ? true : false;
}
bool HasInferInplace() const { return infer_inplace_ != nullptr; }
const OpAttrChecker* Checker() const { return checker_; }

@ -209,7 +209,8 @@ struct OpKernelRegistrarFunctorEx<PlaceType, false, I,
#define REGISTER_OP_WITHOUT_GRADIENT(op_type, op_class, op_maker_class) \
REGISTER_OPERATOR(op_type, op_class, op_maker_class, \
paddle::framework::EmptyGradOpMaker)
paddle::framework::EmptyGradOpMaker<paddle::framework::OpDesc>, \
paddle::framework::EmptyGradOpMaker<paddle::imperative::OpBase>)
/**
* Macro to register OperatorKernel.

@ -1171,7 +1171,7 @@ proto::VarType::Type OperatorWithKernel::IndicateDataType(
proto::VarType::Type dafault_data_type =
static_cast<proto::VarType::Type>(-1);
proto::VarType::Type data_type = dafault_data_type;
for (auto& input : this->inputs_) {
for (auto& input : ctx.Context().inputs) {
ParseInputDataType(ctx, input.first, &data_type);
}
PADDLE_ENFORCE_NE(data_type, dafault_data_type,

@ -385,6 +385,8 @@ class ExecutionContext {
return *boost::get<std::shared_ptr<T>>((*kernel_configs_)[idx]);
}
const RuntimeContext& Context() const { return ctx_; }
private:
const OperatorBase& op_;
const Scope& scope_;

@ -20,6 +20,7 @@ limitations under the License. */
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "paddle/fluid/imperative/type_defs.h"
#include "paddle/fluid/platform/variant.h"
namespace paddle {
@ -54,6 +55,12 @@ using GradOpMakerFN = std::function<std::vector<std::unique_ptr<OpDesc>>(
std::unordered_map<std::string, std::string>* /*grad_to_var*/,
const std::vector<BlockDesc*>& grad_block)>;
using DygraphGradOpMakerFN =
std::function<std::vector<std::unique_ptr<imperative::OpBase>>(
const imperative::OpBase* fw_op_base,
const imperative::NameVarBaseMap& var_base_map_in,
const imperative::NameVarBaseMap& var_base_map_out)>;
using InferVarTypeFN =
std::function<void(framework::InferVarTypeContext* /*context*/)>;

@ -0,0 +1,153 @@
// Copyright (c) 2019 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 <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include "paddle/fluid/imperative/layer.h"
#include "paddle/fluid/imperative/type_defs.h"
#include "paddle/fluid/platform/enforce.h"
#include "paddle/fluid/platform/macros.h"
namespace paddle {
namespace imperative {
class GradOpBaseMakerBase {
public:
explicit GradOpBaseMakerBase(const OpBase* fw_op_base,
const NameVarBaseMap& var_base_map_in,
const NameVarBaseMap& var_base_map_out)
: fw_op_base_(fw_op_base),
var_base_map_in_(var_base_map_in),
var_base_map_out_(var_base_map_out) {}
virtual ~GradOpBaseMakerBase() = default;
virtual std::vector<std::unique_ptr<OpBase>> operator()() const = 0;
std::vector<std::shared_ptr<VarBase>> InputGrad(
const std::string& name, bool drop_empty_grad = true) const {
return GetVarBaseList(name, true, true);
}
std::vector<std::shared_ptr<VarBase>> OutputGrad(
const std::string& name) const {
return GetVarBaseList(name, true, false);
}
std::vector<std::shared_ptr<VarBase>> Input(const std::string name) const {
return GetVarBaseList(name, false, true);
}
std::vector<std::shared_ptr<VarBase>> Output(const std::string& name) const {
return GetVarBaseList(name, false, false);
}
std::vector<std::shared_ptr<VarBase>> Empty() const { return {}; }
std::vector<std::string> InputNames() const {
std::vector<std::string> vec_temp;
vec_temp.reserve(var_base_map_in_.size());
for (auto& it : var_base_map_in_) {
vec_temp.emplace_back(it.first);
}
return vec_temp;
}
std::vector<std::string> OutputNames() const {
std::vector<std::string> vec_temp;
vec_temp.reserve(var_base_map_out_.size());
for (auto& it : var_base_map_out_) {
vec_temp.emplace_back(it.first);
}
return vec_temp;
}
const std::unordered_map<std::string, framework::Attribute>& Attrs() const {
return fw_op_base_->Attrs();
}
const framework::Attribute& GetAttr(const std::string& name) const {
auto& map = fw_op_base_->Attrs();
auto it = map.find(name);
PADDLE_ENFORCE(it != map.end(),
"Cannot find attribute [%s] in operator [%s]", name,
fw_op_base_->Type());
return it->second;
}
template <typename T>
inline const T& Attr(const std::string& name) const {
return boost::get<T>(GetAttr(name));
}
std::string ForwardOpType() const { return fw_op_base_->Type(); }
protected:
bool HasInput(const std::string& name) const {
auto it = var_base_map_in_.find(name);
return it != var_base_map_in_.end();
}
private:
std::vector<std::shared_ptr<VarBase>> GetVarBaseList(const std::string& name,
bool is_grad,
bool is_input) const {
const NameVarBaseMap& data_map =
is_input ? var_base_map_in_ : var_base_map_out_;
auto iterator = data_map.find(name);
std::vector<std::shared_ptr<imperative::VarBase>> vec_temp;
if (iterator != data_map.end()) {
vec_temp.reserve(iterator->second.size());
for (auto& var_base_temp : iterator->second) {
if (is_grad) {
PADDLE_ENFORCE_NOT_NULL(var_base_temp->GradVarBase(),
"VarBase grad of OP [%s] should not be null",
fw_op_base_->Type());
auto grad_var_base_tmp = var_base_temp->GradVarBase();
auto* tensor = grad_var_base_tmp->MutableVar()
->GetMutable<framework::LoDTensor>();
tensor->Resize(
var_base_temp->Var().Get<framework::LoDTensor>().dims());
vec_temp.emplace_back(grad_var_base_tmp);
} else {
vec_temp.emplace_back(var_base_temp);
}
}
}
return vec_temp;
}
private:
const OpBase* fw_op_base_;
const NameVarBaseMap& var_base_map_in_;
const NameVarBaseMap& var_base_map_out_;
protected:
std::vector<framework::BlockDesc*> grad_block_;
};
} // namespace imperative
} // namespace paddle

@ -173,6 +173,7 @@ void BasicEngine::PrepareDeps() {
void BasicEngine::SumGradient(OpBase* op, std::shared_ptr<VarBase> src,
VarBase* dst) {
auto iter = accumulators_.find(dst);
PADDLE_ENFORCE_EQ(iter != accumulators_.end(), true,
"Cannot find gradient of variable %s", dst->Name());
iter->second->Add(std::move(src), op->id());
@ -195,16 +196,16 @@ void BasicEngine::Execute() {
NameVarBaseMap tmp_outs;
// A var may be coresponding to several grad var in one op
std::unordered_map<VarBase*, std::vector<std::shared_ptr<VarBase>>> var_map;
size_t counter = 0;
for (auto& bwd_out : bwd_outs) {
auto& tmp_var_list = tmp_outs[bwd_out.first];
tmp_var_list.reserve(bwd_out.second.size());
for (auto& var : bwd_out.second) {
auto tmp_var = std::make_shared<VarBase>(
false, "Gtmp@" + std::to_string(counter++)); // Do not need grad
auto tmp_var =
std::make_shared<VarBase>(false, "Gtmp@"); // Do not need grad
tmp_var_list.emplace_back(tmp_var);
if (var) {
var_map[var.get()].emplace_back(std::move(tmp_var));
var->ClearGradOps();
}
}
@ -227,6 +228,7 @@ void BasicEngine::Execute() {
}
// Step 3: Collect ready ops
for (auto* grad_pending_op : cur_op->GradPendingOps()) {
PADDLE_ENFORCE_NOT_NULL(grad_pending_op);
auto iter = op_deps_.find(grad_pending_op);

@ -53,7 +53,18 @@ static framework::VariableNameMap CreateVarNameMap(
const framework::OpInfo& op_info, const std::string& op_type,
const NameVarBaseMap& varbase_map, bool is_input) {
if (op_info.proto_ == nullptr) {
return {};
framework::VariableNameMap result;
for (auto& it : varbase_map) {
auto& var_vector = it.second;
std::vector<std::string> args;
args.reserve(var_vector.size());
for (auto& var_base : var_vector) {
args.emplace_back(var_base->Name());
}
result[it.first] = std::move(args);
}
return result;
}
framework::VariableNameMap result;
@ -220,21 +231,20 @@ std::shared_ptr<VarBase> VarBase::NewVarBase(const platform::Place& dst_place,
}
// create OpBase from optype
OpBase::OpBase(size_t id, const std::string& type, const NameVarBaseMap& ins,
const NameVarBaseMap& outs, framework::AttributeMap attrs,
const NameVarBaseMap& outs, const framework::AttributeMap& attrs,
const platform::Place& place)
: id_(id), place_(place) {
: id_(id), place_(place), attrs_(attrs) {
const auto& info = framework::OpInfoMap::Instance().Get(type);
// Step 1: Run forward
if (info.Checker() != nullptr) {
info.Checker()->Check(&attrs);
info.Checker()->Check(&attrs_);
}
auto input_name_map = CreateVarNameMap(info, type, ins, true);
auto output_name_map = CreateVarNameMap(info, type, outs, false);
op_ = framework::OpRegistry::CreateOp(type, std::move(input_name_map),
std::move(output_name_map),
std::move(attrs));
std::move(output_name_map), attrs);
VLOG(3) << "Construct Op: " << type << std::endl;
}
@ -245,6 +255,18 @@ OpBase::OpBase(size_t id, const framework::OpDesc& op_desc,
VLOG(3) << "Construct Op: " << op_desc.Type() << std::endl;
}
void OpBase::CreateOperatorBase() {
const auto& info = framework::OpInfoMap::Instance().Get(type_);
if (info.Checker() != nullptr) {
info.Checker()->Check(&attrs_);
}
auto input_name_map = CreateVarNameMap(info, type_, ins_, true);
auto output_name_map = CreateVarNameMap(info, type_, outs_, false);
op_ = framework::OpRegistry::CreateOp(type_, std::move(input_name_map),
std::move(output_name_map), attrs_);
}
void OpBase::Run(const NameVarBaseMap& ins, const NameVarBaseMap& outs) {
auto* op_kernel = dynamic_cast<framework::OperatorWithKernel*>(op_.get());
PADDLE_ENFORCE_NOT_NULL(op_kernel, "only support op with kernel");

@ -182,6 +182,7 @@ class VarBase {
framework::Variable var_;
std::string name_;
std::shared_ptr<VarBase> grad_var_;
mutable size_t copied_counter_ = 0;
// grad_op indicates which grad_op will this var be used as input
@ -271,6 +272,7 @@ class RuntimeInferVarTypeContext : public framework::InferVarTypeContext {
const std::vector<std::string>& Output(
const std::string& name) const override {
auto iter = output_names_.find(name);
PADDLE_ENFORCE_EQ(iter != output_names_.end(), true,
"Cannot find output %s", name);
return iter->second;
@ -279,6 +281,7 @@ class RuntimeInferVarTypeContext : public framework::InferVarTypeContext {
framework::proto::VarType::Type GetType(
const std::string& name) const override {
auto iter = var_set_.find(name);
PADDLE_ENFORCE_EQ(iter != var_set_.end(), true,
"Cannot find var %s in GetType", name);
return iter->second->Type();
@ -296,6 +299,7 @@ class RuntimeInferVarTypeContext : public framework::InferVarTypeContext {
framework::proto::VarType::Type GetDataType(
const std::string& name) const override {
auto iter = var_set_.find(name);
PADDLE_ENFORCE_EQ(iter != var_set_.end(), true,
"Cannot find var %s in GetDataType", name);
return iter->second->DataType();
@ -380,6 +384,10 @@ class OpBase : public std::enable_shared_from_this<OpBase> {
return grad_pending_ops_;
}
void SetGradPendingOps(std::vector<OpBase*> vec_temp) {
grad_pending_ops_.swap(vec_temp);
}
void InsertGradPendingOps(OpBase* op) { grad_pending_ops_.emplace_back(op); }
void SortGradPendingOps() {
@ -406,12 +414,56 @@ class OpBase : public std::enable_shared_from_this<OpBase> {
private:
OpBase(size_t id, const std::string& type, const NameVarBaseMap& ins,
const NameVarBaseMap& outs, framework::AttributeMap attrs,
const NameVarBaseMap& outs, const framework::AttributeMap& attrs,
const platform::Place& place);
OpBase(size_t id, const framework::OpDesc& op_desc,
const platform::Place& place);
public:
OpBase() {}
void SetType(const std::string& type) { type_ = type; }
void SetInput(const std::string& name,
std::vector<std::shared_ptr<VarBase>> vec_var_base) {
ins_[name] = std::move(vec_var_base);
}
void SetOutput(const std::string& name,
std::vector<std::shared_ptr<VarBase>> vec_var_base) {
outs_[name] = std::move(vec_var_base);
}
void SetAttrMap(const framework::AttributeMap& attrs) { attrs_ = attrs; }
void SetAttr(const std::string& name, const framework::Attribute& v) {
attrs_[name] = v;
}
void SetBlockAttr(const std::string& name, framework::BlockDesc* block) {
PADDLE_THROW("SetBlockAttr is not support in dygraph OpBase");
}
const framework::AttributeMap& Attrs() { return attrs_; }
void CreateOperatorBase();
void SetId(size_t id) { id_ = id; }
void SetPlace(platform::Place place) { place_ = place; }
bool HasAttr(const std::string& name) const {
return attrs_.find(name) != attrs_.end();
}
const framework::Attribute& GetAttr(const std::string& name) const {
auto it = attrs_.find(name);
PADDLE_ENFORCE(it != attrs_.end(), "can not find attribute [%s]", name);
return it->second;
}
template <typename T>
inline const T& Attr(const std::string& name) const {
return boost::get<T>(GetAttr(name));
}
private:
size_t id_;
std::unique_ptr<framework::OperatorBase> op_;
@ -421,11 +473,14 @@ class OpBase : public std::enable_shared_from_this<OpBase> {
// Not need to be std::weak_ptr, because op is binded to a certain Tracer,
// and would not be used by a Tracer that does not create itself.
std::vector<OpBase*> grad_pending_ops_;
// This part is only used for backward
NameVarBaseMap ins_;
NameVarBaseMap outs_;
std::string type_;
framework::AttributeMap attrs_;
};
} // namespace imperative

@ -37,6 +37,7 @@ void PreparedOp::PrepareData(
const auto* tensor = GetTensorFromVar(var_base->Var());
if (tensor && tensor->IsInitialized()) {
auto tmp_place = tensor->place();
// TODO(jiabin): Support transform data layout when we Verify it on more
// tests
if (!(tmp_place == place)) {

@ -2,4 +2,4 @@ cc_test(nccl_context_test SRCS nccl_context_test.cc DEPS nccl_context)
cc_test(test_gradient_accmulator SRCS test_gradient_accmulator.cc DEPS gradient_accumulator memcpy)
cc_test(test_layer SRCS test_layer.cc DEPS layer proto_desc operator op_registry variable_helper mul_op memcpy)
cc_test(test_prepare_op SRCS test_prepare_op.cc DEPS prepared_operator op_info split_op layer concat_and_split assign_op place)
cc_test(test_tracer SRCS test_tracer.cc DEPS tracer layer proto_desc operator op_registry variable_helper mul_op memcpy)
cc_test(test_tracer SRCS test_tracer.cc DEPS tracer layer proto_desc operator op_registry variable_helper mul_op reduce_sum_op elementwise_add_op memcpy)

@ -74,6 +74,45 @@ TEST(test_tracer, test_trace_op) {
}
}
TEST(test_tracer, test_trace_op_with_backward) {
// Doing an mul
imperative::Tracer tracer;
std::shared_ptr<imperative::VarBase> x_in(
new imperative::VarBase(true, "x_in"));
std::shared_ptr<imperative::VarBase> y_in(
new imperative::VarBase(true, "y_in"));
std::shared_ptr<imperative::VarBase> vout(
new imperative::VarBase(true, "vout"));
platform::CPUPlace place;
std::vector<float> src_data(10, 2.0);
std::vector<int64_t> dims1 = {2, 5};
std::vector<int64_t> dims2 = {5, 2};
auto* x_in_tensor = x_in->MutableVar()->GetMutable<framework::LoDTensor>();
auto* y_in_tensor = y_in->MutableVar()->GetMutable<framework::LoDTensor>();
x_in_tensor->Resize(framework::make_ddim(dims1));
auto* mutable_x = x_in_tensor->mutable_data<float>(place);
paddle::memory::Copy(place, mutable_x, place, src_data.data(),
sizeof(float) * src_data.size());
y_in_tensor->Resize(framework::make_ddim(dims2));
auto* mutable_y = y_in_tensor->mutable_data<float>(place);
paddle::memory::Copy(place, mutable_y, place, src_data.data(),
sizeof(float) * src_data.size());
var_pair x_pair = var_pair("X", vb_vector(1, x_in));
var_pair y_pair = var_pair("Y", vb_vector(1, y_in));
var_pair out_pair = var_pair("Out", vb_vector(1, vout));
imperative::NameVarBaseMap ins = {x_pair, y_pair};
imperative::NameVarBaseMap outs = {out_pair};
framework::AttributeMap mul_attr_map;
mul_attr_map["use_mkldnn"] = false;
tracer.TraceOp("mul", ins, outs, mul_attr_map, place, true);
const auto& out_tensor = vout->Var().Get<framework::LoDTensor>();
for (size_t i = 0; i < vout->Var().Get<framework::LoDTensor>().numel(); i++) {
ASSERT_EQ(out_tensor.data<float>()[i], 20.0);
}
}
TEST(test_tracer, test_track_backward_output) {
// Doing an mul
imperative::Tracer tracer;
@ -151,15 +190,17 @@ TEST(test_tracer, test_trace_op_with_multi_device_inputs) {
imperative::Tracer tracer;
std::shared_ptr<imperative::VarBase> x_in(
new imperative::VarBase(true, "x_in"));
x_in->SetOverridedStopGradient(false); // force to run backward
std::shared_ptr<imperative::VarBase> y_in(
new imperative::VarBase(true, "y_in"));
y_in->SetOverridedStopGradient(false);
std::shared_ptr<imperative::VarBase> vout(
new imperative::VarBase(true, "vout"));
platform::CPUPlace place;
platform::CUDAPlace gpu_place(0);
std::vector<float> src_data(10, 2.0);
std::vector<int64_t> dims1 = {2, 5};
std::vector<int64_t> dims2 = {5, 2};
std::vector<int64_t> dims2 = {2, 5};
auto* x_in_tensor = x_in->MutableVar()->GetMutable<framework::LoDTensor>();
auto* y_in_tensor = y_in->MutableVar()->GetMutable<framework::LoDTensor>();
@ -178,14 +219,54 @@ TEST(test_tracer, test_trace_op_with_multi_device_inputs) {
imperative::NameVarBaseMap outs = {out_pair};
framework::AttributeMap mul_attr_map;
mul_attr_map["use_mkldnn"] = false;
tracer.TraceOp("mul", ins, outs, mul_attr_map, gpu_place, true);
tracer.TraceOp("elementwise_add", ins, outs, mul_attr_map, gpu_place, true);
// run reduce sum
std::shared_ptr<imperative::VarBase> reduce_sum_out(
new imperative::VarBase(true, "reduce_sum_out"));
var_pair reduce_sum_in_pair = var_pair("X", vb_vector(1, vout));
var_pair reduce_sum_out_pair = var_pair("Out", vb_vector(1, reduce_sum_out));
imperative::NameVarBaseMap reduce_in = {reduce_sum_in_pair};
imperative::NameVarBaseMap reduce_out = {reduce_sum_out_pair};
framework::AttributeMap reduce_attr_map;
tracer.TraceOp("reduce_sum", reduce_in, reduce_out, reduce_attr_map,
gpu_place, true);
detail::BackwardStrategy back_st;
imperative::Engine* engine = tracer.GetDefaultEngine();
engine->Init(reduce_sum_out.get(), back_st);
engine->Execute();
framework::LoDTensor rlt;
framework::TensorCopySync(vout->Var().Get<framework::LoDTensor>(), place,
&rlt);
for (size_t i = 0; i < rlt.numel(); i++) {
ASSERT_EQ(rlt.data<float>()[i], 20.0);
ASSERT_EQ(rlt.data<float>()[i], 4.0);
}
framework::LoDTensor out_grad;
framework::TensorCopySync(vout->GradVar().Get<framework::LoDTensor>(), place,
&out_grad);
for (size_t i = 0; i < out_grad.numel(); ++i) {
ASSERT_EQ(out_grad.data<float>()[i], 1.0);
}
framework::LoDTensor x_grad;
framework::TensorCopySync(x_in->GradVar().Get<framework::LoDTensor>(), place,
&x_grad);
for (size_t i = 0; i < x_grad.numel(); ++i) {
ASSERT_EQ(x_grad.data<float>()[i], 1.0);
}
framework::LoDTensor y_grad;
framework::TensorCopySync(y_in->GradVar().Get<framework::LoDTensor>(), place,
&y_grad);
for (size_t i = 0; i < y_grad.numel(); ++i) {
ASSERT_EQ(y_grad.data<float>()[i], 1.0);
}
}
#endif
TEST(test_tracer, test_unique_name_generator) {
@ -201,3 +282,6 @@ TEST(test_tracer, test_unique_name_generator) {
} // namespace paddle
USE_OP(mul);
USE_OP(reduce_sum);
USE_OP(reduce_sum_grad);
USE_OP(elementwise_add);

File diff suppressed because it is too large Load Diff

@ -60,7 +60,6 @@ class Tracer {
const NameVarBaseMap& outs, bool trace_backward);
void TraceBackward(const std::shared_ptr<OpBase>& fwd_op,
const framework::OpDesc& fwd_op_desc,
const NameVarBaseMap& ins, const NameVarBaseMap& outs);
Engine* GetDefaultEngine() const { return engine_.get(); }

File diff suppressed because it is too large Load Diff

@ -87,18 +87,18 @@ class AddPositionEncodingOpMaker : public framework::OpProtoAndCheckerMaker {
}
};
class AddPositionEncodingGradOpDescMaker
: public framework::SingleGradOpDescMaker {
template <typename T>
class AddPositionEncodingGradOpMaker : public framework::SingleGradOpMaker<T> {
public:
using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;
using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
protected:
std::unique_ptr<framework::OpDesc> Apply() const override {
std::unique_ptr<framework::OpDesc> op(new framework::OpDesc());
std::unique_ptr<T> Apply() const override {
std::unique_ptr<T> op(new T());
op->SetType("add_position_encoding_grad");
op->SetInput(framework::GradVarName("Out"), OutputGrad("Out"));
op->SetOutput(framework::GradVarName("X"), InputGrad("X"));
op->SetAttrMap(Attrs());
op->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
op->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
op->SetAttrMap(this->Attrs());
return op;
}
};
@ -109,9 +109,11 @@ class AddPositionEncodingGradOpDescMaker
namespace ops = paddle::operators;
namespace plt = paddle::platform;
REGISTER_OPERATOR(add_position_encoding, ops::AddPositionEncodingOp,
ops::AddPositionEncodingOpMaker,
ops::AddPositionEncodingGradOpDescMaker);
REGISTER_OPERATOR(
add_position_encoding, ops::AddPositionEncodingOp,
ops::AddPositionEncodingOpMaker,
ops::AddPositionEncodingGradOpMaker<paddle::framework::OpDesc>,
ops::AddPositionEncodingGradOpMaker<paddle::imperative::OpBase>);
REGISTER_OPERATOR(add_position_encoding_grad, ops::AddPositionEncodingOpGrad);
REGISTER_OP_CPU_KERNEL(

@ -127,24 +127,25 @@ class AffineChannelOpGrad : public framework::OperatorWithKernel {
}
};
class AffineChannelGradMaker : public framework::SingleGradOpDescMaker {
template <typename T>
class AffineChannelGradMaker : public framework::SingleGradOpMaker<T> {
public:
using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;
using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
std::unique_ptr<framework::OpDesc> Apply() const override {
auto* op = new framework::OpDesc();
std::unique_ptr<T> Apply() const override {
auto* op = new T();
op->SetType("affine_channel_grad");
op->SetInput("X", Input("X"));
op->SetInput(framework::GradVarName("Out"), OutputGrad("Out"));
op->SetInput("Scale", Input("Scale"));
op->SetInput("X", this->Input("X"));
op->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
op->SetInput("Scale", this->Input("Scale"));
op->SetAttrMap(Attrs());
op->SetAttrMap(this->Attrs());
op->SetOutput(framework::GradVarName("X"), InputGrad("X"));
op->SetOutput(framework::GradVarName("Scale"), InputGrad("Scale"));
op->SetOutput(framework::GradVarName("Bias"), InputGrad("Bias"));
op->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
op->SetOutput(framework::GradVarName("Scale"), this->InputGrad("Scale"));
op->SetOutput(framework::GradVarName("Bias"), this->InputGrad("Bias"));
return std::unique_ptr<framework::OpDesc>(op);
return std::unique_ptr<T>(op);
}
};
@ -331,7 +332,9 @@ namespace ops = paddle::operators;
using CPU = paddle::platform::CPUDeviceContext;
REGISTER_OPERATOR(affine_channel, ops::AffineChannelOp,
ops::AffineChannelOpMaker, ops::AffineChannelGradMaker,
ops::AffineChannelOpMaker,
ops::AffineChannelGradMaker<paddle::framework::OpDesc>,
ops::AffineChannelGradMaker<paddle::imperative::OpBase>,
ops::AffineChannelInplaceInferer);
REGISTER_OPERATOR(affine_channel_grad, ops::AffineChannelOpGrad,
ops::AffineChannelNoNeedBufferVarsInference,

@ -197,22 +197,23 @@ class AffineGridOpGrad : public framework::OperatorWithKernel {
}
};
class AffineGridGradMaker : public framework::SingleGradOpDescMaker {
template <typename T>
class AffineGridGradMaker : public framework::SingleGradOpMaker<T> {
public:
using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;
using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
protected:
std::unique_ptr<framework::OpDesc> Apply() const override {
auto* op = new framework::OpDesc();
std::unique_ptr<T> Apply() const override {
auto* op = new T();
op->SetType("affine_grid_grad");
op->SetInput("Theta", Input("Theta"));
op->SetInput("OutputShape", Input("OutputShape"));
op->SetInput(framework::GradVarName("Output"), OutputGrad("Output"));
op->SetInput("Theta", this->Input("Theta"));
op->SetInput("OutputShape", this->Input("OutputShape"));
op->SetInput(framework::GradVarName("Output"), this->OutputGrad("Output"));
op->SetAttrMap(Attrs());
op->SetAttrMap(this->Attrs());
op->SetOutput(framework::GradVarName("Theta"), InputGrad("Theta"));
return std::unique_ptr<framework::OpDesc>(op);
op->SetOutput(framework::GradVarName("Theta"), this->InputGrad("Theta"));
return std::unique_ptr<T>(op);
}
};
@ -221,7 +222,8 @@ class AffineGridGradMaker : public framework::SingleGradOpDescMaker {
namespace ops = paddle::operators;
REGISTER_OPERATOR(affine_grid, ops::AffineGridOp, ops::AffineGridOpMaker,
ops::AffineGridGradMaker);
ops::AffineGridGradMaker<paddle::framework::OpDesc>,
ops::AffineGridGradMaker<paddle::imperative::OpBase>);
REGISTER_OPERATOR(affine_grid_grad, ops::AffineGridOpGrad);
REGISTER_OP_CPU_KERNEL(

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save