test_tracer.cc 22.5 KB
Newer Older
J
Jiabin Yang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// 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.

//
// Created by Jiabin on 2019-08-16.
//

#include <memory>
20
#include <set>
J
Jiabin Yang 已提交
21 22
#include <string>
#include <vector>
23

J
Jiabin Yang 已提交
24
#include "gtest/gtest.h"
J
Jiabin Yang 已提交
25
#include "paddle/fluid/framework/op_registry.h"
26
#include "paddle/fluid/imperative/basic_engine.h"
J
Jiabin Yang 已提交
27
#include "paddle/fluid/imperative/execution_context.h"
J
Jiabin Yang 已提交
28
#include "paddle/fluid/imperative/tracer.h"
29
#include "paddle/fluid/memory/memcpy.h"
J
Jiabin Yang 已提交
30
#include "paddle/fluid/platform/device_context.h"
J
Jiabin Yang 已提交
31 32 33 34 35 36 37 38 39 40 41

namespace imperative = paddle::imperative;
namespace platform = paddle::platform;
namespace framework = paddle::framework;

namespace paddle {
namespace imperative {

using vb_vector = std::vector<std::shared_ptr<imperative::VarBase>>;
using var_pair = std::pair<std::string, vb_vector>;

42 43
using ev_vector = std::vector<std::shared_ptr<egr::EagerVariable>>;
using ev_pair = std::pair<std::string, ev_vector>;
J
Jiabin Yang 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
TEST(test_tracer, test_trace_op) {
  // 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>();
60
  x_in_tensor->Resize(phi::make_ddim(dims1));
J
Jiabin Yang 已提交
61 62 63
  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());
64
  y_in_tensor->Resize(phi::make_ddim(dims2));
J
Jiabin Yang 已提交
65 66 67 68 69 70 71 72 73 74 75
  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;
J
Jiabin Yang 已提交
76
  tracer.TraceOp<VarBase>("mul", ins, outs, mul_attr_map, place, true);
77 78

#ifndef PADDLE_WITH_XPU
J
Jiabin Yang 已提交
79 80
  ASSERT_THROW(tracer.TraceOp<VarBase>("mul", ins, outs, mul_attr_map,
                                       platform::XPUPlace(0), true);
81 82 83
               , platform::EnforceNotMet);
#endif

J
Jiabin Yang 已提交
84
  const auto& out_tensor = vout->Var().Get<framework::LoDTensor>();
85
  for (int i = 0; i < vout->Var().Get<framework::LoDTensor>().numel(); i++) {
J
Jiabin Yang 已提交
86 87 88 89
    ASSERT_EQ(out_tensor.data<float>()[i], 20.0);
  }
}

H
hong 已提交
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
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>();
106
  x_in_tensor->Resize(phi::make_ddim(dims1));
H
hong 已提交
107 108 109
  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());
110
  y_in_tensor->Resize(phi::make_ddim(dims2));
H
hong 已提交
111 112 113 114 115 116 117 118 119 120 121
  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;
J
Jiabin Yang 已提交
122
  tracer.TraceOp<VarBase>("mul", ins, outs, mul_attr_map, place, true);
H
hong 已提交
123
  const auto& out_tensor = vout->Var().Get<framework::LoDTensor>();
124
  for (int i = 0; i < vout->Var().Get<framework::LoDTensor>().numel(); i++) {
H
hong 已提交
125 126 127 128
    ASSERT_EQ(out_tensor.data<float>()[i], 20.0);
  }
}

J
Jiabin Yang 已提交
129 130 131 132 133 134
TEST(test_tracer, test_track_backward_output) {
  // 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(
135
      new imperative::VarBase(true, "y_in"));
136
  x_in->SetOverridedStopGradient(false);
J
Jiabin Yang 已提交
137 138 139 140 141 142 143 144 145
  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>();
146
  x_in_tensor->Resize(phi::make_ddim(dims1));
J
Jiabin Yang 已提交
147 148 149
  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());
150
  y_in_tensor->Resize(phi::make_ddim(dims2));
J
Jiabin Yang 已提交
151 152 153 154 155 156 157 158 159 160 161
  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;
J
Jiabin Yang 已提交
162
  tracer.TraceOp<VarBase>("mul", ins, outs, mul_attr_map, place, true);
163 164 165
  ASSERT_EQ(x_in->GradVarBase()->GradOpNum(), 0UL);
  ASSERT_EQ(y_in->GradVarBase()->GradOpNum(), 0UL);
  ASSERT_EQ(vout->GradVarBase()->GradOpNum(), 1UL);
