DynamicRNN

  • class paddle.fluid.layers.DynamicRNN(name=None)[源代码]

注意:该类型的输入仅支持LoDTensor,如果您需要处理的输入数据是Tensor类型, 请使用StaticRNN( fluid.layers. StaticRNN )。

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

警告

目前不支持在DynamicRNN的 block 中任何层上配置 is_sparse = True

成员函数 step_input

  • step_input(x, level=0)

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

  • 示例1
  1. # 输入,其中Si代表维度为[1, N]的数据
  2. level = 0
  3. x.lod = [[2, 1, 3]]
  4. x.shape = [6, N]
  5. x.data = [[S0],
  6. [S0],
  7. [S1],
  8. [S2],
  9. [S2],
  10. [S2]]
  11.  
  12. # 输出
  13. # step 0,持有3个序列的time step数据
  14. out.lod = [[]]
  15. out.shape = [3, N]
  16. out.data = [[S2],
  17. [S0],
  18. [S1]]
  19.  
  20. # step 1,持有2个序列的time step数据
  21. out.lod = [[]]
  22. out.shape = [2, N]
  23. out.data = [[S2],
  24. [S0]]
  25.  
  26. # step 2,持有1个序列的time step数据
  27. out.lod = [[]]
  28. out.shape = [1, N]
  29. out.data = [[S2]]
  • 参数:
    • x (Variable) - 输入序列LoDTensor,代表由长度不同的多个序列组成的minibatch,要求 x.lod_level >= 1。输入x第一个维度的值等于minibatch内所有序列的长度之和。RNN有多个输入序列时,多个输入LoDTensor的第一个维度必须相同,其它维度可以不同。支持的数据类型有:bool,float16,float32,float64,int8,int16,int32,int64,uint8。
    • level (int,可选) - 用于拆分输入序列的LoD层级,取值范围是 DynamicRNN - 图1 ,默认值是0。

返回: 输入序列每个时间步的数据。执行第 step_idx 个时间步时,若输入 x 中有 num_sequences 个长度不小于 step_idx 的序列,则这个时间步返回值中只包含了这 num_sequences 个序列第 step_idx 时间步的数据。数据类型和输入一致。如果 x.lod_level == 1 ,返回值的维度是

DynamicRNN - 图2 。否则,返回值也是一个变长的LoDTensor。

返回类型:Variable

  • 抛出异常:
    • ValueError :当 step_input() 接口在RNN block() 接口外面被调用时。
    • TypeError:当输入x类型不是Variable时。

代码示例

  1. import paddle.fluid as fluid
  2.  
  3. sentence = fluid.data(name='sentence', shape=[None, 1], dtype='int64', lod_level=1)
  4. embedding = fluid.layers.embedding(input=sentence, size=[65536, 32], is_sparse=True)
  5.  
  6. drnn = fluid.layers.DynamicRNN()
  7. with drnn.block():
  8. # 将embedding标记为RNN的输入,每个时间步取句子中的一个字进行处理
  9. word = drnn.step_input(embedding)
  10. # 将memory初始化为一个值为0的常量Tensor,shape=[batch_size, 200],其中batch_size由输入embedding决定
  11. memory = drnn.memory(shape=[200])
  12. hidden = fluid.layers.fc(input=[word, memory], size=200, act='relu')
  13. # 用hidden更新memory
  14. drnn.update_memory(ex_mem=memory, new_mem=hidden)
  15. # 将hidden标记为RNN的输出
  16. drnn.output(hidden)
  17.  
  18. # 获得RNN的计算结果
  19. rnn_output = drnn()

成员函数 static_input

  • static_input(x)

将变量设置为RNN的静态输入。

  • 示例1,静态输入携带LoD信息
  1. # RNN的输入见step_input中的示例
  2. # 静态输入,其中Si代表维度为[1, M]的数据
  3. x.lod = [[3, 1, 2]]
  4. x.shape = [6, M]
  5. x.data = [[S0],
  6. [S0],
  7. [S0],
  8. [S1],
  9. [S2],
  10. [S2]]
  11.  
  12. # step 0,持有3个序列对应的数据
  13. out.lod = [[2, 3, 1]]
  14. out.shape = [6, M]
  15. out.data = [[S2],
  16. [S2],
  17. [S0],
  18. [S0],
  19. [S0],
  20. [S1]]
  21.  
  22. # step 1,持有2个序列对应的数据
  23. out.lod = [[2, 3]]
  24. out.shape = [5, M]
  25. out.data = [[S2],
  26. [S2],
  27. [S0],
  28. [S0],
  29. [S0]]
  30.  
  31. # step 2,持有1个序列对应的数据
  32. out.lod = [[2]]
  33. out.shape = [2, M]
  34. out.data = [[S2],
  35. [S2]]
  • 示例2,静态输入不携带LoD信息
  1. # RNN的输入见step_input中的示例
  2. # 静态输入,其中Si代表维度为[1, M]的数据
  3. x.lod = [[]]
  4. x.shape = [3, M]
  5. x.data = [[S0],
  6. [S1],
  7. [S2]]
  8.  
  9. # step 0,持有3个序列对应的数据
  10. out.lod = [[]]
  11. out.shape = [3, M]
  12. out.data = [[S2],
  13. [S0],
  14. [S1]]
  15.  
  16. # step 1,持有2个序列对应的数据
  17. out.lod = [[]]
  18. out.shape = [2, M]
  19. out.data = [[S2],
  20. [S0]]
  21.  
  22. # step 2,持有1个序列对应的数据
  23. out.lod = [[]]
  24. out.shape = [1, M]
  25. out.data = [[S2]]
  • 参数:
    • x (Variable) - 静态输入序列LoDTensor,要求持有与输入LoDTensor(通过 step_input 设置的输入)相同的序列个数。如果输入x的LoD信息为空,则会被当成由 x.shape[0] 个长度为1序列组成。支持的数据类型有:bool,float16,float32,float64,int8,int16,int32,int64,uint8。

