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

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. */

Y
Yi Wang 已提交
15
#include "paddle/fluid/framework/executor.h"
Y
Yang Yang 已提交
16

17
#include "paddle/fluid/framework/channel.h"
Y
Yi Wang 已提交
18 19 20 21 22
#include "paddle/fluid/framework/feed_fetch_method.h"
#include "paddle/fluid/framework/lod_rank_table.h"
#include "paddle/fluid/framework/lod_tensor_array.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/reader.h"
G
gongweibao 已提交
23
#include "paddle/fluid/operators/detail/macros.h"
Y
Yi Wang 已提交
24
#include "paddle/fluid/platform/place.h"
X
Xin Pan 已提交
25
#include "paddle/fluid/platform/profiler.h"
Y
Yang Yu 已提交
26

D
dzhwinter 已提交
27
DECLARE_bool(benchmark);
28
DEFINE_bool(use_mkldnn, false, "Use MKLDNN to run");
Q
qijun 已提交
29 30 31

namespace paddle {
namespace framework {
X
Xin Pan 已提交
32 33 34 35 36
namespace {
// block id starts from 0. This id is used to represent the codeblock
// wrapping the first block 0.
int kProgramId = -1;
}  // namespace
Q
qijun 已提交
37

Q
Qiao Longfei 已提交
38 39 40
ExecutorPrepareContext::ExecutorPrepareContext(
    const framework::ProgramDesc& prog, size_t block_id)
    : prog_(prog), block_id_(block_id) {}
Y
Yu Yang 已提交
41

Q
Qiao Longfei 已提交
42 43 44
ExecutorPrepareContext::~ExecutorPrepareContext() {
  VLOG(5) << "destroy ExecutorPrepareContext";
}
Y
Yu Yang 已提交
45

D
dzhwinter 已提交
46
Executor::Executor(const platform::Place& place) : place_(place) {}
Q
qijun 已提交
47

Y
Yancey1989 已提交
48
void Executor::Close() {
W
Wu Yi 已提交
49
#ifdef PADDLE_WITH_DISTRIBUTE
Y
Yancey1989 已提交
50 51
  ::paddle::operators::distributed::RPCClient::GetInstance<
      ::paddle::operators::distributed::GRPCClient>()
Y
Yancey1989 已提交
52
      ->SendComplete();
W
Wu Yi 已提交
53
#endif
Y
Yancey1989 已提交
54
}
W
Wu Yi 已提交
55

Y
Stash  
Yu Yang 已提交
56
void InitializeVariable(Variable* var, proto::VarType::Type var_type) {
57
  if (var_type == proto::VarType::LOD_TENSOR) {
Q
QI JUN 已提交
58
    var->GetMutable<LoDTensor>();
59
  } else if (var_type == proto::VarType::SELECTED_ROWS) {
Q
QI JUN 已提交
60
    var->GetMutable<SelectedRows>();
61
  } else if (var_type == proto::VarType::FEED_MINIBATCH) {
Q
QI JUN 已提交
62
    var->GetMutable<FeedFetchList>();
63
  } else if (var_type == proto::VarType::FETCH_LIST) {
Q
QI JUN 已提交
64
    var->GetMutable<FeedFetchList>();
65
  } else if (var_type == proto::VarType::STEP_SCOPES) {
Y
Yu Yang 已提交
66
    var->GetMutable<std::vector<framework::Scope>>();
67
  } else if (var_type == proto::VarType::LOD_RANK_TABLE) {
Y
Yu Yang 已提交
68
    var->GetMutable<LoDRankTable>();
69
  } else if (var_type == proto::VarType::LOD_TENSOR_ARRAY) {
Y
Yu Yang 已提交
70
    var->GetMutable<LoDTensorArray>();
71
  } else if (var_type == proto::VarType::PLACE_LIST) {
Y
Yang Yu 已提交
72
    var->GetMutable<platform::PlaceList>();
73
  } else if (var_type == proto::VarType::READER) {
F
fengjiayi 已提交
74
    var->GetMutable<ReaderHolder>();
75 76
  } else if (var_type == proto::VarType::CHANNEL) {
    var->GetMutable<ChannelHolder>();
T
typhoonzero 已提交
77 78
  } else if (var_type == proto::VarType::RAW) {
    // GetMutable will be called in operator
Q
QI JUN 已提交
79 80
  } else {
    PADDLE_THROW(
Y
Yu Yang 已提交
81
        "Variable type %d is not in "
F
fengjiayi 已提交
82
        "[LOD_TENSOR, SELECTED_ROWS, FEED_MINIBATCH, FETCH_LIST, "
T
typhoonzero 已提交
83
        "LOD_RANK_TABLE, PLACE_LIST, READER, CHANNEL, RAW]",
Y
Yu Yang 已提交
84
        var_type);
Q
QI JUN 已提交
85 86 87
  }
}

L
Liu Yiqun 已提交
88 89 90
void Executor::CreateVariables(const ProgramDesc& pdesc, Scope* scope,
                               int block_id) {
  auto& global_block = pdesc.Block(block_id);
91 92 93 94 95 96 97 98 99 100 101 102 103 104

  const Scope* ancestor_scope = scope;
  while (ancestor_scope->parent()) {
    ancestor_scope = ancestor_scope->parent();
  }

  if (ancestor_scope != scope) {
    for (auto& var : global_block.AllVars()) {
      if (var->Name() == framework::kEmptyVarName) {
        continue;
      }

      if (var->Persistable()) {
        auto* ptr = const_cast<Scope*>(ancestor_scope)->Var(var->Name());
105
        InitializeVariable(ptr, var->GetType());
106 107 108 109
        VLOG(3) << "Create Variable " << var->Name()
                << " global, which pointer is " << ptr;
      } else {
        auto* ptr = scope->Var(var->Name());
110
        InitializeVariable(ptr, var->GetType());
111 112 113 114 115 116 117
        VLOG(3) << "Create Variable " << var->Name()
                << " locally, which pointer is " << ptr;
      }
    }
  } else {
    for (auto& var : global_block.AllVars()) {
      auto* ptr = scope->Var(var->Name());
118
      InitializeVariable(ptr, var->GetType());
119 120 121 122 123 124
      VLOG(3) << "Create variable " << var->Name() << ", which pointer is "
              << ptr;
    }
  }
}

Y
Yu Yang 已提交
125
void Executor::Run(const ProgramDesc& pdesc, Scope* scope, int block_id,
T
typhoonzero 已提交
126
                   bool create_local_scope, bool create_vars) {
X
Xin Pan 已提交
127
  platform::RecordBlock b(block_id);
128
  if (FLAGS_use_mkldnn) EnableMKLDNN(pdesc);
Q
Qiao Longfei 已提交
129 130
  auto ctx = Prepare(pdesc, block_id);
  RunPreparedContext(ctx.get(), scope, create_local_scope, create_vars);
Q
qijun 已提交
131 132
}

133 134 135 136 137 138 139
// Check whether the block already has feed operators and feed_holder.
// Return false if the block does not have any feed operators.
// If some feed operators have been prepended to the block, check that
// the info contained in these feed operators matches the feed_targets
// and feed_holder_name. Raise exception when any mismatch is found.
// Return true if the block has feed operators and holder of matching info.
static bool has_feed_operators(
140
    const BlockDesc& block,
L
Liu Yiqun 已提交
141
    const std::map<std::string, const LoDTensor*>& feed_targets,
142 143
    const std::string& feed_holder_name) {
  size_t feed_count = 0;
144
  for (auto* op : block.AllOps()) {
145 146
    if (op->Type() == kFeedOpType) {
      feed_count++;
L
Liu Yiqun 已提交
147
      // The input variable's name of feed_op should be feed_holder_name.
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
      PADDLE_ENFORCE_EQ(op->Input("X")[0], feed_holder_name,
                        "Input to feed op should be '%s'", feed_holder_name);
      std::string feed_target_name = op->Output("Out")[0];
      PADDLE_ENFORCE(
          feed_targets.find(feed_target_name) != feed_targets.end(),
          "Feed operator output name '%s' cannot be found in 'feed_targets'",
          feed_target_name);
    }
  }

  if (feed_count > 0) {
    PADDLE_ENFORCE_EQ(
        feed_count, feed_targets.size(),
        "The number of feed operators should match 'feed_targets'");

163
    if (!feed_holder_name.empty()) {
L
Liu Yiqun 已提交
164
      // When feed operator are present, so should be feed_holder.
165 166 167 168 169 170 171
      auto var = block.FindVar(feed_holder_name);
      PADDLE_ENFORCE_NOT_NULL(var, "Block should already have a '%s' variable",
                              feed_holder_name);
      PADDLE_ENFORCE_EQ(var->GetType(), proto::VarType::FEED_MINIBATCH,
                        "'%s' variable should be 'FEED_MINIBATCH' type",
                        feed_holder_name);
    }
172 173 174 175 176 177 178 179 180 181 182 183
  }

  return feed_count > 0;
}

// Check whether the block already has fetch operators and fetch_holder.
// Return false if the block does not have any fetch operators.
// If some fetch operators have been appended to the block, check that
// the info contained in these fetch operators matches the fetch_targets
// and fetch_holder_name. Raise exception when any mismatch is found.
// Return true if the block has fetch operators and holder of matching info.
static bool has_fetch_operators(
L
Liu Yiqun 已提交
184 185
    const BlockDesc& block,
    const std::map<std::string, LoDTensor*>& fetch_targets,
186 187
    const std::string& fetch_holder_name) {
  size_t fetch_count = 0;
188
  for (auto* op : block.AllOps()) {
189 190
    if (op->Type() == kFetchOpType) {
      fetch_count++;
L
Liu Yiqun 已提交
191
      // The output variable's name of fetch_op should be fetch_holder_name.
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
      PADDLE_ENFORCE_EQ(op->Output("Out")[0], fetch_holder_name,
                        "Output of fetch op should be '%s'", fetch_holder_name);
      std::string fetch_target_name = op->Input("X")[0];
      PADDLE_ENFORCE(
          fetch_targets.find(fetch_target_name) != fetch_targets.end(),
          "Fetch operator input name '%s' cannot be found in 'fetch_targets'",
          fetch_target_name);
    }
  }

  if (fetch_count > 0) {
    PADDLE_ENFORCE_EQ(
        fetch_count, fetch_targets.size(),
        "The number of fetch operators should match 'fetch_targets'");

207
    if (!fetch_holder_name.empty()) {
L
Liu Yiqun 已提交
208
      // When fetch operator are present, so should be fetch_holder.
209 210 211 212 213 214 215
      auto var = block.FindVar(fetch_holder_name);
      PADDLE_ENFORCE_NOT_NULL(var, "Block should already have a '%s' variable",
                              fetch_holder_name);
      PADDLE_ENFORCE_EQ(var->GetType(), proto::VarType::FETCH_LIST,
                        "'%s' variable should be 'FETCH_LIST' type",
                        fetch_holder_name);
    }
216 217 218 219 220 221
  }

  return fetch_count > 0;
}

void Executor::Run(const ProgramDesc& program, Scope* scope,
222 223
                   std::map<std::string, const LoDTensor*>* feed_targets,
                   std::map<std::string, LoDTensor*>* fetch_targets,
W
Wu Yi 已提交
224 225
                   bool create_local_scope, bool create_vars,
                   const std::string& feed_holder_name,
226
                   const std::string& fetch_holder_name) {
X
Xin Pan 已提交
227
  platform::RecordBlock b(kProgramId);
228
  if (FLAGS_use_mkldnn) EnableMKLDNN(program);
229
  bool has_feed_ops =
230
      has_feed_operators(program.Block(0), *feed_targets, feed_holder_name);
231
  bool has_fetch_ops =
232
      has_fetch_operators(program.Block(0), *fetch_targets, fetch_holder_name);
233 234

  ProgramDesc* copy_program = const_cast<ProgramDesc*>(&program);
S
sneaxiy 已提交
235
  std::unique_ptr<ProgramDesc> unique_ptr_of_copy_program;
236
  if (!has_feed_ops || !has_fetch_ops) {
S
sneaxiy 已提交
237 238
    unique_ptr_of_copy_program.reset(new ProgramDesc(program));
    copy_program = unique_ptr_of_copy_program.get();
239
  }
240 241
  auto* global_block = copy_program->MutableBlock(0);

242
  if (!has_feed_ops) {
243 244
    // create feed_holder variable
    auto* feed_holder = global_block->Var(feed_holder_name);
245
    feed_holder->SetType(proto::VarType::FEED_MINIBATCH);
246 247 248
    feed_holder->SetPersistable(true);

    int i = 0;
249
    for (auto& feed_target : (*feed_targets)) {
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
      std::string var_name = feed_target.first;
      VLOG(3) << "feed target's name: " << var_name;

      // prepend feed op
      auto* op = global_block->PrependOp();
      op->SetType(kFeedOpType);
      op->SetInput("X", {feed_holder_name});
      op->SetOutput("Out", {var_name});
      op->SetAttr("col", {static_cast<int>(i)});
      op->CheckAttrs();

      i++;
    }
  }

265
  if (!has_fetch_ops) {
266 267
    // create fetch_holder variable
    auto* fetch_holder = global_block->Var(fetch_holder_name);
268
    fetch_holder->SetType(proto::VarType::FETCH_LIST);
269 270 271
    fetch_holder->SetPersistable(true);

    int i = 0;
272
    for (auto& fetch_target : (*fetch_targets)) {
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
      std::string var_name = fetch_target.first;
      VLOG(3) << "fetch target's name: " << var_name;

      // append fetch op
      auto* op = global_block->AppendOp();
      op->SetType(kFetchOpType);
      op->SetInput("X", {var_name});
      op->SetOutput("Out", {fetch_holder_name});
      op->SetAttr("col", {static_cast<int>(i)});
      op->CheckAttrs();

      i++;
    }
  }

288
  auto ctx = Prepare(*copy_program, 0);
W
Wu Yi 已提交
289 290 291
  RunPreparedContext(ctx.get(), scope, feed_targets, fetch_targets,
                     create_local_scope, create_vars, feed_holder_name,
                     fetch_holder_name);
292 293
}

Q
Qiao Longfei 已提交
294 295
std::unique_ptr<ExecutorPrepareContext> Executor::Prepare(
    const ProgramDesc& program, int block_id) {
D
dzhwinter 已提交
296
  VLOG(3) << "before create prepare" << block_id << " " << program.Size();
Q
Qiyang Min 已提交
297 298
  std::unique_ptr<ExecutorPrepareContext> ctx(
      new ExecutorPrepareContext(program, block_id));
D
dzhwinter 已提交
299 300 301
  VLOG(3) << "after create prepare";
 // PADDLE_ENFORCE_LT(static_cast<size_t>(block_id), program.Size());
  VLOG(3) << "before create op_desc";
Y
Yu Yang 已提交
302
  auto& block = program.Block(block_id);
D
dzhwinter 已提交
303 304
  VLOG(3) << "create before" << ctx->ops_.size() << " " << block.AllOps().size();
  int counter = 0;
Y
Yu Yang 已提交
305 306
  for (auto& op_desc : block.AllOps()) {
    ctx->ops_.push_back(OpRegistry::CreateOp(*op_desc));
D
dzhwinter 已提交
307
      VLOG(3) << "create op " << "index " << ++counter << " type " << op_desc->Type();
Y
Yu Yang 已提交
308
  }
D
dzhwinter 已提交
309
  VLOG(3) << "create finished" << ctx->ops_.size() << " " << block.AllOps().size();
Q
Qiyang Min 已提交
310
  return ctx;
Y
Yu Yang 已提交
311 312
}

T
refine  
typhoonzero 已提交
313
std::vector<std::shared_ptr<ExecutorPrepareContext>> Executor::Prepare(
T
typhoonzero 已提交
314
    const ProgramDesc& program, const std::vector<int>& block_ids) {
D
dzhwinter 已提交
315
  VLOG(3) << "inside prepare";
T
typhoonzero 已提交
316
  std::vector<std::shared_ptr<ExecutorPrepareContext>> result;
D
dzhwinter 已提交
317
  VLOG(3) << "before go through block_ids";
T
typhoonzero 已提交
318
  for (auto& bid : block_ids) {
D
dzhwinter 已提交
319
    VLOG(3) << "block id" << bid;
T
typhoonzero 已提交
320
    auto* ctx = new ExecutorPrepareContext(program, bid);
D
dzhwinter 已提交
321
    //PADDLE_ENFORCE_LT(static_cast<size_t>(bid), program.Size());
T
typhoonzero 已提交
322
    auto& block = program.Block(bid);
D
dzhwinter 已提交
323 324
    int counter = 0;
    VLOG(3) << "create before" << ctx->ops_.size() << " " << block.AllOps().size();
T
typhoonzero 已提交
325
    for (auto& op_desc : block.AllOps()) {
D
dzhwinter 已提交
326

T
typhoonzero 已提交
327
      ctx->ops_.push_back(OpRegistry::CreateOp(*op_desc));
D
dzhwinter 已提交
328
      VLOG(3) << "create op " << "index " << ++counter << " type " << op_desc->Type();
T
typhoonzero 已提交
329
    }
D
dzhwinter 已提交
330
    VLOG(3) << "create finished" << ctx->ops_.size() << " " << block.AllOps().size();
T
typhoonzero 已提交
331 332 333 334 335
    result.push_back(std::shared_ptr<ExecutorPrepareContext>(ctx));
  }
  return result;
}

D
dzhwinter 已提交
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 367 368 369 370 371 372 373 374
// void CheckResult(const std::string op_type, ExecutorPrepareContext* ctx, Scope* local_scope) {
//     VLOG(3) << "before checking result";
//   auto& dev_ctx = *platform::DeviceContextPool::Instance().Get(place_);
//   std::vector<std::string> outputs;
//   auto& block = ctx->prog_.Block(0);
//   bool found = false;
//   framework::OpDesc* myop = nullptr;
//   for(auto& op : block.AllOps()) {
//     if(op->Type() == "load_combine" || op->Type() == "fetch" || op->Type() == "feed") return;
//     if (op->Type() == op_type) {
//         found = true;
//         myop = op;
//         break;
//       }
//     }
//   }
//   if(!found) {
//     VLOG(3) << "not found op!";
//     return;
//   }
//     auto* op = myop;
//      VLOG(3) << "start op output" << op->Type();
//     for(auto var_name: op->OutputArgumentNames()) {
//       auto* var = local_scope->Var(var_name);
//       auto* var_desc = block.FindVar(var_name);
//       if (var_desc->Persistable()) continue;
//       auto* tensor = var->GetMutable<framework::LoDTensor>();
//       framework::Tensor check;
//       VLOG(3) << "before tensor copy";
//       framework::TensorCopy(*tensor, platform::CPUPlace(), dev_ctx, &check);
//       VLOG(3) << "after tensor copy";
//       float sum = .0;
//       for(size_t i=0; i < check.numel(); ++i) {
//           sum += check.data<float>()[i];
//       }
//       VLOG(3) << "op " << op->Type() << " output var " << var_name << " sum " << sum;
//   VLOG(3) << "after checking result";
// }

Y
Yu Yang 已提交
375
void Executor::RunPreparedContext(ExecutorPrepareContext* ctx, Scope* scope,
Q
qiaolongfei 已提交
376 377
                                  bool create_local_scope, bool create_vars,
                                  bool keep_kids) {
D
dzhwinter 已提交
378
  VLOG(3) << "RunPreparedContext inside";
Y
Yu Yang 已提交
379 380 381 382
  Scope* local_scope = scope;
  if (create_vars) {
    if (create_local_scope) {
      local_scope = &scope->NewScope();
383 384
    }
    CreateVariables(ctx->prog_, local_scope, ctx->block_id_);
L
Liu Yiqun 已提交
385
  }
Y
Yu Yang 已提交
386 387

  for (auto& op : ctx->ops_) {
388
    op->Run(*local_scope, place_);
D
dzhwinter 已提交
389
   // CheckResult(op->Type(), ctx, local_scope);
Y
Yu Yang 已提交
390 391 392 393 394
    if (FLAGS_benchmark) {
      VLOG(2) << "Memory used after operator " + op->Type() + " running: "
              << memory::memory_usage(place_);
    }
  }
395
  platform::DeviceContextPool::Instance().Get(place_)->Wait();
D
dzhwinter 已提交
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 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 445 446 447 448 449 450 451 452 453 454 455

  VLOG(3) << "start checking";
    auto& dev_ctx = *platform::DeviceContextPool::Instance().Get(place_);
  std::vector<std::string> outputs;
  auto& block = ctx->prog_.Block(0);

  for(auto& op : block.AllOps()) {
    if(op->Type() == "load_combine" || op->Type() == "fetch" || op->Type() == "feed") continue;
    // for(auto& real_op : ctx->ops_) {
    //   if(real_op->Type() == op->Type()) {
    //     VLOG(3) << real_op->Type() << " " <<place_ << " " << real_op->DebugStringEx(local_scope);
    //   }
    // }
     
     //VLOG(3) << "start op output" << op->Type();
        for(auto var_name: op->InputArgumentNames()) {
      auto* var = local_scope->Var(var_name);
      auto* var_desc = block.FindVar(var_name);
      if (var_desc->Persistable()) continue;
      auto* tensor = var->GetMutable<framework::LoDTensor>();
      framework::Tensor check;
      VLOG(3) << "before tensor copy";
   
      framework::TensorCopy(*tensor, platform::CPUPlace(), dev_ctx, &check);
      
      VLOG(3) << "after tensor copy";
      float sum = .0;
      for(size_t i=0; i < check.numel(); ++i) {
          sum += check.data<float>()[i];
      }
      VLOG(3) << "op " << op->Type() << " input var " << var_name << " sum " << sum;
    }

    VLOG(3) << "op " << op->Type() << "input finished";
    for(auto var_name: op->OutputArgumentNames()) {
      auto* var = local_scope->Var(var_name);
      auto* var_desc = block.FindVar(var_name);
      if (var_desc->Persistable()) continue;
      auto* tensor = var->GetMutable<framework::LoDTensor>();
      framework::Tensor check;
      VLOG(3) << "before tensor copy";
      if(op->Type() == "batch_norm" && platform::is_gpu_place(place_)) {
        VLOG(3) << "op " << op->Type() << " output var " << var_name << " " << tensor->numel();
        tensor->mutable_data<float>(place_);
         framework::TensorCopy(*tensor, platform::CPUPlace(), dev_ctx, &check);
      } else {
         framework::TensorCopy(*tensor, platform::CPUPlace(), dev_ctx, &check);
      }
      
      VLOG(3) << "after tensor copy";
      float sum = .0;
      for(size_t i=0; i < check.numel(); ++i) {
          sum += check.data<float>()[i];
      }
      VLOG(3) << "op " << op->Type() << " output var " << var_name << " sum " << sum;
    }
  }

  VLOG(3) << "after checking result";

Q
qiaolongfei 已提交
456
  if (local_scope != scope) {
Y
Yu Yang 已提交
457
    scope->DeleteScope(local_scope);
458
  } else {
Q
qiaolongfei 已提交
459 460 461 462 463
    if (!keep_kids) {
      // By default, we should delete all kid scopes after run executor because
      // some operators may create local scope when running, such as while_op.
      // But when while_op also create a local executor to run it's sub block,
      // the sub scopes it created should not be dropped immediately, because
Q
qiaolongfei 已提交
464 465
      // while_grad_op will use some variables created during while_op run, so
      // we need to keep the kids and wait for the outer executor to drop them.
Q
qiaolongfei 已提交
466 467
      scope->DropKids();
    }
Y
Yu Yang 已提交
468
  }
Q
qiaolongfei 已提交
469

Y
Yu Yang 已提交
470 471 472 473 474 475 476 477
  if (FLAGS_benchmark) {
    VLOG(2) << "-------------------------------------------------------";
    VLOG(2) << "Memory used after deleting local scope: "
            << memory::memory_usage(place_);
    VLOG(2) << "-------------------------------------------------------";
  }
}

478 479
void Executor::RunPreparedContext(
    ExecutorPrepareContext* ctx, Scope* scope,
480
    std::map<std::string, const LoDTensor*>* feed_targets,
W
Wu Yi 已提交
481 482 483
    std::map<std::string, LoDTensor*>* fetch_targets, bool create_local_scope,
    bool create_vars, const std::string& feed_holder_name,
    const std::string& fetch_holder_name) {
484 485
  auto& global_block = ctx->prog_.Block(ctx->block_id_);

486
  PADDLE_ENFORCE(
487
      has_feed_operators(global_block, *feed_targets, feed_holder_name),
488 489
      "Program in ExecutorPrepareContext should has feed_ops.");
  PADDLE_ENFORCE(
490
      has_fetch_operators(global_block, *fetch_targets, fetch_holder_name),
491 492
      "Program in the prepared context should has fetch_ops.");

493 494 495 496 497
  // map the data of feed_targets to feed_holder
  for (auto* op : global_block.AllOps()) {
    if (op->Type() == kFeedOpType) {
      std::string feed_target_name = op->Output("Out")[0];
      int idx = boost::get<int>(op->GetAttr("col"));
498 499
      SetFeedVariable(scope, *(*feed_targets)[feed_target_name],
                      feed_holder_name, idx);
500 501 502
    }
  }

W
Wu Yi 已提交
503
  RunPreparedContext(ctx, scope, create_local_scope, create_vars);
504 505 506 507 508 509

  // obtain the data of fetch_targets from fetch_holder
  for (auto* op : global_block.AllOps()) {
    if (op->Type() == kFetchOpType) {
      std::string fetch_target_name = op->Input("X")[0];
      int idx = boost::get<int>(op->GetAttr("col"));
510
      *(*fetch_targets)[fetch_target_name] =
511 512 513 514 515
          GetFetchVariable(*scope, fetch_holder_name, idx);
    }
  }
}

516 517 518 519 520 521 522 523 524 525 526
void Executor::EnableMKLDNN(const ProgramDesc& program) {
#ifdef PADDLE_WITH_MKLDNN
  VLOG(3) << "use_mkldnn=True";
  for (size_t bid = 0; bid < program.Size(); ++bid) {
    auto* block = const_cast<ProgramDesc&>(program).MutableBlock(bid);
    for (auto* op : block->AllOps()) {
      if (op->HasAttr("use_mkldnn")) {
        op->SetAttr("use_mkldnn", true);
      }
    }
  }
527 528 529
#else
  LOG(WARNING)
      << "'MKLDNN' is not supported, Please re-compile with WITH_MKLDNN option";
530 531 532
#endif
}

Q
qijun 已提交
533 534
}  // namespace framework
}  // namespace paddle