DynamicRNN_cn.rst 17.6 KB
Newer Older
H
Hao Wang 已提交
1 2 3
.. _cn_api_fluid_layers_DynamicRNN:

DynamicRNN
4
===================
H
Hao Wang 已提交
5 6 7

.. py:class:: paddle.fluid.layers.DynamicRNN(name=None)

8 9
**注意:该类型的输入仅支持LoDTensor,如果您需要处理的输入数据是Tensor类型,
请使用StaticRNN( fluid.layers.** :ref:`cn_api_fluid_layers_StaticRNN` **)。**
H
Hao Wang 已提交
10

11 12 13 14 15
DynamicRNN可以处理一批序列数据,其中每个样本序列的长度可以不同,每个序列的长度信息记录在LoD里面。
DynamicRNN会按照时间步 (time step) 将输入序列展开,用户可以在 :code:`block` 中定义每个时间步要进行的运算。
由于每个输入样本的序列长度不相同,RNN执行的step数由最长的序列决定。
DynamicRNN的实现采用非padding的方式,每个时间步都会对输入数据进行收缩处理,移除已经处理完的序列的信息。
因此,随着时间步的增加,每个时间步处理的样本数(batch size)会逐渐减少。
H
Hao Wang 已提交
16

17 18 19 20 21 22 23 24 25 26 27 28 29 30
.. warning::
  目前不支持在DynamicRNN的 :code:`block` 中任何层上配置 :code:`is_sparse = True` 。

参数:
    - **name** (str,可选) - 具体用法参见 :ref:`api_guide_Name` ,一般无需设置,默认值为None。

成员函数列表:
    - :ref:`cn_api_fluid_layers_DynamicRNN_step_input` ,设置输入变量
    - :ref:`cn_api_fluid_layers_DynamicRNN_static_input` ,设置静态输入变量
    - :ref:`cn_api_fluid_layers_DynamicRNN_block` ,定义每个时间步执行的运算
    - :ref:`cn_api_fluid_layers_DynamicRNN_memory` ,创建用于在时间步之间传递信息的变量
    - :ref:`cn_api_fluid_layers_DynamicRNN_update_memory` ,更新需要传递的时间步信息
    - :ref:`cn_api_fluid_layers_DynamicRNN_output` ,设置时间步的输出变量
    - :ref:`cn_api_fluid_layers_DynamicRNN_call` ,获取RNN的输出序列
H
Hao Wang 已提交
31 32


33
.. _cn_api_fluid_layers_DynamicRNN_step_input:
H
Hao Wang 已提交
34

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
成员函数 step_input
---------------------------------

.. py:method:: step_input(x, level=0)

将序列x设置为DynamicRNN输入。输入序列中最长的序列长度,将决定了RNN运算的长度。
必须至少为DynamicRNN设置一个输入,也可以设置多个输入。
如果多个输入x的 :code:`x.lod_level` 都为1,则要求多个输入LoDTensor携带完全相同的LoD信息。
当输入x的 :code:`x.lod_level >= 2` 时,输入序列将按指定level进行展开,每个时间步携带 :code:`x.lod_level - level - 1` 层LoD信息,
此时要求多个输入序列的LoD在指定level上的信息完全一样。

- 示例1

.. code-block:: text

    # 输入,其中Si代表维度为[1, N]的数据
    level = 0
    x.lod = [[2, 1, 3]]
    x.shape = [6, N]
    x.data = [[S0],
              [S0],
              [S1],
              [S2],
              [S2],
              [S2]]

    # 输出
    # step 0,持有3个序列的time step数据
    out.lod = [[]]
    out.shape = [3, N]
    out.data = [[S2],
                [S0],
                [S1]]

    # step 1,持有2个序列的time step数据
    out.lod = [[]]
    out.shape = [2, N]
    out.data = [[S2],
                [S0]]

    # step 2,持有1个序列的time step数据
    out.lod = [[]]
    out.shape = [1, N]
    out.data = [[S2]]


参数:
    - **x** (Variable) - 输入序列LoDTensor,代表由长度不同的多个序列组成的minibatch,要求 :code:`x.lod_level >= 1`。输入x第一个维度的值等于minibatch内所有序列的长度之和。RNN有多个输入序列时,多个输入LoDTensor的第一个维度必须相同,其它维度可以不同。支持的数据类型有:bool,float16,float32,float64,int8,int16,int32,int64,uint8。
    - **level** (int,可选) - 用于拆分输入序列的LoD层级,取值范围是 :math:`[0, x.lod\_level)`,默认值是0。

