executor_test.cc 11.0 KB
Newer Older
Q
qijun 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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/framework/executor.h"
Y
Yang Yang 已提交
16 17

#include <memory>
Q
qijun 已提交
18
#include <vector>
Y
Yang Yang 已提交
19

Y
Yang Yang 已提交
20
#include "gtest/gtest.h"
Y
Yang Yang 已提交
21
#include "paddle/framework/attribute.h"
Y
Yang Yang 已提交
22
#include "paddle/framework/backward.h"
Y
Yang Yang 已提交
23 24
#include "paddle/framework/block_desc.h"
#include "paddle/framework/op_desc.h"
Y
Yang Yang 已提交
25 26 27
#include "paddle/framework/op_registry.h"
#include "paddle/framework/operator.h"

Q
qijun 已提交
28 29 30 31 32 33 34 35 36 37
USE_OP(elementwise_add);
USE_OP(gaussian_random);
USE_OP(feed);
USE_OP(fetch);
USE_OP(mul);
USE_OP(sum);
USE_OP(squared_l2_distance);
USE_OP(fill_constant);
USE_OP(sgd);

Q
qijun 已提交
38 39 40
using namespace paddle::platform;
using namespace paddle::framework;

Y
Yang Yang 已提交
41 42
void AddOp(const std::string& type, const VariableNameMap& inputs,
           const VariableNameMap& outputs, AttributeMap attrs,
Y
Yang Yang 已提交
43
           paddle::framework::BlockDescBind* block) {
Y
Yang Yang 已提交
44 45 46
  // insert output
  for (auto kv : outputs) {
    for (auto v : kv.second) {
D
dongzhihong 已提交
47
      auto var = block->Var(v);
Y
Yang Yang 已提交
48
      var->SetDataType(paddle::framework::DataType::FP32);
Y
Yang Yang 已提交
49 50 51 52
    }
  }

  // insert op
Y
Yang Yang 已提交
53 54
  auto op = block->AppendOp();
  op->SetType(type);
Y
Yang Yang 已提交
55
  for (auto& kv : inputs) {
Y
Yang Yang 已提交
56
    op->SetInput(kv.first, kv.second);
Y
Yang Yang 已提交
57
  }
Y
Yang Yang 已提交
58
  for (auto& kv : outputs) {
Y
Yang Yang 已提交
59
    op->SetOutput(kv.first, kv.second);
Y
Yang Yang 已提交
60
  }
Y
Yang Yang 已提交
61
  op->SetAttrMap(attrs);
Y
Yang Yang 已提交
62 63
}

Y
Yang Yang 已提交
64
// Tensors in feed value variable will only be in CPUPlace
Q
qijun 已提交
65
// So we can memcpy the data from vector<T> to feed_value
Q
qijun 已提交
66
template <typename T>
Y
Yang Yang 已提交
67 68
void SetFeedVariable(const std::vector<std::vector<T>>& inputs,
                     const std::vector<std::vector<int64_t>>& dims) {
Q
qijun 已提交
69
  Variable* g_feed_value = GetGlobalScope().FindVar("feed_value");
Q
qijun 已提交
70 71
  auto& feed_inputs =
      *(g_feed_value->GetMutable<std::vector<paddle::framework::Tensor>>());
Y
Yang Yang 已提交
72
  size_t size = inputs.size();
73
  feed_inputs.resize(size);
Q
qijun 已提交
74
  for (size_t i = 0; i < size; i++) {
Y
Yang Yang 已提交
75
    T* dst = feed_inputs[i].mutable_data<T>(make_ddim(dims[i]), CPUPlace());
76
    memcpy(dst, inputs[i].data(), inputs[i].size() * sizeof(T));
Q
qijun 已提交
77 78 79
  }
}

Y
Yang Yang 已提交
80 81
// Tensors in fetch value variable will only be in CPUPlace
// So we can memcpy the data from fetch_value to vector<T>
Q
qijun 已提交
82
template <typename T>
Y
Yang Yang 已提交
83
std::vector<std::vector<T>> GetFetchVariable() {
Q
qijun 已提交
84
  Variable* g_fetch_value = GetGlobalScope().FindVar("fetch_value");
Q
qijun 已提交
85 86
  auto& fetch_outputs =
      *(g_fetch_value->GetMutable<std::vector<paddle::framework::Tensor>>());
Q
qijun 已提交
87

Y
Yang Yang 已提交
88
  size_t size = fetch_outputs.size();
Q
qijun 已提交
89 90 91 92
  std::vector<std::vector<T>> result;
  result.reserve(size);
  for (size_t i = 0; i < size; i++) {
    std::vector<T> tmp;
93
    tmp.resize(fetch_outputs[i].numel());
Q
qijun 已提交
94 95 96 97
    memcpy(tmp.data(), fetch_outputs[i].data<T>(),
           fetch_outputs[i].numel() * sizeof(T));
    result.push_back(tmp);
  }
Y
Yang Yang 已提交
98

Q
qijun 已提交
99 100 101
  return result;
}