J
Jiabin Yang 已提交
166 167 168 169 170 171 172 173 174 175
}

TEST(test_tracer, test_track_backward_input) {
  // 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(
176
      new imperative::VarBase(true, "vout"));
J
Jiabin Yang 已提交
177
  platform::CPUPlace place;
178
  x_in->SetOverridedStopGradient(false);
J
Jiabin Yang 已提交
179 180 181 182 183 184
  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>();
185
  x_in_tensor->Resize(phi::make_ddim(dims1));
J
Jiabin Yang 已提交
186 187 188
  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());
189
  y_in_tensor->Resize(phi::make_ddim(dims2));
J
Jiabin Yang 已提交
190 191 192 193 194 195 196 197 198 199 200
  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;
J
Jiabin Yang 已提交
201
  tracer.TraceOp<VarBase>("mul", ins, outs, mul_attr_map, place, true);
202

203 204 205
  ASSERT_EQ(x_in->GradVarBase()->GradOpNum(), 0UL);
  ASSERT_EQ(y_in->GradVarBase()->GradOpNum(), 0UL);
  ASSERT_EQ(vout->GradVarBase()->GradOpNum(), 1UL);
J
Jiabin Yang 已提交
206
}
207
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
208 209 210 211 212
TEST(test_tracer, test_trace_op_with_multi_device_inputs) {
  // Doing an mul
  imperative::Tracer tracer;
  std::shared_ptr<imperative::VarBase> x_in(
      new imperative::VarBase(true, "x_in"));
H
hong 已提交
213
  x_in->SetOverridedStopGradient(false);  // force to run backward
214 215
  std::shared_ptr<imperative::VarBase> y_in(
      new imperative::VarBase(true, "y_in"));
H
hong 已提交
216
  y_in->SetOverridedStopGradient(false);
217 218 219 220 221 222
  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};
H
hong 已提交
223
  std::vector<int64_t> dims2 = {2, 5};
224 225 226

  auto* x_in_tensor = x_in->MutableVar()->GetMutable<framework::LoDTensor>();
  auto* y_in_tensor = y_in->MutableVar()->GetMutable<framework::LoDTensor>();
227
  x_in_tensor->Resize(phi::make_ddim(dims1));
228 229 230
  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());
231
  y_in_tensor->Resize(phi::make_ddim(dims2));
232 233 234 235 236 237 238 239 240 241
  auto* mutable_y = y_in_tensor->mutable_data<float>(gpu_place);
  paddle::memory::Copy(gpu_place, mutable_y, place, src_data.data(),
                       sizeof(float) * src_data.size(), 0);
  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;
J
Jiabin Yang 已提交
242 243
  tracer.TraceOp<VarBase>("elementwise_add", ins, outs, mul_attr_map, gpu_place,
                          true);
H
hong 已提交
244 245 246 247 248 249 250 251 252

  // 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;
J
Jiabin Yang 已提交
253 254
  tracer.TraceOp<VarBase>("reduce_sum", reduce_in, reduce_out, reduce_attr_map,
                          gpu_place, true);
255
  imperative::BasicEngine engine;
256 257 258 259

  std::vector<std::shared_ptr<imperative::VarBase>> tensors{reduce_sum_out};
  std::vector<std::shared_ptr<imperative::VarBase>> grad_tensors{nullptr};
  engine.Init(tensors, grad_tensors);
260
  engine.Execute();
H
hong 已提交
261

262 263 264
  framework::LoDTensor rlt;
  framework::TensorCopySync(vout->Var().Get<framework::LoDTensor>(), place,
                            &rlt);
265
  for (int i = 0; i < rlt.numel(); i++) {
H
hong 已提交
266 267 268 269 270 271
    ASSERT_EQ(rlt.data<float>()[i], 4.0);
  }

  framework::LoDTensor out_grad;
  framework::TensorCopySync(vout->GradVar().Get<framework::LoDTensor>(), place,
                            &out_grad);
272
  for (int i = 0; i < out_grad.numel(); ++i) {
H
hong 已提交
273 274 275 276 277 278 279
    ASSERT_EQ(out_grad.data<float>()[i], 1.0);
  }

  framework::LoDTensor x_grad;
  framework::TensorCopySync(x_in->GradVar().Get<framework::LoDTensor>(), place,
                            &x_grad);