返回: 经过按照RNN输入LoD信息重排序、且收缩处理后的静态输入LoDTensor。执行第 step_idx 个时间步时,如果输入序列中只有 num_sequences 长度不小于 step_idx 的序列,静态输入也会进行收缩处理,只返回对应的 num_sequences 个序列对应的数据。数据类型和输入一致。如果 x.lod == None ,返回值的维度是

DynamicRNN - 图3 。否则,返回值是一个变长的LoDTensor。

返回类型:Variable

  • 抛出异常:
    • ValueError:当 static_input() 接口在RNN block() 接口外面被调用时。
    • TypeError:当输入x类型不是Variable类型时。
    • RuntimeError:当 static_input() 接口在 step_input() 接口之前被调用时。

代码示例

  1. import paddle.fluid as fluid
  2.  
  3. sentence = fluid.data(name='sentence', shape=[None, 32], dtype='float32', lod_level=1)
  4. encoder_proj = fluid.data(name='encoder_proj', shape=[None, 32], dtype='float32', lod_level=1)
  5. decoder_boot = fluid.data(name='boot', shape=[None, 10], dtype='float32')
  6.  
  7. drnn = fluid.layers.DynamicRNN()
  8. with drnn.block():
  9. # 将sentence标记为RNN的输入,每个时间步取句子中的一个字进行处理
  10. current_word = drnn.step_input(sentence)
  11. # 将encode_proj标记为RNN的静态输入
  12. encoder_word = drnn.static_input(encoder_proj)
  13. # 使用boot_memory初始化memory,并且需要依据输入序列进行重排序
  14. memory = drnn.memory(init=decoder_boot, need_reorder=True)
  15. fc_1 = fluid.layers.fc(input=encoder_word, size=30)
  16. fc_2 = fluid.layers.fc(input=current_word, size=30)
  17. decoder_inputs = fc_1 + fc_2
  18. hidden, _, _ = fluid.layers.gru_unit(input=decoder_inputs, hidden=memory, size=30)
  19. # 用hidden更新memory
  20. drnn.update_memory(ex_mem=memory, new_mem=hidden)
  21. out = fluid.layers.fc(input=hidden, size=10, bias_attr=True, act='softmax')
  22. # 将out标记为RNN的输出
  23. drnn.output(out)
  24.  
  25. # 获得RNN的计算结果
  26. rnn_output = drnn()

成员函数 block

  • block()

定义每个时间步执行的操作。 block 语句里面定义的算子序列,将会被执行 max_sequence_len 次( max_sequence_len 是输入序列中大的序列长度)。

  • 抛出异常:
    • ValueError:当RNN block() 接口被多次调用时。

成员函数 memory

  • memory(init=None, shape=None, value=0.0, need_reorder=False, dtype='float32')

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

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

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

返回类型:Variable

  • 抛出异常:
    • ValueError:当 memory() 接口在RNN block() 接口外面被调用时。
    • TypeError:当init被设置了,但是不是Variable类型时。
    • ValueError:当 memory() 接口在 step_input() 接口之前被调用时。

代码示例一

  1. import paddle.fluid as fluid
  2.  
  3. sentence = fluid.data(name='sentence', shape=[None, 32], dtype='float32', lod_level=1)
  4. boot_memory = fluid.data(name='boot', shape=[None, 10], dtype='float32')
  5.  
  6. drnn = fluid.layers.DynamicRNN()
  7. with drnn.block():
  8. # 将sentence标记为RNN的输入,每个时间步取句子中的一个字进行处理
  9. word = drnn.step_input(sentence)
  10. # 使用boot_memory初始化memory,并且需要依据输入序列进行重排序
  11. memory = drnn.memory(init=boot_memory, need_reorder=True)
  12. hidden = fluid.layers.fc(input=[word, memory], size=10, act='tanh')
  13. # 用hidden更新memory
  14. drnn.update_memory(ex_mem=memory, new_mem=hidden)
  15. # 将hidden标记为RNN的输出
  16. drnn.output(hidden)
  17.  
  18. # 获得RNN的计算结果
  19. rnn_output = drnn()

