From 97798f9a41a7cd72681ce17ce35dc0f189827f9e Mon Sep 17 00:00:00 2001 From: Wei Shengyu Date: Mon, 6 Sep 2021 14:54:55 +0800 Subject: [PATCH] Add grad grad for AvgPool2D (#35388) * add pool2d grad grad * dbg * add unittest * update format * add more unittests * dbg --- paddle/fluid/operators/pool_cudnn_op.cu.cc | 18 ++++ paddle/fluid/operators/pool_op.cc | 23 ++++- paddle/fluid/operators/pool_op.cu | 7 ++ paddle/fluid/operators/pool_op.h | 14 +++ .../fluid/tests/unittests/test_nn_grad.py | 98 +++++++++++++++++++ 5 files changed, 159 insertions(+), 1 deletion(-) diff --git a/paddle/fluid/operators/pool_cudnn_op.cu.cc b/paddle/fluid/operators/pool_cudnn_op.cu.cc index 1bdb3728f53..8fcd40a9a2d 100644 --- a/paddle/fluid/operators/pool_cudnn_op.cu.cc +++ b/paddle/fluid/operators/pool_cudnn_op.cu.cc @@ -505,6 +505,20 @@ class PoolCUDNNGradOpKernel : public framework::OpKernel { } }; +template +class PoolCUDNNGradGradOpKernel : public PoolCUDNNOpKernel { + public: + void Compute(const framework::ExecutionContext &ctx) const override { + std::string pooling_type = ctx.Attr("pooling_type"); + if (pooling_type == "max") { + PADDLE_THROW(platform::errors::InvalidArgument( + "Pool op grad grad only supports avgpool.")); + } else { + PoolCUDNNOpKernel::Compute(ctx); + } + } +}; + } // namespace operators } // namespace paddle @@ -534,6 +548,10 @@ REGISTER_OP_KERNEL(pool2d_grad, CUDNN, plat::CUDAPlace, ops::PoolCUDNNGradOpKernel, ops::PoolCUDNNGradOpKernel, ops::PoolCUDNNGradOpKernel); +REGISTER_OP_KERNEL(pool2d_grad_grad, CUDNN, plat::CUDAPlace, + ops::PoolCUDNNGradGradOpKernel, + ops::PoolCUDNNGradGradOpKernel, + ops::PoolCUDNNGradGradOpKernel); REGISTER_OP_KERNEL(pool3d, CUDNN, plat::CUDAPlace, ops::PoolCUDNNOpKernel, diff --git a/paddle/fluid/operators/pool_op.cc b/paddle/fluid/operators/pool_op.cc index 03766ebb465..9d8f086ce0f 100644 --- a/paddle/fluid/operators/pool_op.cc +++ b/paddle/fluid/operators/pool_op.cc @@ -469,6 +469,20 @@ Example: )DOC"); } +template +class Pool2dOpGradGradMaker : public framework::SingleGradOpMaker { + public: + using framework::SingleGradOpMaker::SingleGradOpMaker; + + protected: + void Apply(GradOpPtr grad_op) const override { + grad_op->SetType("pool2d_grad_grad"); + grad_op->SetInput("X", this->OutputGrad(framework::GradVarName("X"))); + grad_op->SetOutput("Out", this->InputGrad(framework::GradVarName("Out"))); + grad_op->SetAttrMap(this->Attrs()); + } +}; + class PoolOpInferVarType : public framework::PassInDtypeAndVarTypeToOutput { protected: std::unordered_map& GetInputOutputWithSameType() @@ -687,7 +701,10 @@ REGISTER_OPERATOR( pool2d, ops::PoolOp, ops::Pool2dOpMaker, ops::PoolOpInferVarType, paddle::framework::DefaultGradOpMaker, paddle::framework::DefaultGradOpMaker); -REGISTER_OPERATOR(pool2d_grad, ops::PoolOpGrad); +REGISTER_OPERATOR(pool2d_grad, ops::PoolOpGrad, + ops::Pool2dOpGradGradMaker, + ops::Pool2dOpGradGradMaker); +REGISTER_OPERATOR(pool2d_grad_grad, ops::PoolOp); REGISTER_OP_CPU_KERNEL( pool2d, ops::PoolKernel, @@ -695,6 +712,10 @@ REGISTER_OP_CPU_KERNEL( REGISTER_OP_CPU_KERNEL( pool2d_grad, ops::PoolGradKernel, ops::PoolGradKernel); +REGISTER_OP_CPU_KERNEL( + pool2d_grad_grad, + ops::PoolGradGradKernel, + ops::PoolGradGradKernel); REGISTER_OPERATOR( pool3d, ops::PoolOp, ops::Pool3dOpMaker, ops::PoolOpInferVarType, diff --git a/paddle/fluid/operators/pool_op.cu b/paddle/fluid/operators/pool_op.cu index 6b1e9f93033..069ce0c1fda 100644 --- a/paddle/fluid/operators/pool_op.cu +++ b/paddle/fluid/operators/pool_op.cu @@ -28,6 +28,13 @@ REGISTER_OP_CUDA_KERNEL( ops::PoolGradKernel); +REGISTER_OP_CUDA_KERNEL( + pool2d_grad_grad, + ops::PoolGradGradKernel, + ops::PoolGradGradKernel, + ops::PoolGradGradKernel); + REGISTER_OP_CUDA_KERNEL( pool3d, ops::PoolKernel, ops::PoolKernel, diff --git a/paddle/fluid/operators/pool_op.h b/paddle/fluid/operators/pool_op.h index e84c92d9a16..9ee8eab1a79 100644 --- a/paddle/fluid/operators/pool_op.h +++ b/paddle/fluid/operators/pool_op.h @@ -357,5 +357,19 @@ class PoolGradKernel : public framework::OpKernel { } }; +template +class PoolGradGradKernel : public PoolKernel { + public: + void Compute(const framework::ExecutionContext& context) const override { + std::string pooling_type = context.Attr("pooling_type"); + if (pooling_type == "max") { + PADDLE_THROW(platform::errors::InvalidArgument( + "Pool op grad grad only supports avgpool.")); + } else { + PoolKernel::Compute(context); + } + } +}; + } // namespace operators } // namespace paddle diff --git a/python/paddle/fluid/tests/unittests/test_nn_grad.py b/python/paddle/fluid/tests/unittests/test_nn_grad.py index 33d313e709e..722926b0d77 100644 --- a/python/paddle/fluid/tests/unittests/test_nn_grad.py +++ b/python/paddle/fluid/tests/unittests/test_nn_grad.py @@ -381,5 +381,103 @@ class TestConcatDoubleGradCheck(unittest.TestCase): self.func(p) +class TestAvgPool2DDoubleGradCheckCase1(unittest.TestCase): + @prog_scope() + def func(self, place): + input_NCHW = fluid.layers.data( + name="input_NCHW", + shape=[2, 3, 5, 5], + append_batch_size=False, + dtype="float32") + + input_NCHW.persistable = True + y = layers.pool2d(input_NCHW, pool_size=2, pool_type="avg") + x_arr = np.random.uniform(-1, 1, [2, 3, 5, 5]).astype(np.float32) + + gradient_checker.double_grad_check( + [input_NCHW], y, x_init=x_arr, place=place, eps=0.05) + + def test_grad(self): + places = [fluid.CPUPlace()] + if core.is_compiled_with_cuda(): + places.append(fluid.CUDAPlace(0)) + for p in places: + self.func(p) + + +class TestAvgPool2DDoubleGradCheckCase2(unittest.TestCase): + @prog_scope() + def func(self, place): + input_NHWC = fluid.layers.data( + name="input_NHWC", + shape=[2, 5, 5, 3], + append_batch_size=False, + dtype="float32") + + input_NHWC.persistable = True + y = layers.pool2d( + input_NHWC, pool_size=2, pool_type="avg", data_format="NHWC") + x_arr = np.random.uniform(-1, 1, [2, 5, 5, 3]).astype(np.float32) + + gradient_checker.double_grad_check( + [input_NHWC], y, x_init=x_arr, place=place, eps=0.05) + + def test_grad(self): + places = [fluid.CPUPlace()] + if core.is_compiled_with_cuda(): + places.append(fluid.CUDAPlace(0)) + for p in places: + self.func(p) + + +class TestAvgPool2DDoubleGradCheckCase3(unittest.TestCase): + @prog_scope() + def func(self, place): + input_NCHW = fluid.layers.data( + name="input_NCHW", + shape=[2, 3, 5, 5], + append_batch_size=False, + dtype="float32") + + input_NCHW.persistable = True + y = layers.pool2d( + input_NCHW, pool_size=2, pool_type="avg", pool_padding=[1, 1]) + x_arr = np.random.uniform(-1, 1, [2, 3, 5, 5]).astype(np.float32) + + gradient_checker.double_grad_check( + [input_NCHW], y, x_init=x_arr, place=place, eps=0.05) + + def test_grad(self): + places = [fluid.CPUPlace()] + if core.is_compiled_with_cuda(): + places.append(fluid.CUDAPlace(0)) + for p in places: + self.func(p) + + +class TestAvgPool2DDoubleGradCheckCase4(unittest.TestCase): + @prog_scope() + def func(self, place): + input_NCHW = fluid.layers.data( + name="input_NCHW", + shape=[2, 3, 5, 5], + append_batch_size=False, + dtype="float32") + + input_NCHW.persistable = True + y = layers.pool2d(input_NCHW, pool_size=[4, 4], pool_type="avg") + x_arr = np.random.uniform(-1, 1, [2, 3, 5, 5]).astype(np.float32) + + gradient_checker.double_grad_check( + [input_NCHW], y, x_init=x_arr, place=place, eps=0.05) + + def test_grad(self): + places = [fluid.CPUPlace()] + if core.is_compiled_with_cuda(): + places.append(fluid.CUDAPlace(0)) + for p in places: + self.func(p) + + if __name__ == "__main__": unittest.main() -- GitLab