280
  for (int i = 0; i < x_grad.numel(); ++i) {
H
hong 已提交
281 282 283 284 285 286 287
    ASSERT_EQ(x_grad.data<float>()[i], 1.0);
  }

  framework::LoDTensor y_grad;
  framework::TensorCopySync(y_in->GradVar().Get<framework::LoDTensor>(), place,
                            &y_grad);

288
  for (int i = 0; i < y_grad.numel(); ++i) {
H
hong 已提交
289
    ASSERT_EQ(y_grad.data<float>()[i], 1.0);
290 291
  }
}
H
hong 已提交
292

293
#endif
294 295 296 297 298 299

TEST(test_tracer, test_unique_name_generator) {
  // generate two unique names
  imperative::Tracer tracer;
  auto fc_1 = tracer.GenerateUniqueName("fc");
  auto fc_2 = tracer.GenerateUniqueName("fc");
L
Leo Chen 已提交
300 301
  ASSERT_STREQ("fc_0", fc_1.c_str());
  ASSERT_STREQ("fc_1", fc_2.c_str());
302 303
  // use `eager_tmp` as key if not specify it.
  auto tmp_var_2 = tracer.GenerateUniqueName();
304 305 306
  ASSERT_STREQ("dygraph_tmp_2", tmp_var_2.c_str());
  auto tmp_var_3 = tracer.GenerateUniqueName("dygraph_tmp");
  ASSERT_STREQ("dygraph_tmp_3", tmp_var_3.c_str());
307 308
}

309 310 311 312 313 314 315 316 317 318 319 320
TEST(test_tracer, test_current_tracer) {
  // use current_tracer
  auto tracer = std::make_shared<imperative::Tracer>();
  imperative::SetCurrentTracer(tracer);
  auto current_tracer = imperative::GetCurrentTracer();
  ASSERT_EQ(current_tracer, tracer);
}

TEST(test_tracer, test_expected_place) {
  // default expected place is CPUPlace
  imperative::Tracer tracer;
  ASSERT_EQ(platform::is_cpu_place(tracer.ExpectedPlace()), true);
W
WangXi 已提交
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
  {
#ifdef PADDLE_WITH_CUDA
    // set to CUDAPlace
    platform::CUDAPlace gpu_place(0);
    tracer.SetExpectedPlace(gpu_place);
    ASSERT_EQ(platform::is_gpu_place(tracer.ExpectedPlace()), true);
#endif
  }
  {
#ifdef PADDLE_WITH_XPU
    // set to XPUPlace
    platform::XPUPlace xpu_place(0);
    tracer.SetExpectedPlace(xpu_place);
    ASSERT_EQ(platform::is_xpu_place(tracer.ExpectedPlace()), true);
#endif
  }
337 338
}

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
TEST(test_tracer, test_var_without_grad_var) {
  // Doing an mul
  imperative::Tracer tracer;
  std::shared_ptr<imperative::VarBase> x_in(
      new imperative::VarBase(true, "x_in"));
  x_in->ClearGradVarBase();
  std::shared_ptr<imperative::VarBase> y_in(
      new imperative::VarBase(true, "y_in"));
  std::shared_ptr<imperative::VarBase> vout(
      new imperative::VarBase(true, "vout"));
  x_in->SetOverridedStopGradient(false);
  y_in->SetOverridedStopGradient(false);
  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>();
358
  x_in_tensor->Resize(phi::make_ddim(dims1));
359 360 361
  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());
362
  y_in_tensor->Resize(phi::make_ddim(dims2));
363 364 365 366 367 368 369 370 371 372 373
  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;
J
Jiabin Yang 已提交
374
  tracer.TraceOp<VarBase>("mul", ins, outs, mul_attr_map, place, true);
375 376 377 378 379 380

  const auto& out_tensor = vout->Var().Get<framework::LoDTensor>();
  for (int i = 0; i < vout->Var().Get<framework::LoDTensor>().numel(); i++) {
    ASSERT_EQ(out_tensor.data<float>()[i], 20.0);
  }

381 382 383
  ASSERT_EQ(x_in->GradVarBase()->GradOpNum(), 0UL);
  ASSERT_EQ(y_in->GradVarBase()->GradOpNum(), 0UL);
  ASSERT_EQ(vout->GradVarBase()->GradOpNum(), 1UL);
384

385 386
  std::vector<std::shared_ptr<imperative::VarBase>> tensors{vout};
  std::vector<std::shared_ptr<imperative::VarBase>> grad_tensors{nullptr};