返回: 输入序列每个时间步的数据。执行第 :code:`step_idx` 个时间步时,若输入 :code:`x` 中有 :code:`num_sequences` 个长度不小于 :code:`step_idx` 的序列,则这个时间步返回值中只包含了这 :code:`num_sequences` 个序列第 :code:`step_idx` 时间步的数据。数据类型和输入一致。如果 :code:`x.lod_level == 1` ,返回值的维度是 :math:`\{num\_sequences, x.shape[1], ...\}`。否则,返回值也是一个变长的LoDTensor。

返回类型:Variable

抛出异常:
    - :code:`ValueError` :当 :code:`step_input()` 接口在RNN :code:`block()` 接口外面被调用时。
    - :code:`TypeError`:当输入x类型不是Variable时。
H
Hao Wang 已提交
92 93 94 95 96 97


**代码示例**

..  code-block:: python

98
      import paddle.fluid as fluid
H
Hao Wang 已提交
99

100 101
      sentence = fluid.data(name='sentence', shape=[None, 1], dtype='int64', lod_level=1)
      embedding = fluid.layers.embedding(input=sentence, size=[65536, 32], is_sparse=True)
H
Hao Wang 已提交
102

103 104 105 106 107 108 109 110 111 112 113
      drnn = fluid.layers.DynamicRNN()
      with drnn.block():
          # 将embedding标记为RNN的输入,每个时间步取句子中的一个字进行处理
          word = drnn.step_input(embedding)
          # 将memory初始化为一个值为0的常量Tensor,shape=[batch_size, 200],其中batch_size由输入embedding决定
          memory = drnn.memory(shape=[200])
          hidden = fluid.layers.fc(input=[word, memory], size=200, act='relu')
          # 用hidden更新memory
          drnn.update_memory(ex_mem=memory, new_mem=hidden)
          # 将hidden标记为RNN的输出
          drnn.output(hidden)
H
Hao Wang 已提交
114

115 116
      # 获得RNN的计算结果
      rnn_output = drnn()
H
Hao Wang 已提交
117 118


119 120 121 122
.. _cn_api_fluid_layers_DynamicRNN_static_input:

成员函数 static_input
---------------------------------
H
Hao Wang 已提交
123 124 125

.. py:method:: static_input(x)

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
将变量设置为RNN的静态输入。

- 示例1,静态输入携带LoD信息

.. code-block:: text

    # RNN的输入见step_input中的示例
    # 静态输入,其中Si代表维度为[1, M]的数据
    x.lod = [[3, 1, 2]]
    x.shape = [6, M]
    x.data = [[S0],
              [S0],
              [S0],
              [S1],
              [S2],
              [S2]]

    # step 0,持有3个序列对应的数据
    out.lod = [[2, 3, 1]]
    out.shape = [6, M]
    out.data = [[S2],
                [S2],
                [S0],
                [S0],
                [S0],
                [S1]]

    # step 1,持有2个序列对应的数据
    out.lod = [[2, 3]]
    out.shape = [5, M]
    out.data = [[S2],
                [S2],
                [S0],
                [S0],
                [S0]]

    # step 2,持有1个序列对应的数据
    out.lod = [[2]]
    out.shape = [2, M]
    out.data = [[S2],
                [S2]]


- 示例2,静态输入不携带LoD信息

.. code-block:: text

    # RNN的输入见step_input中的示例
    # 静态输入,其中Si代表维度为[1, M]的数据
    x.lod = [[]]
    x.shape = [3, M]
    x.data = [[S0],
              [S1],
              [S2]]

    # step 0,持有3个序列对应的数据
    out.lod = [[]]
    out.shape = [3, M]
    out.data = [[S2],
                [S0],
                [S1]]

    # step 1,持有2个序列对应的数据
    out.lod = [[]]
    out.shape = [2, M]
    out.data = [[S2],
                [S0]]

    # step 2,持有1个序列对应的数据
    out.lod = [[]]
    out.shape = [1, M]
    out.data = [[S2]]

H
Hao Wang 已提交
199 200

参数:
201 202 203
    - **x** (Variable) - 静态输入序列LoDTensor,要求持有与输入LoDTensor(通过 :code:`step_input` 设置的输入)相同的序列个数。如果输入x的LoD信息为空,则会被当成由 :code:`x.shape[0]` 个长度为1序列组成。支持的数据类型有:bool,float16,float32,float64,int8,int16,int32,int64,uint8。

