diff --git a/paddle/fluid/framework/details/op_registry.h b/paddle/fluid/framework/details/op_registry.h index e5b58ec68761469a03929435d1a73bf0a2d1660e..a9a4fb08a2ca4689e8b6a6f10f83d065332ac192 100644 --- a/paddle/fluid/framework/details/op_registry.h +++ b/paddle/fluid/framework/details/op_registry.h @@ -16,6 +16,7 @@ limitations under the License. */ #include #include +#include #include #include #include @@ -183,6 +184,10 @@ struct OpInfoFiller { T maker(fwd_op, no_grad_set, grad_to_var, grad_block); return maker(); }; + + info->use_default_grad_op_desc_maker_ = + std::is_base_of, T>::value || + std::is_base_of, T>::value; } }; diff --git a/paddle/fluid/framework/grad_op_desc_maker.h b/paddle/fluid/framework/grad_op_desc_maker.h index f2f4c53eea2150b68f15d2a655809d94611b2034..25a64b69ae8b459d6daefb502e9fba84b5bcf3ba 100644 --- a/paddle/fluid/framework/grad_op_desc_maker.h +++ b/paddle/fluid/framework/grad_op_desc_maker.h @@ -147,7 +147,7 @@ class SingleGradOpDescMaker : public GradOpDescMakerBase { public: using GradOpDescMakerBase::GradOpDescMakerBase; - std::vector> operator()() const { + std::vector> operator()() const final { std::vector> retv; retv.emplace_back(this->Apply()); return retv; @@ -158,14 +158,14 @@ class SingleGradOpDescMaker : public GradOpDescMakerBase { }; template -class DefaultGradOpDescMaker : public SingleGradOpDescMaker { +class DefaultGradOpDescMaker final : public SingleGradOpDescMaker { public: using SingleGradOpDescMaker::SingleGradOpDescMaker; protected: - virtual std::unique_ptr Apply() const { + std::unique_ptr Apply() const final { auto* grad = new OpDesc(); - grad->SetType(this->GradOpType()); + grad->SetType(this->ForwardOpType() + "_grad"); for (auto& input_param : this->InputNames()) { grad->SetInput(input_param, this->Input(input_param)); @@ -182,18 +182,12 @@ class DefaultGradOpDescMaker : public SingleGradOpDescMaker { return std::unique_ptr(grad); } - - virtual std::string GradOpType() const { - return this->ForwardOpType() + "_grad"; - } }; -class EmptyGradOpMaker : public GradOpDescMakerBase { +class EmptyGradOpMaker final : public GradOpDescMakerBase { public: using GradOpDescMakerBase::GradOpDescMakerBase; - std::vector> operator()() const override { - return {}; - } + std::vector> operator()() const final { return {}; } }; } // namespace framework diff --git a/paddle/fluid/framework/op_info.cc b/paddle/fluid/framework/op_info.cc index af75baa5c4b98f7d092834c05eb57e9c7e131b29..c815e194d43e149f9efe0daec820c42e87f81d0c 100644 --- a/paddle/fluid/framework/op_info.cc +++ b/paddle/fluid/framework/op_info.cc @@ -13,6 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. */ #include "paddle/fluid/framework/op_info.h" +#include +#include +#include namespace paddle { namespace framework { @@ -24,5 +27,17 @@ OpInfoMap& OpInfoMap::Instance() { static OpInfoMap g_op_info_map; return g_op_info_map; } + +std::vector OpInfoMap::GetUseDefaultGradOpDescMakerOps() const { + // Use set to sort op names + std::set result_ops; + for (auto& pair : map_) { + if (pair.second.use_default_grad_op_desc_maker_) { + result_ops.insert(pair.first); + } + } + return std::vector(result_ops.begin(), result_ops.end()); +} + } // namespace framework } // namespace paddle diff --git a/paddle/fluid/framework/op_info.h b/paddle/fluid/framework/op_info.h index e200d188b3f2462657bbac086d7659b1f85e55e9..daa72769c4957ff5ad0e7b3141bbf97bd348b408 100644 --- a/paddle/fluid/framework/op_info.h +++ b/paddle/fluid/framework/op_info.h @@ -17,6 +17,7 @@ limitations under the License. */ #include #include #include +#include #include "paddle/fluid/framework/attribute.h" #include "paddle/fluid/framework/no_need_buffer_vars_inference.h" @@ -42,6 +43,10 @@ struct OpInfo { InferInplaceOpFN infer_inplace_; InferNoNeedBufferVarsFN infer_no_need_buffer_vars_; + // NOTE(zjl): this flag is added to check whether + // the grad maker is the default one. + bool use_default_grad_op_desc_maker_{false}; + bool HasOpProtoAndChecker() const { return proto_ != nullptr && checker_ != nullptr; } @@ -105,6 +110,8 @@ class OpInfoMap { std::unordered_map* mutable_map() { return &map_; } + std::vector GetUseDefaultGradOpDescMakerOps() const; + private: OpInfoMap() = default; std::unordered_map map_; diff --git a/paddle/fluid/op_use_default_grad_op_maker.spec b/paddle/fluid/op_use_default_grad_op_maker.spec new file mode 100644 index 0000000000000000000000000000000000000000..568db2cf06d3f1993ebc540bf83a28de8d225bd1 --- /dev/null +++ b/paddle/fluid/op_use_default_grad_op_maker.spec @@ -0,0 +1,94 @@ +abs +acos +asin +atan +attention_lstm +bilinear_tensor_product +brelu +conv_shift +cos +cos_sim +dequantize +elementwise_div +elementwise_max +elementwise_min +elu +fc +flatten +fsp +fused_embedding_fc_lstm +fused_embedding_seq_pool +fusion_gru +fusion_lstm +fusion_repeated_fc_relu +fusion_seqconv_eltadd_relu +fusion_seqexpand_concat_fc +fusion_seqpool_concat +fusion_squared_mat_sub +gelu +gru +hard_shrink +hierarchical_sigmoid +hinge_loss +huber_loss +leaky_relu +log +logsigmoid +lookup_table +lrn +lstm_unit +lstmp +max_pool2d_with_index +max_pool3d_with_index +maxout +modified_huber_loss +nce +norm +pool2d +pool3d +pow +prelu +quantize +rank_loss +reduce_max +reduce_mean +reduce_min +reduce_prod +reduce_sum +requantize +reshape +rnn_memory_helper +round +row_conv +sequence_concat +sequence_conv +sequence_expand +sequence_expand_as +sequence_pad +sequence_scatter +sequence_slice +sequence_softmax +sequence_unpad +sigmoid_cross_entropy_with_logits +sin +softplus +softshrink +softsign +space_to_depth +spp +square +squared_l2_distance +squared_l2_norm +squeeze +stanh +swish +tanh_shrink +teacher_student_sigmoid_loss +temporal_shift +tensor_array_to_tensor +thresholded_relu +transpose +tree_conv +unpool +unsqueeze +warpctc diff --git a/paddle/fluid/operators/fused/fused_embedding_seq_pool_op.cc b/paddle/fluid/operators/fused/fused_embedding_seq_pool_op.cc index 9cc94ab88d59dbf8215aca6cd8be3ba19afe32d0..3ee962d37b10bb2c40926f5563ec73ce6d7894c8 100644 --- a/paddle/fluid/operators/fused/fused_embedding_seq_pool_op.cc +++ b/paddle/fluid/operators/fused/fused_embedding_seq_pool_op.cc @@ -107,17 +107,6 @@ And the output will change the LoD information with input Ids. } }; -class FusedEmbeddingSeqPoolOpGradDescMaker - : public framework::DefaultGradOpDescMaker { - using ::paddle::framework::DefaultGradOpDescMaker< - true>::DefaultGradOpDescMaker; - - protected: - virtual std::string GradOpType() const { - return "fused_embedding_seq_pool_grad"; - } -}; - class FusedEmbeddingSeqPoolOpGrad : public framework::OperatorWithKernel { public: using framework::OperatorWithKernel::OperatorWithKernel; @@ -160,7 +149,7 @@ class FusedEmbeddingSeqPoolOpGradVarTypeInference namespace ops = paddle::operators; REGISTER_OPERATOR(fused_embedding_seq_pool, ops::FusedEmbeddingSeqPoolOp, - ops::FusedEmbeddingSeqPoolOpGradDescMaker, + paddle::framework::DefaultGradOpDescMaker, ops::FusedEmbeddingSeqPoolOpMaker); REGISTER_OPERATOR(fused_embedding_seq_pool_grad, ops::FusedEmbeddingSeqPoolOpGrad, diff --git a/paddle/fluid/operators/lookup_table_op.cc b/paddle/fluid/operators/lookup_table_op.cc index d635fc617bc63e1f625e93d21886f6ad134947f6..de1baaf510005b634f20e6606048caab3a4b1073 100644 --- a/paddle/fluid/operators/lookup_table_op.cc +++ b/paddle/fluid/operators/lookup_table_op.cc @@ -119,15 +119,6 @@ or not. And the output only shares the LoD information with input Ids. } }; -class LookupTableOpGradDescMaker - : public framework::DefaultGradOpDescMaker { - using ::paddle::framework::DefaultGradOpDescMaker< - true>::DefaultGradOpDescMaker; - - protected: - virtual std::string GradOpType() const { return "lookup_table_grad"; } -}; - class LookupTableOpGrad : public framework::OperatorWithKernel { public: using framework::OperatorWithKernel::OperatorWithKernel; @@ -169,7 +160,8 @@ class LookupTableOpGradVarTypeInference : public framework::VarTypeInference { namespace ops = paddle::operators; REGISTER_OPERATOR(lookup_table, ops::LookupTableOp, - ops::LookupTableOpGradDescMaker, ops::LookupTableOpMaker); + paddle::framework::DefaultGradOpDescMaker, + ops::LookupTableOpMaker); REGISTER_OPERATOR(lookup_table_grad, ops::LookupTableOpGrad, ops::LookupTableOpGradVarTypeInference); diff --git a/paddle/fluid/operators/nce_op.cc b/paddle/fluid/operators/nce_op.cc index fa7cc58c08455457dd129afd130067704ec72c7c..3caa4e60656956051bdaf3db4a3aebe1da996b03 100644 --- a/paddle/fluid/operators/nce_op.cc +++ b/paddle/fluid/operators/nce_op.cc @@ -187,14 +187,6 @@ By default this operator uses a uniform distribution for sampling. } }; -class NCEOpGradDescMaker : public framework::DefaultGradOpDescMaker { - using ::paddle::framework::DefaultGradOpDescMaker< - true>::DefaultGradOpDescMaker; - - protected: - virtual std::string GradOpType() const { return "nce_grad"; } -}; - class NCEOpGrad : public framework::OperatorWithKernel { public: using framework::OperatorWithKernel::OperatorWithKernel; @@ -259,7 +251,9 @@ class NCEOpGradVarTypeInference : public framework::VarTypeInference { } // namespace paddle namespace ops = paddle::operators; -REGISTER_OPERATOR(nce, ops::NCEOp, ops::NCEOpGradDescMaker, ops::NCEOpMaker); +REGISTER_OPERATOR(nce, ops::NCEOp, + paddle::framework::DefaultGradOpDescMaker, + ops::NCEOpMaker); REGISTER_OPERATOR(nce_grad, ops::NCEOpGrad, ops::NCEOpGradVarTypeInference); REGISTER_OP_CPU_KERNEL(nce, ops::NCEKernel, ops::NCEKernel); diff --git a/paddle/fluid/pybind/pybind.cc b/paddle/fluid/pybind/pybind.cc index b011858a54291ed01c4c3bbe50b914d526529776..8b6731256bae27bf8e5af47fcd329141fd388846 100644 --- a/paddle/fluid/pybind/pybind.cc +++ b/paddle/fluid/pybind/pybind.cc @@ -29,6 +29,7 @@ limitations under the License. */ #include "paddle/fluid/framework/lod_rank_table.h" #include "paddle/fluid/framework/lod_tensor.h" #include "paddle/fluid/framework/lod_tensor_array.h" +#include "paddle/fluid/framework/op_info.h" #include "paddle/fluid/framework/op_registry.h" #include "paddle/fluid/framework/parallel_executor.h" #include "paddle/fluid/framework/prune.h" @@ -156,6 +157,9 @@ PYBIND11_MODULE(core, m) { return paddle::operators::AppendPythonCallableObjectAndReturnId(py_obj); }); + m.def("_get_use_default_grad_op_desc_maker_ops", + [] { return OpInfoMap::Instance().GetUseDefaultGradOpDescMakerOps(); }); + // NOTE(zjl): ctest would load environment variables at the beginning even // though we have not `import paddle.fluid as fluid`. So we add this API // to enable eager deletion mode in unittest. diff --git a/paddle/scripts/paddle_build.sh b/paddle/scripts/paddle_build.sh index 025528e85c4bf4da63b588dd91681d7bf7bb78fe..fc52c281c4f0de2b05ab2b58aa81cdbf1216e6a7 100755 --- a/paddle/scripts/paddle_build.sh +++ b/paddle/scripts/paddle_build.sh @@ -425,6 +425,13 @@ function assert_api_not_changed() { sed -i '/.*ComposeNotAligned.*/d' new.spec python ${PADDLE_ROOT}/tools/diff_api.py ${PADDLE_ROOT}/paddle/fluid/API.spec new.spec + + # Currently, we only check in PR_CI python 2.7 + if [ "$SYSTEM" != "Darwin" ]; then + if [ "$1" == "" ] || [ "$1" == "cp27-cp27m" ] || [ "$1" == "cp27-cp27mu" ]; then + python ${PADDLE_ROOT}/tools/diff_use_default_grad_op_maker.py ${PADDLE_ROOT}/paddle/fluid/op_use_default_grad_op_maker.spec + fi + fi deactivate } @@ -434,9 +441,12 @@ function assert_api_spec_approvals() { fi API_FILES=("paddle/fluid/API.spec" + "paddle/fluid/op_use_default_grad_op_maker.spec" "python/paddle/fluid/parallel_executor.py" "paddle/fluid/framework/operator.h" "paddle/fluid/framework/tensor.h" + "paddle/fluid/framework/details/op_registry.h" + "paddle/fluid/framework/grad_op_desc_maker.h" "paddle/fluid/framework/lod_tensor.h" "paddle/fluid/framework/selected_rows.h" "paddle/fluid/framework/op_desc.h" diff --git a/tools/diff_use_default_grad_op_maker.py b/tools/diff_use_default_grad_op_maker.py new file mode 100644 index 0000000000000000000000000000000000000000..9e362f611bbf381f480be6f216c28a53dc0440fa --- /dev/null +++ b/tools/diff_use_default_grad_op_maker.py @@ -0,0 +1,66 @@ +# Copyright (c) 2019 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. + +import os + +os.environ['CUDA_VISIBLE_DEVICES'] = '' + +import paddle.fluid as fluid +import sys + + +def get_op_diff(filename): + ops_created_by_py_func = set( + fluid.core._get_use_default_grad_op_desc_maker_ops()) + + with open(filename, 'r') as f: + ops_read_from_file = set([line.strip() for line in f.readlines()]) + + diff_ops = [] + + for op in ops_read_from_file: + if op not in ops_created_by_py_func: + diff_ops.append(op) + else: + ops_created_by_py_func.remove(op) + + err_msg = [] + diff_ops = list(diff_ops) + if len(diff_ops) > 0: + err_msg.append('Added grad op with DefaultGradOpDescMaker: ' + str( + diff_ops)) + + ops_created_by_py_func = list(ops_created_by_py_func) + if len(ops_created_by_py_func) > 0: + err_msg.append('Remove grad op with DefaultGradOpDescMaker: ' + str( + ops_created_by_py_func)) + + return err_msg + + +if len(sys.argv) != 2: + print('Usage: python diff_use_default_grad_op_maker.py [filepath]') + sys.exit(1) + +file_path = str(sys.argv[1]) +err_msg = get_op_diff(file_path) + +if len(err_msg) > 0: + _, filename = os.path.split(file_path) + print('File `{}` is wrong compared to your PR revision!'.format(filename)) + print( + 'Please use `python generate_op_use_grad_op_desc_maker_spec.py [filepath]` to generate new `{}` file'. + format(filename)) + print('Error message is: ' + '; '.join(err_msg)) + sys.exit(1) diff --git a/tools/generate_op_use_grad_op_desc_maker_spec.py b/tools/generate_op_use_grad_op_desc_maker_spec.py new file mode 100644 index 0000000000000000000000000000000000000000..69b062a8716692f19bbd63928064cf74c171b88f --- /dev/null +++ b/tools/generate_op_use_grad_op_desc_maker_spec.py @@ -0,0 +1,29 @@ +# Copyright (c) 2019 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. + +import os + +os.environ['CUDA_VISIBLE_DEVICES'] = '' + +import paddle.fluid as fluid +import sys + +if len(sys.argv) != 2: + print('Usage: python generate_op_use_grad_op_desc_maker_spec.py [filepath]') + sys.exit(1) + +with open(sys.argv[1], 'w') as f: + ops = fluid.core._get_use_default_grad_op_desc_maker_ops() + for op in ops: + f.write(op + '\n')