diff --git a/paddle/fluid/prim/api/api.yaml b/paddle/fluid/prim/api/api.yaml index fc64b758adee0..67353d342fa06 100644 --- a/paddle/fluid/prim/api/api.yaml +++ b/paddle/fluid/prim/api/api.yaml @@ -1,13 +1,14 @@ +- add +- subtract +- multiply +- divide - unsqueeze - pow - exp - scale -- multiply - matmul - expand -- divide - sum -- add - abs - assign - concat @@ -24,4 +25,3 @@ - scatter_nd_add - tile - transpose -- subtract diff --git a/paddle/fluid/prim/api/auto_code_generated/tensor_operants_gen.py b/paddle/fluid/prim/api/auto_code_generated/tensor_operants_gen.py index b0dc1d646984f..3b266927e183b 100644 --- a/paddle/fluid/prim/api/auto_code_generated/tensor_operants_gen.py +++ b/paddle/fluid/prim/api/auto_code_generated/tensor_operants_gen.py @@ -48,6 +48,14 @@ class EagerTensorOperants : public TensorOperantsBase { public: EagerTensorOperants() = default; + Tensor add(const Tensor& x, const Scalar& y); + + Tensor subtract(const Tensor& x, const Scalar& y); + + Tensor multiply(const Tensor& x, const Scalar& y); + + Tensor divide(const Tensor& x, const Scalar& y); + """ @@ -73,6 +81,22 @@ class EagerTensorOperants : public TensorOperantsBase { namespace prim { +Tensor EagerTensorOperants::add(const Tensor& x, const Scalar& y) { + return ::add_ad_func(x, ::full_like_ad_func(x, y)); +} + +Tensor EagerTensorOperants::subtract(const Tensor& x, const Scalar& y) { + return ::subtract_ad_func(x, ::full_like_ad_func(x, y)); +} + +Tensor EagerTensorOperants::multiply(const Tensor& x, const Scalar& y) { + return ::multiply_ad_func(x, ::full_like_ad_func(x, y)); +} + +Tensor EagerTensorOperants::divide(const Tensor& x, const Scalar& y) { + return ::divide_ad_func(x, ::full_like_ad_func(x, y)); +} + """ @@ -112,6 +136,14 @@ class StaticTensorOperants : public TensorOperantsBase { public: StaticTensorOperants() = default; + Tensor add(const Tensor& x, const Scalar& y); + + Tensor subtract(const Tensor& x, const Scalar& y); + + Tensor multiply(const Tensor& x, const Scalar& y); + + Tensor divide(const Tensor& x, const Scalar& y); + """ @@ -128,6 +160,7 @@ class StaticTensorOperants : public TensorOperantsBase { #include "paddle/fluid/prim/utils/static/static_tensor_operants.h" #include "paddle/fluid/prim/api/generated_prim/prim_generated_api.h" +#include "paddle/fluid/prim/api/manual_prim/prim_manual_api.h" #include "paddle/fluid/prim/utils/static/desc_tensor.h" """ @@ -139,6 +172,22 @@ class StaticTensorOperants : public TensorOperantsBase { namespace prim { using DescTensor = paddle::prim::DescTensor; +Tensor StaticTensorOperants::add(const Tensor& x, const Scalar& y) { + return paddle::prim::add(x, paddle::prim::full(x.shape(), y, x.dtype(), x.place())); +} + +Tensor StaticTensorOperants::subtract(const Tensor& x, const Scalar& y) { + return paddle::prim::subtract(x, paddle::prim::full(x.shape(), y, x.dtype(), x.place())); +} + +Tensor StaticTensorOperants::multiply(const Tensor& x, const Scalar& y) { + return paddle::prim::multiply(x, paddle::prim::full(x.shape(), y, x.dtype(), x.place())); +} + +Tensor StaticTensorOperants::divide(const Tensor& x, const Scalar& y) { + return paddle::prim::divide(x, paddle::prim::full(x.shape(), y, x.dtype(), x.place())); +} + """ diff --git a/paddle/fluid/prim/api/composite_backward/composite_backward_api.h b/paddle/fluid/prim/api/composite_backward/composite_backward_api.h index c036170197b5b..fe9679485d50d 100644 --- a/paddle/fluid/prim/api/composite_backward/composite_backward_api.h +++ b/paddle/fluid/prim/api/composite_backward/composite_backward_api.h @@ -61,9 +61,7 @@ void gather_grad(const Tensor& x, template void tanh_grad(const Tensor& out, const Tensor& grad_out, Tensor* grad_x) { if (!grad_x) return; - auto tmp = out.pow(2.0); - tmp = scale(tmp, -1.0, 1.0, true); - auto grad_x_tmp = grad_out * tmp; + auto grad_x_tmp = grad_out * (out.pow(2.0) * -1.0 + 1.0); set_output(grad_x_tmp, grad_x); } @@ -203,10 +201,7 @@ void divide_grad(const Tensor& x, Tensor* dy) { if (dy) { // dy = -(x/y^2) * dout - auto tmp0 = y.pow(2.0); - auto tmp1 = x / tmp0; - auto tmp2 = scale(tmp1, -1.0, 0.0, true); - auto dy_res = tmp2 * out_grad; + auto dy_res = x / y.pow(2.0) * -1.0 * out_grad; if (x.dims() != y.dims()) { // Maybe need reduce here phi::DDim reduce_dim = get_reduce_dims(y.dims(), x.dims()); @@ -247,8 +242,7 @@ void divide_grad(const Tensor& x, template void sqrt_grad(const Tensor& out, const Tensor& out_grad, Tensor* x_grad) { if (x_grad) { - auto div_x = full(phi::vectorize(out.dims()), 0.5); - auto x_grad_tmp = out_grad * div_x / out; + auto x_grad_tmp = out_grad / 2.0 / out; set_output(x_grad_tmp, x_grad); } } diff --git a/paddle/fluid/prim/api/manual_prim/static_prim_api.cc b/paddle/fluid/prim/api/manual_prim/static_prim_api.cc index 51708241bb7e6..affca5940180e 100644 --- a/paddle/fluid/prim/api/manual_prim/static_prim_api.cc +++ b/paddle/fluid/prim/api/manual_prim/static_prim_api.cc @@ -67,23 +67,51 @@ Tensor full(const IntArray& shape, framework::OpDesc* op = block->AppendOp(); op->SetType("fill_constant"); op->SetAttr("shape", shape.GetData()); - PADDLE_ENFORCE_EQ( - ((dtype == DataType::FLOAT32) || (dtype == DataType::FLOAT64) || - (dtype == DataType::FLOAT16)), - true, - phi::errors::InvalidArgument( - "We only support float32/float16 for full, but we got data type: %s", + switch (dtype) { + case phi::DataType::FLOAT16: + op->SetAttr("str_value", std::to_string(value.to())); + break; + case phi::DataType::FLOAT32: + op->SetAttr("value", value.to()); + break; + case phi::DataType::FLOAT64: + op->SetAttr("str_value", std::to_string(value.to())); + break; + case phi::DataType::BOOL: + op->SetAttr("str_value", std::to_string(value.to())); + break; + case phi::DataType::INT8: + op->SetAttr("str_value", std::to_string(value.to())); + break; + case phi::DataType::UINT8: + op->SetAttr("str_value", std::to_string(value.to())); + break; + case phi::DataType::INT16: + op->SetAttr("str_value", std::to_string(value.to())); + break; + case phi::DataType::UINT16: + op->SetAttr("str_value", std::to_string(value.to())); + break; + case phi::DataType::INT32: + op->SetAttr("str_value", std::to_string(value.to())); + break; + case phi::DataType::UINT32: + op->SetAttr("str_value", std::to_string(value.to())); + break; + case phi::DataType::INT64: + op->SetAttr("str_value", std::to_string(value.to())); + break; + case phi::DataType::UINT64: + op->SetAttr("str_value", std::to_string(value.to())); + break; + default: + PADDLE_THROW(phi::errors::Unimplemented( + "We support " + "bool/float16/float32/float64/int8/int16/int32/int64/uint8/uint16/" + "uint32/uint64 for full, but we got data type: %s", phi::DataTypeToString(dtype))); - if (dtype == phi::DataType::FLOAT32) { - op->SetAttr("value", value.to()); - } else if (dtype == phi::DataType::FLOAT64) { - op->SetAttr("str_value", std::to_string(value.to())); - } else if (dtype == phi::DataType::FLOAT16) { - op->SetAttr("str_value", std::to_string(value.to())); - } else { - PADDLE_THROW(phi::errors::Unimplemented( - "We only support float64/float32/float16 for full")); } + op->SetAttr("dtype", paddle::framework::TransToProtoVarType(dtype)); op->SetOutput( "Out", {std::static_pointer_cast(out.impl())->Name()}); diff --git a/paddle/fluid/prim/tests/CMakeLists.txt b/paddle/fluid/prim/tests/CMakeLists.txt index f85108a7c8ee5..5bee3db307cb7 100644 --- a/paddle/fluid/prim/tests/CMakeLists.txt +++ b/paddle/fluid/prim/tests/CMakeLists.txt @@ -29,6 +29,8 @@ cc_test_old( prim_utils operator elementwise_mul_op + elementwise_add_op + fill_constant_op activation_op phi_api phi_dygraph_api diff --git a/paddle/fluid/prim/tests/test_static_prim.cc b/paddle/fluid/prim/tests/test_static_prim.cc index 4ca26f87efb62..8abe7c43dc0fe 100644 --- a/paddle/fluid/prim/tests/test_static_prim.cc +++ b/paddle/fluid/prim/tests/test_static_prim.cc @@ -35,6 +35,7 @@ PD_DECLARE_KERNEL(tanh, CPU, ALL_LAYOUT); PD_DECLARE_KERNEL(tanh_grad, CPU, ALL_LAYOUT); PD_DECLARE_KERNEL(pow, CPU, ALL_LAYOUT); PD_DECLARE_KERNEL(scale, CPU, ALL_LAYOUT); +PD_DECLARE_KERNEL(add, CPU, ALL_LAYOUT); PD_DECLARE_KERNEL(multiply, CPU, ALL_LAYOUT); PD_DECLARE_KERNEL(concat, CPU, ALL_LAYOUT); #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) @@ -43,6 +44,7 @@ PD_DECLARE_KERNEL(tanh, GPU, ALL_LAYOUT); PD_DECLARE_KERNEL(tanh_grad, GPU, ALL_LAYOUT); PD_DECLARE_KERNEL(pow, GPU, ALL_LAYOUT); PD_DECLARE_KERNEL(scale, GPU, ALL_LAYOUT); +PD_DECLARE_KERNEL(add, KPS, ALL_LAYOUT); PD_DECLARE_KERNEL(multiply, KPS, ALL_LAYOUT); PD_DECLARE_KERNEL(concat, GPU, ALL_LAYOUT); #endif @@ -192,7 +194,7 @@ TEST(StaticPrim, TanhBackwardComposite) { target_block, grad_sub_block)); ASSERT_EQ(target_block->AllOps().size(), static_cast(1)); - ASSERT_EQ(grad_ops.size(), static_cast(3)); + ASSERT_EQ(grad_ops.size(), static_cast(6)); ASSERT_EQ(target_block->AllOps()[0]->Type(), "tanh"); ASSERT_EQ(target_block->AllOps()[0]->Inputs().at("X").size(), static_cast(1)); @@ -210,14 +212,9 @@ TEST(StaticPrim, TanhBackwardComposite) { ASSERT_EQ(grad_ops[0]->Outputs().at("Out").size(), static_cast(1)); - ASSERT_EQ(grad_ops[1]->Type(), "scale"); - ASSERT_EQ(grad_ops[1]->Inputs().at("X").size(), static_cast(1)); - ASSERT_EQ(grad_ops[1]->Inputs().at("X")[0], - grad_ops[0]->Outputs().at("Out")[0]); - ASSERT_EQ(PADDLE_GET_CONST(float, grad_ops[1]->GetAttr("scale")), - static_cast(-1.0)); - ASSERT_EQ(PADDLE_GET_CONST(float, grad_ops[1]->GetAttr("bias")), - static_cast(1.0)); + ASSERT_EQ(grad_ops[1]->Type(), "fill_constant"); + ASSERT_EQ(PADDLE_GET_CONST(int, grad_ops[1]->GetAttr("dtype")), + static_cast(5)); // ProtoDataType::FP32 ASSERT_EQ(grad_ops[1]->Outputs().at("Out").size(), static_cast(1)); @@ -226,9 +223,31 @@ TEST(StaticPrim, TanhBackwardComposite) { ASSERT_EQ(grad_ops[2]->Inputs().at("Y").size(), static_cast(1)); ASSERT_EQ(grad_ops[2]->Inputs().at("Y")[0], grad_ops[1]->Outputs().at("Out")[0]); - ASSERT_EQ(grad_ops[2]->Inputs().at("X")[0], "b@GRAD"); ASSERT_EQ(grad_ops[2]->Outputs().at("Out").size(), static_cast(1)); + + ASSERT_EQ(grad_ops[3]->Type(), "fill_constant"); + ASSERT_EQ(PADDLE_GET_CONST(int, grad_ops[3]->GetAttr("dtype")), + static_cast(5)); // ProtoDataType::FP32 + ASSERT_EQ(grad_ops[3]->Outputs().at("Out").size(), + static_cast(1)); + + ASSERT_EQ(grad_ops[4]->Type(), "elementwise_add"); + ASSERT_EQ(grad_ops[4]->Inputs().at("X").size(), static_cast(1)); + ASSERT_EQ(grad_ops[4]->Inputs().at("Y").size(), static_cast(1)); + ASSERT_EQ(grad_ops[4]->Inputs().at("Y")[0], + grad_ops[3]->Outputs().at("Out")[0]); + ASSERT_EQ(grad_ops[4]->Outputs().at("Out").size(), + static_cast(1)); + + ASSERT_EQ(grad_ops[5]->Type(), "elementwise_mul"); + ASSERT_EQ(grad_ops[5]->Inputs().at("X").size(), static_cast(1)); + ASSERT_EQ(grad_ops[5]->Inputs().at("Y").size(), static_cast(1)); + ASSERT_EQ(grad_ops[5]->Inputs().at("Y")[0], + grad_ops[4]->Outputs().at("Out")[0]); + ASSERT_EQ(grad_ops[5]->Inputs().at("X")[0], "b@GRAD"); + ASSERT_EQ(grad_ops[5]->Outputs().at("Out").size(), + static_cast(1)); } TEST(StaticCompositeGradMaker, TestMutiInputMethod) { @@ -368,8 +387,10 @@ TEST(StaticPrim, TestFlags) { } // namespace prim } // namespace paddle +USE_OP_ITSELF(fill_constant); USE_OP_ITSELF(tanh); USE_OP_ITSELF(tanh_grad); USE_OP_ITSELF(pow); USE_OP_ITSELF(elementwise_mul); +USE_OP_ITSELF(elementwise_add); USE_OP_ITSELF(scale); diff --git a/paddle/phi/api/include/tensor.h b/paddle/phi/api/include/tensor.h index c10218b8f1541..da094a336e7f2 100644 --- a/paddle/phi/api/include/tensor.h +++ b/paddle/phi/api/include/tensor.h @@ -548,6 +548,14 @@ class PADDLE_API Tensor final { Tensor operator/(const Tensor& other) const; + Tensor operator+(const Scalar& other) const; + + Tensor operator-(const Scalar& other) const; + + Tensor operator*(const Scalar& other) const; + + Tensor operator/(const Scalar& other) const; + /* Part 8: Autograd methods */ /** @@ -663,6 +671,11 @@ class PADDLE_API Tensor final { Tensor divide(const Tensor& y) const; Tensor multiply(const Tensor& y) const; Tensor subtract(const Tensor& y) const; + Tensor add(const Scalar& y) const; + Tensor divide(const Scalar& y) const; + Tensor multiply(const Scalar& y) const; + Tensor subtract(const Scalar& y) const; + Tensor exp() const; Tensor floor() const; Tensor gather_nd(const Tensor& index) const; diff --git a/paddle/phi/api/yaml/generator/tensor_operants_gen.py b/paddle/phi/api/yaml/generator/tensor_operants_gen.py index 45ac6ee926324..50e679bcc76da 100644 --- a/paddle/phi/api/yaml/generator/tensor_operants_gen.py +++ b/paddle/phi/api/yaml/generator/tensor_operants_gen.py @@ -52,6 +52,14 @@ class TensorOperantsBase { public: virtual ~TensorOperantsBase() = default; + + virtual Tensor add(const Tensor& x, const Scalar& y) = 0; + + virtual Tensor divide(const Tensor& x, const Scalar& y) = 0; + + virtual Tensor multiply(const Tensor& x, const Scalar& y) = 0; + + virtual Tensor subtract(const Tensor& x, const Scalar& y) = 0; """ @@ -90,6 +98,38 @@ class TensorOperantsBase { Tensor Tensor::operator/(const Tensor &other) const { return divide(other); } + +Tensor Tensor::operator+(const Scalar &other) const { + return add(other); +} + +Tensor Tensor::operator-(const Scalar &other) const { + return subtract(other); +} + +Tensor Tensor::operator*(const Scalar &other) const { + return multiply(other); +} + +Tensor Tensor::operator/(const Scalar &other) const { + return divide(other); +} + +Tensor Tensor::add(const Scalar& y) const { + return paddle::OperantsManager::Instance().add(static_cast(*this), y); +} + +Tensor Tensor::divide(const Scalar& y) const { + return paddle::OperantsManager::Instance().divide(static_cast(*this), y); +} + +Tensor Tensor::multiply(const Scalar& y) const { + return paddle::OperantsManager::Instance().multiply(static_cast(*this), y); +} + +Tensor Tensor::subtract(const Scalar& y) const { + return paddle::OperantsManager::Instance().subtract(static_cast(*this), y); +} """ @@ -126,6 +166,15 @@ class PhiTensorOperants : public TensorOperantsBase { public: PhiTensorOperants() = default; + + Tensor add(const Tensor& x, const Scalar& y); + + Tensor subtract(const Tensor& x, const Scalar& y); + + Tensor multiply(const Tensor& x, const Scalar& y); + + Tensor divide(const Tensor& x, const Scalar& y); + """ @@ -150,6 +199,22 @@ class PhiTensorOperants : public TensorOperantsBase { namespace paddle { namespace operants { + +Tensor PhiTensorOperants::add(const Tensor& x, const Scalar& y) { + return paddle::experimental::add(x, paddle::experimental::full_like(x, y)); +} + +Tensor PhiTensorOperants::subtract(const Tensor& x, const Scalar& y) { + return paddle::experimental::subtract(x, paddle::experimental::full_like(x, y)); +} + +Tensor PhiTensorOperants::multiply(const Tensor& x, const Scalar& y) { + return paddle::experimental::multiply(x, paddle::experimental::full_like(x, y)); +} + +Tensor PhiTensorOperants::divide(const Tensor& x, const Scalar& y) { + return paddle::experimental::divide(x, paddle::experimental::full_like(x, y)); +} """ @@ -225,6 +290,15 @@ class OperantsManager { public: static OperantsManager& Instance(); + + Tensor add(const Tensor& x, const Scalar& y); + + Tensor subtract(const Tensor& x, const Scalar& y); + + Tensor multiply(const Tensor& x, const Scalar& y); + + Tensor divide(const Tensor& x, const Scalar& y); + """ @@ -395,17 +469,28 @@ def gene_operants_manager_code(self): def gene_operants_manager_implementation(self): func_name = self.get_api_func_name() + final_code = "" + if func_name in ["add", "subtract", "multiply", "divide"]: + final_code += f""" +{self.get_return_type()} OperantsManager::{func_name}(const Tensor& x, const Scalar& y) {{{self.gene_operants_manager_code()}}} +""" # func decalaration if func_name[-1] != '_': - return f""" + return ( + final_code + + f""" {self.get_return_type()} OperantsManager::{func_name}({self.get_define_args()}) {{{self.gene_operants_manager_code()}}} """ + ) else: - return f""" + return ( + final_code + + f""" {self.get_return_type(inplace_flag=True)} OperantsManager::{func_name}({self.get_define_args(inplace_flag=True)}) {{ {self.gene_operants_manager_code()} }} """ + ) def generate_tensor_operants_api( diff --git a/python/paddle/fluid/tests/custom_op/custom_tensor_operator.cc b/python/paddle/fluid/tests/custom_op/custom_tensor_operator.cc index e36fc3faca5a2..f46d0ec8954b2 100644 --- a/python/paddle/fluid/tests/custom_op/custom_tensor_operator.cc +++ b/python/paddle/fluid/tests/custom_op/custom_tensor_operator.cc @@ -49,6 +49,36 @@ PD_BUILD_GRAD_OP(custom_add) .Outputs({paddle::Grad("X")}) .SetKernelFn(PD_KERNEL(AddBackward)); +// y = x + 1 +std::vector ScalarAddForward(const paddle::Tensor& x) { + if (x.is_cpu() || x.is_gpu()) { + return {x + 1}; + } else { + PD_THROW("Not implemented."); + } +} + +// dy / dx = 1 * grad_out +std::vector ScalarAddBackward(const paddle::Tensor& x, + const paddle::Tensor& out, + const paddle::Tensor& grad_out) { + if (x.is_cpu() || x.is_gpu()) { + return {grad_out * 1}; + } else { + PD_THROW("Not implemented."); + } +} + +PD_BUILD_OP(custom_scalar_add) + .Inputs({"X"}) + .Outputs({"Out"}) + .SetKernelFn(PD_KERNEL(ScalarAddForward)); + +PD_BUILD_GRAD_OP(custom_scalar_add) + .Inputs({"X", "Out", paddle::Grad("Out")}) + .Outputs({paddle::Grad("X")}) + .SetKernelFn(PD_KERNEL(ScalarAddBackward)); + // y = x - 1 std::vector SubtractForward(const paddle::Tensor& x) { if (x.is_cpu() || x.is_gpu()) { @@ -80,6 +110,37 @@ PD_BUILD_GRAD_OP(custom_subtract) .Outputs({paddle::Grad("X")}) .SetKernelFn(PD_KERNEL(SubtractBackward)); +// y = x - 1 +std::vector ScalarSubtractForward(const paddle::Tensor& x) { + if (x.is_cpu() || x.is_gpu()) { + return {x - 1}; + } else { + PD_THROW("Not implemented."); + } +} + +// dy / dx = 1 * grad_out +std::vector ScalarSubtractBackward( + const paddle::Tensor& x, + const paddle::Tensor& out, + const paddle::Tensor& grad_out) { + if (x.is_cpu() || x.is_gpu()) { + return {grad_out * 1}; + } else { + PD_THROW("Not implemented."); + } +} + +PD_BUILD_OP(custom_scalar_subtract) + .Inputs({"X"}) + .Outputs({"Out"}) + .SetKernelFn(PD_KERNEL(ScalarSubtractForward)); + +PD_BUILD_GRAD_OP(custom_scalar_subtract) + .Inputs({"X", "Out", paddle::Grad("Out")}) + .Outputs({paddle::Grad("X")}) + .SetKernelFn(PD_KERNEL(ScalarSubtractBackward)); + // y = x * 5 std::vector MultiplyForward(const paddle::Tensor& x) { if (x.is_cpu() || x.is_gpu()) { @@ -114,6 +175,37 @@ PD_BUILD_GRAD_OP(custom_multiply) .Outputs({paddle::Grad("X")}) .SetKernelFn(PD_KERNEL(MultiplyBackward)); +// y = x * 5 +std::vector ScalarMultiplyForward(const paddle::Tensor& x) { + if (x.is_cpu() || x.is_gpu()) { + return {x * 5}; + } else { + PD_THROW("Not implemented."); + } +} + +// dy / dx = grad_out * 5 +std::vector ScalarMultiplyBackward( + const paddle::Tensor& x, + const paddle::Tensor& out, + const paddle::Tensor& grad_out) { + if (x.is_cpu() || x.is_gpu()) { + return {grad_out * 5}; + } else { + PD_THROW("Not implemented."); + } +} + +PD_BUILD_OP(custom_scalar_multiply) + .Inputs({"X"}) + .Outputs({"Out"}) + .SetKernelFn(PD_KERNEL(ScalarMultiplyForward)); + +PD_BUILD_GRAD_OP(custom_scalar_multiply) + .Inputs({"X", "Out", paddle::Grad("Out")}) + .Outputs({paddle::Grad("X")}) + .SetKernelFn(PD_KERNEL(ScalarMultiplyBackward)); + // y = 1 / x std::vector DivideForward(const paddle::Tensor& x) { if (x.is_cpu() || x.is_gpu()) { @@ -145,3 +237,36 @@ PD_BUILD_GRAD_OP(custom_divide) .Inputs({"X", "Out", paddle::Grad("Out")}) .Outputs({paddle::Grad("X")}) .SetKernelFn(PD_KERNEL(DivideBackward)); + +// y = 1 / x / 1 +std::vector ScalarDivideForward(const paddle::Tensor& x) { + if (x.is_cpu() || x.is_gpu()) { + paddle::Tensor ones = paddle::full(x.shape(), 1.0, x.dtype(), x.place()); + return {ones / x / 1}; + } else { + PD_THROW("Not implemented."); + } +} + +// dy / dx = - (1 / x / x) * grad_out +std::vector ScalarDivideBackward( + const paddle::Tensor& x, + const paddle::Tensor& out, + const paddle::Tensor& grad_out) { + if (x.is_cpu() || x.is_gpu()) { + paddle::Tensor zeros = paddle::full(x.shape(), 0.0, x.dtype(), x.place()); + return {zeros - grad_out / (x * x)}; + } else { + PD_THROW("Not implemented."); + } +} + +PD_BUILD_OP(custom_scalar_divide) + .Inputs({"X"}) + .Outputs({"Out"}) + .SetKernelFn(PD_KERNEL(ScalarDivideForward)); + +PD_BUILD_GRAD_OP(custom_scalar_divide) + .Inputs({"X", "Out", paddle::Grad("Out")}) + .Outputs({paddle::Grad("X")}) + .SetKernelFn(PD_KERNEL(ScalarDivideBackward)); diff --git a/python/paddle/fluid/tests/custom_op/test_custom_tensor_operator.py b/python/paddle/fluid/tests/custom_op/test_custom_tensor_operator.py index 7ea1ae2eacc23..59f047e0e1a18 100644 --- a/python/paddle/fluid/tests/custom_op/test_custom_tensor_operator.py +++ b/python/paddle/fluid/tests/custom_op/test_custom_tensor_operator.py @@ -228,6 +228,16 @@ def setUp(self): self.dtypes.append('float16') def test_all(self): + self.add = self.custom_module.custom_add + self.subtract = self.custom_module.custom_subtract + self.multiply = self.custom_module.custom_multiply + self.divide = self.custom_module.custom_divide + self._test_static() + self._test_dynamic() + self.add = self.custom_module.custom_scalar_add + self.subtract = self.custom_module.custom_scalar_subtract + self.multiply = self.custom_module.custom_scalar_multiply + self.divide = self.custom_module.custom_scalar_divide self._test_static() self._test_dynamic() @@ -238,35 +248,31 @@ def _test_static(self): continue x = np.random.uniform(-1, 1, [4, 8]).astype(dtype) - out = test_custom_add_static( - self.custom_module.custom_add, device, dtype, x - ) + out = test_custom_add_static(self.add, device, dtype, x) pd_out = test_custom_add_static( - self.custom_module.custom_add, device, dtype, x, False + self.add, device, dtype, x, False ) np.testing.assert_allclose(out, pd_out, rtol=1e-5, atol=1e-8) out = test_custom_subtract_static( - self.custom_module.custom_subtract, device, dtype, x + self.subtract, device, dtype, x ) pd_out = test_custom_subtract_static( - self.custom_module.custom_subtract, device, dtype, x, False + self.subtract, device, dtype, x, False ) np.testing.assert_allclose(out, pd_out, rtol=1e-5, atol=1e-8) out = test_custom_multiply_static( - self.custom_module.custom_multiply, device, dtype, x + self.multiply, device, dtype, x ) pd_out = test_custom_multiply_static( - self.custom_module.custom_multiply, device, dtype, x, False + self.multiply, device, dtype, x, False ) np.testing.assert_allclose(out, pd_out, rtol=1e-5, atol=1e-8) - out = test_custom_divide_static( - self.custom_module.custom_divide, device, dtype, x - ) + out = test_custom_divide_static(self.divide, device, dtype, x) pd_out = test_custom_divide_static( - self.custom_module.custom_divide, device, dtype, x, False + self.divide, device, dtype, x, False ) np.testing.assert_allclose(out, pd_out, rtol=1e-5, atol=1e-8) @@ -278,10 +284,10 @@ def _test_dynamic(self): x = np.random.uniform(-1, 1, [4, 8]).astype(dtype) out, x_grad = test_custom_add_dynamic( - self.custom_module.custom_add, device, dtype, x + self.add, device, dtype, x ) pd_out, pd_x_grad = test_custom_add_dynamic( - self.custom_module.custom_add, device, dtype, x, False + self.add, device, dtype, x, False ) np.testing.assert_allclose(out, pd_out, rtol=1e-5, atol=1e-8) np.testing.assert_allclose( @@ -289,10 +295,10 @@ def _test_dynamic(self): ) out, x_grad = test_custom_subtract_dynamic( - self.custom_module.custom_subtract, device, dtype, x + self.subtract, device, dtype, x ) pd_out, pd_x_grad = test_custom_subtract_dynamic( - self.custom_module.custom_subtract, device, dtype, x, False + self.subtract, device, dtype, x, False ) np.testing.assert_allclose(out, pd_out, rtol=1e-5, atol=1e-8) np.testing.assert_allclose( @@ -300,10 +306,10 @@ def _test_dynamic(self): ) out, x_grad = test_custom_multiply_dynamic( - self.custom_module.custom_multiply, device, dtype, x + self.multiply, device, dtype, x ) pd_out, pd_x_grad = test_custom_multiply_dynamic( - self.custom_module.custom_multiply, device, dtype, x, False + self.multiply, device, dtype, x, False ) np.testing.assert_allclose(out, pd_out, rtol=1e-5, atol=1e-8) np.testing.assert_allclose( @@ -311,10 +317,10 @@ def _test_dynamic(self): ) out, x_grad = test_custom_divide_dynamic( - self.custom_module.custom_divide, device, dtype, x + self.divide, device, dtype, x ) pd_out, pd_x_grad = test_custom_divide_dynamic( - self.custom_module.custom_divide, device, dtype, x, False + self.divide, device, dtype, x, False ) np.testing.assert_allclose(out, pd_out, rtol=1e-5, atol=1e-8) diff --git a/python/paddle/fluid/tests/unittests/prim/test_comp_get_grad_op_desc_prim_enabled.py b/python/paddle/fluid/tests/unittests/prim/test_comp_get_grad_op_desc_prim_enabled.py index c576be20388fb..a912d4a445fb8 100644 --- a/python/paddle/fluid/tests/unittests/prim/test_comp_get_grad_op_desc_prim_enabled.py +++ b/python/paddle/fluid/tests/unittests/prim/test_comp_get_grad_op_desc_prim_enabled.py @@ -41,7 +41,14 @@ {'Out': ['y']}, set(), tuple(), - ('pow', 'scale', 'elementwise_mul'), + ( + 'pow', + 'fill_constant', + 'elementwise_mul', + 'fill_constant', + 'elementwise_add', + 'elementwise_mul', + ), ), ('empty', {}, {'Out': ['y']}, set(), tuple(), tuple()), ), diff --git a/python/paddle/fluid/tests/unittests/prim/test_comp_skip_op_set.py b/python/paddle/fluid/tests/unittests/prim/test_comp_skip_op_set.py index 15648226e7859..a2c65411053d3 100644 --- a/python/paddle/fluid/tests/unittests/prim/test_comp_skip_op_set.py +++ b/python/paddle/fluid/tests/unittests/prim/test_comp_skip_op_set.py @@ -27,7 +27,14 @@ def setUp(self): self.no_grad_var = set() self.grad_sub_block = tuple() self.desired_ops = 'tanh_grad' - self.desired_ops_no_skip = ('pow', 'scale', 'elementwise_mul') + self.desired_ops_no_skip = ( + 'pow', + 'fill_constant', + 'elementwise_mul', + 'fill_constant', + 'elementwise_add', + 'elementwise_mul', + ) paddle.enable_static() block = framework.Block(framework.Program(), 0) block.append_op(