layer.cc 20.7 KB
Newer Older
J
Jiabin Yang 已提交
1
// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15
//
// 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"
16

17
#include "paddle/fluid/framework/op_registry.h"
J
Jiabin Yang 已提交
18
#include "paddle/fluid/framework/variable_helper.h"
19 20
#include "paddle/fluid/imperative/infer_var_type_context.h"
#include "paddle/fluid/imperative/op_base.h"
J
Jiabin Yang 已提交
21 22
#include "paddle/fluid/imperative/prepared_operator.h"
#include "paddle/fluid/operators/math/math_function.h"
M
minqiyang 已提交
23
#include "paddle/fluid/platform/device_context.h"
J
Jiabin Yang 已提交
24
#include "paddle/fluid/platform/enforce.h"
C
chengduo 已提交
25
#include "paddle/fluid/platform/profiler.h"
26 27 28 29 30
#ifdef PADDLE_WITH_MKLDNN
#include "paddle/fluid/platform/mkldnn_helper.h"
#endif

DECLARE_bool(use_mkldnn);
31 32 33
namespace paddle {
namespace imperative {

J
Jiabin Yang 已提交
34
using framework::Variable;
Z
Zeng Jinle 已提交
35 36 37 38 39 40 41 42
void ThreadSafeNameSet::Insert(const std::string& name) {
  std::lock_guard<std::mutex> guard(mtx_);
  set_.insert(name);
}

void ThreadSafeNameSet::Remove(const std::string& name) {
  std::lock_guard<std::mutex> guard(mtx_);
  auto iter = set_.find(name);
43 44 45
  PADDLE_ENFORCE_EQ(
      iter != set_.end(), true,
      platform::errors::NotFound("Variable name %s does not exist", name));
Z
Zeng Jinle 已提交
46 47 48 49 50 51 52 53 54 55 56 57
  set_.erase(iter);
}

std::vector<std::string> ThreadSafeNameSet::Names() const {
  std::lock_guard<std::mutex> guard(mtx_);
  return std::vector<std::string>(set_.begin(), set_.end());
}

ThreadSafeNameSet VarBase::name_set_;

std::vector<std::string> VarBase::AliveVarNames() { return name_set_.Names(); }

J
Jiabin Yang 已提交
58 59 60 61 62 63 64 65 66
static framework::RuntimeContext PrepareRuntimeContext(
    const NameVarBaseMap& ins, const NameVarBaseMap& outs) {
  framework::VariableValueMap inputs, outputs;
  for (auto& in_pair : ins) {
    auto& in_ctx = inputs[in_pair.first];
    in_ctx.reserve(in_pair.second.size());
    for (auto& in_var : in_pair.second) {
      in_ctx.emplace_back(in_var->MutableVar());
    }
M
minqiyang 已提交
67 68
  }

J
Jiabin Yang 已提交
69 70 71 72 73
  for (auto& out_pair : outs) {
    auto& out_ctx = outputs[out_pair.first];
    out_ctx.reserve(out_pair.second.size());
    for (auto& out_var : out_pair.second) {
      out_ctx.emplace_back(out_var->MutableVar());
74
    }
J
Jiabin Yang 已提交
75 76 77 78
  }
  return framework::RuntimeContext(std::move(inputs), std::move(outputs));
}

79
template <typename VarType>
J
Jiabin Yang 已提交
80 81
static std::string DebugString(
    const std::string& name,
82
    const std::vector<std::shared_ptr<VarType>>& vars) {
J
Jiabin Yang 已提交
83 84
  std::stringstream ss;
  ss << name << "{";
M
minqiyang 已提交
85

J
Jiabin Yang 已提交
86 87
  for (size_t i = 0; i < vars.size(); ++i) {
    if (i > 0) ss << ", ";
M
minqiyang 已提交
88

J
Jiabin Yang 已提交
89 90 91 92 93
    if (vars[i] == nullptr) {
      ss << "NULL";
      continue;
    }
    ss << vars[i]->Name() << "[";
94
    const framework::Variable& var = vars[i]->Var();
J
Jiabin Yang 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107
    if (!var.IsInitialized()) {
      ss << "NOT_INITED_VAR";
    } else if (var.IsType<framework::LoDTensor>()) {
      auto& tensor = var.Get<framework::LoDTensor>();
      ss << "LoDTensor<";
      if (tensor.IsInitialized()) {
        ss << framework::DataTypeToString(tensor.type()) << ", ";
        ss << tensor.place() << ", ";
        ss << "(" << tensor.dims() << ")";
      } else {
        ss << "NOT_INITED";
      }
      ss << ">";
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
    } else if (var.IsType<framework::SelectedRows>()) {
      ss << "SelectedRows<";
      auto& selected_rows = var.Get<framework::SelectedRows>();
      auto& tensor = selected_rows.value();
      auto& rows = selected_rows.rows();
      if (tensor.IsInitialized()) {
        ss << framework::DataTypeToString(tensor.type()) << ", ";
        ss << tensor.place() << ", ";
        ss << "height(" << selected_rows.height() << "), rows(";
        std::for_each(rows.cbegin(), rows.cend(),
                      [&ss](const int64_t r) { ss << r << " "; });
        ss << "), dims(" << tensor.dims() << ")";
      } else {
        ss << "NOT_INITED";
      }
      ss << ">";
J
Jiabin Yang 已提交
124 125 126 127
    } else {
      ss << "UNRESOLVED_TYPE";
    }
    ss << "]";
128
  }
129

J
Jiabin Yang 已提交
130 131
  ss << "}";
  return ss.str();
132 133
}

134 135 136 137
template <typename VarType>
static std::string LayerDebugStringImpl(const std::string& op_type,
                                        const NameVarMap<VarType>& ins,
                                        const NameVarMap<VarType>& outs) {
J
Jiabin Yang 已提交
138 139 140 141 142 143 144 145
  std::stringstream ss;
  ss << "Op(" << op_type << "): ";

  ss << "Inputs: ";

  size_t i = 0;
  for (auto& pair : ins) {
    if (i > 0) ss << ", ";
146
    ss << DebugString<VarType>(pair.first, pair.second);
J
Jiabin Yang 已提交
147
    ++i;
148 149
  }

J
Jiabin Yang 已提交
150 151 152 153
  ss << ",   Outputs: ";
  i = 0;
  for (auto& pair : outs) {
    if (i > 0) ss << ", ";
154
    ss << DebugString<VarType>(pair.first, pair.second);
J
Jiabin Yang 已提交
155 156 157 158
    ++i;
  }
  return ss.str();
}
159

160 161 162 163 164 165 166 167 168 169
std::string LayerDebugString(const std::string& op_type,
                             const NameVarMap<VarBase>& ins,
                             const NameVarMap<VarBase>& outs) {
  return LayerDebugStringImpl<VarBase>(op_type, ins, outs);
}

std::string LayerDebugString(const std::string& op_type,
                             const NameVarMap<VariableWrapper>& ins,
                             const NameVarMap<VariableWrapper>& outs) {
  return LayerDebugStringImpl<VariableWrapper>(op_type, ins, outs);
J
Jiabin Yang 已提交
170
}
171

172
VarBase::VarBase(const std::shared_ptr<VariableWrapper>& var)
173
    : var_(var), grad_node_(var->GetGradNode()) {
174 175
  if (auto grad_var = var_->GetGradVar()) {
    grad_var_ = std::make_shared<VarBase>(grad_var);
176 177 178 179 180 181 182 183 184 185 186 187
  }

  if (IsDebugEnabled()) {
    VLOG(10) << "Construct VarBase: " << Name();
    name_set_.Insert(Name());
  }
}

size_t VarBase::GradOpNum() const {
  return grad_node_ ? grad_node_->size() : 0;
}

188
void VarBase::ClearGradient(bool set_to_zero) {
189
  VLOG(4) << "ClearGradient " << Name();
J
Jiabin Yang 已提交
190
  if (grad_var_) {
191 192 193
    if (grad_var_->Var().IsType<framework::SelectedRows>()) {
      auto* grad_t =
          grad_var_->MutableVar()->GetMutable<framework::SelectedRows>();
194
      if (grad_t->mutable_value()->IsInitialized()) {
195 196 197
#ifdef PADDLE_WITH_MKLDNN
        if (FLAGS_use_mkldnn) ClearMKLDNNCache(grad_t->place());
#endif
198 199 200 201
        grad_t->mutable_rows()->clear();
        grad_t->mutable_value()->clear();
      }
    } else {
202
      platform::RecordEvent record_event("ClearGradient");
203 204
      auto* grad_t =
          grad_var_->MutableVar()->GetMutable<framework::LoDTensor>();
205
      if (grad_t->IsInitialized()) {
206 207 208 209 210 211 212
        if (set_to_zero) {
          auto* dev_ctx =
              platform::DeviceContextPool::Instance().Get(grad_t->place());
          operators::math::set_constant(*dev_ctx, grad_t, 0.0);
        } else {
          grad_t->clear();
        }
213 214 215
#ifdef PADDLE_WITH_MKLDNN
        if (FLAGS_use_mkldnn) ClearMKLDNNCache(grad_t->place());
#endif
216
      }
217
    }
218 219 220 221
    // TODO(zhouwei): It's better to free memory of grad by grad_t->claer.
    // But will have some bug on mac CPU of yolov3 model, why?
    // After fix this bug, function SetIsEmpty() isn't need
    grad_var_->SharedVar()->SetIsEmpty(true);
222
  }
J
Jiabin Yang 已提交
223
}
224

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
void VarBase::_GradientSetEmpty(bool is_empty) {
  VLOG(4) << "Set gradient " << Name() << " is_empty:" << is_empty;
  if (grad_var_) {
    auto share_var = grad_var_->SharedVar();
    if (share_var) {
      share_var->SetIsEmpty(is_empty);
    }
  }
}

bool VarBase::_IsGradientSetEmpty() {
  bool res = true;
  if (grad_var_) {
    auto share_var = grad_var_->SharedVar();
    if (share_var) {
      res = share_var->is_empty_;
      VLOG(4) << "Check gradient " << Name() << " is empty:" << res;
    }
  }
  return res;
}

J
Jiabin Yang 已提交
247
std::shared_ptr<VarBase> VarBase::NewVarBase(const platform::Place& dst_place,
M
minqiyang 已提交
248
                                             const bool blocking) const {
249
  PADDLE_ENFORCE_EQ(
250 251
      Var().IsInitialized() && (Var().IsType<framework::LoDTensor>() ||
                                Var().IsType<framework::SelectedRows>()),
252 253 254
      true, platform::errors::InvalidArgument(
                "Variable is not initialized or Variable's type is not "
                "LoDTensor or SelectedRows when getting numpy tensor"));
255

256 257
  if (Var().IsType<framework::LoDTensor>()) {
    auto& src_tensor = Var().Get<framework::LoDTensor>();
258 259
    // TODO(Jiabin): change this after move unique_name generator to CXX
    auto new_var = std::make_shared<VarBase>(
260
        true, Name() + std::to_string(copied_counter_++));
261

262 263
    auto* dst_tensor =
        new_var->MutableVar()->GetMutable<framework::LoDTensor>();
264
    dst_tensor->set_lod(src_tensor.lod());
265 266 267
    new_var->SetPersistable(Persistable());
    new_var->SetDataType(DataType());
    new_var->SetType(Type());
268 269 270 271 272 273 274
    framework::TensorCopy(src_tensor, dst_place, dst_tensor);
    if (blocking) {
      platform::DeviceContextPool::Instance().Get(dst_place)->Wait();
      auto src_place = src_tensor.place();
      if (!(src_place == dst_place)) {
        platform::DeviceContextPool::Instance().Get(src_place)->Wait();
      }
275
    }
276 277
    VLOG(4) << "copy tensor " << Name() << " from " << Place() << " to "
            << dst_place;
278 279
    return new_var;
  } else {
280
    auto& src_selected_rows = Var().Get<framework::SelectedRows>();
281 282 283 284
    auto new_var = std::make_shared<VarBase>(
        false, "Itmp" + std::to_string(copied_counter_++));
    new_var->SetType(framework::proto::VarType::SELECTED_ROWS);
    auto* dst_selected_rows =
285
        new_var->MutableVar()->GetMutable<framework::SelectedRows>();
286 287 288 289 290 291 292 293 294 295 296 297

    framework::TensorCopy(src_selected_rows.value(), dst_place,
                          dst_selected_rows->mutable_value());
    if (blocking) {
      platform::DeviceContextPool::Instance().Get(dst_place)->Wait();
      auto src_place = src_selected_rows.place();
      if (!(src_place == dst_place)) {
        platform::DeviceContextPool::Instance().Get(src_place)->Wait();
      }
    }
    dst_selected_rows->set_height(src_selected_rows.height());
    dst_selected_rows->set_rows(src_selected_rows.rows());
298 299
    VLOG(4) << "copy tensor " << Name() << " from " << Place() << " to "
            << dst_place;
300 301
    return new_var;
  }
M
minqiyang 已提交
302 303
}

304
void VarBase::CopyFrom(const VarBase& src, const bool blocking) {
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
  if (src.SharedVar()->IsEmpty()) {
    return;
  }

  VLOG(3) << "Deep copy Tensor from " << src.Name() << " to " << Name();
  if (Var().IsInitialized()) {
    PADDLE_ENFORCE_EQ(DataType(), src.DataType(),
                      platform::errors::PreconditionNotMet(
                          "Tensor %s has different data type with Tensor %s, "
                          "Tensor Copy cannot be performed!",
                          Name(), src.Name()));
    PADDLE_ENFORCE_EQ(Type(), src.Type(),
                      platform::errors::PreconditionNotMet(
                          "Tensor %s has different type with Tensor %s, Tensor "
                          "Copy cannot be performed!",
                          Name(), src.Name()));
  } else {
322 323
    SetDataType(src.DataType());
    SetType(src.Type());
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
    SetPersistable(src.Persistable());
    InnerSetOverridedStopGradient(src.OverridedStopGradient());
  }

  platform::Place place = src.Place();
  if (src.Var().IsType<framework::LoDTensor>()) {
    auto& src_tensor = src.Var().Get<framework::LoDTensor>();
    auto* dst_tensor = MutableVar()->GetMutable<framework::LoDTensor>();
    if (dst_tensor && dst_tensor->IsInitialized()) {
      PADDLE_ENFORCE_EQ(dst_tensor->dims(), src_tensor.dims(),
                        platform::errors::PreconditionNotMet(
                            "Tensor %s has different dims with Tensor %s, "
                            "Tensor Copy cannot be performed!",
                            Name(), src.Name()));
      PADDLE_ENFORCE_EQ(dst_tensor->lod(), src_tensor.lod(),
                        platform::errors::PreconditionNotMet(
                            "Tensor %s has different dims with Tensor %s, "
                            "Tensor Copy cannot be performed!",
                            Name(), src.Name()));
      place = Place();
    } else {
      dst_tensor->set_lod(src_tensor.lod());
      dst_tensor->Resize(src_tensor.dims());
    }
    framework::TensorCopy(src_tensor, place, dst_tensor);
  } else if (src.Var().IsType<framework::SelectedRows>()) {
    auto& src_selected_rows = src.Var().Get<framework::SelectedRows>();
    auto* dst_selected_rows =
        MutableVar()->GetMutable<framework::SelectedRows>();
    dst_selected_rows->set_height(src_selected_rows.height());
    dst_selected_rows->set_rows(src_selected_rows.rows());

    auto& src_tensor = src_selected_rows.value();
    auto* dst_tensor = dst_selected_rows->mutable_value();
    if (dst_tensor && dst_tensor->IsInitialized()) {
      PADDLE_ENFORCE_EQ(dst_tensor->dims(), src_tensor.dims(),
                        platform::errors::PreconditionNotMet(
                            "Tensor %s has different dims with Tensor %s, "
                            "Tensor Copy cannot be performed!",
                            Name(), src.Name()));
      place = Place();
    } else {
      dst_tensor->Resize(src_tensor.dims());
367
    }
368 369 370 371
    framework::TensorCopy(src_tensor, place, dst_tensor);
  }
  if (blocking) {
    platform::DeviceContextPool::Instance().Get(place)->Wait();
372 373 374
  }
}

375 376 377 378 379 380 381 382 383
void VarBase::BumpInplaceVersion() {
  PADDLE_ENFORCE_EQ(
      Var().IsInitialized(), true,
      platform::errors::InvalidArgument(
          "Tensor %s has not been initialized, please check if it has no data.",
          Name()));
  MutableVar()->BumpInplaceVersion();
}

384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
// NOTE(weilong wu):
// This function try to copy the data from target varbase,
// and fill into the grad_var_ of the current varbase.
void VarBase::_CopyGradientFrom(const VarBase& src) {
  if (Var().IsInitialized()) {
    PADDLE_ENFORCE_EQ(DataType(), src.DataType(),
                      platform::errors::PreconditionNotMet(
                          "Tensor %s has different data type with Tensor %s",
                          Name(), src.Name()));
    PADDLE_ENFORCE_EQ(Type(), src.Type(),
                      platform::errors::PreconditionNotMet(
                          "Tensor %s has different type with Tensor %s, Tensor "
                          "ShareGradientDataWith cannot be performed!",
                          Name(), src.Name()));
  }
  VLOG(4) << " VarBase copy gradient with " << src.Name();
  if (grad_var_) {
    auto& src_tensor = src.Var().Get<framework::LoDTensor>();
    PADDLE_ENFORCE_EQ(src_tensor.IsInitialized(), true,
                      platform::errors::InvalidArgument(
                          "tensor has not been initialized", src.Name()));
    auto* grad_t = grad_var_->MutableVar()->GetMutable<framework::LoDTensor>();
    auto* var_ = MutableVar()->GetMutable<framework::LoDTensor>();
    grad_t->ShareDataWith(src_tensor);
    grad_t->Resize(var_->dims());
  }
}

412 413
pten::KernelContext OpBase::pt_kernel_context_;

414
void OpBase::SetType(const std::string& type) {
H
hong 已提交
415
  op_ = framework::OpRegistry::CreateOp(type, {}, {}, {}, false);
J
Jiabin Yang 已提交
416
}
417

418 419 420
void OpBase::ClearBackwardTrace() {
  ins_.clear();
  outs_.clear();
H
hong 已提交
421 422
}

423 424 425 426 427
template <typename VarType>
static void OpBaseRunImpl(const framework::OperatorBase& op,
                          const NameVarMap<VarType>& ins,
                          const NameVarMap<VarType>& outs,
                          const framework::AttributeMap& attrs,
428
                          const framework::AttributeMap& default_attrs,
429 430
                          const platform::Place& place,
                          pten::KernelContext* pt_kernel_context) {
431
  auto* op_kernel = dynamic_cast<const framework::OperatorWithKernel*>(&op);
432 433 434
  PADDLE_ENFORCE_NOT_NULL(
      op_kernel, platform::errors::PermissionDenied(
                     "Only support operator with kernel in Dygraph mode."));
435
  auto& info = op.Info();
J
Jiabin Yang 已提交
436
  if (info.infer_var_type_) {
437 438
    RuntimeInferVarTypeContext<VarType> infer_var_type_ctx(ins, outs, attrs,
                                                           default_attrs);
J
Jiabin Yang 已提交
439
    info.infer_var_type_(&infer_var_type_ctx);
X
Xin Pan 已提交
440
  }
441

J
Jiabin Yang 已提交
442 443 444
  // Initialize output var type
  for (auto& var_pair : outs) {
    for (auto& var : var_pair.second) {
445 446 447
      if (var) {
        InitializeVariable(var->MutableVar(), var->Type());
      }
448 449
    }
  }
X
Xin Pan 已提交
450

451
  VLOG(5) << LayerDebugString(op.Type(), ins, outs);
452

453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
  /**
   * [ Why need temporary inputs here? ]
   *
   * PrepareData should not change original input tensor inplace.
   * Suppose the user defines a tensor(int), enters an op to execute,
   * and then this op rewrites GetExpectedKernelForVar, and converts
   * this tensor to float type during execution. After the dynamic
   * graph is executed, the user-defined variable will be lost, and
   * the user cannot get the originally defined int tensor, because
   * it has been converted to float, this should be regarded as a bug
   * in certain usage scenarios
   *
   * In static graph mode, when op is executed, a temporary scope
   * `transfer_scope` is created before PrepareData, the data after
   * transform is stored in the temporary scope, and then discarded
   * after the execution of op, but the original input is directly
   * overwritten in the previous dynamic graph implemention.
   */
471 472
  auto prepared_op = PreparedOp::Prepare(ins, outs, *op_kernel, place, attrs,
                                         default_attrs, pt_kernel_context);
473 474 475
  auto tmp_ins_ptr =
      PrepareData<VarType>(*op_kernel, ins, prepared_op.kernel_type());
  if (tmp_ins_ptr == nullptr) {
476
    prepared_op.Run(ins, outs, attrs, default_attrs);
477
  } else {
478
    prepared_op.Run(*tmp_ins_ptr, outs, attrs, default_attrs);
479
  }
480

481
  VLOG(4) << LayerDebugString(op.Type(), ins, outs);
482 483 484 485 486 487 488 489 490 491

  // set the output var
  for (auto& var_pair : outs) {
    for (auto& var : var_pair.second) {
      // NOTE(zhiqu): The ouput may be NULL because of pruning.
      if (var) {
        SetForwardDataTypeOfGradVar(var);
      }
    }
  }
492 493
}

494 495 496 497
void OpBase::Run(const framework::OperatorBase& op,
                 const NameVarMap<VarBase>& ins,
                 const NameVarMap<VarBase>& outs,
                 const framework::AttributeMap& attrs,
498
                 const framework::AttributeMap& default_attrs,
499
                 const platform::Place& place) {
500 501
  OpBaseRunImpl<VarBase>(op, ins, outs, attrs, default_attrs, place,
                         &pt_kernel_context_);
502 503 504 505 506 507
}

void OpBase::Run(const framework::OperatorBase& op,
                 const NameVarMap<VariableWrapper>& ins,
                 const NameVarMap<VariableWrapper>& outs,
                 const framework::AttributeMap& attrs,
508
                 const framework::AttributeMap& default_attrs,
509
                 const platform::Place& place) {
510 511
  OpBaseRunImpl<VariableWrapper>(op, ins, outs, attrs, default_attrs, place,
                                 &pt_kernel_context_);
512 513
}

514
void ClearNoNeedBufferInputs(OpBase* op) {
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
  auto& inferer = op->Info().NoNeedBufferVarsInferer();
  if (!inferer) return;
  auto* ins = op->GetMutableInsMap();
  const auto& no_need_buffer_slots =
      inferer(*ins, op->GetOutsMap(), op->Attrs());
  if (no_need_buffer_slots.empty()) return;

  for (auto& slot : no_need_buffer_slots) {
    auto iter = ins->find(slot);
    if (iter == ins->end()) continue;
    VLOG(2) << "Clear data buffer of " << slot << " in " << op->Type();

    PADDLE_ENFORCE_EQ(
        iter->second.IsGrad(), false,
        platform::errors::InvalidArgument(
            "Only forward variable buffers can be clear, this may be a bug"));

    for (auto& each_var : *(iter->second.MutableVarList())) {
      if (!each_var) continue;

      auto& var = each_var->Var();
      PADDLE_ENFORCE_EQ(var.IsType<framework::LoDTensor>(), true,
                        platform::errors::PermissionDenied(
                            "NoNeedBufferVars only support LoDTensor"));
      auto new_var = new VariableWrapper(each_var->Name());
      auto* new_tensor =
          new_var->MutableVar()->GetMutable<framework::LoDTensor>();
      auto& old_tensor = var.Get<framework::LoDTensor>();
      new_tensor->Resize(old_tensor.dims());
      new_tensor->set_lod(old_tensor.lod());
      each_var.reset(new_var);
    }
  }
}

std::shared_ptr<GradOpNode> CreateGradOpNode(
    const framework::OperatorBase& op, const NameVarBaseMap& ins,
    const NameVarBaseMap& outs, const framework::AttributeMap& attrs,
553
    const framework::AttributeMap& default_attrs, const platform::Place& place,
554
    const std::map<std::string, std::string>& inplace_map) {
555 556 557 558 559
  const auto& info = op.Info();
  if (!info.dygraph_grad_op_maker_) {
    return nullptr;
  }

560 561
  auto grad_node = info.dygraph_grad_op_maker_(op.Type(), ins, outs, attrs,
                                               default_attrs, inplace_map);
562
  if (grad_node && !grad_node->empty()) {
563 564 565 566
    for (auto& grad_op : *grad_node) {
      grad_op.SetId(OpBase::GenerateUniqueId());
      grad_op.SetPlace(place);
      ClearNoNeedBufferInputs(&grad_op);
567 568 569 570 571 572 573
    }
    return grad_node;
  } else {
    return nullptr;
  }
}

574 575
}  // namespace imperative
}  // namespace paddle