提交 00b86b1f 编写于 作者: Y Yu Yang

Follow comments

上级 aed8803a
...@@ -4,14 +4,14 @@ ...@@ -4,14 +4,14 @@
单双层RNN API对比介绍 单双层RNN API对比介绍
##################### #####################
这篇教程主要介绍了\ :ref:`glossary_双层RNN`\ 的API接口。本文以PaddlePaddle的\ :ref:`glossary_双层RNN`\ 单元测试为示例,用多对效果完全相同的、分别使用单双层RNN作为网络配置的模型,来讲解如何使用\ :ref:`glossary_双层RNN`\ 。本文中所有的例子,都只是介绍\ :ref:`glossary_双层RNN`\ 的API接口,并不是使用\ :ref:`glossary_双层RNN`\ 解决实际的问题。如果想要了解\ :ref:`glossary_双层RNN`\ 在具体问题中的使用,请参考\ :ref:`algo_hrnn_demo`\ 。本文中示例所使用的单元测试文件是\ `test_RecurrentGradientMachine.cpp <https://github.com/reyoung/Paddle/blob/develop/paddle/gserver/tests/test_RecurrentGradientMachine.cpp>`_\ 。 本文以PaddlePaddle的\ :ref:`glossary_双层RNN`\ 单元测试为示例,用多对效果完全相同的、分别使用单双层RNN作为网络配置的模型,来讲解如何使用\ :ref:`glossary_双层RNN`\ 。本文中所有的例子,都只是介绍\ :ref:`glossary_双层RNN`\ 的API接口,并不是使用\ :ref:`glossary_双层RNN`\ 解决实际的问题。如果想要了解\ :ref:`glossary_双层RNN`\ 在具体问题中的使用,请参考\ :ref:`algo_hrnn_demo`\ 。本文中示例所使用的单元测试文件是\ `test_RecurrentGradientMachine.cpp <https://github.com/reyoung/Paddle/blob/develop/paddle/gserver/tests/test_RecurrentGradientMachine.cpp>`_\ 。
示例1:双层RNN,子序列间无Memory 示例1:双层RNN,子序列间无Memory
================================ ================================
在\ :ref:`glossary_双层RNN`\ 中的经典情况是将内层的每一个\ :ref:`glossary_sequence`\ 数据,分别进行序列操作。并且内层的序列操作之间是独立没有依赖的,即不需要使用\ :ref:`glossary_Memory`\ 的 在\ :ref:`glossary_双层RNN`\ 中的经典情况是将内层的每一个\ :ref:`glossary_sequence`\ 数据,分别进行序列操作;并且内层的序列操作之间独立无依赖,即不需要使用\ :ref:`glossary_Memory`\
在本示例中,单层\ :ref:`glossary_RNN`\ 和\ :ref:`glossary_双层RNN`\ 的网络配置,都是将每一句分好词后的句子,使用LSTM作为encoder,压缩成一个向量。区别是\ :ref:`glossary_RNN`\ 使用两层序列模型,将多句话看成一个整体,同时使用encoder压缩,二者语意上完全一致。这组语意相同的示例配置如下 在本示例中,单层\ :ref:`glossary_RNN`\ 和\ :ref:`glossary_双层RNN`\ 的网络配置,都是将每一句分好词后的句子,使用LSTM作为encoder,压缩成一个向量。区别是\ :ref:`glossary_RNN`\ 使用两层序列模型,将多句话看成一个整体同时使用encoder压缩。二者语意上完全一致。这组语义相同的示例配置如下:
* 单层\ :ref:`glossary_RNN`\: `sequence_layer_group.conf <https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/gserver/tests/sequence_layer_group.conf>`_ * 单层\ :ref:`glossary_RNN`\: `sequence_layer_group.conf <https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/gserver/tests/sequence_layer_group.conf>`_
* :ref:`glossary_双层RNN`\: `sequence_nest_layer_group.conf <https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/gserver/tests/sequence_nest_layer_group.conf>`_ * :ref:`glossary_双层RNN`\: `sequence_nest_layer_group.conf <https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/gserver/tests/sequence_nest_layer_group.conf>`_
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
:language: text :language: text
- 双层序列数据一共有4个样本。 每个样本间用空行分开,整体数据和原始数据完全一样。而对于双层序列的LSTM来说,第一条数据同时encode两条数据成两个向量。这四条数据同时处理的句子为\ :code:`[2, 3, 2, 3]`\ 。 - 双层序列数据一共有4个样本。 每个样本间用空行分开,整体数据和原始数据完全一样。但于双层序列的LSTM来说,第一个样本同时encode两条数据成两个向量。这四条数据同时处理的句子数量为\ :code:`[2, 3, 2, 3]`\ 。
.. literalinclude:: ../../../paddle/gserver/tests/Sequence/tour_train_wdseg.nest .. literalinclude:: ../../../paddle/gserver/tests/Sequence/tour_train_wdseg.nest
:language: text :language: text
...@@ -51,17 +51,17 @@ ...@@ -51,17 +51,17 @@
:lines: 42-71 :lines: 42-71
:linenos: :linenos:
- 这是对于同样的数据,本示例中双层\ :ref:`glossary_sequence`\ 的\ :ref:`glossary_DataProvider`\ 代码,其说明如下: - 对于同样的数据,双层\ :ref:`glossary_sequence`\ 的\ :ref:`glossary_DataProvider`\ 的代码。其说明如下:
- :ref:`glossary_DataProvider`\ 共返回两组数据,分别是sentences和labels。即在双层序列的原始数据中,每一组内的所有句子和labels - :ref:`glossary_DataProvider`\ 共返回两组数据,分别是sentences和labels。即在双层序列的原始数据中,每一组内的所有句子和labels
- sentences是双层\ :ref:`glossary_sequence`\ 的数据。他内部包括了每组数据中的所有句子,又使用句子中每一个单词的词表index表示每一个句子,故为双层\ :ref:`glossary_sequence`\ 。类型为 integer_value_sub_sequence - sentences是双层\ :ref:`glossary_sequence`\ 的数据。由于它内部包含了每组数据中的所有句子,且每个句子表示为对应的词表索引数组,因此它是integer_value_sub_sequence 类型的,即双层\ :ref:`glossary_sequence`\
- labels是每组内每个句子的标签,故而是一个单层\ :ref:`glossary_sequence`\ 。 - labels是每组内每个句子的标签,故而是一个单层\ :ref:`glossary_sequence`\ 。
:ref:`glossary_trainer_config`\ 的模型配置 :ref:`glossary_trainer_config`\ 的模型配置
------------------------------------------ ------------------------------------------
首先,我们看一下单层\ :ref:`glossary_RNN`\ 的配置。代码中9-15行即为单层RNN序列的使用代码。这里使用了PaddlePaddle预定义好的\ :ref:`glossary_RNN`\ 处理函数。在这个函数中,\ :ref:`glossary_RNN`\ 对于每一个\ :ref:`glossary_timestep`\ 通过了一个LSTM网络。 首先,我们看一下单层\ :ref:`glossary_RNN`\ 的配置。代码中9-15行(高亮部分)即为单层RNN序列的使用代码。这里使用了PaddlePaddle预定义好的\ :ref:`glossary_RNN`\ 处理函数。在这个函数中,\ :ref:`glossary_RNN`\ 对于每一个\ :ref:`glossary_timestep`\ 通过了一个LSTM网络。
.. literalinclude:: ../../../paddle/gserver/tests/sequence_layer_group.conf .. literalinclude:: ../../../paddle/gserver/tests/sequence_layer_group.conf
:language: python :language: python
...@@ -70,19 +70,19 @@ ...@@ -70,19 +70,19 @@
:emphasize-lines: 9-15 :emphasize-lines: 9-15
其次,我们看一下语义相同的\ :ref:`glossary_双层RNN`\ 的网络配置 其次,我们看一下语义相同的\ :ref:`glossary_双层RNN`\ 的网络配置\:
* PaddlePaddle中的许多layer并不在意输入是否是\ :ref:`glossary_sequence`\ ,例如\ :code:`embedding_layer`\ 。在这些layer中,所有的操作都是针对每一个\ :ref:`glossary_timestep`\ 来进行的。 * PaddlePaddle中的许多layer并不在意输入是否是\ :ref:`glossary_sequence`\ ,例如\ :code:`embedding_layer`\ 。在这些layer中,所有的操作都是针对每一个\ :ref:`glossary_timestep`\ 来进行的。
* 在该配置中,7-26行将双层\ :ref:`glossary_sequence`\ 数据,先变换成单层\ :ref:`glossary_sequence`\ 数据,在对每一个单层\ :ref:`glossary_sequence`\ 进行处理。 * 在该配置的7-26行(高亮部分),将双层\ :ref:`glossary_sequence`\ 数据先变换成单层\ :ref:`glossary_sequence`\ 数据,再对每一个单层\ :ref:`glossary_sequence`\ 进行处理。
* 使用\ :code:`recurrent_group`\ 这个函数进行变换,在变换时需要将输入序列传入。由于我们想要的变换是双层\ :ref:`glossary_sequence`\ => 单层\ :ref:`glossary_sequence`\ ,所以我们需要将输入数据标记成\ :code:`SubsequenceInput`\ 。 * 使用\ :code:`recurrent_group`\ 这个函数进行变换,在变换时需要将输入序列传入。由于我们想要的变换是双层\ :ref:`glossary_sequence`\ => 单层\ :ref:`glossary_sequence`\ ,所以我们需要将输入数据标记成\ :code:`SubsequenceInput`\ 。
* 在本例中,我们将原始数据的每一组,通过\ :code:`recurrent_group`\ 进行拆解,拆解成的每一句话再通过一个LSTM网络。这和单层\ :ref:`glossary_RNN`\ 的配置是等价的。 * 在本例中,我们将原始数据的每一组,通过\ :code:`recurrent_group`\ 进行拆解,拆解成的每一句话再通过一个LSTM网络。这和单层\ :ref:`glossary_RNN`\ 的配置是等价的。
* 与单层\ :ref:`glossary_RNN`\ 的配置类似,我们只需要知道使用LSTM encode成的最后一个向量。所以对\ :code:`recurrent_group`\ 进行了\ :code:`last_seq`\ 操作。但是,和单层\ :ref:`glossary_RNN`\ 有区别的地方是,我们是对每一个子序列取最后一个元素。于是我们设置\ :code:`agg_level=AggregateLevel.EACH_SEQUENCE`\ 。 * 与单层\ :ref:`glossary_RNN`\ 的配置类似,我们只需要使用LSTM encode成的最后一个向量。所以对\ :code:`recurrent_group`\ 进行了\ :code:`last_seq`\ 操作。但和单层\ :ref:`glossary_RNN`\ 不同,我们是对每一个子序列取最后一个元素,因此\ :code:`agg_level=AggregateLevel.EACH_SEQUENCE`\ 。
* 至此,\ :code:`lstm_last`\ 便和单层\ :ref:`glossary_RNN`\ 配置中的\ :code:`lstm_last`\ 具有相同的结果了。 * 至此,\ :code:`lstm_last`\ 便和单层\ :ref:`glossary_RNN`\ 配置中的\ :code:`lstm_last`\ 具有相同的结果了。
.. literalinclude:: ../../../paddle/gserver/tests/sequence_nest_layer_group.conf .. literalinclude:: ../../../paddle/gserver/tests/sequence_nest_layer_group.conf
:language: python :language: python
...@@ -93,30 +93,34 @@ ...@@ -93,30 +93,34 @@
示例2::ref:`glossary_双层RNN`,子序列间有\ :ref:`glossary_Memory` 示例2::ref:`glossary_双层RNN`,子序列间有\ :ref:`glossary_Memory`
================================================================== ==================================================================
本示例中,意图使用单层\ :ref:`glossary_RNN`\ 和\ :ref:`glossary_双层RNN`\ 同时实现一个完全等价的全连接\ :ref:`glossary_RNN`\ 。对于单层\ :ref:`glossary_RNN`\ ,输入数据为一个完整的\ :ref:`glossary_sequence`\ ,例如\ :code:`[4, 5, 2, 0, 9, 8, 1, 4]`\ 。而对于\ :ref:`glossary_双层RNN`\ ,输入数据为在单层\ :ref:`glossary_RNN`\ 数据里面,任意将一些数据组合成双层\ :ref:`glossary_sequence`\ ,例如\ :code:`[ [4, 5, 2], [0, 9], [8, 1, 4]]`。 本示例意图使用单层\ :ref:`glossary_RNN`\ 和\ :ref:`glossary_双层RNN`\ 实现两个完全等价的全连接\ :ref:`glossary_RNN`\ 。
* 对于单层\ :ref:`glossary_RNN`\ ,输入数据为一个完整的\ :ref:`glossary_sequence`\ ,例如\ :code:`[4, 5, 2, 0, 9, 8, 1, 4]`\ 。
* 对于\ :ref:`glossary_双层RNN`\ ,输入数据为在单层\ :ref:`glossary_RNN`\ 数据里面,任意将一些数据组合成双层\ :ref:`glossary_sequence`\ ,例如\ :code:`[ [4, 5, 2], [0, 9], [8, 1, 4]]`。
:ref:`glossary_trainer_config`\ 的模型配置 :ref:`glossary_trainer_config`\ 的模型配置
------------------------------------------ ------------------------------------------
我们选取单双层序列配置中的不同部分,来对比分析两者语义相同的原因。 我们选取单双层序列配置中的不同部分,来对比分析两者语义相同的原因。
- 单层序列:过了一个很简单的recurrent_group。每一个时间步,当前的输入y和上一个时间步的输出rnn_state做了一个全链接。 - 单层\ :ref:`glossary_rnn`\ :过了一个很简单的recurrent_group。每一个时间步,当前的输入y和上一个时间步的输出rnn_state做了一个全链接。
.. literalinclude:: ../../../paddle/gserver/tests/sequence_rnn.conf .. literalinclude:: ../../../paddle/gserver/tests/sequence_rnn.conf
:language: python :language: python
:lines: 36-48 :lines: 36-48
- 双层序列,外层memory是一个元素: - \ :ref:`glossary_双层RNN`\ ,外层memory是一个元素:
- 内层inner_step的recurrent_group和单层序列的几乎一样。除了boot_layer=outer_mem,表示将外层的outer_mem作为内层memory的初始状态。外层outer_step中,outer_mem是一个子句的最后一个向量,即整个双层group是将前一个子句的最后一个向量,作为下一个子句memory的初始状态。 - 内层inner_step的recurrent_group和单层序列的几乎一样。除了boot_layer=outer_mem,表示将外层的outer_mem作为内层memory的初始状态。外层outer_step中,outer_mem是一个子句的最后一个向量,即整个双层group是将前一个子句的最后一个向量,作为下一个子句memory的初始状态。
- 从输入数据上看,单双层序列的句子是一样的,只是双层序列将其又做了子序列划分。因此双层序列的配置中,必须将前一个子句的最后一个元素,作为boot_layer传给下一个子句的memory,才能保证和单层序列的配置中“每个时间步都用了上一个时间步的输出结果”一致。 - 从输入数据上看,单双层序列的句子是一样的,只是双层序列将其又做了子序列划分。因此双层序列的配置中,必须将前一个子句的最后一个元素,作为boot_layer传给下一个子句的memory,才能保证和单层序列的配置中“每个时间步都用了上一个时间步的输出结果”一致。
.. literalinclude:: ../../../paddle/gserver/tests/sequence_nest_rnn.conf .. literalinclude:: ../../../paddle/gserver/tests/sequence_nest_rnn.conf
:language: python :language: python
:lines: 39-66 :lines: 39-66
.. warning:: .. warning::
PaddlePaddle目前只支持在每一个时间步中,Memory的sequence长度一致的情况。 PaddlePaddle目前只支持在每个时间步中,Memory的\ :ref:`glossary_sequence`\ 长度一致的情况。
示例3:双层RNN,输入不等长 示例3:双层RNN,输入不等长
========================== ==========================
...@@ -127,31 +131,39 @@ ...@@ -127,31 +131,39 @@
<style> .red {color:red} </style> <style> .red {color:red} </style>
**输入不等长** 是指recurrent_group的多个输入序列,在每个\ :ref:`glossary_timestep`\ 的子序列长度可以不相等。但\ :ref:`glossary_双层RNN`\ 目前需要整体的输出,与某一个输入的序列信息是一致的。使用\ :red:`targetInlink`\ 可以指定和输出序列信息一致。 **输入不等长** 是指recurrent_group的多个输入序列,在每个\ :ref:`glossary_timestep`\ 的子序列长度可以不相等。但序列输出时,需要指定与某一个输入的序列信息是一致的。使用\ :red:`targetInlink`\ 可以指定哪一个输入和输出序列信息一致,默认指定第一个输入。
示例3的配置分别为\ `单层不等长RNN <https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/gserver/tests/sequence_rnn_multi_unequalength_inputs.conf>`_\ 和\ `双层不等长RNN <https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/gserver/tests/sequence_nest_rnn_multi_unequalength_inputs.conf>`_\ 。
本例参考配置分别为\ `单层不等长RNN <https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/gserver/tests/sequence_rnn_multi_unequalength_inputs.conf>`_\ 和\ `双层不等长RNN <https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/gserver/tests/sequence_nest_rnn_multi_unequalength_inputs.conf>`_\ 示例3对于单层\ :ref:`glossary_RNN`\ 和\ :ref:`glossary_双层RNN`\ 数据完全相同
本例中对于单层\ :ref:`glossary_RNN`\ 和\ :ref:`glossary_双层RNN`\ 数据完全相同,对于单层\ :ref:`glossary_RNN`\ 的数据一共有两个样本,他们分别是\ :code:`[1, 2, 4, 5, 2], [5, 4, 1, 3, 1]`\ 和\ :code:`[0, 2, 2, 5, 0, 1, 2], [1, 5, 4, 2, 3, 6, 1]`\ 。对于每一个单层\ :ref:`glossary_RNN`\ 的数据,均有两组特征。在单层数据的基础上,\ :ref:`glossary_双层RNN`\ 数据随意加了一些隔断,例如将第一条数据转化为\ :code:`[[0, 2], [2, 5], [0, 1, 2]],[[1, 5], [4], [2, 3, 6, 1]]`\ 。但是需要注意的是Paddle目前只支持序列数目一样的多输入\ :ref:`glossary_双层RNN`\ 。即两个特征,均有三个子序列。每个子序列长度可以不一致,但是子序列的数目必须一样。 * 对于单层\ :ref:`glossary_RNN`\ 的数据一共有两个样本,他们分别是\ :code:`[1, 2, 4, 5, 2], [5, 4, 1, 3, 1]`\ 和\ :code:`[0, 2, 2, 5, 0, 1, 2], [1, 5, 4, 2, 3, 6, 1]`\ 。对于每一个单层\ :ref:`glossary_RNN`\ 的数据,均有两组特征。
* 在单层数据的基础上,\ :ref:`glossary_双层RNN`\ 数据随意加了一些隔断,例如将第一条数据转化为\ :code:`[[0, 2], [2, 5], [0, 1, 2]],[[1, 5], [4], [2, 3, 6, 1]]`\ 。
* 需要注意的是Paddle目前只支持子序列数目一样的多输入\ :ref:`glossary_双层RNN`\ 。例如本里中的两个特征,均有三个子序列。每个子序列长度可以不一致,但是子序列的数目必须一样。
:ref:`glossary_trainer_config`\ 的模型配置 :ref:`glossary_trainer_config`\ 的模型配置
------------------------------------------ ------------------------------------------
本例中的配置,使用了单层\ :ref:`glossary_RNN`\ 和\ :ref:`glossary_双层RNN`\ 使用一个\ :code:`recurrent_group`\ 将两个序列同时过完全连接的\ :ref:`glossary_RNN`\ 。对于单层\ :ref:`glossary_RNN`\ 的code如下。 和示例2中的配置累死,示例3的配置使用了单层\ :ref:`glossary_RNN`\ 和\ :ref:`glossary_双层RNN`\ ,实现两个完全等价的全连接\ :ref:`glossary_RNN`\ 。
* 单层\ :ref:`glossary_RNN`\ \:
.. literalinclude:: ../../../paddle/gserver/tests/sequence_rnn_multi_unequalength_inputs.py .. literalinclude:: ../../../paddle/gserver/tests/sequence_rnn_multi_unequalength_inputs.py
:language: python :language: python
:lines: 42-59 :lines: 42-59
:linenos: :linenos:
而双层序列的代码如下。 * :ref:`glossary_双层RNN`\ \:
.. literalinclude:: ../../../paddle/gserver/tests/sequence_nest_rnn_multi_unequalength_inputs.py .. literalinclude:: ../../../paddle/gserver/tests/sequence_nest_rnn_multi_unequalength_inputs.py
:language: python :language: python
:lines: 41-80 :lines: 41-80
:linenos: :linenos:
在上面代码中,单层和双层序列的使用和示例2中的示例类似,区别是同时处理了两个输入。而对于双层序列,两个输入的子序列长度也并不相同。但是,我们使用了\ :code:`targetInlink`\ 参数设置了外层\ :code:`recurrent_group`\ 的输出格式。所以外层输出的序列形状,和\ :code:`emb2`的序列形状一致。 在上面代码中,单层和双层序列的使用和示例2中的示例类似,区别是同时处理了两个输入。而对于双层序列,两个输入的子序列长度也并不相同。但是,我们使用了\ :code:`targetInlink`\ 参数设置了外层\ :code:`recurrent_group`\ 的输出格式。所以外层输出的序列形状,和\ :code:`emb2`\ 的序列形状一致。
示例4:beam_search的生成 示例4:beam_search的生成
======================== ========================
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册