387
  imperative::BasicEngine engine;
388
  engine.Init(tensors, grad_tensors);
389
  engine.Execute();
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408

  // check the grad
  framework::LoDTensor x_grad;
  framework::TensorCopySync(x_in->GradVar().Get<framework::LoDTensor>(), place,
                            &x_grad);

  for (int i = 0; i < x_grad.numel(); ++i) {
    ASSERT_EQ(x_grad.data<float>()[i], 4.0);
  }

  framework::LoDTensor y_grad;
  framework::TensorCopySync(y_in->GradVar().Get<framework::LoDTensor>(), place,
                            &y_grad);

  for (int i = 0; i < y_grad.numel(); ++i) {
    ASSERT_EQ(y_grad.data<float>()[i], 4.0);
  }
}

409 410 411 412 413 414 415 416 417
template <typename T>
using WeakPtrSet =
    std::set<std::weak_ptr<T>, std::owner_less<std::weak_ptr<T>>>;

static void TestVarOpDestructionMain(const platform::Place& place,
                                     int64_t tensor_size = 10,
                                     size_t loop_num = 10) {
  WeakPtrSet<VariableWrapper> var_wrappers;
  WeakPtrSet<VarBase> var_bases;
418
  WeakPtrSet<GradOpNode> op_bases;
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444

  Tracer tracer;

  {
    auto x = std::make_shared<VarBase>("x");
    auto y = std::make_shared<VarBase>("y");

    x->MutableVar()
        ->GetMutable<framework::LoDTensor>()
        ->Resize({tensor_size, tensor_size})
        .mutable_data<float>(place);

    y->MutableVar()
        ->GetMutable<framework::LoDTensor>()
        ->Resize({tensor_size, tensor_size})
        .mutable_data<float>(place);

    x->SetOverridedStopGradient(false);
    y->SetOverridedStopGradient(true);

    for (size_t i = 0; i < loop_num; ++i) {
      size_t var_wrapper_num = var_wrappers.size();
      size_t var_base_num = var_bases.size();
      size_t op_base_num = op_bases.size();

      auto z = std::make_shared<VarBase>("z_" + std::to_string(i));
J
Jiabin Yang 已提交
445 446 447
      tracer.TraceOp<VarBase>("mul", NameVarBaseMap{{"X", {x}}, {"Y", {y}}},
                              NameVarBaseMap{{"Out", {z}}},
                              framework::AttributeMap{}, place, true);
448

449 450 451
      ASSERT_EQ(z->GradOpNum(), 0UL);
      ASSERT_EQ(z->GradVarBase()->GradOpNum(), 1UL);
      auto new_op = z->GradVarBase()->GradNode();
452

453 454
      ASSERT_EQ(x->GradOpNum(), 0UL);
      ASSERT_EQ(y->GradOpNum(), 0UL);
455

456
      std::unordered_set<std::shared_ptr<GradOpNode>> expected_pending_ops;
457
      if (i == 0) {
458 459
        ASSERT_EQ(x->GradVarBase()->GradOpNum(), 0UL);
        ASSERT_EQ(y->GradVarBase()->GradOpNum(), 0UL);
460
      } else {
461 462
        ASSERT_EQ(x->GradVarBase()->GradOpNum(), 1UL);
        ASSERT_EQ(y->GradVarBase()->GradOpNum(), 0UL);
463

464 465
        if (x->GradVarBase()->GradNode()) {
          expected_pending_ops.emplace(x->GradVarBase()->GradNode());
466
        }
467 468 469

        if (y->GradVarBase()->GradNode()) {
          expected_pending_ops.emplace(y->GradVarBase()->GradNode());
470 471
        }

472 473
        std::unordered_set<std::shared_ptr<GradOpNode>> actual_pending_ops;
        for (auto& op : new_op->GradPendingNodes()) {
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
          actual_pending_ops.emplace(op);
        }

        ASSERT_TRUE(expected_pending_ops == actual_pending_ops);
        ASSERT_EQ(expected_pending_ops.count(new_op), 0UL);
      }

      var_wrappers.emplace(x->SharedVar());
      var_wrappers.emplace(x->GradVarBase()->SharedVar());
      var_wrappers.emplace(y->SharedVar());
      var_wrappers.emplace(y->GradVarBase()->SharedVar());
      var_wrappers.emplace(z->SharedVar());
      var_wrappers.emplace(z->GradVarBase()->SharedVar());

      var_bases.emplace(x);
      var_bases.emplace(x->GradVarBase());
      var_bases.emplace(y);
      var_bases.emplace(y->GradVarBase());
      var_bases.emplace(z);
      var_bases.emplace(z->GradVarBase());

      for (auto& op : expected_pending_ops) {
        op_bases.emplace(op);
      }

      if (i == 0) {
        ASSERT_EQ(var_wrapper_num, 0UL);
        ASSERT_EQ(var_base_num, 0UL);
        ASSERT_EQ(op_base_num, 0UL);
        ASSERT_EQ(var_wrappers.size(), 6UL);
        ASSERT_EQ(var_bases.size(), 6UL);
        ASSERT_EQ(op_bases.size(), 0UL);
      } else {
        ASSERT_EQ(var_wrappers.size(), var_wrapper_num + 2);
        ASSERT_EQ(var_bases.size(), var_base_num + 2);
        ASSERT_EQ(op_bases.size(), op_base_num + 1);
      }

      x = z;  // recurrent usage
    }
  }

  for (auto& var : var_wrappers) {
    ASSERT_TRUE(var.expired());
  }

  for (auto& var : var_bases) {
    ASSERT_TRUE(var.expired());
  }

  for (auto& op : op_bases) {
    ASSERT_TRUE(op.expired());
  }
}