Q
qijun 已提交
102
class ExecutorTesterRandom : public ::testing::Test {
Q
qijun 已提交
103 104
 public:
  virtual void SetUp() override {
Y
Yang Yang 已提交
105
    int input_dim = 3, batch_size = 2, embed_dim = 5;
Y
Yang Yang 已提交
106

Y
Yang Yang 已提交
107 108 109 110 111 112
    auto temp_init_root_block = init_pdesc_.add_blocks();
    temp_init_root_block->set_idx(0);
    temp_init_root_block->set_parent_idx(-1);
    paddle::framework::ProgramDescBind& init_program =
        paddle::framework::ProgramDescBind::Instance(&init_pdesc_);
    paddle::framework::BlockDescBind* init_root_block = init_program.Block(0);
Y
Yang Yang 已提交
113

Y
Yang Yang 已提交
114
    AddOp("gaussian_random", {}, {{"Out", {"w1"}}},
Y
Yang Yang 已提交
115
          {{"dims", std::vector<int>{input_dim, embed_dim}}}, init_root_block);
Y
Yang Yang 已提交
116
    AddOp("gaussian_random", {}, {{"Out", {"w2"}}},
Y
Yang Yang 已提交
117
          {{"dims", std::vector<int>{embed_dim, input_dim}}}, init_root_block);
118 119
    AddOp("fetch", {{"Input", {"w1"}}}, {}, {{"col", 0}}, init_root_block);
    AddOp("fetch", {{"Input", {"w2"}}}, {}, {{"col", 1}}, init_root_block);
Y
Yang Yang 已提交
120 121 122 123

    // flush
    init_program.Proto();

Y
Yang Yang 已提交
124
    // run block
Y
Yang Yang 已提交
125 126 127 128 129 130
    auto temp_root_block = pdesc_.add_blocks();
    temp_root_block->set_idx(0);
    temp_root_block->set_parent_idx(-1);
    paddle::framework::ProgramDescBind& program =
        paddle::framework::ProgramDescBind::Instance(&pdesc_);
    paddle::framework::BlockDescBind* root_block = program.Block(0);
Q
qijun 已提交
131

Y
Yang Yang 已提交
132
    // feed data
Y
Yang Yang 已提交
133
    inputs_.push_back({1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
Y
Yang Yang 已提交
134 135 136 137 138
    dims_.push_back({batch_size, input_dim});
    AddOp("feed", {}, {{"Out", {"a"}}},
          {{"dims", std::vector<int>{batch_size, input_dim}}, {"col", 0}},
          root_block);

Y
Yang Yang 已提交
139
    // forward
Y
Yang Yang 已提交
140
    AddOp("mul", {{"X", {"a"}}, {"Y", {"w1"}}}, {{"Out", {"b"}}}, {},
Y
Yang Yang 已提交
141
          root_block);
Y
Yang Yang 已提交
142
    AddOp("mul", {{"X", {"b"}}, {"Y", {"w2"}}}, {{"Out", {"a_out"}}}, {},
Y
Yang Yang 已提交
143
          root_block);
Y
Yang Yang 已提交
144 145
    AddOp("squared_l2_distance", {{"X", {"a"}}, {"Y", {"a_out"}}},
          {{"Out", {"l2_distance"}}, {"sub_result", {"l2_distance_sub"}}}, {},
Y
Yang Yang 已提交
146
          root_block);
Y
Yang Yang 已提交
147

Y
Yang Yang 已提交
148 149 150 151 152 153 154 155
    // backward
    AddOp("fill_constant", {}, {{"Out", {"l2_distance@GRAD"}}},
          {{"shape", std::vector<int>{batch_size, 1}}, {"value", float(1.0)}},
          root_block);
    AppendBackward(program, {});

    // update
    AddOp("fill_constant", {}, {{"Out", {"learning_rate"}}},
Y
Yang Yang 已提交
156 157
          {{"shape", std::vector<int>{1}}, {"value", float(0.001)}},
          root_block);
Y
Yang Yang 已提交
158 159 160 161 162 163 164 165 166
    AddOp("sgd", {{"Param", {"w1"}},
                  {"LearningRate", {"learning_rate"}},
                  {"Grad", {"w1@GRAD"}}},
          {{"ParamOut", {"w1"}}}, {}, root_block);
    AddOp("sgd", {{"Param", {"w2"}},
                  {"LearningRate", {"learning_rate"}},
                  {"Grad", {"w2@GRAD"}}},
          {{"ParamOut", {"w2"}}}, {}, root_block);

167 168
    AddOp("fetch", {{"Input", {"w1"}}}, {}, {{"col", 0}}, root_block);
    AddOp("fetch", {{"Input", {"w2"}}}, {}, {{"col", 1}}, root_block);
Y
Yang Yang 已提交
169
    AddOp("fetch", {{"Input", {"l2_distance"}}}, {}, {{"col", 0}}, root_block);
Y
Yang Yang 已提交
170

Y
Yang Yang 已提交
171 172
    // flush
    program.Proto();
Q
qijun 已提交
173
  }
Y
Yang Yang 已提交
174

Q
qijun 已提交
175
 protected:
Y
Yang Yang 已提交
176
  ProgramDesc init_pdesc_;
Q
qijun 已提交
177
  ProgramDesc pdesc_;
Y
Yang Yang 已提交
178 179
  std::vector<std::vector<float>> inputs_;
  std::vector<std::vector<int64_t>> dims_;
Q
qijun 已提交
180 181
};

Y
Yang Yang 已提交
182
class ExecutorTesterFeedAndFetch : public ::testing::Test {
Q
qijun 已提交
183 184
 public:
  virtual void SetUp() override {
Y
Yang Yang 已提交
185 186 187 188 189 190 191 192
    auto temp_root_block = pdesc_.add_blocks();
    temp_root_block->set_idx(0);
    temp_root_block->set_parent_idx(-1);

    // wrap to BlockDescBind
    paddle::framework::ProgramDescBind& program =
        paddle::framework::ProgramDescBind::Instance(&pdesc_);
    paddle::framework::BlockDescBind* root_block = program.Block(0);
Q
qijun 已提交
193

194 195
    std::vector<int> dim{6};

Y
Yang Yang 已提交
196 197 198 199
    AddOp("feed", {}, {{"Out", {"a"}}}, {{"dims", dim}, {"col", 0}},
          root_block);
    AddOp("feed", {}, {{"Out", {"b"}}}, {{"dims", dim}, {"col", 1}},
          root_block);
200 201
    AddOp("fetch", {{"Input", {"a"}}}, {}, {{"col", 0}}, root_block);
    AddOp("fetch", {{"Input", {"b"}}}, {}, {{"col", 1}}, root_block);
Q
qijun 已提交
202

Y
Yang Yang 已提交
203 204 205
    // flush
    program.Proto();

206 207
    std::vector<float> vec1 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
    std::vector<float> vec2 = {4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
Q
qijun 已提交
208 209
    inputs_.push_back(vec1);
    inputs_.push_back(vec2);
Y
Yang Yang 已提交
210 211
    dims_.push_back({static_cast<int64_t>(vec1.size())});
    dims_.push_back({static_cast<int64_t>(vec2.size())});
Q
qijun 已提交
212 213 214 215 216
  }

 protected:
  ProgramDesc pdesc_;
  std::vector<std::vector<float>> inputs_;
Y
Yang Yang 已提交
217
  std::vector<std::vector<int64_t>> dims_;
Q
qijun 已提交
218 219
};

Q
qijun 已提交
220
#ifndef PADDLE_WITH_CUDA
Q
qijun 已提交
221
TEST_F(ExecutorTesterRandom, CPU) {
Q
qijun 已提交
222
  std::vector<Place> places;
223 224 225 226 227 228 229 230
  CPUPlace cpu_place;
  places.push_back(cpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  paddle::memory::Used(cpu_place);
Q
qijun 已提交
231

Y
Yang Yang 已提交
232 233
  std::unique_ptr<Executor> executor(new Executor(places));

Q
qijun 已提交
234 235 236
  executor->Run(init_pdesc_, &GetGlobalScope(), 0);
  SetFeedVariable<float>(inputs_, dims_);
  executor->Run(pdesc_, &GetGlobalScope(), 0);
Y
Yang Yang 已提交
237
  std::vector<std::vector<float>> result = GetFetchVariable<float>();
Q
qijun 已提交
238 239
}

Y
Yang Yang 已提交
240
TEST_F(ExecutorTesterFeedAndFetch, CPU) {
Q
qijun 已提交
241 242 243 244
  std::vector<Place> places;
  CPUPlace cpu_place;
  places.push_back(cpu_place);

245 246 247 248 249 250
  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  paddle::memory::Used(cpu_place);

Y
Yang Yang 已提交
251
  std::unique_ptr<Executor> executor(new Executor(places));
Q
qijun 已提交
252

Y
Yang Yang 已提交
253
  for (int batch_id = 0; batch_id < 3; batch_id++) {
Y
Yang Yang 已提交
254
    SetFeedVariable<float>(inputs_, dims_);
Q
qijun 已提交
255
    executor->Run(pdesc_, &GetGlobalScope(), 0);
Y
Yang Yang 已提交
256
    std::vector<std::vector<float>> result = GetFetchVariable<float>();
Y
Yang Yang 已提交
257 258 259 260 261
    PADDLE_ENFORCE_EQ(result.size(), inputs_.size());
    for (size_t i = 0; i < result.size(); ++i) {
      PADDLE_ENFORCE_EQ(result[i].size(), inputs_[i].size());
      for (size_t j = 0; j < result[i].size(); ++j) {
        PADDLE_ENFORCE_EQ(result[i][j], inputs_[i][j]);
Q
qijun 已提交
262 263
      }
    }
Q
qijun 已提交
264
  }
Q
qijun 已提交
265
}
Q
qijun 已提交
266
#else
Q
qijun 已提交
267 268 269 270 271
TEST_F(ExecutorTesterRandom, GPU) {
  std::vector<Place> places;
  GPUPlace gpu_place(0);
  places.push_back(gpu_place);

Q
qijun 已提交
272 273 274 275 276 277 278
  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  // If paddle is compiled with GPU, both CPU and GPU BuddyAllocator
  // need to be used at first.
  paddle::memory::Used(CPUPlace());
279 280
  paddle::memory::Used(gpu_place);

Y
Yang Yang 已提交
281
  std::unique_ptr<Executor> executor(new Executor(places));
Y
Yang Yang 已提交
282

Q
qijun 已提交
283
  executor->Run(init_pdesc_, &GetGlobalScope(), 0);
Y
Yang Yang 已提交
284
  for (int batch_id = 0; batch_id < 3; batch_id++) {
Y
Yang Yang 已提交
285
    SetFeedVariable<float>(inputs_, dims_);
Q
qijun 已提交
286
    executor->Run(pdesc_, &GetGlobalScope(), 0);
Y
Yang Yang 已提交
287
  }
Q
qijun 已提交
288 289
}

Y
Yang Yang 已提交
290
TEST_F(ExecutorTesterFeedAndFetch, GPU) {
Q
qijun 已提交
291
  std::vector<Place> places;
Q
qijun 已提交
292 293
  GPUPlace gpu_place(0);
  places.push_back(gpu_place);
Q
qijun 已提交
294 295 296 297 298 299 300
  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  // If paddle is compiled with GPU, both CPU and GPU BuddyAllocator
  // need to be used at first.
  paddle::memory::Used(CPUPlace());
301 302
  paddle::memory::Used(gpu_place);

Y
Yang Yang 已提交
303
  std::unique_ptr<Executor> executor(new Executor(places));
Q
qijun 已提交
304

Y
Yang Yang 已提交
305
  for (int batch_id = 0; batch_id < 3; batch_id++) {
Y
Yang Yang 已提交
306
    SetFeedVariable<float>(inputs_, dims_);
Q
qijun 已提交
307
    executor->Run(pdesc_, &GetGlobalScope(), 0);
Y
Yang Yang 已提交
308
    std::vector<std::vector<float>> result = GetFetchVariable<float>();
Y
Yang Yang 已提交
309 310 311 312 313
    PADDLE_ENFORCE_EQ(result.size(), inputs_.size());
    for (size_t i = 0; i < result.size(); ++i) {
      PADDLE_ENFORCE_EQ(result[i].size(), inputs_[i].size());
      for (size_t j = 0; j < result[i].size(); ++j) {
        PADDLE_ENFORCE_EQ(result[i][j], inputs_[i][j]);
Q
qijun 已提交
314 315 316
      }
    }
  }
Y
Yang Yang 已提交
317
}
Q
qijun 已提交
318
#endif