diff --git a/paddle/fluid/operators/concat_op.cc b/paddle/fluid/operators/concat_op.cc index 0b3697156d36b48e7d7cbf6c175daa160754e46c..e84f0222142cadf66a22465e9a2a66c6a5ccb721 100644 --- a/paddle/fluid/operators/concat_op.cc +++ b/paddle/fluid/operators/concat_op.cc @@ -201,6 +201,20 @@ class ConcatGradOpMaker : public framework::SingleGradOpMaker { } }; +template +class ConcatDoubleGradOpMaker : public framework::SingleGradOpMaker { + public: + using framework::SingleGradOpMaker::SingleGradOpMaker; + + protected: + void Apply(GradOpPtr grad_op) const override { + grad_op->SetType("concat"); + grad_op->SetInput("X", this->OutputGrad(framework::GradVarName("X"))); + grad_op->SetOutput("Out", this->InputGrad(framework::GradVarName("Out"))); + grad_op->SetAttrMap(this->Attrs()); + } +}; + } // namespace operators } // namespace paddle @@ -209,6 +223,8 @@ REGISTER_OPERATOR(concat, ops::ConcatOp, ops::ConcatOpMaker, ops::ConcatGradOpMaker, ops::ConcatGradOpMaker); REGISTER_OPERATOR(concat_grad, ops::ConcatOpGrad, + ops::ConcatDoubleGradOpMaker, + ops::ConcatDoubleGradOpMaker, ops::ConcatOpGradNoNeedBufferVarInferer); REGISTER_OP_CPU_KERNEL( concat, ops::ConcatKernel, diff --git a/paddle/fluid/operators/pad3d_op.cc b/paddle/fluid/operators/pad3d_op.cc index 1d41b823b6551647803ae5641f72955dbbc1eb62..0751cf25587889bd5809b95224c971824c20c15e 100644 --- a/paddle/fluid/operators/pad3d_op.cc +++ b/paddle/fluid/operators/pad3d_op.cc @@ -893,6 +893,22 @@ class Pad3dOpGradMaker : public framework::SingleGradOpMaker { } }; +template +class Pad3dOpDoubleGradMaker : public framework::SingleGradOpMaker { + public: + using framework::SingleGradOpMaker::SingleGradOpMaker; + + void Apply(GradOpPtr grad_op) const override { + if (this->HasInput("Paddings")) { + grad_op->SetInput("Paddings", this->Input("Paddings")); + } + grad_op->SetType("pad3d"); + grad_op->SetInput("X", this->OutputGrad(framework::GradVarName("X"))); + grad_op->SetOutput("Out", this->InputGrad(framework::GradVarName("Out"))); + grad_op->SetAttrMap(this->Attrs()); + } +}; + DECLARE_NO_NEED_BUFFER_VARS_INFERER(Pad3dOpGradNoNeedBufferVarsInferer, "X"); } // namespace operators @@ -904,6 +920,8 @@ REGISTER_OPERATOR(pad3d, ops::Pad3dOp, ops::Pad3dOpMaker, ops::Pad3dOpGradMaker, ops::Pad3dOpGradMaker); REGISTER_OPERATOR(pad3d_grad, ops::Pad3dOpGrad, + ops::Pad3dOpDoubleGradMaker, + ops::Pad3dOpDoubleGradMaker, ops::Pad3dOpGradNoNeedBufferVarsInferer); REGISTER_OP_CPU_KERNEL(pad3d, ops::Pad3dCPUKernel, ops::Pad3dCPUKernel, ops::Pad3dCPUKernel, diff --git a/paddle/fluid/operators/pad_op.cc b/paddle/fluid/operators/pad_op.cc index 91de48100aaaaee2b0e63cb4f9745a856d11f61a..577f4f39411e290a88a91bafb61f7dafa7c1cb5f 100644 --- a/paddle/fluid/operators/pad_op.cc +++ b/paddle/fluid/operators/pad_op.cc @@ -142,6 +142,19 @@ class PadOpGradMaker : public framework::SingleGradOpMaker { } }; +template +class PadOpDoubleGradMaker : public framework::SingleGradOpMaker { + public: + using framework::SingleGradOpMaker::SingleGradOpMaker; + + void Apply(GradOpPtr grad_op) const override { + grad_op->SetType("pad"); + grad_op->SetInput("X", this->OutputGrad(framework::GradVarName("X"))); + grad_op->SetOutput("Out", this->InputGrad(framework::GradVarName("Out"))); + grad_op->SetAttrMap(this->Attrs()); + } +}; + } // namespace operators } // namespace paddle @@ -150,7 +163,9 @@ namespace ops = paddle::operators; REGISTER_OPERATOR(pad, ops::PadOp, ops::PadOpMaker, ops::PadOpGradMaker, ops::PadOpGradMaker); -REGISTER_OPERATOR(pad_grad, ops::PadOpGrad); +REGISTER_OPERATOR(pad_grad, ops::PadOpGrad, + ops::PadOpDoubleGradMaker, + ops::PadOpDoubleGradMaker); REGISTER_OP_CPU_KERNEL( pad, ops::PadKernel, ops::PadKernel, diff --git a/python/paddle/fluid/tests/unittests/test_nn_grad.py b/python/paddle/fluid/tests/unittests/test_nn_grad.py index 6a5e1ba14732fcfb0f9326dc50f2a1ea2c2622a0..d7bbc355d5d104ebff50d45601c917505cceeda1 100644 --- a/python/paddle/fluid/tests/unittests/test_nn_grad.py +++ b/python/paddle/fluid/tests/unittests/test_nn_grad.py @@ -394,5 +394,70 @@ class TestTransposeDoubleGradCheckCase1(unittest.TestCase): self.func(p) +class TestConstantPadDoubleGradCheck(unittest.TestCase): + @prog_scope() + def func(self, place): + x_shape = [2, 3, 4, 5] + pad = [1, 1, 1, 1] + eps = 0.005 + dtype = np.float64 + + x = layers.data('x', x_shape, False, dtype) + x.persistable = True + out = paddle.nn.functional.pad(x, pad) + x_arr = np.random.uniform(-1, 1, x_shape).astype(dtype) + + gradient_checker.double_grad_check( + [x], out, x_init=x_arr, place=place, eps=eps) + + 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 TestConstantPadDoubleGradCheckCase1(TestConstantPadDoubleGradCheck): + @prog_scope() + def func(self, place): + x_shape = [2, 3, 4, 5] + pad = [1, 0, 1, 0, 1, 0, 1, 0] + dtype = np.float64 + + x = layers.data('x', x_shape, False, dtype) + x.persistable = True + out = paddle.nn.functional.pad(x, pad) + x_arr = np.random.uniform(-1, 1, x_shape).astype(dtype) + + gradient_checker.double_grad_check([x], out, x_init=x_arr, place=place) + + +class TestConcatDoubleGradCheck(unittest.TestCase): + @prog_scope() + def func(self, place): + x_shape = [2, 3, 4, 5] + pad = [1, 1, 1, 1] + dtype = np.float64 + + x1 = layers.data('x', x_shape, False, dtype) + x2 = layers.data('x', x_shape, False, dtype) + x1.persistable = True + x2.persistable = True + out = paddle.concat([x1, x2], axis=0) + x2_arr = np.random.uniform(-1, 1, x_shape).astype(dtype) + x1_arr = np.random.uniform(-1, 1, x_shape).astype(dtype) + + gradient_checker.double_grad_check( + [x1, x2], out, x_init=[x1_arr, x2_arr], place=place) + + 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()