返回: 经过按照RNN输入LoD信息重排序、且收缩处理后的静态输入LoDTensor。执行第 :code:`step_idx` 个时间步时,如果输入序列中只有 :code:`num_sequences` 长度不小于 :code:`step_idx` 的序列,静态输入也会进行收缩处理,只返回对应的 :code:`num_sequences` 个序列对应的数据。数据类型和输入一致。如果 :code:`x.lod == None` ,返回值的维度是 :math:`\{num\_sequences, x.shape[1], ...\}` 。否则,返回值是一个变长的LoDTensor。
H
Hao Wang 已提交
204

205 206 207 208 209 210
返回类型:Variable

抛出异常:
    - :code:`ValueError`:当 :code:`static_input()` 接口在RNN :code:`block()` 接口外面被调用时。
    - :code:`TypeError`:当输入x类型不是Variable类型时。
    - :code:`RuntimeError`:当 :code:`static_input()` 接口在 :code:`step_input()` 接口之前被调用时。
H
Hao Wang 已提交
211 212 213 214 215 216

**代码示例**

..  code-block:: python

    import paddle.fluid as fluid
217 218 219 220 221

    sentence = fluid.data(name='sentence', shape=[None, 32], dtype='float32', lod_level=1)
    encoder_proj = fluid.data(name='encoder_proj', shape=[None, 32], dtype='float32', lod_level=1)
    decoder_boot = fluid.data(name='boot', shape=[None, 10], dtype='float32')

H
Hao Wang 已提交
222 223
    drnn = fluid.layers.DynamicRNN()
    with drnn.block():
224
        # 将sentence标记为RNN的输入,每个时间步取句子中的一个字进行处理
H
Hao Wang 已提交
225
        current_word = drnn.step_input(sentence)
226
        # 将encode_proj标记为RNN的静态输入
H
Hao Wang 已提交
227
        encoder_word = drnn.static_input(encoder_proj)
228 229 230 231
        # 使用boot_memory初始化memory,并且需要依据输入序列进行重排序
        memory = drnn.memory(init=decoder_boot, need_reorder=True)
        fc_1 = fluid.layers.fc(input=encoder_word, size=30)
        fc_2 = fluid.layers.fc(input=current_word, size=30)
H
Hao Wang 已提交
232
        decoder_inputs = fc_1 + fc_2
233 234 235 236 237
        hidden, _, _ = fluid.layers.gru_unit(input=decoder_inputs, hidden=memory, size=30)
        # 用hidden更新memory
        drnn.update_memory(ex_mem=memory, new_mem=hidden)
        out = fluid.layers.fc(input=hidden, size=10, bias_attr=True, act='softmax')
        # 将out标记为RNN的输出
H
Hao Wang 已提交
238
        drnn.output(out)
239 240

    # 获得RNN的计算结果
H
Hao Wang 已提交
241 242 243
    rnn_output = drnn()


244 245 246 247 248
.. _cn_api_fluid_layers_DynamicRNN_block:

成员函数 block
---------------------------------

H
Hao Wang 已提交
249 250
.. py:method:: block()

251
定义每个时间步执行的操作。 :code:`block` 语句里面定义的算子序列,将会被执行 :code:`max_sequence_len` 次( :code:`max_sequence_len` 是输入序列中大的序列长度)。
H
Hao Wang 已提交
252

253 254
抛出异常:
    - :code:`ValueError`:当RNN :code:`block()` 接口被多次调用时。
H
Hao Wang 已提交
255 256


257
.. _cn_api_fluid_layers_DynamicRNN_memory:
H
Hao Wang 已提交
258

259 260
成员函数 memory
---------------------------------
H
Hao Wang 已提交
261

262
.. py:method:: memory(init=None, shape=None, value=0.0, need_reorder=False, dtype='float32')
H
Hao Wang 已提交
263

264 265
为RNN创建一个memory变量,用于在时间步之间传递信息。
它可以用一个已有的Tensor来初始化,也可以初始化为一个特定维度的常量Tensor。
H
Hao Wang 已提交
266

