-
Notifications
You must be signed in to change notification settings - Fork 5.9k
add unused input vars check for OpWithKernel, test=develop #21169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 18 commits
08d70cb
dc41961
032ef2f
7aff856
e69b905
afc8da5
1db659b
5b1047d
e97a64d
d45ae40
7f2b8ca
67b9f4f
234dc12
a180079
a470fbc
0fe1a68
98f1509
6ee0ab0
301f835
1d9bb16
c8dff60
cfc3a6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,11 +28,13 @@ limitations under the License. */ | |
| #include "paddle/fluid/framework/operator.h" | ||
| #include "paddle/fluid/framework/shape_inference.h" | ||
| #include "paddle/fluid/framework/transfer_scope_cache.h" | ||
| #include "paddle/fluid/framework/unused_var_check.h" | ||
| #include "paddle/fluid/framework/var_type.h" | ||
| #include "paddle/fluid/platform/profiler.h" | ||
|
|
||
| DECLARE_bool(benchmark); | ||
| DECLARE_bool(check_nan_inf); | ||
| DECLARE_bool(enable_unused_var_check); | ||
| DEFINE_int32(inner_op_parallelism, 0, "number of threads for inner op"); | ||
| DEFINE_bool(fast_check_nan_inf, false, | ||
| "Fast checking NAN/INF after each operation. It will be a little" | ||
|
|
@@ -428,6 +430,8 @@ bool ExecutionContext::HasOutput(const std::string& name) const { | |
| } | ||
|
|
||
| const Variable* ExecutionContext::InputVar(const std::string& name) const { | ||
| LogVarUsageIfUnusedVarCheckEnabled(name); | ||
|
|
||
| auto it = ctx_.inputs.find(name); | ||
| if (it == ctx_.inputs.end()) return nullptr; | ||
|
|
||
|
|
@@ -457,6 +461,8 @@ const Tensor* ExecutionContext::Input<Tensor>(const std::string& name) const { | |
| template <> | ||
| const std::vector<const Tensor*> ExecutionContext::MultiInput<Tensor>( | ||
| const std::string& name) const { | ||
| LogVarUsageIfUnusedVarCheckEnabled(name); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Call this function with
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. To reduce code duplication, I will put the |
||
|
|
||
| auto it = ctx_.inputs.find(name); | ||
| if (it == ctx_.inputs.end()) { | ||
| return {}; | ||
|
|
@@ -910,6 +916,11 @@ void OperatorWithKernel::RunImpl(const Scope& scope, | |
| RuntimeInferShapeContext infer_shape_ctx(*this, exec_scope, *runtime_ctx); | ||
| this->InferShape(&infer_shape_ctx); | ||
| } | ||
|
|
||
| if (FLAGS_enable_unused_var_check) { | ||
| GetThreadLocalUsedVarNameSet()->clear(); | ||
| } | ||
|
|
||
| // TODO(panyx0718): ExecutionContext should only depend on RuntimeContext | ||
| // not Scope. Imperative mode only pass inputs and get outputs. | ||
| (*kernel_func_)(ExecutionContext(*this, exec_scope, *dev_ctx, *runtime_ctx, | ||
|
|
@@ -919,6 +930,14 @@ void OperatorWithKernel::RunImpl(const Scope& scope, | |
| // there is inplace variable has been transfered. | ||
| TransferInplaceVarsBack(scope, transfered_inplace_vars, *transfer_scope); | ||
| } | ||
| if (FLAGS_enable_unused_var_check) { | ||
| // skip op that uses mkldnn because it has different memory reuse strategy. | ||
| // use attr here because some GradMakers (like ActivationGradOpMaker) add | ||
| // input when use_mkldnn=true; | ||
| if (!(HasAttr("use_mkldnn") && Attr<bool>("use_mkldnn"))) { | ||
| CheckUnusedVar(*this, scope); | ||
| } | ||
| } | ||
|
|
||
| /*For profiling/benchmark only*/ | ||
| if (FLAGS_benchmark) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,7 @@ limitations under the License. */ | |
| #include "paddle/fluid/framework/scope.h" | ||
| #include "paddle/fluid/framework/selected_rows.h" | ||
| #include "paddle/fluid/framework/tensor.h" | ||
| #include "paddle/fluid/framework/unused_var_check.h" | ||
| #include "paddle/fluid/memory/malloc.h" | ||
| #include "paddle/fluid/platform/device_context.h" | ||
| #include "paddle/fluid/platform/variant.h" | ||
|
|
@@ -268,6 +269,8 @@ class ExecutionContext { | |
|
|
||
| const std::vector<const Variable*> MultiInputVar( | ||
| const std::string& name) const { | ||
| LogVarUsageIfUnusedVarCheckEnabled(name); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same above.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, thanks. |
||
|
|
||
| auto it = ctx_.inputs.find(name); | ||
| if (it == ctx_.inputs.end()) { | ||
| return {}; | ||
|
|
@@ -298,6 +301,8 @@ class ExecutionContext { | |
|
|
||
| template <typename T> | ||
| const std::vector<const T*> MultiInput(const std::string& name) const { | ||
| LogVarUsageIfUnusedVarCheckEnabled(name); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same above.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, thanks. |
||
|
|
||
| auto it = ctx_.inputs.find(name); | ||
| if (it == ctx_.inputs.end()) { | ||
| return {}; | ||
|
|
@@ -349,6 +354,7 @@ class ExecutionContext { | |
|
|
||
| //! Get actual name vector for this input. | ||
| const std::vector<std::string>& Inputs(const std::string& name) const { | ||
| LogVarUsageIfUnusedVarCheckEnabled(name); | ||
|
||
| return op_.Inputs(name); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| /* Copyright (c) 2016 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 <gflags/gflags.h> | ||
| #include <glog/logging.h> | ||
|
|
||
| #include <string> | ||
| #include <unordered_set> | ||
| #include <vector> | ||
| #include "paddle/fluid/framework/operator.h" | ||
| #include "paddle/fluid/framework/unused_var_check.h" | ||
| #include "paddle/fluid/platform/enforce.h" | ||
|
|
||
| DEFINE_bool(enable_unused_var_check, false, | ||
| "Checking whether operator contains unused inputs, " | ||
| "especially for grad operator. It should be in unittest."); | ||
|
|
||
| const std::unordered_set<std::string> op_has_unsed_vars_white_list = { | ||
| "auc", | ||
| "batch_norm", | ||
| "batch_norm_grad", | ||
| "sync_batch_norm_grad", | ||
| "center_loss_grad", | ||
| "crop", | ||
| "cvm", | ||
| "cos_sim_grad", | ||
| "dgc_momentum", | ||
| "fake_quantize_range_abs_max", | ||
| "fill_zeros_like", | ||
| "fusion_seqpool_cvm_concat", | ||
| "reshape2_grad_grad", | ||
| "reshape2_grad", | ||
| "gru_grad", | ||
| "hierarchical_sigmoid_grad", | ||
| "nce_grad", | ||
| "roi_perspective_transform_grad", | ||
| "sequence_conv_grad", | ||
| "gru_unit_grad", | ||
| "affine_grid_grad", | ||
| "fill_any_like", | ||
| "precision_recall", | ||
| "unsqueeze_grad", | ||
| "kldiv_loss_grad", | ||
| "cvm_grad", | ||
| "stack_grad", | ||
| "warpctc_grad", | ||
| "sync_batch_norm", | ||
| "match_matrix_tensor_grad", | ||
| "ngraph_engine"}; | ||
|
|
||
| namespace paddle { | ||
| namespace framework { | ||
|
|
||
| std::unordered_set<std::string> *GetThreadLocalUsedVarNameSet() { | ||
| thread_local std::unordered_set<std::string> used_var_name_set; | ||
| return &used_var_name_set; | ||
| } | ||
|
|
||
| void LogVarUsageIfUnusedVarCheckEnabled(const std::string &name) { | ||
| if (FLAGS_enable_unused_var_check) { | ||
| VLOG(6) << "Variable used:" << name; | ||
| GetThreadLocalUsedVarNameSet()->insert(name); | ||
| } | ||
| } | ||
|
|
||
| void CheckUnusedVar(const OperatorBase &op, const Scope &scope) { | ||
| // skip op in white list and it should be fixed in the future. | ||
| if (op_has_unsed_vars_white_list.count(op.Type()) != 0) { | ||
| return; | ||
| } | ||
| auto *used_set = GetThreadLocalUsedVarNameSet(); | ||
| std::vector<std::string> unsed_input_var_names; | ||
| auto &inferer = op.Info().NoNeedBufferVarsInferer(); | ||
| std::unordered_set<std::string> no_need_buffer_ins = {}; | ||
| if (inferer) { | ||
| no_need_buffer_ins = inferer(op.Inputs(), op.Outputs(), op.Attrs()); | ||
| } | ||
|
|
||
| for (auto &pair : op.Inputs()) { | ||
| // skip no need buffer vars declared | ||
| if (no_need_buffer_ins.count(pair.first) != 0) { | ||
| VLOG(6) << op.Type() << " " << pair.first; | ||
| continue; | ||
| } | ||
| if (used_set->count(pair.first) == 0) { | ||
| for (auto &in_var_name : pair.second) { | ||
| auto *in_var = scope.FindVar(in_var_name); | ||
| if (in_var != nullptr && in_var->IsInitialized()) { | ||
| auto *tensor = &in_var->Get<LoDTensor>(); | ||
| if (tensor != nullptr && tensor->IsInitialized()) { | ||
| unsed_input_var_names.emplace_back(pair.first); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (!unsed_input_var_names.empty()) { | ||
| std::string err_msg = "Operator " + op.Type() + " has input(s) not uesed: "; | ||
| for (auto &in_var_name : unsed_input_var_names) { | ||
| err_msg += in_var_name; | ||
| err_msg += ", "; | ||
| } | ||
| err_msg += | ||
| "please make sure it(they) is(are) needed. If not, remove it(them) " | ||
| "from inputs of the operator; if yes, register " | ||
| "NoNeedBufferVarsInference or add " | ||
| "the operator to " | ||
| "white list in unused_var_check.cc. See more details at " | ||
| "[https://github.com/PaddlePaddle/Paddle/wiki/" | ||
| "OP-Should-Not-Have-Unused-Input]"; | ||
| PADDLE_ENFORCE_EQ(unsed_input_var_names.size(), 0, | ||
| platform::errors::PermissionDenied( | ||
| "Unused input variables check failed: %s", err_msg)); | ||
| } | ||
| } | ||
|
|
||
| } // namespace framework | ||
| } // namespace paddle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call this function with
if (FLAGS_enable_unused_var_check)?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. To reduce code duplication, I will put the if statement inside LogVarUsageIfUnusedVarCheckEnabled.