sequence_lod.py 56.3 KB
Newer Older
1
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

15
import paddle
16
from .layer_function_generator import templatedoc
17 18 19 20 21 22 23 24
from ..framework import (
    core,
    Variable,
    _non_static_mode,
    in_dygraph_mode,
    _in_legacy_dygraph,
    convert_np_dtype_to_dtype_,
)
25
from ..layer_helper import LayerHelper
26
from ..data_feeder import check_variable_and_dtype, check_type, check_dtype
27
from ..core import VarDesc
28
from paddle import _C_ops, _legacy_C_ops
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

__all__ = [
    'sequence_conv',
    'sequence_softmax',
    'sequence_pool',
    'sequence_concat',
    'sequence_first_step',
    'sequence_last_step',
    'sequence_slice',
    'sequence_expand',
    'sequence_expand_as',
    'sequence_pad',
    'sequence_unpad',
    'sequence_reshape',
    'sequence_scatter',
    'sequence_enumerate',
    'sequence_mask',
    'sequence_reverse',
]


@templatedoc()
51 52 53 54 55 56 57 58 59 60 61 62
def sequence_conv(
    input,
    num_filters,
    filter_size=3,
    filter_stride=1,
    padding=True,
    padding_start=None,
    bias_attr=None,
    param_attr=None,
    act=None,
    name=None,
):
63
    r"""
S
swtkiwi 已提交
64

65
    Note:
L
LoneRanger 已提交
66
        Only receives LoDTensor as input. If your input is Tensor, please use conv2d Op.(fluid.layers.** :ref:`api_paddle_nn_functional_conv2d` ).
67 68 69 70 71 72

    This operator receives input sequences with variable length and other convolutional
    configuration parameters(num_filters, filter_size) to apply the convolution operation.
    It fills all-zero padding data on both sides of the sequence by default to ensure that
    the output is the same length as the input. You can customize the padding behavior by
    configuring the parameter :attr:`padding\_start` .
73

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
    **Warning:** the parameter :attr:`padding` take no effect and will be deprecated in the future.

    .. code-block:: text

            Here we will illustrate the details of the padding operation:
            For a mini-batch of 2 variable lengths sentences, containing 3, and 1 time-steps:
            Assumed input (X) is a [4, N] float LoDTensor, and for the sake of simplicity, we assume N=2.
            input.data = [[1, 1],
                          [2, 2],
                          [3, 3],
                          [4, 4]]

            This is to say that input (X) has 4 words and the dimension of each word
            representation is 2.

            * Case1:

                If padding_start is -1 and filter_size is 3.
                The length of padding data is calculated as follows:
                up_pad_len = max(0, -padding_start) = 1
                down_pad_len = max(0, filter_size + padding_start - 1) = 1

                The output of the input sequence after padding is:
                data_aftet_padding = [[0, 0, 1, 1, 2, 2],
                                      [1, 1, 2, 2, 3, 3],
                                      [2, 2, 3, 3, 0, 0],
                                      [0, 0, 4, 4, 0, 0]]

                It will be multiplied by the filter weight to get the final output.
                Assume num_filters = 3
                output.data = [[ 0.3234, -0.2334,  0.7433],
                               [ 0.5646,  0.9464, -0.1223],
                               [-0.1343,  0.5653,  0.4555],
                               [ 0.9954, -0.1234, -0.1234]]
                output.shape = [4, 3]     # 3 = num_filters
                output.lod = [[0, 3, 4]]  # Remain the same


    Args:
        input (Variable): LoDTensor with shape :math:`(M, K)`, where M is the total time-step of mini-batch
            and K is hidden_size of input. Only lod_level of 1 is supported. The data type should be float32 or
            float64.
        num_filters (int): the number of filters.
L
LoneRanger 已提交
117
        filter_size (int, optional): the height of filter. Specified filter width is not supported, the width is
118
            hidden_size by default. Default: 3.
L
LoneRanger 已提交
119 120
        filter_stride (int, optional): stride of the filter. Currently only supports :attr:`stride` = 1.
        padding (bool, optional): the parameter :attr:`padding` take no effect and will be discarded in the
121 122 123 124
            future. Currently, it will always pad input to make sure the length of the output is
            the same as input whether :attr:`padding` is set true or false. Because the length of
            input sequence may be shorter than :attr:`filter\_size`, which will cause the convolution
            result to not be computed correctly. These padding data will not be trainable or updated
T
tianshuo78520a 已提交
125
            while training. Default: True.
L
LoneRanger 已提交
126
        padding_start (int, optional): It is used to indicate the start index for padding the input
127 128 129 130 131
            sequence, which can be negative. The negative number means to pad
            :attr:`|padding_start|` time-steps of all-zero data at the beginning of each instance.
            The positive number means to skip :attr:`padding_start` time-steps of each instance,
            and it will pad :math:`filter\_size + padding\_start - 1` time-steps of all-zero data
            at the end of the sequence to ensure that the output is the same length as the input.
L
LoneRanger 已提交
132
            If set None, the same length :math:`\frac{filter\_size}{2}` of data will be filled
133 134
            on both sides of the sequence. If set 0, the length of :math:`filter\_size - 1` data
            is padded at the end of each input sequence. Default: None.
L
LoneRanger 已提交
135 136 137 138 139
        bias_attr (ParamAttr, optional): To specify the bias parameter property. Default: None, which means the
            default bias parameter property is used. See usage for details in :ref:`api_paddle_ParamAttr` .
        param_attr (ParamAttr, optional): To specify the weight parameter property. Default: None, which means the
            default weight parameter property is used. See usage for details in :ref:`api_paddle_ParamAttr` .
        act (str, optional): Activation to be applied to the output of this layer, such as tanh, softmax,
140 141 142 143 144 145 146 147 148 149 150
            sigmoid, relu. For more information, please refer to :ref:`api_guide_activations_en` . Default: None.
        name (str, optional): The default value is None.  Normally there is no need for user to set this property.
            For more information, please refer to :ref:`api_guide_Name` .

    Returns:
        Variable: LoDTensor with the same length as input. The data type is float32 or float64, which is same as input.

    Examples:

        .. code-block:: python

151 152
             import paddle
             paddle.enable_static()
153

154 155
             x = paddle.static.data(name='x', shape=[-1, 10], dtype='float32', lod_level=1)
             x_conved = paddle.static.nn.sequence_conv(input=x, num_filters=2, filter_size=3, padding_start=-1)
156 157
    """

158 159 160 161 162 163
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
    check_variable_and_dtype(
        input, 'input', ['float32', 'float64'], 'sequence_conv'
    )
164 165 166
    helper = LayerHelper('sequence_conv', **locals())
    dtype = helper.input_dtype()
    filter_shape = [filter_size * input.shape[1], num_filters]
167 168 169
    filter_param = helper.create_parameter(
        attr=helper.param_attr, shape=filter_shape, dtype=dtype
    )