267 268 269 270 271 272
参数:
    - **init** (Variable,可选) – 设置memory初始值的LoDTensor。如果init不是None,将使用init来初始化memory,要求持有与输入LoDTensor(通过 :code:`step_input` 设置的输入)相同的序列个数。如果输入init的LoD信息为空,则会被当成由 :code:`init.shape[0]` 个长度为1序列组成。默认值是None。
    - **shape** (list|tuple,可选) – 当init是None时,用来设置memory的维度。注意:shape中不包含batch_size。若设置 :math:`shape=\{D_1, D_2, ...\}`,memory Tensor的实际维度为 :math:`\{batch\_size, D_1, D_2, ...\}`,其中batch_size由输入序列决定。默认值是None。
    - **value** (float,可选) – 当init是None时,用来设置memory的初始值。默认值是0.0。
    - **need_reorder** (bool,可选) – 当init不是None时,用来决定init是否需要重新排序。动态RNN在计算时,会按照输入LoDTensor中序列的长度对输入进行排序,因此当init中的信息与输入序列样本紧密关联时,需要设置 :code:`need_reorder=True`。默认值是False。
    - **dtype** (str|numpy.dtype,可选) – 当init是None是,初始化memory的数据类型。默认值是"float32"。可设置的字符串值有:"float32","float64","int32","int64"。
H
Hao Wang 已提交
273

274
返回:经过收缩处理后的memory LoDTensor。执行第 :code:`step_idx` 个时间步时,如果输入序列中只有 :code:`num_sequences` 长度不小于 :code:`step_idx` 的序列,memory也会进行收缩处理,只返回对应的 :code:`num_sequences` 个序列对应的数据。
H
Hao Wang 已提交
275

276
返回类型:Variable
H
Hao Wang 已提交
277

278 279 280 281
抛出异常:
    - :code:`ValueError`:当 :code:`memory()` 接口在RNN :code:`block()` 接口外面被调用时。
    - :code:`TypeError`:当init被设置了,但是不是Variable类型时。
    - :code:`ValueError`:当 :code:`memory()` 接口在 :code:`step_input()` 接口之前被调用时。
H
Hao Wang 已提交
282

283
**代码示例一**
H
Hao Wang 已提交
284 285 286

..  code-block:: python

287
    import paddle.fluid as fluid
H
Hao Wang 已提交
288

289 290
    sentence = fluid.data(name='sentence', shape=[None, 32], dtype='float32', lod_level=1)
    boot_memory = fluid.data(name='boot', shape=[None, 10], dtype='float32')
H
Hao Wang 已提交
291

292 293 294 295 296 297 298 299 300 301 302 303 304 305
    drnn = fluid.layers.DynamicRNN()
    with drnn.block():
        # 将sentence标记为RNN的输入,每个时间步取句子中的一个字进行处理
        word = drnn.step_input(sentence)
        # 使用boot_memory初始化memory,并且需要依据输入序列进行重排序
        memory = drnn.memory(init=boot_memory, need_reorder=True)
        hidden = fluid.layers.fc(input=[word, memory], size=10, act='tanh')
        # 用hidden更新memory
        drnn.update_memory(ex_mem=memory, new_mem=hidden)
        # 将hidden标记为RNN的输出
        drnn.output(hidden)

    # 获得RNN的计算结果
    rnn_output = drnn()
H
Hao Wang 已提交
306 307


308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
**代码示例二**

..  code-block:: python

    import paddle.fluid as fluid

    sentence = fluid.data(name='sentence', shape=[None, 32], dtype='float32', lod_level=1)

    drnn = fluid.layers.DynamicRNN()
    with drnn.block():
        # 将sentence标记为RNN的输入,每个时间步取句子中的一个字进行处理
        word = drnn.step_input(sentence)
        # 将memory初始化为一个值为0的常量Tensor,shape=[batch_size, 10],其中batch_size由输入sentence决定
        memory = drnn.memory(shape=[10], dtype='float32', value=0)
        hidden = fluid.layers.fc(input=[word, memory], size=10, act='tanh')
        # 用hidden更新memory
        drnn.update_memory(ex_mem=memory, new_mem=hidden)
        # 将hidden标记为RNN的输出
        drnn.output(hidden)

    # 获得RNN的计算结果
    rnn_output = drnn()
H
Hao Wang 已提交
330 331


332
.. _cn_api_fluid_layers_DynamicRNN_update_memory:
H
Hao Wang 已提交
333

334 335
成员函数 update_memory
---------------------------------
H
Hao Wang 已提交
336 337 338

.. py:method:: update_memory(ex_mem, new_mem)

