executor_test.cc 10.9 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 28
#include "paddle/framework/op_registry.h"
#include "paddle/framework/operator.h"

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

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) {
Y
Yang Yang 已提交
47 48
      auto var = block->NewVar(v);
      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) {
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() {
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));

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

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

244 245 246 247 248 249
  // 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 已提交
250
  std::unique_ptr<Executor> executor(new Executor(places));
Q
qijun 已提交
251

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

Q
qijun 已提交
271 272 273 274 275 276 277
  // 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());
278 279
  paddle::memory::Used(gpu_place);

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

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

Y
Yang Yang 已提交
289
TEST_F(ExecutorTesterFeedAndFetch, GPU) {
Q
qijun 已提交
290
  std::vector<Place> places;
Q
qijun 已提交
291 292
  GPUPlace gpu_place(0);
  places.push_back(gpu_place);
Q
qijun 已提交
293 294 295 296 297 298 299
  // 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());
300 301
  paddle::memory::Used(gpu_place);

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

Y
Yang Yang 已提交
304
  for (int batch_id = 0; batch_id < 3; batch_id++) {
Y
Yang Yang 已提交
305
    SetFeedVariable<float>(inputs_, dims_);
Y
Yang Yang 已提交
306
    executor->Run(pdesc_, GetGlobalScope(), 0);
Y
Yang Yang 已提交
307
    std::vector<std::vector<float>> result = GetFetchVariable<float>();
Y
Yang Yang 已提交
308 309 310 311 312
    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 已提交
313 314 315
      }
    }
  }
Y
Yang Yang 已提交
316
}
Q
qijun 已提交
317
#endif