170 171 172 173
    pre_bias = helper.create_variable_for_type_inference(dtype)
    if padding_start is None:
        padding_start = -int(filter_size // 2)

174 175 176 177 178 179 180 181 182 183 184 185 186
    helper.append_op(
        type='sequence_conv',
        inputs={
            'X': [input],
            'Filter': [filter_param],
        },
        outputs={"Out": pre_bias},
        attrs={
            'contextStride': filter_stride,
            'contextStart': padding_start,
            'contextLength': filter_size,
        },
    )
187 188 189 190 191
    pre_act = helper.append_bias_op(pre_bias)
    return helper.append_activation(pre_act)


def sequence_softmax(input, use_cudnn=False, name=None):
192
    r"""
S
swtkiwi 已提交
193

194
    Note:
195
        The input type of the OP must be LoDTensor. For Tensor, use:** :ref:`api_fluid_layers_softmax`
196 197 198 199 200 201 202 203 204 205 206

    A LoD-tensor can be regarded as several sequences, and this op apply softmax algo on each sequence.
    The shape of input Tensor can be :math:`[N, 1]` or :math:`[N]`, where :math:`N`
    is the sum of the length of all sequences. Recommended usage: :math:`[N]`.

    For i-th sequence in a mini-batch:

    .. math::

        Out(X[lod[i]:lod[i+1]], :) = \\frac{\exp(X[lod[i]:lod[i+1], :])}{\sum(\exp(X[lod[i]:lod[i+1], :]))}

207
    For example, for a LoD-Tensor with 6 sequences ([3, 2, 4, 1, 2, 3] - sequence length list in order),
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
    the lod in the runtime is [[0, 3, 5, 9, 10, 12, 15]],
    then softmax will be computed among :math:`X[0:3,:],X[3:5,:],X[5:9,:],X[9:10,:],X[10:12,:],X[12:15,:]`,
    and :math:`N` turns out to be 15.

    .. code-block:: text

        *Case 1:

            Given:
                input.data = [0.7, 1, 0.6,
                              1.5, 1.1,
                              1.2, 0.2, 0.6, 1.9,
                              3.1,
                              2.5, 0.8,
                              0.1, 2.4, 1.3]
                input.lod = [[0, 3, 5, 9, 10, 12, 15]]
            then:
                 output.data = [0.30724832, 0.41474187, 0.2780098,
                                0.59868765, 0.40131235,
227
                                0.2544242, 0.09359743, 0.13963096, 0.5123474,
228 229 230
                                1.,
                                0.84553474, 0.15446526,
                                0.06995796, 0.69777346, 0.23226859]
231 232
                 output.lod = [[0, 3, 5, 9, 10, 12, 15]]

233 234

    Args:
235 236 237
        input (Variable):A LoDTensor with shape of  :math:`[N, 1]` or  :math:`[N]`, Recommended usage: :math:`[N]`.
                         Supported data types: float32, float64.
        use_cudnn (bool, optional): Use cudnn kernel or not. Effective only when the cudnn version of the paddle
238
                                    library is installed and GPU is used for training or reasoning. Default: False.
239
        name (str, optional): The default value is None. Normally there is no need for user to set this property.
240 241 242 243 244 245 246 247
                              For more information, please refer to :ref:`api_guide_Name`

    Returns:
        Variable: A LoD-Tensor which has the same shape and data type with input.

    Examples:

        .. code-block:: python
248

249 250
             import paddle
             paddle.enable_static()
251

252
             x = paddle.static.data(name='x', shape=[7, 1],
253
                              dtype='float32', lod_level=1)
254
             x_sequence_softmax_1 = paddle.static.nn.sequence_softmax(input=x)
255

256
             y = paddle.static.data(name='y', shape=[7],
257
                 dtype='float32', lod_level=1)
258
             x_sequence_softmax_2 = paddle.static.nn.sequence_softmax(input=y)
259
    """
260 261 262
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
263
    helper = LayerHelper('sequence_softmax', **locals())
264 265 266
    check_variable_and_dtype(
        input, 'input', ['float32', 'float64'], 'sequence_softmax'
    )
267 268
    dtype = helper.input_dtype()
    softmax_out = helper.create_variable_for_type_inference(dtype)
269 270 271 272 273 274
    helper.append_op(
        type="sequence_softmax",
        inputs={"X": input},
        outputs={"Out": softmax_out},
        attrs={"use_cudnn": use_cudnn},
    )
275 276 277 278
    return softmax_out


def sequence_pool(input, pool_type, is_test=False, pad_value=0.0):
279
    r"""
S
swtkiwi 已提交
280

281
    Note:
282
        Only receives LoDTensor as input. If your input is Tensor, please use pool2d Op.(fluid.layers.** :ref:`api_fluid_layers_pool2d` ).
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339

    This operator only supports LoDTensor as input. It will apply specified pooling
    operation on the input LoDTensor. It pools features of all time-steps of each
    sequence at the last lod_level using :attr:`pool_type` mentioned in the parameters,
    such as sum, average, sqrt, etc.

    It supports six pool_type:

    - average: :math:`Out[i] = \\frac{\sum_i X_i}{N}`
    - sum:     :math:`Out[i] = \sum_jX_{ij}`
    - sqrt:    :math:`Out[i] = \\frac{\sum_jX_{ij}}{\sqrt{len(X_i)}}`
    - max:     :math:`Out[i] = max(X_i)`
    - last:    :math:`Out[i] = X_{N_i}`
    - first:   :math:`Out[i]` = X_0

    where :math:`N_i` is the length of i-th input sequence.

    .. code-block:: text

        Case 1:
        input is a 1-level LoDTensor and pad_value = 0.0:
            input.lod = [[0, 2, 5, 7, 7]]
            input.data = [[1.], [3.], [2.], [4.], [6.], [5.], [1.]]
            input.shape = [7, 1]

        output is LoDTensor:
            out.shape = [4, 1]
            with condition out.shape[0] == len(x.lod[-1]) == 4

        for different pool_type:
            average: out.data = [[2.], [4.], [3.], [0.0]], where 2.=(1. + 3.)/2, 4.=(2. + 4. + 6.)/3, 3.=(5. + 1.)/2
            sum    : out.data = [[4.], [12.], [6.], [0.0]], where 4.=1. + 3., 12.=2. + 4. + 6., 6.=5. + 1.
            sqrt   : out.data = [[2.82], [6.93], [4.24], [0.0]], where 2.82=(1. + 3.)/sqrt(2), 6.93=(2. + 4. + 6.)/sqrt(3), 4.24=(5. + 1.)/sqrt(2)
            max    : out.data = [[3.], [6.], [5.], [0.0]], where 3.=max(1., 3.), 6.=max(2., 4., 6.), 5.=max(5., 1.)
            last   : out.data = [[3.], [6.], [1.], [0.0]], where 3.=last(1., 3.), 6.=last(2., 4., 6.), 1.=last(5., 1.)
            first  : out.data = [[1.], [2.], [5.], [0.0]], where 1.=first(1., 3.), 2.=first(2., 4., 6.), 5.=first(5., 1.)

            and all above [0.0] at last of out.data is padding data.

        Case 2:
        input is a 2-level LoDTensor containing 3 sequences with length info [2, 0, 3],
        where 0 means empty sequence.
        The first sequence contains 2 subsequence with length info [1, 2];
        The last sequence contains 3 subsequence with length info [1, 0, 3].
            input.lod = [[0, 2, 2, 5], [0, 1, 3, 4, 4, 7]]
            input.data = [[1.], [3.], [2.], [4.], [6.], [5.], [1.]]
            input.shape = [7, 1]

        If pool_typ = sum, it will apply pooling on last lod_level [0, 1, 3, 4, 4, 7]. pad_value = 0.0
        output is LoDTensor:
            out.shape= [5, 1]
            out.lod = [[0, 2, 2, 5]]
            where out.shape[0] == len(x.lod[-1]) == 5
            sum: out.data = [[1.], [5.], [4.], [0.0], [12.]]
            where 1.=1., 5.=3. + 2., 4.=4., 0.0=pad_value, 12.=6. + 5. + 1.

    Args:
340
        input (variable): LoDTensor with lod_level no more than 2. The data type should be float32 or float64.
341 342 343 344 345 346 347
        pool_type (str): The pooling type that supports average, sum, sqrt, max, last or first.
        is_test (bool): Only works when :attr:`pool_type` is max. If set False, a temporary Tenosr maxIndex is
            created to record the index information corresponding to the maximum value, which is used for backward
            gradient calculation in the training phase. Default: False.
        pad_value (float): Used to pad the pooling result for empty input sequence. Default: 0.0

    Returns:
348
        Variable: LoDTensor after pooling with data type float32 or float64.
349 350 351 352 353

    Examples:

        .. code-block:: python

354 355
            import paddle
            paddle.enable_static()
356

357 358 359 360 361 362 363
            x = paddle.static.data(name='x', shape=[None, 10], dtype='float32', lod_level=1)
            avg_x = paddle.static.nn.sequence_pool(input=x, pool_type='average')
            sum_x = paddle.static.nn.sequence_pool(input=x, pool_type='sum')
            sqrt_x = paddle.static.nn.sequence_pool(input=x, pool_type='sqrt')
            max_x = paddle.static.nn.sequence_pool(input=x, pool_type='max')
            last_x = paddle.static.nn.sequence_pool(input=x, pool_type='last')
            first_x = paddle.static.nn.sequence_pool(input=x, pool_type='first')
364
    """
365 366 367 368 369 370
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
    check_variable_and_dtype(
        input, 'input', ['float32', 'float64'], 'sequence_pool'
    )
371 372 373 374 375
    helper = LayerHelper('sequence_pool', **locals())
    dtype = helper.input_dtype()
    pool_out = helper.create_variable_for_type_inference(dtype)
    max_index = helper.create_variable_for_type_inference(dtype)

376 377 378 379 380 381 382 383 384 385
    helper.append_op(
        type="sequence_pool",
        inputs={"X": input},
        outputs={"Out": pool_out, "MaxIndex": max_index},
        attrs={
            "pooltype": pool_type.upper(),
            "is_test": is_test,
            "pad_value": pad_value,
        },
    )
386 387 388 389 390 391 392 393 394 395 396 397

    # when pool_type is max, variable max_index is initialized,
    # so we stop the gradient explicitly here
    if pool_type == 'max':
        max_index.stop_gradient = True

    return pool_out


@templatedoc()
def sequence_concat(input, name=None):
    """
S
swtkiwi 已提交
398

399
    Note:
400
        Only receives LoDTensor as input. If your input is Tensor, please use concat Op.(fluid.layers.** :ref:`api_fluid_layers_concat` ).
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435

    This operator only supports LoDTensor as input. It concatenates the multiple LoDTensor from input by the LoD information,
    and outputs the concatenated LoDTensor.

    .. code-block:: text

        input is a list of LoDTensor:
            input = [x1, x2]
        where:
            x1.lod = [[0, 3, 5]]
            x1.data = [[1], [2], [3], [4], [5]]
            x1.shape = [5, 1]

            x2.lod = [[0, 2, 4]]
            x2.data = [[6], [7], [8], [9]]
            x2.shape = [4, 1]
        and should satisfy: len(x1.lod[0]) == len(x2.lod[0])

        output is LoDTensor:
            out.lod = [[0, 3+2, 5+4]]
            out.data = [[1], [2], [3], [6], [7], [4], [5], [8], [9]]
            out.shape = [9, 1]

    Args:
        input(list of Variable): List of LoDTensor to be concatenated. The length of each LoDTensor should be same.
            The data type can be float32, float64 or int64.
        name(str, optional): The default value is None.  Normally there is no need for user to set this property.
            For more information, please refer to :ref:`api_guide_Name` .

    Returns:
        Variable: Output the concatenated LoDTensor. The data type is same as input.

    Examples:
        .. code-block:: python

436 437 438 439 440 441
            import paddle
            paddle.enable_static()

            x = paddle.static.data(name='x', shape=[-1, 10], dtype='float32', lod_level=1)
            y = paddle.static.data(name='y', shape=[-1, 10], dtype='float32', lod_level=1)
            out = paddle.static.nn.sequence_concat(input=[x, y])
442
    """
443 444 445
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
446
    helper = LayerHelper('sequence_concat', **locals())
447 448 449

    check_type(input, 'input', list, 'fluid.layers.sequence_concat')
    for i, input_x in enumerate(input):
450 451 452 453 454 455
        check_variable_and_dtype(
            input_x,
            'input[' + str(i) + ']',
            ['int64', 'float32', 'float64'],
            'fluid.layers.sequence_concat',
        )
456

457
    out = helper.create_variable_for_type_inference(dtype=helper.input_dtype())
458 459 460
    helper.append_op(
        type='sequence_concat', inputs={'X': input}, outputs={'Out': [out]}
    )
461 462 463 464 465
    return out


def sequence_first_step(input):
    """
S
swtkiwi 已提交
466

467
    Only supports LoDTensor as input. Given the input LoDTensor, it will
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
    select first time-step feature of each sequence as output.

    .. code-block:: text

       Case 1:
        input is 1-level LoDTensor:
            input.lod = [[0, 2, 5, 7]]
            input.data = [[1.], [3.], [2.], [4.], [6.], [5.], [1.]]
            input.shape = [7, 1]

        output is a LoDTensor:
            out.shape = [3, 1]
            out.shape[0] == len(x.lod[-1]) == 3
            out.data = [[1.], [2.], [5.]], where 1.=first(1., 3.), 2.=first(2., 4., 6.), 5.=first(5., 1.)

        Case 2:
        input is a 2-level LoDTensor containing 3 sequences with length info [2, 0, 3],
        where 0 means empty sequence.
        The first sequence contains 2 subsequence with length info [1, 2];
        The last sequence contains 3 subsequence with length info [1, 0, 3].
            input.lod = [[0, 2, 2, 5], [0, 1, 3, 4, 4, 7]]
            input.data = [[1.], [3.], [2.], [4.], [6.], [5.], [1.]]
            input.shape = [7, 1]

        It will apply pooling on last lod_level [0, 1, 3, 4, 4, 7]. pad_value = 0.0
        output is a LoDTensor:
            out.shape= [5, 1]
            out.lod = [[0, 2, 2, 5]]
            out.shape[0] == len(x.lod[-1]) == 5
            out.data = [[1.], [3.], [4.], [0.0], [6.]]
            where 1.=first(1.), 3.=first(3., 2.), 4.=first(4.), 0.0 = pad_value, 6.=first(6., 5., 1.)

    Args:
501
        input(Variable): LoDTensor with lod_level no more than 2. The data type should be float32 or float64.
502 503

    Returns:
504
        Variable: LoDTensor consist of the sequence's first step vector. The data type is float32 or float64.
505 506 507 508 509

    Examples:

        .. code-block:: python

510 511 512 513 514
             import paddle
             paddle.enable_static()

             x = paddle.static.data(name='x', shape=[None, 10], dtype='float32', lod_level=1)
             x_first_step = paddle.static.nn.sequence_first_step(input=x)
515
    """
516 517 518
    check_variable_and_dtype(
        input, 'input', ['float32', 'float64'], 'sequence_first_step'
    )
519 520 521 522 523
    return sequence_pool(input=input, pool_type="first")


def sequence_last_step(input):
    """
S
swtkiwi 已提交
524

525
    Only supports LoDTensor as input. Given the input LoDTensor, it will
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
    select last time-step feature of each sequence as output.

    .. code-block:: text

        Case 1:
        input is 1-level LoDTensor:
            input.lod = [[0, 2, 5, 7]]
            input.data = [[1.], [3.], [2.], [4.], [6.], [5.], [1.]]
            input.shape = [7, 1]

        output is a LoDTensor:
            out.shape = [3, 1]
            out.shape[0] == len(x.lod[-1]) == 3
            out.data = [[3.], [6.], [1.]], where 3.=last(1., 3.), 6.=last(2., 4., 6.), 1.=last(5., 1.)

        Case 2:
        input is a 2-level LoDTensor containing 3 sequences with length info [2, 0, 3],
        where 0 means empty sequence.
        The first sequence contains 2 subsequence with length info [1, 2];
        The last sequence contains 3 subsequence with length info [1, 0, 3].
            input.lod = [[0, 2, 2, 5], [0, 1, 3, 4, 4, 7]]
            input.data = [[1.], [3.], [2.], [4.], [6.], [5.], [1.]]
            input.shape = [7, 1]

        It will apply pooling on last lod_level [0, 1, 3, 4, 4, 7]. pad_value = 0.0
        output is a LoDTensor:
            out.shape= [5, 1]
            out.lod = [[0, 2, 2, 5]]
            out.shape[0] == len(x.lod[-1]) == 5
            out.data = [[1.], [2.], [4.], [0.0], [1.]]
            where 1.=last(1.), 2.=last(3., 2.), 4.=last(4.), 0.0 = pad_value, 1=last(6., 5., 1.)


    Args:
        input(Variable): LoDTensor with lod_level no more than 2. The data type should be float32.

    Returns:
        Variable: LoDTensor consist of the sequence's last step vector. The data type is float32.

    Examples:

        .. code-block:: python

569 570
             import paddle
             paddle.enable_static()
571

572 573
             x = paddle.static.data(name='x', shape=[None, 10], dtype='float32', lod_level=1)
             x_last_step = paddle.static.nn.sequence_last_step(input=x)
574
    """
575 576 577
    check_variable_and_dtype(
        input, 'input', ['float32', 'float64'], 'sequence_last_step'
    )
578 579 580 581 582
    return sequence_pool(input=input, pool_type="last")


def sequence_slice(input, offset, length, name=None):
    """
S
swtkiwi 已提交
583

584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
    **Sequence Slice Layer**

    The layer crops a subsequence from given sequence with given start
    offset and subsequence length.

    It only supports sequence data (LoDTensor with lod_level equal to 1).

    .. code-block:: text

              - Case:

            Given the input Variable **input**:

                input.data = [[a1, a2], [b1, b2], [c1, c2], [d1, d2], [e1, e2]],
                input.lod = [[3, 2]],
                input.dims = (5, 2),

            with offset.data = [[0], [1]] and length.data = [[2], [1]],

            the output Variable will be

                out.data = [[a1, a2], [b1, b2], [e1, e2]],
                out.lod = [[2, 1]],
                out.dims = (3, 2).

    Note:
          The first dimension size of **input**, **offset** and **length**
          should be equal. The **offset** should start from 0.

    Args:
        input(Variable): LoDTensor, The input Variable which consists of the complete
615 616
                         sequences.The data type can be float32, float64, int32 or int64
        offset(Variable): LoDTensor, The offset to slice each sequence. The data
617
                         type is int32 or int64.
618
        length(Variable): LoDTensor, The length of each subsequence. The data
619 620 621 622 623 624 625 626 627 628 629 630
                         type is int32 or int64.
        name(str|None): The default value is None.  Normally there is no need
                        for user to set this property.  For more information,
                        please refer to :ref:`api_guide_Name`

    Returns:
        Variable: The output subsequences.

    Examples:

        .. code-block:: python

631 632
             import paddle
             paddle.enable_static()
633

634
             import numpy as np
635
             seqs = paddle.static.data(name='x', shape=[10, 5],
636
                              dtype='float32', lod_level=1)
637 638 639
             offset = paddle.assign(np.array([[0, 1]]).astype("int32"))
             length = paddle.assign(np.array([[2, 1]]).astype("int32"))
             subseqs = paddle.static.nn.sequence_slice(input=seqs, offset=offset,
640 641
                                                   length=length)
    """
642 643 644
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
645
    helper = LayerHelper("sequence_slice", **locals())
646

647 648 649 650 651 652 653 654 655 656 657 658
    check_variable_and_dtype(
        input,
        'input',
        ['float32', 'float64', 'int32', 'int64'],
        'sequence_slice',
    )
    check_variable_and_dtype(
        offset, 'offset', ['int32', 'int64'], 'sequence_slice'
    )
    check_variable_and_dtype(
        length, 'length', ['int32', 'int64'], 'sequence_slice'
    )
659

660 661 662 663 664 665
    dtype = helper.input_dtype()
    out = helper.create_variable_for_type_inference(dtype)

    offset.stop_gradient = True
    length.stop_gradient = True

666 667 668 669 670
    helper.append_op(
        type="sequence_slice",
        inputs={"X": input, "Offset": offset, "Length": length},
        outputs={"Out": out},
    )
671 672 673 674 675

    return out


def sequence_expand(x, y, ref_level=-1, name=None):
676
    r"""
S
swtkiwi 已提交
677 678

        Sequence Expand Layer. This layer will expand the input variable ``x`` \
679 680 681 682 683 684
        according to specified level ``ref_level`` lod of ``y``. Please note that \
        the lod level of ``x`` is at most 1. If the lod level of ``x`` is 1, than \
        the size of lod of ``x`` must be equal to the length of ``ref_level`` lod \
        of ``y``. If the lod level of ``x`` is 0, then the first dim of ``x`` should \
        be equal to the size of ``ref_level`` of ``y``. The rank of **x** is at least 2. \
        When rank of ``x`` is greater than 2, then it would be viewed as a 2-D tensor.
685

686
    Note:
687

688
        Please note that the input ``x`` should be LodTensor or Tensor, \
689 690
        and input ``y`` must be LodTensor.

691
    **Following examples will explain how sequence_expand works:**
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711

    .. code-block:: text

        Case 1

        Consider 2 sequences [a][b] and [c][d], now we want to expand them to [a][b], [a][b], [c][d] and [c][d].
        Sequence [a][b] expand twice and [c][d] expands twice, so the lod which according to is [2, 2].

        Input x is a 1-level LoDTensor:
            x.lod  = [[2,        2]]    #lod based on length may be easier to understand
            x.data = [[a], [b], [c], [d]]
            x.dims = [4, 1]

        input y is a LoDTensor:
            y.lod = [[2,    2],    #the 0th level lod, according to this level
                     [3, 3, 1, 1]] #the 1st level lod, it has nothing to do with this level

        ref_level: 0

        then output is a 1-level LoDTensor out:
T
tianshuo78520a 已提交
712
            out.lod =  [[2,        2,        2,        2]]    #lod based on offset
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
            out.data = [[a], [b], [a], [b], [c], [d], [c], [d]]
            out.dims = [8, 1]


        Case 2

        Consider 3 sequences [a], [b], [c], now we want to expand them to [a][a], [c][c][c].
        It's obvious that the lod info of expanded sequences is [2, 0, 3].

        x is a Tensor:
            x.data = [[a], [b], [c]]
            x.dims = [3, 1]

        y is a LoDTensor:
            y.lod = [[2, 0, 3]]

        ref_level: -1

        then output is a 1-level LodTensor:
            out.data = [[a], [a], [c], [c], [c]]
            out.dims = [5, 1]

    Args:
        x (Variable): The input variable which is a Tensor or LoDTensor, with the \
            dims ``[M, K]``. The lod level is at most 1. The data type should be \
738
            float32, float64, int32 or int64.
739 740 741 742 743 744
        y (Variable): The input variable which is a LoDTensor, the lod level is \
            at least 1.
        ref_level (int): Lod level of ``y`` to be referred by ``x``. If set to -1, \
                         refer the last level of lod.
        name(str, optional): For detailed information, please refer \
            to :ref:`api_guide_Name`. Usually name is no need to set and \
745
            None by default.
746

747
    Returns:
748
            Tensor, The expanded variable which is a LoDTensor, with dims ``[N, K]``. \
749 750 751 752 753
            ``N`` depends on the lod info of ``x`` and ``y``. \
            The data type is same as input.

    Examples:
        .. code-block:: python
754

755 756 757
            import paddle
            from paddle import fluid
            paddle.enable_static()
758 759
            import numpy as np

760 761
            x = paddle.static.data(name='x', shape=[4, 1], dtype='float32')
            y = paddle.static.data(name='y', shape=[8, 1],
762
                        dtype='float32', lod_level=1)
763
            out = paddle.static.nn.sequence_expand(x=x, y=y, ref_level=0)
764

765 766
            exe = paddle.static.Executor(fluid.CPUPlace())
            place = paddle.CPUPlace()
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795

            np_data = np.array([[1], [2], [3], [4]]).astype('float32')
            x_lod_tensor = fluid.create_lod_tensor(np_data, [[2, 2]], place)
            print(x_lod_tensor)
            #lod: [[0, 2, 4]]
            #    dim: 4, 1
            #    layout: NCHW
            #    dtype: float
            #    data: [1 2 3 4]

            np_data = np.array([[1], [2], [3], [4], [5], [6], [7], [8]]).astype('float32')
	    y_lod_tensor = fluid.create_lod_tensor(np_data, [[2, 2], [3,3,1,1]], place)
            print(y_lod_tensor)
            #lod: [[0, 2, 4][0, 3, 6, 7, 8]]
            #    dim: 8, 1
            #    layout: NCHW
            #    dtype: int64_t
            #    data: [0 0 1 1 1 1 1 0]

            out_main = exe.run(fluid.default_main_program(),
                            feed={'x': x_lod_tensor, 'y': y_lod_tensor},
                            fetch_list=[out], return_numpy=False)
            print(out_main[0])
            #lod: [[0, 2, 4, 6, 8]]
            #    dim: 8, 1
            #    layout: NCHW
            #    dtype: float
            #    data: [1 2 1 2 3 4 3 4]
    """
796 797 798 799 800 801
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
    check_variable_and_dtype(
        x, 'x', ['float32', 'float64', 'int32', 'int64'], 'sequence_expand'
    )
802 803
    helper = LayerHelper('sequence_expand', **locals())
    dtype = helper.input_dtype(input_param_name='x')
804
    tmp = helper.create_variable_for_type_inference(dtype)
805 806 807 808 809 810
    helper.append_op(
        type='sequence_expand',
        inputs={'X': x, 'Y': y},
        outputs={'Out': tmp},
        attrs={'ref_level': ref_level},
    )
811 812 813 814
    return tmp


def sequence_expand_as(x, y, name=None):
815
    r"""
S
swtkiwi 已提交
816 817

        Sequence Expand As Layer. This OP will expand the input variable ``x`` \
818 819 820 821 822 823
        according to the zeroth level lod of ``y``. Current implementation requires \
        the level number of ``y``'s lod must be 1, and the first dimension of \
        ``x`` should be equal to the size of ``y``'s zeroth level lod, thus \
        the expanded LodTensor has the same lod info as ``y``. The expanded result \
        has nothing to do with ``x``'s lod, so the lod of Input(X) is not considered.

824 825
    Note:
        Please note that the input ``x`` should be LodTensor or Tensor, \
826 827 828 829 830 831 832 833 834 835
        and input ``y`` must be LodTensor.

    Following examples will explain how sequence_expand_as works:

    .. code-block:: text

        Case 1:

        Consider 4 sequences [a], [b], [c], [d], now we want to expand them to [a][a][a], [b][b][b], [c] and [d].
        It's obvious that the lod info of expanded sequences is [0, 3, 6, 7, 8].
836
        Given a 1-level LodTensor ``x``:
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862
            x.data = [[a], [b], [c], [d]]
            x.dims = [4, 1]
        and input ``y``
            y.lod = [[3, 3, 1, 1]] #lod based on length may be easier to understand

        then we get 1-level LoDTensor out:
            Out.lod =  [[0,            3,              6,  7,  8]] #based on offset
            Out.data = [[a], [a], [a], [b], [b], [b], [c], [d]]
            Out.dims = [8, 1]


        Case 2:

        Given a common Tensor ``x``:
            x.data = [[a, b], [c, d], [e, f]]
            x.dims = [3, 2]
        and input ``y``:
            y.lod = [[0, 2, 3, 6]]

        then we get a 1-level LoDTensor:
            out.lod =  [[0,             2,     3,                    6]]
            out.data = [[a, b], [a, b] [c, d], [e, f], [e, f], [e, f]]
            out.dims = [6, 2]

    Args:
        x (Variable): The input variable which is a Tensor or LoDTensor, with the \
863
            dims ``[M, K]``. The data type should be float32, float64, int32 \
864 865 866 867 868 869
            or int64.
        y (Variable): The input variable which is a LoDTensor with 1-level lod.
        name (str, optional): For detailed information, please refer \
            to :ref:`api_guide_Name`. Usually name is no need to set and \
            None by default.

870
    Returns:
871
            Tensor, The expanded variable which is a LoDTensor with the dims ``[N, K]``. \
872 873 874 875 876 877
            ``N`` depends on the lod of ``y``, and the lod level must be 1. \
            The data type is same as input.

    Examples:
        .. code-block:: python

878
            import paddle
879
            import paddle.fluid as fluid
880
            paddle.enable_static()
881 882
            import numpy as np

883 884 885
            x = paddle.static.data(name='x', shape=[4, 1], dtype='float32')
            y = paddle.static.data(name='y', shape=[8, 1], dtype='float32', lod_level=1)
            out = paddle.static.nn.sequence_expand_as(x=x, y=y)
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917

            exe = fluid.Executor(fluid.CPUPlace())
            place = fluid.CPUPlace()

            np_data = np.array([[1], [2], [3], [4]]).astype('float32')
            x_lod_tensor = fluid.create_lod_tensor(np_data, [[2, 2]], place)
            print(x_lod_tensor)
            #lod: [[0, 2, 4]]
            #    dim: 4, 1
            #    layout: NCHW
            #    dtype: float
            #    data: [1 2 3 4]

            np_data = np.array([[1], [2], [3], [4], [5], [6], [7], [8]]).astype('float32')
	    y_lod_tensor = fluid.create_lod_tensor(np_data, [[3,3,1,1]], place)
            print(y_lod_tensor)
            #lod: [[0, 3, 6, 7, 8]]
            #    dim: 8, 1
            #    layout: NCHW
            #    dtype: int64_t
            #    data: [0 0 1 0 1 1 1 0]

            out_main = exe.run(fluid.default_main_program(),
                            feed={'x': x_lod_tensor, 'y': y_lod_tensor},
                            fetch_list=[out], return_numpy=False)
            print(out_main[0])
            #lod: [[0, 3, 6, 7, 8]]
            #    dim: 8, 1
            #    layout: NCHW
            #    dtype: float
            #    data: [1 1 1 2 2 2 3 4]
    """
918 919 920 921 922 923
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
    check_variable_and_dtype(
        x, 'x', ['float32', 'float64', 'int32', 'int64'], 'sequence_expand_as'
    )
924
    check_type(y, 'y', Variable, 'sequence_expand_as')
925 926
    helper = LayerHelper('sequence_expand_as', **locals())
    dtype = helper.input_dtype(input_param_name='x')
927
    tmp = helper.create_variable_for_type_inference(dtype)
928 929 930
    helper.append_op(
        type='sequence_expand_as', inputs={'X': x, 'Y': y}, outputs={'Out': tmp}
    )
931 932 933 934
    return tmp


def sequence_pad(x, pad_value, maxlen=None, name=None):
935
    r"""
S
swtkiwi 已提交
936

937 938 939 940
        This layer padding the sequences in a same batch to a common length (according
        to ``maxlen``). The padding value is defined by ``pad_value``, and will be
        appended to the tail of sequences. The result is a Python tuple ``(Out, Length)``:
        the LodTensor ``Out`` is the padded sequences, and LodTensor ``Length`` is
S
sunzhongkai588 已提交
941 942
        the length information of input sequences. For removing padding data (unpadding operation), See :ref:`api_fluid_layers_sequence_unpad`.

943
    Note:
S
sunzhongkai588 已提交
944
        Please note that the input ``x`` should be LodTensor.
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965

    .. code-block:: text

        Case 1:
        Given input 1-level LoDTensor x:
            x.lod = [[0,  2,   5]]
            x.data = [[a],[b],[c],[d],[e]]
        pad_value:
            pad_value.data = [0]
        maxlen = 4

        the output tuple (Out, Length):
            Out.data = [[[a],[b],[0],[0]],[[c],[d],[e],[0]]]
            Length.data = [2, 3]      #Original sequences length

        Case 2:
        Given input 1-level LoDTensor x:
            x.lod =  [[0,             2,                     5]]
            x.data = [[a1,a2],[b1,b2],[c1,c2],[d1,d2],[e1,e2]]
        pad_value:
            pad_value.data = [0]
T
tianshuo78520a 已提交
966
        default maxlen = None, (the virtual value is 3, according to the shape of x)
967 968 969 970 971 972 973 974 975 976 977

        the output tuple (Out, Length):
            Out.data = [[[a1,a2],[b1,b2],[0,0]],[[c1,c2],[d1,d2],[e1,e2]]]
            Length.data = [2, 3]

        Case 3:
        Given input 1-level LoDTensor x:
            x.lod =  [[0,             2,                     5]]
            x.data = [[a1,a2],[b1,b2],[c1,c2],[d1,d2],[e1,e2]]
        pad_value:
            pad_value.data = [p1,p2]
T
tianshuo78520a 已提交
978
        default maxlen = None, (the virtual value is 3)
979 980 981 982 983 984 985 986 987

        get tuple (Out, Length):
            Out.data = [[[a1,a2],[b1,b2],[p1,p2]],[[c1,c2],[d1,d2],[e1,e2]]]
            Length.data = [2, 3]



    Args:
        x (Variable): Input 1-level LodTensor with dims ``[M, K]``. The batch \
T
tianshuo78520a 已提交
988
            size is described by lod infor (the number of sequences ). \
989 990 991 992 993 994 995 996 997 998 999 1000
            The data type should be float32, float64, int8, int32 or int64.
        pad_value (Variable): Padding value. It can be a scalar or a 1D tensor \
            with length ``K``. If it's a scalar, it will be automatically broadcasted \
            to a Tensor. The data type should be as same as ``x``.
        maxlen (int, optional): The length of padded sequences, None by default. \
            When it is None, all sequences will be padded up to the length of the \
            longest one among them; when it a certain positive value, it must be \
            greater than the length of the longest original sequence.
        name (str, optional): For detailed information, please refer \
            to :ref:`api_guide_Name`. Usually name is no need to set and \
            None by default.

1001
    Returns:
1002
            tuple, A Python tuple (Out, Length): the 1st is a 0 level LodTensor \
1003 1004 1005 1006 1007 1008 1009
            ``Out``, with the shape ``[batch_size, maxlen, K]``; the second is the original \
            sequences length infor ``Length``, which should be a 0-level 1D LodTensor. \
            The size of ``Length`` is equal to batch size, and the data type is int64.

    Examples:
        .. code-block:: python

1010 1011
            import paddle
            paddle.enable_static()
1012 1013 1014
            import paddle.fluid as fluid
            import numpy

1015 1016 1017 1018
            x = paddle.static.data(name='x', shape=[10, 5], dtype='float32', lod_level=1)
            pad_value = paddle.assign(
                numpy.array([0.0], dtype=numpy.float32))
            out = paddle.static.nn.sequence_pad(x=x, pad_value=pad_value)
1019 1020
    """

1021 1022 1023
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
1024
    helper = LayerHelper('sequence_pad', **locals())
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
    check_variable_and_dtype(
        x,
        'x',
        ['float32', 'float64', 'int32', 'int64'],
        'fluid.layers.sequence_pad',
    )
    check_variable_and_dtype(
        pad_value,
        'pad_value',
        ['float32', 'float64', 'int32', 'int64'],
        'fluid.layers.sequence_pad',
    )
1037
    dtype = helper.input_dtype(input_param_name='x')
1038
    out = helper.create_variable_for_type_inference(dtype)
1039
    length = helper.create_variable_for_type_inference(VarDesc.VarType.INT64)
1040 1041 1042 1043 1044 1045

    pad_value.stop_gradient = True
    length.stop_gradient = True

    if maxlen is None:
        maxlen = -1
1046 1047 1048 1049 1050 1051
    helper.append_op(
        type='sequence_pad',
        inputs={'X': x, 'PadValue': pad_value},
        outputs={'Out': out, 'Length': length},
        attrs={'padded_length': maxlen},
    )
1052 1053 1054 1055 1056
    return out, length


def sequence_unpad(x, length, name=None):
    """
S
swtkiwi 已提交
1057

1058
    Note:
1059
        The input of this API is Tensor and the output is LoDTensor.  For padding operation, See:**  :ref:`api_fluid_layers_sequence_pad`
1060

1061
    Remove the padding data from the input based on the length information and returns a LoDTensor.
1062 1063 1064

    .. code-block:: text

1065
        Case 1:
1066

1067 1068 1069 1070
        Given input Variable **x**:
            x.data = [[ 1.0,  2.0,  3.0,  4.0,  5.0],
                      [ 6.0,  7.0,  8.0,  9.0, 10.0],
                      [11.0, 12.0, 13.0, 14.0, 15.0]],
1071

1072 1073
        in which there are 3 sequences padded to length 5, and the actual length
        specified by input Variable **length**:
1074

1075
            length.data = [2, 3, 4],
1076

1077
        after unpadding, the output Variable will be:
1078

1079 1080
            out.data = [[1.0, 2.0, 6.0, 7.0, 8.0, 11.0, 12.0, 13.0, 14.0]]
            out.lod = [[0, 2, 5, 9]]
1081 1082 1083 1084

    Args:
        x(Variable): A Tensor which contains padding data, and its shape size can not be less than 2.
                     Supported data types: float32, float64, int32, int64.
1085
        length(Variable): A 1D Tensor that stores the actual length of each sample, and the Tensor
1086
                          has the same shape with the 0th dimension of the X . Supported data types: int64.
1087
        name(str|None, optional):  The default value is None.  Normally there is no need for user to set this property.
1088 1089 1090 1091 1092 1093 1094 1095
                         For more information, please refer to :ref:`api_guide_Name`

    Returns:
        Variable: A LoDTensor whose recursive sequence length is consistent with the information of the length parameter and it has the same data type with input.

    Examples:
        .. code-block:: python

1096 1097
            import paddle
            paddle.enable_static()
1098 1099 1100 1101
            import paddle.fluid as fluid
            import numpy

            # pad data
1102 1103 1104
            x = paddle.static.data(name='x', shape=[10, 5], dtype='float32', lod_level=1)
            pad_value = paddle.assign(numpy.array([0.0], dtype=numpy.float32))
            pad_data, len = paddle.static.nn.sequence_pad(x=x, pad_value=pad_value)
1105

1106
            # unpad data
1107
            unpad_data = paddle.static.nn.sequence_unpad(x=pad_data, length=len)
1108 1109
    """

1110 1111 1112
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
1113
    helper = LayerHelper('sequence_unpad', **locals())
1114 1115 1116 1117 1118 1119 1120 1121 1122
    check_variable_and_dtype(
        x,
        'x',
        ['float32', 'float64', 'int32', 'int64'],
        'fluid.layers.sequence_unpad',
    )
    check_variable_and_dtype(
        length, 'length', ['int64'], 'fluid.layers.sequence_unpad'
    )
1123
    dtype = helper.input_dtype(input_param_name='x')
1124 1125 1126 1127
    out = helper.create_variable_for_type_inference(dtype)

    length.stop_gradient = True

1128 1129 1130 1131 1132
    helper.append_op(
        type='sequence_unpad',
        inputs={'X': x, 'Length': length},
        outputs={'Out': out},
    )
1133 1134 1135 1136 1137
    return out


def sequence_reshape(input, new_dim):
    """
S
swtkiwi 已提交
1138

1139
    Note:
1140
        Only receives LoDTensor as input. If your input is Tensor, please use reshape Op.(fluid.layers.** :ref:`api_fluid_layers_reshape` ).
1141

1142
    Only supports LoDTensor as input. Given :attr:`new_dim` ,
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
    it will compute new shape according to original length of each sequence,
    original dimensions and :attr:`new_dim` . Then it will output a new LoDTensor
    containing :attr:`new_dim` . Currently it only supports 1-level LoDTensor.
    Please make sure that (original length * original dimensions) can be divided
    by the :attr:`new_dim` with no remainder for each sequence.

    .. code-block:: text

        input is a LoDTensor:
            input.lod  = [[0, 2, 6]]
            input.data = [[1,  2], [3,  4],
                          [5,  6], [7,  8],
                          [9, 10], [11, 12]]
            input.shape = [6, 2]

        set new_dim = 4
        out is a LoDTensor:
            out.lod  = [[0, 1, 3]]
            out.data = [[1,  2,  3,  4],
                        [5,  6,  7,  8],
                        [9, 10, 11, 12]]
            out.shape = [3, 4]


    Args:

       input (Variable): 1-level LoDTensor with shape :math:`[M, K]` . The data type should
            be int32, int64, float32 or float64.
       new_dim (int): New dimension that the input LoDTensor is reshaped to.

    Returns:
        Variable: Reshaped LoDTensor according to new dimension. The data type is same as input.

    Examples:
        .. code-block:: python

1179 1180 1181 1182 1183
            import paddle
            paddle.enable_static()

            x = paddle.static.data(name='x', shape=[None, 16], dtype='float32', lod_level=1)
            x_reshaped = paddle.static.nn.sequence_reshape(input=x, new_dim=4)
1184
    """
1185 1186 1187
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
1188
    helper = LayerHelper('sequence_reshape', **locals())
1189 1190 1191 1192 1193 1194
    check_variable_and_dtype(
        input,
        'input',
        ['float32', 'float64', 'int32', 'int64'],
        'fluid.layers.sequence_reshape',
    )
1195
    out = helper.create_variable_for_type_inference(helper.input_dtype())
1196 1197 1198 1199 1200 1201
    helper.append_op(
        type='sequence_reshape',
        inputs={'X': [input]},
        outputs={'Out': [out]},
        attrs={'new_dim': new_dim},
    )
1202 1203 1204 1205 1206
    return out


def sequence_scatter(input, index, updates, name=None):
    """
S
swtkiwi 已提交
1207

1208 1209
    Note:
        The index and updates parameters of the OP must be LoDTensor.
1210

T
tianshuo78520a 已提交
1211
    Plus the updates data to the corresponding input according to the index.
1212 1213

    The updated algorithm is as follows: output[instance_index][index [pos]] = input[instance_index][index [pos]] +  updates[pos],
1214 1215
    where instance_idx is the K sample corresponding to pos in batch.

1216
    The value of output[i][j] depends on whether j can be found in the i+1th interval of the index. If found,
1217 1218
    out[i][j] = input[i][j] + update[m] [n], otherwise, out[i][j] = input[i][j].

1219 1220 1221
    For example, in the following example, the lod information for index is divided into three sequences. Among
    them, because the element 0 can be found in the first interval of the index, it is updated with the value of
    the corresponding position of the updates, out[0][0] = input[0][0]+updates[0][0] . Because element 1 cannot
1222 1223 1224
    be found in the third interval of index, out[2][1] = input[2][1].

    .. code-block:: text
1225

1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
        *Case 1:

            Given:
                input.data = [[1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
                              [1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
                              [1.0, 1.0, 1.0, 1.0, 1.0, 1.0]]
                              input.dims = [3, 6]

                index.data = [[0], [1], [2], [5], [4], [3], [2], [1], [3], [2], [5], [4]]
                index.lod =  [[0,        3,                       8,                 12]]

                updates.data = [[0.3], [0.3], [0.4], [0.1], [0.2], [0.3], [0.4], [0.0], [0.2], [0.3], [0.1], [0.4]]
                updates.lod =  [[  0,            3,                                 8,                         12]]

            Then:
                out.data = [[1.3, 1.3, 1.4, 1.0, 1.0, 1.0],
                            [1.0, 1.0, 1.4, 1.3, 1.2, 1.1],
                            [1.0, 1.0, 1.3, 1.2, 1.4, 1.1]]
                out.dims = X.dims = [3, 6]

    Args:
        input (Variable): A Tensor with shape of  :math:`[N, k_1... k_n]`. Supported data types: float32, float64, int32, int64.
1248
        index (Variable):  A LoDTensor contains index information. Its LoD level must be 1 and its data type can be int32 or int64.
1249
        updates (Variable): A LodTensor contains updates information. It has the same  LoD level with the index and has the
1250
                            same data type  with the input. Supported data types: float32, float64, int32, int64.
1251
        name (str, optional): The default value is None.  Normally there is no need for user to set this property.  For more information,
1252 1253 1254 1255 1256 1257 1258 1259
                              please refer to :ref:`api_guide_Name`

    Returns:
        Variable: A Tensor which has been updated. It has the same shape and data type with input.

    Examples:

        .. code-block:: python
1260

1261 1262
            import paddle
            paddle.enable_static()
1263

1264 1265 1266 1267
            input = paddle.static.data(name="x", shape=[None, 3, 6], dtype='float32' )
            index = paddle.static.data(name='index', shape=[12, 1],  dtype='int64', lod_level=1)
            updates = paddle.static.data(name='updates', shape=[12, 1], dtype='float32', lod_level=1)
            output = paddle.static.nn.sequence_scatter(input, index, updates)
1268 1269

    """
1270 1271 1272
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
1273
    helper = LayerHelper('sequence_scatter', **locals())
1274

1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
    check_variable_and_dtype(
        input,
        'input',
        ['float32', 'float64', 'int32', 'int64'],
        'sequence_scatter',
    )
    check_variable_and_dtype(
        index, 'index', ['int32', 'int64'], 'sequence_scatter'
    )
    check_variable_and_dtype(
        updates,
        'updates',
        ['float32', 'float64', 'int32', 'int64'],
        'sequence_scatter',
    )
1290

1291 1292
    dtype = helper.input_dtype()
    out = helper.create_variable_for_type_inference(dtype)
1293 1294 1295 1296 1297
    helper.append_op(
        type="sequence_scatter",
        inputs={"X": input, "Ids": index, "Updates": updates},
        outputs={"Out": out},
    )
1298 1299 1300 1301
    return out


def sequence_enumerate(input, win_size, pad_value=0, name=None):
1302
    r"""
S
swtkiwi 已提交
1303

1304
    Generate a new sequence for the input index sequence with \
L
LoneRanger 已提交
1305 1306 1307
    shape ``[d_1, win_size]``, which enumerates all the \
    sub-sequences with length ``win_size`` of the input with \
    shape ``[d_1, 1]``, and padded by ``pad_value`` if necessary in generation.
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330

    Please note that the `input` must be LodTensor.

    .. code-block:: text

        Input x:
            x.lod = [[0, 3, 5]]
            x.data = [[1], [2], [3], [4], [5]]
            x.dims = [5, 1]

        Attrs:
            win_size = 2
            pad_value = 0

        Output:
            out.lod = [[0, 3, 5]]
            out.data = [[1, 2], [2, 3], [3, 0], [4, 5], [5, 0]]
            out.dims = [5, 2]


    Args:
        input (Variable): The input variable which is a index sequence, \
            which should be a LodTensor with shape ``[d_1, 1]`` and 1-level lod info. \
1331
            The data type should be int32 or int64.
1332 1333 1334 1335 1336 1337
        win_size (int): The window size for enumerating all sub-sequences.
        pad_value (int, optional): The padding value, default 0.
        name(str, optional): For detailed information, please refer \
            to :ref:`api_guide_Name`. Usually name is no need to set and \
            None by default.

1338
    Returns:
1339
            Tensor, The enumerate sequence variable which is a LoDTensor with \
1340 1341 1342 1343 1344 1345
            shape ``[d_1, win_size]`` and 1-level lod info. \
            The data type is same as ``input``.

    Examples:
        .. code-block:: python

1346 1347
            import paddle
            paddle.enable_static()
1348

1349 1350
            x = paddle.static.data(name='x', shape=[-1, 1], dtype='int32', lod_level=1)
            out = paddle.static.nn.sequence_enumerate(input=x, win_size=3, pad_value=0)
1351
    """
1352 1353 1354 1355 1356 1357
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
    check_variable_and_dtype(
        input, 'input', ['int32', 'int64'], 'sequence_enumerate'
    )
1358
    helper = LayerHelper('sequence_enumerate', **locals())
1359 1360 1361 1362 1363 1364 1365 1366 1367
    out = helper.create_variable_for_type_inference(
        helper.input_dtype(), stop_gradient=True
    )
    helper.append_op(
        type='sequence_enumerate',
        inputs={'X': input},
        outputs={'Out': out},
        attrs={'win_size': win_size, 'pad_value': pad_value},
    )
1368 1369 1370 1371
    return out


def sequence_mask(x, maxlen=None, dtype='int64', name=None):
1372
    r"""
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403
    **SequenceMask Layer**

    This layer outputs a mask according to the input :code:`x` and
    :code:`maxlen` with data type of :code:`dtype`.

    Supposing :code:`x` is a Tensor with shape [d_1, d_2, ..., d_n], the
    :code:`y` is a mask with shape [d_1, d_2, ..., d_n, maxlen], where:

    .. math::

        y(i_1, i_2,..., i_n, j) = (j < x(i_1, i_2,..., i_n))

    .. code-block:: text

        Case:

        Consider input:
            x = [3, 1, 1, 0]    max_len = 4

        then we get out:
            mask = [[1, 1, 1, 0],
                    [1, 0, 0, 0],
                    [1, 0, 0, 0],
                    [0, 0, 0, 0]]

    Args:
        x (Variable): Input tensor of sequence_mask layer, \
            whose elements are integers less than :code:`maxlen`. \
            Tensor or LodTensor with shape [d_1, d_2, ..., d_n].
        maxlen (int, optional): Maximum length of the sequence. If :code:`maxlen` \
                           is None, it would be replace with :math:`max(x)`.
1404
        dtype (np.dtype|paddle.dtype|str, optional): Data type of the output, \
1405 1406 1407 1408 1409
             ``int64`` by default.
        name(str, optional): For detailed information, please refer \
            to :ref:`api_guide_Name`. Usually name is no need to set and \
            None by default.

1410
    Returns:
1411 1412
            Tensor, The output sequence mask. Tensor with shape [d_1, d_2, ..., d_n, maxlen]
            and data type of :code:`dtype`. The data type should be bool, float32, float64, int8,
1413 1414 1415 1416 1417
            int32 or int64.

    Examples:
        .. code-block:: python

1418 1419 1420 1421
            import paddle

            lengths = paddle.to_tensor([10, 9, 8])
            mask = paddle.nn.functional.sequence_mask(lengths)
1422

1423 1424 1425 1426
            print(mask.numpy())
            # [[1 1 1 1 1 1 1 1 1 1]
            #  [1 1 1 1 1 1 1 1 1 0]
            #  [1 1 1 1 1 1 1 1 0 0]]
1427 1428

    """
1429

1430
    return paddle.nn.functional.sequence_mask(x, maxlen, dtype, name)
1431 1432 1433 1434 1435


@templatedoc()
def sequence_reverse(x, name=None):
    """
1436
    Note:
1437
        Only receives LoDTensor as input. If your input is Tensor, please use reverse Op.(fluid.layers.** :ref:`api_fluid_layers_reverse` ).
1438

1439
    Only supports LoDTensor as input. It will reverse each sequence for input LoDTensor.
1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
    Currently it only supports 1-level LoDTensor. This operator is very useful when building a
    reverse :ref:`api_fluid_layers_DynamicRNN` network.

    .. code-block:: text

        input(x) is a LoDTensor:
            x.lod  = [[0, 2, 5]]
            x.data = [[1,  2,  3,  4],
                      [5,  6,  7,  8],
                      [9, 10, 11, 12],
                      [13,14, 15, 16],
                      [17,18, 19, 20]]
            x.shape = [5, 4]

        output LoDTensor with same shape and LoD info:
            out.lod  = [[0, 2, 5]]
            out.data = [[5,  6,  7,  8],
                        [1,  2,  3,  4],
                        [17,18, 19, 20],
                        [13,14, 15, 16],
                        [9, 10, 11, 12]]
            out.shape = [5, 4]

    Args:
        x(Variable): LoDTensor with 1-level LoD info. Currently it only supports 1-level LoDTensor.
            The data type should be float32, float64, int8, int32 or int64.
        name(str, optional): The default value is None.  Normally there is no need for user to set this property.
            For more information, please refer to :ref:`api_guide_Name` .

    Returns:
        Variable: LoDTensor reversed from input. The data type is same with input.

    Examples:
        .. code-block:: python

1475 1476 1477 1478 1479
            import paddle
            paddle.enable_static()

            x = paddle.static.data(name='x', shape=[None, 10], dtype='float32', lod_level=1)
            x_reversed = paddle.static.nn.sequence_reverse(x)
1480
    """
1481 1482 1483
    assert (
        not _non_static_mode()
    ), "sequence layer is not supported in dygraph mode yet."
1484
    helper = LayerHelper("sequence_reverse", **locals())
1485 1486 1487 1488 1489 1490
    check_variable_and_dtype(
        x,
        'x',
        ['float32', 'float64', 'int8', 'int32', 'int64'],
        'fluid.layers.sequence_reverse',
    )
1491
    out = helper.create_variable_for_type_inference(dtype=x.dtype)
1492

1493 1494 1495 1496 1497 1498
    helper.append_op(
        type="sequence_reverse",
        inputs={"X": x},
        outputs={"Y": out},
        attrs=dict(),
    )
1499
    return out