From a6e64242d8f73f1a597f2a6634a98453cd07edf1 Mon Sep 17 00:00:00 2001 From: caoying03 Date: Mon, 19 Mar 2018 11:08:33 +0800 Subject: [PATCH] follow comments. --- paddle/fluid/operators/reshape_op.cc | 64 +++++++++++++++++-------- paddle/fluid/operators/reshape_op.h | 14 +++++- python/paddle/fluid/layers/detection.py | 4 +- python/paddle/fluid/layers/nn.py | 52 ++++++++++++-------- 4 files changed, 91 insertions(+), 43 deletions(-) diff --git a/paddle/fluid/operators/reshape_op.cc b/paddle/fluid/operators/reshape_op.cc index c0d08cc6903..489742b492f 100644 --- a/paddle/fluid/operators/reshape_op.cc +++ b/paddle/fluid/operators/reshape_op.cc @@ -44,22 +44,22 @@ class ReshapeOp : public framework::OperatorWithKernel { ctx->SetOutputDim("Out", x_dims); } else { ctx->SetOutputDim("Out", framework::make_ddim(output_shape)); - - // FIXME(caoying): When shape of the output tensor is determined during - // runtime, LoD information of X will not passed to the output. - if (shape[0] == x_dims[0]) { - // Only pass LoD when the first dimension of output and Input(X) - // are the same. - ctx->ShareLoD("X", /*->*/ "Out"); - } } + + // NOTE: Reshape op cannot reshape an input sequence batch into an output + // sequence batch that has a different number of time steps. + // Here output always shares the LoD information with input. But if + // Attr(shape) contains 0 or -1, the actual output shape can only be + // determined during runtime. The check for wheather it is a valid output + // sequence batch is performed in runtime. + ctx->ShareLoD("X", /*->*/ "Out"); } private: bool ValidateShape(const std::vector &shape, const framework::DDim &input_dim, std::vector &output_shape) const { - // only one dimension canbe set to -1, whose size will be automatically + // only one dimension can be set to -1, whose size will be automatically // infered. const int64_t unknown_index = -1; const auto in_size = framework::product(input_dim); @@ -82,7 +82,7 @@ class ReshapeOp : public framework::OperatorWithKernel { } PADDLE_ENFORCE_LE( neg_dims_idx.size(), 1, - "Only one input dimension of Attr(shape) may be unknown."); + "Only one input dimension of Attr(shape) can be unknown."); output_shape.resize(shape.size(), 0); std::transform(shape.begin(), shape.end(), output_shape.begin(), @@ -113,22 +113,46 @@ class ReshapeOpMaker : public framework::OpProtoAndCheckerMaker { AddAttr>( "shape", "(std::vector) Target shape of reshape operator."); AddAttr("inplace", - "Change the source tensor's shape without copy memory.") - .SetDefault(true); + "(default: false) Change the source tensor's shape without " + "memory copy. When Attr(inplace) is set true, the output " + "tensor shares memory with Input(X), otherwise, a new output " + "tensor is created, and its data are copied from Input(x).") + .SetDefault(false); AddComment(R"DOC( Reshape Operator. -Reshape Input(X) into the shape specified by Attr(shape). +Reshape Input(X) into the shape specified by Attr(shape). The data in Input(X) +are unchanged. + +Examples: + +1. Given a 3-D tensor Input(X) with a shape [2, 4, 6], and the target shape +specified by Attr(shape) is [6, 8], the reshape operator will transform Input(X) +into a 2-D tensor with shape [6, 8] and leaving Input(X)'s data unchanged. + +1. Given a 3-D tensor Input(X) with a shape [2, 4, 6], and the target shape +specified by Attr(shape) is [2, 3, -1, 2], the reshape operator will transform +Input(X) into a 4-D tensor with shape [2, 3, 4, 2] and leaving Input(X)'s data +unchanged. In this case, one and only dimension of Attr(shape) can be set to -1, +the value of this dimension is inferred from the total element number of +Input(X) and remaining dimensions. + +1. Given a 3-D tensor Input(X) with a shape [2, 4, 6], and the target shape +specified by Attr(shape) is [-1, 0, 3, 2], the reshape operator will transform +Input(X) into a 4-D tensor with shape [2, 4, 3, 2] and leaving Input(X)'s data +unchanged. In this case, besides -1, 0 means the actual dimension value is going +to be copied from the corresponding dimension of Input(X). -An example: -Given a 2-D tensor X with 2 rows and 2 columns : [[1, 2], [3, 4]] +Note: -and target shape = [1, 4], the reshape operator will transform -the tensor X into a 2-D tensor: [[1, 2, 3, 4]] +1. One and only one dimension in Attr(shape) can be set -1. In this case, +the actual dimension value will be infered from the total element number of +Input(X) and remaining dimensions. +1. More than one dimensions in Attr(shape) can be set to 0, which means the real +dimension value will be copied from Input(X) at runtime. Note that the index of +0 can not access Rank(X). For example, Input(X) is a 3-D tensor with shape +[2, 3, 4], Attr(shape) = [2, 3, 2, 0] is an invalid input. -One dimension in the target shape can be set -1, representing that its -size is unknown. In this case, the real dimension will be infered from -the original shape of Input(X) and other dimensions in the target shape. )DOC"); } }; diff --git a/paddle/fluid/operators/reshape_op.h b/paddle/fluid/operators/reshape_op.h index 9dbc5cec6b2..dd8eaf3e4fc 100644 --- a/paddle/fluid/operators/reshape_op.h +++ b/paddle/fluid/operators/reshape_op.h @@ -24,11 +24,21 @@ template class ReshapeKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& ctx) const { - auto* out = ctx.Output("Out"); - auto* in = ctx.Input("X"); + auto* out = ctx.Output("Out"); + auto* in = ctx.Input("X"); auto out_dims = ValidateShape(ctx.Attr>("shape"), in->dims()); + + if (!in->lod().empty()) { + PADDLE_ENFORCE_EQ( + out_dims[0], in->dims()[0], + "Reshape operator cannot reshape an input sequence batch " + "into an output sequence batch that has a different " + "number of time steps. Please consider using " + "sequence_reshape op."); + } + bool inplace = ctx.Attr("inplace"); if (!inplace) { out->mutable_data(ctx.GetPlace()); diff --git a/python/paddle/fluid/layers/detection.py b/python/paddle/fluid/layers/detection.py index 3ced35d6ced..ec4afa80676 100644 --- a/python/paddle/fluid/layers/detection.py +++ b/python/paddle/fluid/layers/detection.py @@ -130,9 +130,9 @@ def detection_output(loc, code_type='decode_center_size') old_shape = scores.shape - scores = ops.reshape(x=scores, shape=(-1, old_shape[-1])) + scores = nn.reshape(x=scores, shape=(-1, old_shape[-1])) scores = nn.softmax(input=scores) - scores = ops.reshape(x=scores, shape=old_shape) + scores = nn.reshape(x=scores, shape=old_shape) scores = nn.transpose(scores, perm=[0, 2, 1]) nmsed_outs = helper.create_tmp_variable(dtype=decoded_box.dtype) diff --git a/python/paddle/fluid/layers/nn.py b/python/paddle/fluid/layers/nn.py index 48d244f3f60..85693578e10 100644 --- a/python/paddle/fluid/layers/nn.py +++ b/python/paddle/fluid/layers/nn.py @@ -3299,13 +3299,35 @@ def autoincreased_step_counter(counter_name=None, begin=1, step=1): def reshape(x, shape, act=None, inplace=True, name=None): """ - Gives a new shape to Tensor without changing its data. - This layer takes a tensor as input and the attribute shape specifying the - new shape. The shape attribute must be specified. At most one dimension of - the new shape can be -1. In this case, the value is inferred from the size - of the tensor and the remaining dimensions. A dimension could also be 0, - in which case the actual dimension value is going to be copied from the - input tensor. + Gives a new shape to the input Tensor without changing its data. + + This layer takes a tensor and the attribute shape which specifies the + new shape as its inputs. The shape attribute must be given. It cannot be + empty. One and only one dimension of shape can be -1. More than one + dimension of shape can be 0. + + -1 means the value of this dimension is inferred from the total element + number of x and remaining dimensions. + + 0 means the actual dimension value is going to be copied from the + corresponding dimension of x. + + 1. Given a 3-D tensor x with a shape [2, 4, 6], and the target shape + specified by Attr(shape) is [6, 8], the reshape operator will transform x + into a 2-D tensor with shape [6, 8] and leaving x's data unchanged. + + 1. Given a 3-D tensor x with a shape [2, 4, 6], and the target shape + specified by Attr(shape) is [2, 3, -1, 2], the reshape operator will + transform x into a 4-D tensor with shape [2, 3, 4, 2] and leaving x's data + unchanged. In this case, one and only dimension of Attr(shape) can be set + to -1, the value of this dimension is inferred from the total element number + of x and remaining dimensions. + + 1. Given a 3-D tensor x with a shape [2, 4, 6], and the target shape + specified by Attr(shape) is [-1, 0, 3, 2], the reshape operator will + transform x into a 4-D tensor with shape [2, 4, 3, 2] and leaving x's data + unchanged. In this case, besides -1, 0 means the actual dimension value is + going to be copied from the corresponding dimension of x during runtime. Args: input(variable): The input tensor. @@ -3320,18 +3342,10 @@ def reshape(x, shape, act=None, inplace=True, name=None): Examples: .. code-block:: python - - Given a 2-D tensor X with shape [2 x 2], and the new shape: [1, 4]. - The reshape layer will change tensor X into a 2-D tensor with - shape [1 x 4] with its data unchanged. - - Given a 3-D tensor x with shape [2, 3, 4] and the new shape: [3, -1]. - The reshape layer will change tensor X into a 2-D tensor with shape: - [3 x 8] with its data unchanged. - - Given a 3-D tensor x with shape [2, 3, 8] and the new shape: - [-1, 0, 2, 2]. The reshape layer will change tensor X into a 4-D tensor - with shape [4, 3, 2, 2] with its data unchanged. + data = fluid.layers.data(name='data', shape=[2, 4, 6], dtype='float32') + reshaped = fluid.layers.reshape( + x=data, shape=[-1, 0, 3, 2], act='tanh', inplace=True + ) """ -- GitLab