TEST(test_tracer, test_var_op_destruction) {
  TestVarOpDestructionMain(platform::CPUPlace());
531
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
532 533 534 535
  TestVarOpDestructionMain(platform::CUDAPlace(0));
#endif
}

J
Jiabin Yang 已提交
536 537 538 539 540 541 542 543 544 545 546 547 548 549
TEST(test_tracer, test_execution_context) {
  auto op = framework::OpRegistry::CreateOp("mul", {}, {}, {}, false);
  framework::Scope scope;
  auto ctx = framework::RuntimeContext({}, {});
  NameVarBaseMap ins = {{"X", {nullptr}}, {"Y", {nullptr}}};
  NameVarBaseMap outs = {{"Out", {nullptr}}};
  platform::DeviceContextPool& pool = platform::DeviceContextPool::Instance();
  auto* dev_ctx = pool.Get(platform::CPUPlace());
  auto dy_ctx = DygraphExecutionContext<VarBase>(
      (*op.get()), scope, *dev_ctx, ctx, ins, outs, framework::AttributeMap{},
      framework::AttributeMap{});
  ASSERT_EQ(dy_ctx.OutputName("Out"), framework::kEmptyVarName);
}

550 551 552 553 554 555 556 557 558 559 560 561 562
TEST(test_tracer, eager_tracer) {
  // Doing an mul
  imperative::Tracer tracer;
  std::shared_ptr<egr::EagerVariable> x_in(new egr::EagerVariable("x_in"));
  std::shared_ptr<egr::EagerVariable> y_in(new egr::EagerVariable("y_in"));
  std::shared_ptr<egr::EagerVariable> vout(new egr::EagerVariable("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>();
563
  x_in_tensor->Resize(phi::make_ddim(dims1));
564 565 566
  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());
567
  y_in_tensor->Resize(phi::make_ddim(dims2));
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
  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());

  ev_pair x_pair = ev_pair("X", ev_vector(1, x_in));
  ev_pair y_pair = ev_pair("Y", ev_vector(1, y_in));
  ev_pair out_pair = ev_pair("Out", ev_vector(1, vout));
  imperative::NameTensorMap ins = {x_pair, y_pair};
  imperative::NameTensorMap outs = {out_pair};
  framework::AttributeMap mul_attr_map;
  mul_attr_map["use_mkldnn"] = false;
  tracer.TraceOp<egr::EagerVariable>("mul", ins, outs, mul_attr_map, place,
                                     true);

  const auto& out_tensor = vout->Var().Get<framework::LoDTensor>();
  for (int i = 0; i < vout->Var().Get<framework::LoDTensor>().numel(); i++) {
    ASSERT_EQ(out_tensor.data<float>()[i], 20.0);
  }
}

J
Jiabin Yang 已提交
588 589 590 591
}  // namespace imperative
}  // namespace paddle

USE_OP(mul);
592
USE_OP(mul_grad);
593
USE_OP_ITSELF(reduce_sum);
C
chentianyu03 已提交
594
USE_OP_ITSELF(reduce_sum_grad);
595
USE_OP_ITSELF(elementwise_add);