You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
4.0 KiB
112 lines
4.0 KiB
// Copyright (c) 2020 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.
|
|
|
|
#include "paddle/fluid/framework/executor_cache.h"
|
|
|
|
#include <string>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
namespace paddle {
|
|
namespace framework {
|
|
|
|
namespace details {
|
|
|
|
static void AppendSkipDeletionVars(const std::vector<std::string> &append_vars,
|
|
std::vector<std::string> *all_vars) {
|
|
for (auto &var : append_vars) {
|
|
all_vars->emplace_back(var);
|
|
}
|
|
}
|
|
|
|
static void AppendSafeEagerDeletionSkipVars(
|
|
const framework::ProgramDesc &program,
|
|
std::vector<std::string> *skip_vars) {
|
|
const framework::BlockDesc &block = program.Block(0);
|
|
const std::vector<framework::OpDesc *> &all_ops = block.AllOps();
|
|
|
|
std::unordered_set<std::string> grad_op_output;
|
|
std::unordered_set<std::string> grad_op_input;
|
|
for (const framework::OpDesc *op : all_ops) {
|
|
int op_role = BOOST_GET_CONST(
|
|
int, op->GetAttr(framework::OpProtoAndCheckerMaker::OpRoleAttrName()));
|
|
if ((op_role & static_cast<int>(framework::OpRole::kBackward)) == 0) {
|
|
continue;
|
|
}
|
|
|
|
for (const std::string &in_arg_name : op->InputArgumentNames()) {
|
|
grad_op_input.emplace(in_arg_name);
|
|
}
|
|
for (const std::string &out_arg_name : op->OutputArgumentNames()) {
|
|
grad_op_output.emplace(out_arg_name);
|
|
}
|
|
}
|
|
|
|
// For the grad op input variables, if it is not output of grad_op, it may
|
|
// be output of forward op and we should set the variables as skip_var to
|
|
// prevent it being deleted when grad op is called multiple times.
|
|
for (const std::string &var_name : grad_op_input) {
|
|
if (grad_op_output.find(var_name) == grad_op_output.end()) {
|
|
skip_vars->emplace_back(var_name);
|
|
}
|
|
}
|
|
}
|
|
} // namespace details
|
|
|
|
// C++11 removes the need for manual locking. Concurrent execution shall wait if
|
|
// a static local variable is already being initialized.
|
|
// https://stackoverflow.com/questions/11711920/how-to-implement-multithread-safe-singleton-in-c11-without-using-mutex
|
|
ExecutorInfoCache &ExecutorInfoCache::Instance() {
|
|
static ExecutorInfoCache g_exe_cache_info_map;
|
|
return g_exe_cache_info_map;
|
|
}
|
|
|
|
std::shared_ptr<framework::ExecutorPrepareContext> GetExecutorInfoFromCache(
|
|
const framework::Executor &exe, const framework::ExecutionContext &ctx,
|
|
const std::vector<std::vector<std::string>> &ctx_output_names,
|
|
bool is_grad) {
|
|
auto *program = ctx.Attr<BlockDesc *>("global_block")->Program();
|
|
|
|
auto &cached_exe_info = framework::ExecutorInfoCache::Instance();
|
|
auto cache_key = framework::ExecutorInfoCache::KeyInfo(program, is_grad);
|
|
|
|
if (!cached_exe_info.Has(cache_key)) {
|
|
VLOG(1) << "create exe_info for program: " << program
|
|
<< " is_grad: " << is_grad;
|
|
// skip delete vars
|
|
std::vector<std::string> skip_vars;
|
|
for (auto &output_names : ctx_output_names) {
|
|
details::AppendSkipDeletionVars(output_names, &skip_vars);
|
|
}
|
|
if (is_grad) {
|
|
details::AppendSafeEagerDeletionSkipVars(*program, &skip_vars);
|
|
}
|
|
|
|
VLOG(2) << "Prepare to skip " << skip_vars.size()
|
|
<< " var(s): " << string::join_strings(skip_vars, ' ');
|
|
std::shared_ptr<framework::ExecutorPrepareContext> exe_ctx =
|
|
std::move(exe.Prepare(*program, /*block_id=*/0, skip_vars));
|
|
|
|
cached_exe_info.Insert(cache_key, exe_ctx);
|
|
return exe_ctx;
|
|
} else {
|
|
VLOG(1) << "get exe_info from cache by program: " << program
|
|
<< " is_grad: " << is_grad;
|
|
return cached_exe_info.Get(cache_key);
|
|
}
|
|
}
|
|
|
|
} // namespace framework
|
|
} // namespace paddle
|