diff --git a/paddle/fluid/operators/transpose_op.cc b/paddle/fluid/operators/transpose_op.cc index 671997adda863aeace14ddf96705ef3f788c326f..356d077339dd4fe0c65e6760962132c61934d3bf 100644 --- a/paddle/fluid/operators/transpose_op.cc +++ b/paddle/fluid/operators/transpose_op.cc @@ -38,8 +38,8 @@ class TransposeOp : public framework::OperatorWithKernel { auto x_dims = ctx->GetInputDim("X"); std::vector axis = ctx->Attrs().Get>("axis"); - size_t x_rank = x_dims.size(); - size_t axis_size = axis.size(); + int x_rank = x_dims.size(); + int axis_size = axis.size(); // Note: x_rank > axis_size when fuse squeeze2 + transpose2, else x_rank == // axis_size @@ -53,31 +53,38 @@ class TransposeOp : public framework::OperatorWithKernel { x_rank, axis_size)); + std::vector formated_axis = axis; std::vector count(axis_size, 0); - for (size_t i = 0; i < axis_size; i++) { + for (int i = 0; i < axis_size; i++) { + PADDLE_ENFORCE_LT(axis[i], + axis_size, + platform::errors::InvalidArgument( + "The reduce dim index %d should be in the " + "range [ -dimension(X), dimension(X) ) " + "which dimesion = %d. But received dim index = %d.", + i, + axis_size, + axis[i])); PADDLE_ENFORCE_GE(axis[i], - 0, + -axis_size, + platform::errors::InvalidArgument( + "The reduce dim index %d should be in the " + "range [ -dimension(X), dimension(X) ) " + "which dimesion = %d. But received dim index = %d.", + i, + axis_size, + axis[i])); + + if (axis[i] < 0) { + formated_axis[i] = axis[i] + axis_size; + } + PADDLE_ENFORCE_EQ(++count[formated_axis[i]], + 1, platform::errors::InvalidArgument( - "The axis should be greater than or equal to 0." - "But received %d of axis[%d]", - axis[i], - i)); - - PADDLE_ENFORCE_EQ( - axis[i] < static_cast(axis_size) && ++count[axis[i]] == 1, - true, - platform::errors::InvalidArgument( - "Each element of Attribute axis should " - "be a unique value range from 0 to (dims - 1), " - "where the dims is the axis's size, " - "unique value means this axis value can appear only once. " - "But received axis[%d] is %d, axis_size is %d, " - "count[axis[%d]] is %d", - i, - axis[i], - axis_size, - i, - count[axis[i]])); + "Each element of axis should be unique. but " + "axis[%d] is %d appear not only once", + i, + axis[i])); } framework::DDim out_dims(x_dims); @@ -94,8 +101,8 @@ class TransposeOp : public framework::OperatorWithKernel { << "Rotating Shape in Transpose from: kMKLDNN to: kNHWC output_shape"; } #endif - for (size_t i = 0; i < axis_size; i++) { - out_dims[i] = x_dims[axis[i]]; + for (int i = 0; i < axis_size; i++) { + out_dims[i] = x_dims[formated_axis[i]]; } ctx->SetOutputDim("Out", out_dims); } diff --git a/paddle/phi/infermeta/unary.cc b/paddle/phi/infermeta/unary.cc index 773c158d380741a78db963dae19e3d722843241f..0f001ff023e9e60859da5344eed53cfb487f6407 100644 --- a/paddle/phi/infermeta/unary.cc +++ b/paddle/phi/infermeta/unary.cc @@ -1658,25 +1658,17 @@ static phi::DDim ValidateShape(const std::vector shape, phi::make_ddim(shape), i)); unk_dim_idx = i; + output_shape[i] = shape[i]; } else if (shape[i] == 0) { - // for 0-Size Tensor, 0 is 0 - // for not 0-Size Tensor, 0 represent copy origin shape - if (in_size > 0) { - PADDLE_ENFORCE_LT( - static_cast(i), - in_dims.size(), - phi::errors::InvalidArgument( - "The index of 0 in `shape` must be less than " - "the input tensor X's dimensions. " - "But received shape = [%s], shape[%d] = 0, X's shape = [%s], " - "X's dimensions = %d.", - phi::make_ddim(shape), - i, - in_dims, - in_dims.size())); + if (static_cast(i) < in_dims.size()) { output_shape[i] = in_dims[i]; } else { - output_shape[i] = shape[i]; + PADDLE_ENFORCE_EQ( + in_size, + 0, + phi::errors::InvalidArgument("If The index of 0 in `shape` >= " + "the input tensor X's dimensions, " + "It can only be Zero-Sized Tensor")); } capacity *= output_shape[i]; } else { @@ -4233,8 +4225,8 @@ void TransposeInferMeta(const MetaTensor& x, const std::vector& axis, MetaTensor* out) { auto x_dims = x.dims(); - size_t x_rank = x_dims.size(); - size_t axis_size = axis.size(); + int x_rank = x_dims.size(); + int axis_size = axis.size(); PADDLE_ENFORCE_EQ( x_rank, @@ -4246,36 +4238,43 @@ void TransposeInferMeta(const MetaTensor& x, x_rank, axis_size)); + std::vector formated_axis = axis; std::vector count(axis_size, 0); - for (size_t i = 0; i < axis_size; i++) { - PADDLE_ENFORCE_GE( - axis[i], - 0, - errors::InvalidArgument("The axis should be greater than or equal to 0." - "But received %d of axis[%d]", - axis[i], - i)); + for (int i = 0; i < axis_size; i++) { + PADDLE_ENFORCE_LT(axis[i], + x_rank, + errors::InvalidArgument( + "The reduce dim index %d should be in the " + "range [ -dimension(X), dimension(X) ) " + "which dimesion = %d. But received dim index = %d.", + i, + x_rank, + axis[i])); + PADDLE_ENFORCE_GE(axis[i], + -x_rank, + errors::InvalidArgument( + "The reduce dim index %d should be in the " + "range [ -dimension(X), dimension(X) ) " + "which dimesion = %d. But received dim index = %d.", + i, + x_rank, + axis[i])); + if (axis[i] < 0) { + formated_axis[i] = axis[i] + x_rank; + } PADDLE_ENFORCE_EQ( - axis[i] < static_cast(axis_size) && ++count[axis[i]] == 1, - true, - errors::InvalidArgument( - "Each element of Attribute axis should " - "be a unique value range from 0 to (dims - 1), " - "where the dims is the axis's size, " - "unique value means this axis value can appear only once. " - "But received axis[%d] is %d, axis_size is %d, " - "count[axis[%d]] is %d", - i, - axis[i], - axis_size, - i, - count[axis[i]])); + ++count[formated_axis[i]], + 1, + errors::InvalidArgument("Each element of axis should be unique. but " + "axis[%d] is %d appear not only once", + i, + axis[i])); } phi::DDim out_dims(x_dims); - for (size_t i = 0; i < axis_size; ++i) { - out_dims[i] = x_dims[axis[i]]; + for (int i = 0; i < axis_size; ++i) { + out_dims[i] = x_dims[formated_axis[i]]; } out->set_dims(out_dims); @@ -4285,9 +4284,17 @@ void TransposeInferMeta(const MetaTensor& x, void TransposeGradInferMeta(const MetaTensor& x, const std::vector& axis, MetaTensor* out) { - std::vector reversed_axis(axis); + size_t x_rank = x.dims().size(); + std::vector formated_axis = axis; for (size_t i = 0; i < axis.size(); i++) { - reversed_axis[axis[i]] = i; + if (axis[i] < 0) { + formated_axis[i] = axis[i] + x_rank; + } + } + + std::vector reversed_axis(axis); + for (size_t i = 0; i < formated_axis.size(); i++) { + reversed_axis[formated_axis[i]] = i; } TransposeInferMeta(x, reversed_axis, out); diff --git a/paddle/phi/kernels/cpu/transpose_kernel.cc b/paddle/phi/kernels/cpu/transpose_kernel.cc index 583df78cc25f38d54994eaebfaadb68ef2429b0f..62d7513d6a458b2c9879c4dda9c7773f3cfefe7d 100644 --- a/paddle/phi/kernels/cpu/transpose_kernel.cc +++ b/paddle/phi/kernels/cpu/transpose_kernel.cc @@ -20,7 +20,6 @@ #include "paddle/phi/common/bfloat16.h" #include "paddle/phi/core/kernel_registry.h" #include "paddle/phi/kernels/funcs/math_function.h" -#include "paddle/phi/kernels/impl/transpose_grad_kernel_impl.h" namespace phi { @@ -29,45 +28,54 @@ void TransposeKernel(const Context& ctx, const DenseTensor& x, const std::vector& axis, DenseTensor* out) { + size_t x_rank = x.dims().size(); + std::vector formated_axis = axis; + for (size_t i = 0; i < axis.size(); i++) { + if (axis[i] < 0) { + formated_axis[i] = axis[i] + x_rank; + } + } + ctx.template Alloc(out); if (out->numel() == 0) { return; } - int rank = axis.size(); + int rank = formated_axis.size(); switch (rank) { case 0: phi::Copy(ctx, x, ctx.GetPlace(), false, out); break; case 1: funcs::Transpose trans1; - trans1(ctx, x, out, axis); + trans1(ctx, x, out, formated_axis); break; case 2: funcs::Transpose trans2; - trans2(ctx, x, out, axis); + trans2(ctx, x, out, formated_axis); break; case 3: funcs::Transpose trans3; - trans3(ctx, x, out, axis); + trans3(ctx, x, out, formated_axis); break; case 4: funcs::Transpose trans4; - trans4(ctx, x, out, axis); + trans4(ctx, x, out, formated_axis); break; case 5: funcs::Transpose trans5; - trans5(ctx, x, out, axis); + trans5(ctx, x, out, formated_axis); break; case 6: funcs::Transpose trans6; - trans6(ctx, x, out, axis); + trans6(ctx, x, out, formated_axis); break; default: // for rank >= 7 situation funcs::TransposeNormal trans_normal; - trans_normal(ctx, x, out, axis); + trans_normal(ctx, x, out, formated_axis); } } + } // namespace phi PD_REGISTER_KERNEL(transpose, diff --git a/paddle/phi/kernels/gpu/transpose_kernel.cu b/paddle/phi/kernels/gpu/transpose_kernel.cu index 8ae9c6ed3dbd423ed2226ea2205aa3b789549b8e..a6df2419efd81b5834f321cc3123f2366bed1094 100644 --- a/paddle/phi/kernels/gpu/transpose_kernel.cu +++ b/paddle/phi/kernels/gpu/transpose_kernel.cu @@ -30,15 +30,23 @@ void TransposeKernel(const Context& ctx, const DenseTensor& x, const std::vector& axis, DenseTensor* out) { + size_t x_rank = x.dims().size(); + std::vector formated_axis = axis; + for (size_t i = 0; i < axis.size(); i++) { + if (axis[i] < 0) { + formated_axis[i] = axis[i] + x_rank; + } + } + ctx.template Alloc(out); if (out->numel() == 0) { return; } - if (axis.size() == 0) { + if (formated_axis.size() == 0) { phi::Copy(ctx, x, ctx.GetPlace(), false, out); return; } - phi::funcs::TransposeGPUKernelDriver(ctx, x, axis, out); + phi::funcs::TransposeGPUKernelDriver(ctx, x, formated_axis, out); } } // namespace phi diff --git a/paddle/phi/kernels/impl/transpose_grad_kernel_impl.h b/paddle/phi/kernels/impl/transpose_grad_kernel_impl.h index 6bb555fe28f1123065c01505cd6d11435ac09a7c..71f35fa1fdf0e697427b47a9773d968d206c9617 100644 --- a/paddle/phi/kernels/impl/transpose_grad_kernel_impl.h +++ b/paddle/phi/kernels/impl/transpose_grad_kernel_impl.h @@ -25,11 +25,18 @@ void TransposeGradKernel(const Context& dev_ctx, const DenseTensor& out_grad, const std::vector& axis, DenseTensor* x_grad) { - std::vector reversed_axis(axis); + size_t axis_size = axis.size(); + std::vector formated_axis = axis; + for (size_t i = 0; i < axis_size; i++) { + if (axis[i] < 0) { + formated_axis[i] = axis[i] + axis_size; + } + } + std::vector reversed_axis(axis); dev_ctx.template Alloc(x_grad); - for (size_t i = 0; i < axis.size(); i++) { - reversed_axis[axis[i]] = i; + for (size_t i = 0; i < axis_size; i++) { + reversed_axis[formated_axis[i]] = i; } TransposeKernel(dev_ctx, out_grad, reversed_axis, x_grad); diff --git a/paddle/phi/kernels/xpu/transpose_grad_kernel.cc b/paddle/phi/kernels/xpu/transpose_grad_kernel.cc index cd597ee8411db9445971f7e530186bab52d89241..043d2c8e3df5ad1bace143c3459a58cf8222aef4 100644 --- a/paddle/phi/kernels/xpu/transpose_grad_kernel.cc +++ b/paddle/phi/kernels/xpu/transpose_grad_kernel.cc @@ -29,25 +29,31 @@ void TransposeGradKernel(const Context& dev_ctx, if (x_grad->numel() == 0) { return; } - if (axis.size() == 0) { + + size_t axis_size = axis.size(); + if (axis_size == 0) { phi::Copy(dev_ctx, out_grad, dev_ctx.GetPlace(), false, x_grad); return; } - std::vector reversed_axis(axis); - for (size_t i = 0; i < axis.size(); i++) { - reversed_axis[axis[i]] = i; + std::vector formated_axis = axis; + for (size_t i = 0; i < axis_size; i++) { + if (axis[i] < 0) { + formated_axis[i] = axis[i] + axis_size; + } } - int ndims = axis.size(); - std::vector out_shape_host(ndims, 0); - for (int i = 0; i < ndims; ++i) { - out_shape_host[i] = out_grad.dims()[i]; + + std::vector reversed_axis(axis); + for (size_t i = 0; i < axis_size; i++) { + reversed_axis[formated_axis[i]] = i; } + + std::vector out_grad_dim_vec = phi::vectorize(out_grad.dims()); int r = xpu::transpose( dev_ctx.x_context(), reinterpret_cast(out_grad.data()), reinterpret_cast(x_grad->data()), - out_shape_host, + out_grad_dim_vec, reversed_axis); PADDLE_ENFORCE_XDNN_SUCCESS(r, "transpose_grad"); } diff --git a/paddle/phi/kernels/xpu/transpose_kernel.cc b/paddle/phi/kernels/xpu/transpose_kernel.cc index 0f2d2fb8259fbc5e15a144cbfaaf34168e9c2a47..398a2281dcea8bf2c2c766efebdb7c2c37e829e2 100644 --- a/paddle/phi/kernels/xpu/transpose_kernel.cc +++ b/paddle/phi/kernels/xpu/transpose_kernel.cc @@ -24,26 +24,31 @@ void TransposeKernel(const Context& dev_ctx, const DenseTensor& x, const std::vector& axis, DenseTensor* out) { + size_t x_rank = x.dims().size(); + std::vector formated_axis = axis; + for (size_t i = 0; i < axis.size(); i++) { + if (axis[i] < 0) { + formated_axis[i] = axis[i] + x_rank; + } + } + using XPUType = typename XPUTypeTrait::Type; dev_ctx.template Alloc(out); if (out->numel() == 0) { return; } - if (axis.size() == 0) { + if (formated_axis.size() == 0) { phi::Copy(dev_ctx, x, dev_ctx.GetPlace(), false, out); return; } - int ndims = axis.size(); - std::vector x_shape_host(ndims, 0); - for (int i = 0; i < ndims; ++i) { - x_shape_host[i] = x.dims()[i]; - } + + std::vector x_dim_vec = phi::vectorize(x.dims()); int r = xpu::transpose(dev_ctx.x_context(), reinterpret_cast(x.data()), reinterpret_cast(out->data()), - x_shape_host, - axis); + x_dim_vec, + formated_axis); PADDLE_ENFORCE_XDNN_SUCCESS(r, "transpose"); } diff --git a/python/paddle/fluid/tests/unittests/test_transpose_op.py b/python/paddle/fluid/tests/unittests/test_transpose_op.py index 75d701f30c2cb61ef05206ce1651b5b398c1a1fc..4ec40ea9eb87e9d345d6617b00f0b768e3815d38 100644 --- a/python/paddle/fluid/tests/unittests/test_transpose_op.py +++ b/python/paddle/fluid/tests/unittests/test_transpose_op.py @@ -117,6 +117,12 @@ class TestCase9(TestTransposeOp): self.axis = (6, 1, 3, 5, 0, 2, 4, 7) +class TestCase10(TestTransposeOp): + def initTestCase(self): + self.shape = (10, 8, 2) + self.axis = (-1, 1, -3) + + class TestCase_ZeroDim(TestTransposeOp): def initTestCase(self): self.shape = () diff --git a/python/paddle/fluid/tests/unittests/xpu/test_transpose_op_xpu.py b/python/paddle/fluid/tests/unittests/xpu/test_transpose_op_xpu.py index 12507d206a43da348aaf005321b9f49bc5c998f5..7907b03d909972619caed0fc61f57a896dc63e2e 100644 --- a/python/paddle/fluid/tests/unittests/xpu/test_transpose_op_xpu.py +++ b/python/paddle/fluid/tests/unittests/xpu/test_transpose_op_xpu.py @@ -127,5 +127,11 @@ class TestCase9(TestXPUTransposeOp): self.axis = (6, 1, 3, 5, 0, 2, 4, 7) +class TestCase10(TestXPUTransposeOp): + def initTestCase(self): + self.shape = (2, 3, 2) + self.axis = (-1, 1, -3) + + if __name__ == "__main__": unittest.main()