339
将需要在时间步之间传递的信息更新。
H
Hao Wang 已提交
340 341

参数:
342 343
  - **ex_mem** (Variable) - 上一个时间步的信息。
  - **new_mem** (Variable) - 新的时间步信息。:code:`new_mem` 的维度和数据类型必须与 :code:`ex_mem` 一致。
H
Hao Wang 已提交
344

345
返回:无
H
Hao Wang 已提交
346

347 348 349 350 351 352 353 354 355 356 357
抛出异常:
    - :code:`ValueError`:当 :code:`update_memory()` 接口在RNN :code:`block()` 接口外面被调用时。
    - :code:`TypeError`:当 :code:`ex_mem` 或 :code:`new_mem` 不是Variable类型时。
    - :code:`ValueError`:当 :code:`ex_mem` 不是使用 :code:`memory()` 接口定义的memory时。
    - :code:`ValueError`:当 :code:`update_memory()` 接口在 :code:`step_input()` 接口之前被调用时。


.. _cn_api_fluid_layers_DynamicRNN_output:

成员函数 output
---------------------------------
H
Hao Wang 已提交
358 359 360

.. py:method:: output(*outputs)

361
设置outputs为RNN每个时间步的输出变量。
H
Hao Wang 已提交
362

363 364 365 366
参数:
    - **\*outputs** (Variable ...) - 输出Tensor,可同时将多个Variable标记为输出。

返回:无
H
Hao Wang 已提交
367

368 369
抛出异常:
    - :code:`ValueError`:当 :code:`output()` 接口在RNN :code:`block()` 接口外面被调用时。
H
Hao Wang 已提交
370 371


372
.. _cn_api_fluid_layers_DynamicRNN_call:
H
Hao Wang 已提交
373

374 375
成员函数 __call__
---------------------------------
H
Hao Wang 已提交
376

377
.. py:method:: __call__()
H
Hao Wang 已提交
378

379
获取RNN计算的输出序列。
H
Hao Wang 已提交
380

381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 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
若定义了 :code:`drnn = DynamicRNN()`,则可以调用 :code:`drnn()` 获得输出序列,该输出序列是通过将每一个时间步的output数据合并得到的一个LoDTensor。
当RNN的输入x(通过 :code:`step_input()` 接口设置)的 :code:`x.lod_level` 为1时,该输出LoDTensor将会和输入x持有完全相同的LoD信息。
通过 :code:`drnn()` 获取的RNN输出LoDTensor中包含了所有时间步的计算结果,可调用 :ref:`cn_api_fluid_layers_sequence_last_step` 获取最后一个时间步的计算结果。

参数:


返回:RNN的输出序列。

返回类型:Variable或Variable list

抛出异常:
    - :code:`ValueError` :当 :code:`__call__()` 接口在RNN :code:`block()` 定义之前被调用时。

**代码示例**

..  code-block:: python

    import paddle.fluid as fluid

    sentence = fluid.data(name='sentence', shape=[None, 32], dtype='float32', lod_level=1)
    encoder_proj = fluid.data(name='encoder_proj', shape=[None, 32], dtype='float32', lod_level=1)
    decoder_boot = fluid.data(name='boot', shape=[None, 10], dtype='float32')

    drnn = fluid.layers.DynamicRNN()
    with drnn.block():
        # 将sentence标记为RNN的输入,每个时间步取句子中的一个字进行处理
        current_word = drnn.step_input(sentence)
        # 将encode_proj标记为RNN的静态输入
        encoder_word = drnn.static_input(encoder_proj)
        # 使用boot_memory初始化memory,并且需要依据输入序列进行重排序
        memory = drnn.memory(init=decoder_boot, need_reorder=True)
        fc_1 = fluid.layers.fc(input=encoder_word, size=30)
        fc_2 = fluid.layers.fc(input=current_word, size=30)
        decoder_inputs = fc_1 + fc_2
        hidden, _, _ = fluid.layers.gru_unit(input=decoder_inputs, hidden=memory, size=30)
        # 用hidden更新memory
        drnn.update_memory(ex_mem=memory, new_mem=hidden)
        out = fluid.layers.fc(input=hidden, size=10, bias_attr=True, act='softmax')
        # 将hidden和out标记为RNN的输出
        drnn.output(hidden, out)

    # 获得RNN的计算结果
    hidden, out = drnn()
    # 提取RNN最后一个时间步的计算结果
    last = fluid.layers.sequence_last_step(out)