代码示例二

  1. import paddle.fluid as fluid
  2.  
  3. sentence = fluid.data(name='sentence', shape=[None, 32], dtype='float32', lod_level=1)
  4.  
  5. drnn = fluid.layers.DynamicRNN()
  6. with drnn.block():
  7. # 将sentence标记为RNN的输入,每个时间步取句子中的一个字进行处理
  8. word = drnn.step_input(sentence)
  9. # 将memory初始化为一个值为0的常量Tensor,shape=[batch_size, 10],其中batch_size由输入sentence决定
  10. memory = drnn.memory(shape=[10], dtype='float32', value=0)
  11. hidden = fluid.layers.fc(input=[word, memory], size=10, act='tanh')
  12. # 用hidden更新memory
  13. drnn.update_memory(ex_mem=memory, new_mem=hidden)
  14. # 将hidden标记为RNN的输出
  15. drnn.output(hidden)
  16.  
  17. # 获得RNN的计算结果
  18. rnn_output = drnn()

成员函数 update_memory

  • update_memory(ex_mem, new_mem)

将需要在时间步之间传递的信息更新。

  • 参数:
    • ex_mem (Variable) - 上一个时间步的信息。
    • new_mem (Variable) - 新的时间步信息。new_mem 的维度和数据类型必须与 ex_mem 一致。

返回:无

  • 抛出异常:
    • ValueError:当 update_memory() 接口在RNN block() 接口外面被调用时。
    • TypeError:当 ex_memnew_mem 不是Variable类型时。
    • ValueError:当 ex_mem 不是使用 memory() 接口定义的memory时。
    • ValueError:当 update_memory() 接口在 step_input() 接口之前被调用时。

成员函数 output

  • output(*outputs)

设置outputs为RNN每个时间步的输出变量。

  • 参数:
    • *outputs (Variable …) - 输出Tensor,可同时将多个Variable标记为输出。

返回:无

  • 抛出异常:
    • ValueError:当 output() 接口在RNN block() 接口外面被调用时。

成员函数 call

  • __call__()

获取RNN计算的输出序列。

若定义了 drnn = DynamicRNN(),则可以调用 drnn() 获得输出序列,该输出序列是通过将每一个时间步的output数据合并得到的一个LoDTensor。 当RNN的输入x(通过 step_input() 接口设置)的 x.lod_level 为1时,该输出LoDTensor将会和输入x持有完全相同的LoD信息。 通过 drnn() 获取的RNN输出LoDTensor中包含了所有时间步的计算结果,可调用 sequence_last_step 获取最后一个时间步的计算结果。

  • 参数:

返回:RNN的输出序列。

返回类型:Variable或Variable list

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

代码示例

  1. import paddle.fluid as fluid
  2.  
  3. sentence = fluid.data(name='sentence', shape=[None, 32], dtype='float32', lod_level=1)
  4. encoder_proj = fluid.data(name='encoder_proj', shape=[None, 32], dtype='float32', lod_level=1)
  5. decoder_boot = fluid.data(name='boot', shape=[None, 10], dtype='float32')
  6.  
  7. drnn = fluid.layers.DynamicRNN()
  8. with drnn.block():
  9. # 将sentence标记为RNN的输入,每个时间步取句子中的一个字进行处理
  10. current_word = drnn.step_input(sentence)
  11. # 将encode_proj标记为RNN的静态输入
  12. encoder_word = drnn.static_input(encoder_proj)
  13. # 使用boot_memory初始化memory,并且需要依据输入序列进行重排序
  14. memory = drnn.memory(init=decoder_boot, need_reorder=True)
  15. fc_1 = fluid.layers.fc(input=encoder_word, size=30)
  16. fc_2 = fluid.layers.fc(input=current_word, size=30)
  17. decoder_inputs = fc_1 + fc_2
  18. hidden, _, _ = fluid.layers.gru_unit(input=decoder_inputs, hidden=memory, size=30)
  19. # 用hidden更新memory
  20. drnn.update_memory(ex_mem=memory, new_mem=hidden)
  21. out = fluid.layers.fc(input=hidden, size=10, bias_attr=True, act='softmax')
  22. # 将hidden和out标记为RNN的输出
  23. drnn.output(hidden, out)
  24.  
  25. # 获得RNN的计算结果
  26. hidden, out = drnn()
  27. # 提取RNN最后一个时间步的计算结果
  28. last = fluid.layers.sequence_last_step(out)