diff --git a/.travis.yml b/.travis.yml
index 5b14f8e61e614..047ca6ffe79bd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -56,7 +56,7 @@ before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo paddle/scripts/travis/before_install.linux.sh; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then paddle/scripts/travis/before_install.osx.sh; fi
- if [[ "$JOB" == "PRE_COMMIT" ]]; then sudo ln -s /usr/bin/clang-format-3.8 /usr/bin/clang-format; fi
- - pip install wheel protobuf sphinx recommonmark virtualenv numpy sphinx_rtd_theme pre-commit
+ - pip install wheel protobuf sphinx recommonmark virtualenv numpy sphinx_rtd_theme pre-commit requests==2.9.2 LinkChecker
script:
- paddle/scripts/travis/main.sh
notifications:
diff --git a/cmake/util.cmake b/cmake/util.cmake
index 38366373c6dbc..8a71b23c62d9f 100644
--- a/cmake/util.cmake
+++ b/cmake/util.cmake
@@ -96,6 +96,7 @@ function(link_paddle_exe TARGET_NAME)
target_circle_link_libraries(${TARGET_NAME}
ARCHIVE_START
paddle_gserver
+ paddle_function
${METRIC_LIBS}
ARCHIVE_END
paddle_pserver
@@ -106,6 +107,7 @@ function(link_paddle_exe TARGET_NAME)
paddle_parameter
paddle_proto
paddle_cuda
+ paddle_test_main
${METRIC_LIBS}
${PROTOBUF_LIBRARY}
${LIBGLOG_LIBRARY}
diff --git a/demo/semantic_role_labeling/dataprovider.py b/demo/semantic_role_labeling/dataprovider.py
index 042cd4e7a9e25..360c57ea6283c 100644
--- a/demo/semantic_role_labeling/dataprovider.py
+++ b/demo/semantic_role_labeling/dataprovider.py
@@ -43,7 +43,7 @@ def get_batch_size(yeild_data):
init_hook=hook,
should_shuffle=True,
calc_batch_size=get_batch_size,
- can_over_batch_size=False,
+ can_over_batch_size=True,
cache=CacheType.CACHE_PASS_IN_MEM)
def process(settings, file_name):
with open(file_name, 'r') as fdata:
diff --git a/doc/getstarted/build_and_install/docker_install_en.rst b/doc/getstarted/build_and_install/docker_install_en.rst
index 7633bf4d576ee..57725c0d85997 100644
--- a/doc/getstarted/build_and_install/docker_install_en.rst
+++ b/doc/getstarted/build_and_install/docker_install_en.rst
@@ -39,12 +39,20 @@ The general development workflow with Docker and Bazel is as follows:
code. This image contains all the development tools and
dependencies of PaddlePaddle.
-
.. code-block:: bash
cd paddle
docker build -t paddle:dev -f paddle/scripts/docker/Dockerfile .
+ Sometimes docker build might suffer from a slow network connection to the official Ubuntu apt-source servers. In such case, we can specify an apt-source mirror server that is geologically nearer to us. In the following example, we specified an apt-source server that responds fast in China.You can specify the UBUNTU MIRROR with :code:`--build-arg UBUNTU_MIRROR` like the example below.
+
+ .. code-block:: bash
+
+ docker build \
+ --build-arg UBUNTU_MIRROR="http://mirrors.163.com" \
+ -t paddle:dev \
+ -f paddle/scripts/docker/Dockerfile .
+
3. Run the image as a container and mounting local source code
directory into the container. This allows us to change the code on
diff --git a/doc/howto/deep_model/rnn/rnn_cn.md b/doc/howto/deep_model/rnn/rnn_cn.md
new file mode 100644
index 0000000000000..5ec05b2cab9ba
--- /dev/null
+++ b/doc/howto/deep_model/rnn/rnn_cn.md
@@ -0,0 +1,226 @@
+RNN 配置
+=================
+
+本教程将指导你如何在 PaddlePaddle 中配置循环神经网络(RNN)。PaddlePaddle 高度支持灵活和高效的循环神经网络配置。 在本教程中,您将了解如何:
+
+- 准备用来学习循环神经网络的序列数据。
+- 配置循环神经网络架构。
+- 使用学习完成的循环神经网络模型生成序列。
+
+我们将使用 vanilla 循环神经网络和 sequence to sequence 模型来指导你完成这些步骤。sequence to sequence 模型的代码可以在`demo / seqToseq`找到。
+
+准备序列数据
+---------------------
+
+PaddlePaddle 不需要对序列数据进行任何预处理,例如填充。唯一需要做的是将相应类型设置为输入。例如,以下代码段定义了三个输入。 它们都是序列,它们的大小是`src_dict`,`trg_dict`和`trg_dict`:
+
+``` sourceCode
+settings.input_types = [
+ integer_value_sequence(len(settings.src_dict)),
+ integer_value_sequence(len(settings.trg_dict)),
+ integer_value_sequence(len(settings.trg_dict))]
+```
+
+在`process`函数中,每个`yield`函数将返回三个整数列表。每个整数列表被视为一个整数序列:
+
+``` sourceCode
+yield src_ids, trg_ids, trg_ids_next
+```
+
+有关如何编写数据提供程序的更多细节描述,请参考 [PyDataProvider2](../../ui/data_provider/index.html)。完整的数据提供文件在 `demo/seqToseq/dataprovider.py`。
+
+配置循环神经网络架构
+-----------------------------------------------
+
+### 简单门控循环神经网络(Gated Recurrent Neural Network)
+
+循环神经网络在每个时间步骤顺序地处理序列。下面列出了 LSTM 的架构的示例。
+
+![image](../../../tutorials/sentiment_analysis/bi_lstm.jpg)
+
+一般来说,循环网络从 *t* = 1 到 *t* = *T* 或者反向地从 *t* = *T* 到 *t* = 1 执行以下操作。
+
+*x**t* + 1 = *f**x*(*x**t*),*y**t* = *f**y*(*x**t*)
+
+其中 *f**x*(.) 称为**单步函数**(即单时间步执行的函数,step function),而 *f**y*(.) 称为**输出函数**。在 vanilla 循环神经网络中,单步函数和输出函数都非常简单。然而,PaddlePaddle 可以通过修改这两个函数来实现复杂的网络配置。我们将使用 sequence to sequence 模型演示如何配置复杂的循环神经网络模型。在本节中,我们将使用简单的 vanilla 循环神经网络作为使用`recurrent_group`配置简单循环神经网络的例子。 注意,如果你只需要使用简单的RNN,GRU或LSTM,那么推荐使用`grumemory`和`lstmemory`,因为它们的计算效率比`recurrent_group`更高。
+
+对于 vanilla RNN,在每个时间步长,**单步函数**为:
+
+*x**t* + 1 = *W**x**x**t* + *W**i**I**t* + *b*
+
+其中 *x**t* 是RNN状态,并且 *I**t* 是输入,*W**x* 和 *W**i* 分别是RNN状态和输入的变换矩阵。*b* 是偏差。它的**输出函数**只需要*x**t*作为输出。
+
+`recurrent_group`是构建循环神经网络的最重要的工具。 它定义了**单步函数**,**输出函数**和循环神经网络的输入。注意,这个函数的`step`参数需要实现`step function`(单步函数)和`output function`(输出函数):
+
+
+``` sourceCode
+def simple_rnn(input,
+ size=None,
+ name=None,
+ reverse=False,
+ rnn_bias_attr=None,
+ act=None,
+ rnn_layer_attr=None):
+ def __rnn_step__(ipt):
+ out_mem = memory(name=name, size=size)
+ rnn_out = mixed_layer(input = [full_matrix_projection(ipt),
+ full_matrix_projection(out_mem)],
+ name = name,
+ bias_attr = rnn_bias_attr,
+ act = act,
+ layer_attr = rnn_layer_attr,
+ size = size)
+ return rnn_out
+ return recurrent_group(name='%s_recurrent_group' % name,
+ step=__rnn_step__,
+ reverse=reverse,
+ input=input)
+```
+
+PaddlePaddle 使用“Memory”(记忆模块)实现单步函数。**Memory**是在PaddlePaddle中构造循环神经网络时最重要的概念。 Memory是在单步函数中循环使用的状态,例如*x**t* + 1 = *f**x*(*x**t*)。 一个Memory包含**输出**和**输入**。当前时间步处的Memory的输出作为下一时间步Memory的输入。Memory也可以具有**boot layer(引导层)**,其输出被用作Memory的初始值。 在我们的例子中,门控循环单元的输出被用作输出Memory。请注意,`rnn_out`层的名称与`out_mem`的名称相同。这意味着`rnn_out` (*x**t* + 1)的输出被用作`out_mem`Memory的**输出**。
+
+Memory也可以是序列。在这种情况下,在每个时间步中,我们有一个序列作为循环神经网络的状态。这在构造非常复杂的循环神经网络时是有用的。 其他高级功能包括定义多个Memory,以及使用子序列来定义分级循环神经网络架构。
+
+我们在函数的结尾返回`rnn_out`。 这意味着 `rnn_out` 层的输出被用作门控循环神经网络的**输出**函数。
+
+### Sequence to Sequence Model with Attention
+
+我们将使用 sequence to sequence model with attention 作为例子演示如何配置复杂的循环神经网络模型。该模型的说明如下图所示。
+
+![image](../../../tutorials/text_generation/encoder-decoder-attention-model.png)
+
+在这个模型中,源序列 *S* = {*s*1, …, *s**T*} 用双向门控循环神经网络编码。双向门控循环神经网络的隐藏状态 *H**S* = {*H*1, …, *H**T*} 被称为 *编码向量*。解码器是门控循环神经网络。当解读每一个*y**t*时, 这个门控循环神经网络生成一系列权重 *W**S**t* = {*W*1*t*, …, *W**T**t*}, 用于计算编码向量的加权和。加权和用来生成*y**t*。
+
+模型的编码器部分如下所示。它叫做`grumemory`来表示门控循环神经网络。如果网络架构简单,那么推荐使用循环神经网络的方法,因为它比 `recurrent_group` 更快。我们已经实现了大多数常用的循环神经网络架构,可以参考 [Layers](../../ui/api/trainer_config_helpers/layers_index.html) 了解更多细节。
+
+我们还将编码向量投射到 `decoder_size` 维空间。这通过获得反向循环网络的第一个实例,并将其投射到 `decoder_size` 维空间完成:
+
+``` sourceCode
+# 定义源语句的数据层
+src_word_id = data_layer(name='source_language_word', size=source_dict_dim)
+# 计算每个词的词向量
+src_embedding = embedding_layer(
+ input=src_word_id,
+ size=word_vector_dim,
+ param_attr=ParamAttr(name='_source_language_embedding'))
+# 应用前向循环神经网络
+src_forward = grumemory(input=src_embedding, size=encoder_size)
+# 应用反向递归神经网络(reverse=True表示反向循环神经网络)
+src_backward = grumemory(input=src_embedding,
+ size=encoder_size,
+ reverse=True)
+# 将循环神经网络的前向和反向部分混合在一起
+encoded_vector = concat_layer(input=[src_forward, src_backward])
+
+# 投射编码向量到 decoder_size
+encoder_proj = mixed_layer(input = [full_matrix_projection(encoded_vector)],
+ size = decoder_size)
+
+# 计算反向RNN的第一个实例
+backward_first = first_seq(input=src_backward)
+
+# 投射反向RNN的第一个实例到 decoder size
+decoder_boot = mixed_layer(input=[full_matrix_projection(backward_first)], size=decoder_size, act=TanhActivation())
+```
+
+解码器使用 `recurrent_group` 来定义循环神经网络。单步函数和输出函数在 `gru_decoder_with_attention` 中定义:
+
+``` sourceCode
+group_inputs=[StaticInput(input=encoded_vector,is_seq=True),
+ StaticInput(input=encoded_proj,is_seq=True)]
+trg_embedding = embedding_layer(
+ input=data_layer(name='target_language_word',
+ size=target_dict_dim),
+ size=word_vector_dim,
+ param_attr=ParamAttr(name='_target_language_embedding'))
+group_inputs.append(trg_embedding)
+
+# 对于配备有注意力机制的解码器,在训练中,
+# 目标向量(groudtruth)是数据输入,
+# 而源序列的编码向量可以被无边界的memory访问
+# StaticInput 意味着不同时间步的输入都是相同的值,
+# 否则它以一个序列输入,不同时间步的输入是不同的。
+# 所有输入序列应该有相同的长度。
+decoder = recurrent_group(name=decoder_group_name,
+ step=gru_decoder_with_attention,
+ input=group_inputs)
+```
+
+单步函数的实现如下所示。首先,它定义解码网络的**Memory**。然后定义 attention,门控循环单元单步函数和输出函数:
+
+``` sourceCode
+def gru_decoder_with_attention(enc_vec, enc_proj, current_word):
+ # 定义解码器的Memory
+ # Memory的输出定义在 gru_step 内
+ # 注意 gru_step 应该与它的Memory名字相同
+ decoder_mem = memory(name='gru_decoder',
+ size=decoder_size,
+ boot_layer=decoder_boot)
+ # 计算 attention 加权编码向量
+ context = simple_attention(encoded_sequence=enc_vec,
+ encoded_proj=enc_proj,
+ decoder_state=decoder_mem)
+ # 混合当前词向量和attention加权编码向量
+ decoder_inputs = mixed_layer(inputs = [full_matrix_projection(context),
+ full_matrix_projection(current_word)],
+ size = decoder_size * 3)
+ # 定义门控循环单元循环神经网络单步函数
+ gru_step = gru_step_layer(name='gru_decoder',
+ input=decoder_inputs,
+ output_mem=decoder_mem,
+ size=decoder_size)
+ # 定义输出函数
+ out = mixed_layer(input=[full_matrix_projection(input=gru_step)],
+ size=target_dict_dim,
+ bias_attr=True,
+ act=SoftmaxActivation())
+ return out
+```
+
+生成序列
+-----------------
+
+训练模型后,我们可以使用它来生成序列。通常的做法是使用**beam search** 生成序列。以下代码片段定义 beam search 算法。注意,`beam_search` 函数假设 `step` 的输出函数返回的是下一个时刻输出词的 softmax 归一化概率向量。我们对模型进行了以下更改。
+
+- 使用 `GeneratedInput` 来表示 trg\_embedding。 `GeneratedInput` 将上一时间步所生成的词的向量来作为当前时间步的输入。
+- 使用 `beam_search` 函数。这个函数需要设置:
+ - `bos_id`: 开始标记。每个句子都以开始标记开头。
+ - `eos_id`: 结束标记。每个句子都以结束标记结尾。
+ - `beam_size`: beam search 算法中的beam大小。
+ - `max_length`: 生成序列的最大长度。
+- 使用 `seqtext_printer_evaluator` 根据索引矩阵和字典打印文本。这个函数需要设置:
+ - `id_input`: 数据的整数ID,用于标识生成的文件中的相应输出。
+ - `dict_file`: 用于将词ID转换为词的字典文件。
+ - `result_file`: 生成结果文件的路径。
+
+代码如下:
+
+``` sourceCode
+group_inputs=[StaticInput(input=encoded_vector,is_seq=True),
+ StaticInput(input=encoded_proj,is_seq=True)]
+# 在生成时,解码器基于编码源序列和最后生成的目标词预测下一目标词。
+# 编码源序列(编码器输出)必须由只读Memory的 StaticInput 指定。
+# 这里, GeneratedInputs 自动获取上一个生成的词,并在最开始初始化为起始词,如 。
+trg_embedding = GeneratedInput(
+ size=target_dict_dim,
+ embedding_name='_target_language_embedding',
+ embedding_size=word_vector_dim)
+group_inputs.append(trg_embedding)
+beam_gen = beam_search(name=decoder_group_name,
+ step=gru_decoder_with_attention,
+ input=group_inputs,
+ bos_id=0, # Beginnning token.
+ eos_id=1, # End of sentence token.
+ beam_size=beam_size,
+ max_length=max_length)
+
+seqtext_printer_evaluator(input=beam_gen,
+ id_input=data_layer(name="sent_id", size=1),
+ dict_file=trg_dict_path,
+ result_file=gen_trans_file)
+outputs(beam_gen)
+```
+
+注意,这种生成技术只用于类似解码器的生成过程。如果你正在处理序列标记任务,请参阅 [Semantic Role Labeling Demo](../../demo/semantic_role_labeling/index.html) 了解更多详细信息。
+
+完整的配置文件在`demo/seqToseq/seqToseq_net.py`。
diff --git a/doc/howto/deep_model/rnn_config_cn.rst b/doc/howto/deep_model/rnn_config_cn.rst
new file mode 100644
index 0000000000000..e6d8c1133a5e8
--- /dev/null
+++ b/doc/howto/deep_model/rnn_config_cn.rst
@@ -0,0 +1,287 @@
+RNN 配置
+========
+
+本教程将指导你如何在 PaddlePaddle
+中配置循环神经网络(RNN)。PaddlePaddle
+高度支持灵活和高效的循环神经网络配置。 在本教程中,您将了解如何:
+
+- 准备用来学习循环神经网络的序列数据。
+- 配置循环神经网络架构。
+- 使用学习完成的循环神经网络模型生成序列。
+
+我们将使用 vanilla 循环神经网络和 sequence to sequence
+模型来指导你完成这些步骤。sequence to sequence
+模型的代码可以在\ ``demo / seqToseq``\ 找到。
+
+准备序列数据
+------------
+
+PaddlePaddle
+不需要对序列数据进行任何预处理,例如填充。唯一需要做的是将相应类型设置为输入。例如,以下代码段定义了三个输入。
+它们都是序列,它们的大小是\ ``src_dict``\ ,\ ``trg_dict``\ 和\ ``trg_dict``\ :
+
+.. code:: sourcecode
+
+ settings.input_types = [
+ integer_value_sequence(len(settings.src_dict)),
+ integer_value_sequence(len(settings.trg_dict)),
+ integer_value_sequence(len(settings.trg_dict))]
+
+在\ ``process``\ 函数中,每个\ ``yield``\ 函数将返回三个整数列表。每个整数列表被视为一个整数序列:
+
+.. code:: sourcecode
+
+ yield src_ids, trg_ids, trg_ids_next
+
+有关如何编写数据提供程序的更多细节描述,请参考
+`PyDataProvider2 <../../ui/data_provider/index.html>`__\ 。完整的数据提供文件在
+``demo/seqToseq/dataprovider.py``\ 。
+
+配置循环神经网络架构
+--------------------
+
+简单门控循环神经网络(Gated Recurrent Neural Network)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+循环神经网络在每个时间步骤顺序地处理序列。下面列出了 LSTM 的架构的示例。
+
+.. figure:: ../../../tutorials/sentiment_analysis/bi_lstm.jpg
+ :alt: image
+
+ image
+
+一般来说,循环网络从 *t* = 1 到 *t* = *T* 或者反向地从 *t* = *T* 到 *t*
+= 1 执行以下操作。
+
+*x*\ \ *t* + 1 = *f*\ \ *x*\ (*x*\ \ *t*\ ),\ *y*\ \ *t*\ = *f*\ \ *y*\ (*x*\ \ *t*\ )
+
+其中 *f*\ \ *x*\ (.) 称为\ **单步函数**\ (即单时间步执行的函数,step
+function),而 *f*\ \ *y*\ (.) 称为\ **输出函数**\ 。在 vanilla
+循环神经网络中,单步函数和输出函数都非常简单。然而,PaddlePaddle
+可以通过修改这两个函数来实现复杂的网络配置。我们将使用 sequence to
+sequence
+模型演示如何配置复杂的循环神经网络模型。在本节中,我们将使用简单的
+vanilla
+循环神经网络作为使用\ ``recurrent_group``\ 配置简单循环神经网络的例子。
+注意,如果你只需要使用简单的RNN,GRU或LSTM,那么推荐使用\ ``grumemory``\ 和\ ``lstmemory``\ ,因为它们的计算效率比\ ``recurrent_group``\ 更高。
+
+对于 vanilla RNN,在每个时间步长,\ **单步函数**\ 为:
+
+*x*\ \ *t* + 1 = *W*\ \ *x*\ \ *x*\ \ *t*\ + *W*\ \ *i*\ \ *I*\ \ *t*\ + *b*
+
+其中 *x*\ \ *t*\ 是RNN状态,并且 *I*\ \ *t*\ 是输入,\ *W*\ \ *x*\ 和
+*W*\ \ *i*\ 分别是RNN状态和输入的变换矩阵。\ *b*
+是偏差。它的\ **输出函数**\ 只需要\ *x*\ \ *t*\ 作为输出。
+
+``recurrent_group``\ 是构建循环神经网络的最重要的工具。
+它定义了\ **单步函数**\ ,\ **输出函数**\ 和循环神经网络的输入。注意,这个函数的\ ``step``\ 参数需要实现\ ``step function``\ (单步函数)和\ ``output function``\ (输出函数):
+
+.. code:: sourcecode
+
+ def simple_rnn(input,
+ size=None,
+ name=None,
+ reverse=False,
+ rnn_bias_attr=None,
+ act=None,
+ rnn_layer_attr=None):
+ def __rnn_step__(ipt):
+ out_mem = memory(name=name, size=size)
+ rnn_out = mixed_layer(input = [full_matrix_projection(ipt),
+ full_matrix_projection(out_mem)],
+ name = name,
+ bias_attr = rnn_bias_attr,
+ act = act,
+ layer_attr = rnn_layer_attr,
+ size = size)
+ return rnn_out
+ return recurrent_group(name='%s_recurrent_group' % name,
+ step=__rnn_step__,
+ reverse=reverse,
+ input=input)
+
+PaddlePaddle
+使用“Memory”(记忆模块)实现单步函数。\ **Memory**\ 是在PaddlePaddle中构造循环神经网络时最重要的概念。
+Memory是在单步函数中循环使用的状态,例如\ *x*\ \ *t* + 1 = *f*\ \ *x*\ (*x*\ \ *t*\ )。
+一个Memory包含\ **输出**\ 和\ **输入**\ 。当前时间步处的Memory的输出作为下一时间步Memory的输入。Memory也可以具有\ **boot
+layer(引导层)**\ ,其输出被用作Memory的初始值。
+在我们的例子中,门控循环单元的输出被用作输出Memory。请注意,\ ``rnn_out``\ 层的名称与\ ``out_mem``\ 的名称相同。这意味着\ ``rnn_out``
+(*x*\ \ *t* + 1)的输出被用作\ ``out_mem``\ Memory的\ **输出**\ 。
+
+Memory也可以是序列。在这种情况下,在每个时间步中,我们有一个序列作为循环神经网络的状态。这在构造非常复杂的循环神经网络时是有用的。
+其他高级功能包括定义多个Memory,以及使用子序列来定义分级循环神经网络架构。
+
+我们在函数的结尾返回\ ``rnn_out``\ 。 这意味着 ``rnn_out``
+层的输出被用作门控循环神经网络的\ **输出**\ 函数。
+
+Sequence to Sequence Model with Attention
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+我们将使用 sequence to sequence model with attention
+作为例子演示如何配置复杂的循环神经网络模型。该模型的说明如下图所示。
+
+.. figure:: ../../../tutorials/text_generation/encoder-decoder-attention-model.png
+ :alt: image
+
+ image
+
+在这个模型中,源序列 *S* = {*s*\ 1, …, \ *s*\ \ *T*\ }
+用双向门控循环神经网络编码。双向门控循环神经网络的隐藏状态
+*H*\ \ *S*\ = {*H*\ 1, …, \ *H*\ \ *T*\ } 被称为
+*编码向量*\ 。解码器是门控循环神经网络。当解读每一个\ *y*\ \ *t*\ 时,
+这个门控循环神经网络生成一系列权重
+*W*\ \ *S*\ \ *t*\ = {*W*\ 1\ *t*\ , …, \ *W*\ \ *T*\ \ *t*\ },
+用于计算编码向量的加权和。加权和用来生成\ *y*\ \ *t*\ 。
+
+模型的编码器部分如下所示。它叫做\ ``grumemory``\ 来表示门控循环神经网络。如果网络架构简单,那么推荐使用循环神经网络的方法,因为它比
+``recurrent_group``
+更快。我们已经实现了大多数常用的循环神经网络架构,可以参考
+`Layers <../../ui/api/trainer_config_helpers/layers_index.html>`__
+了解更多细节。
+
+我们还将编码向量投射到 ``decoder_size``
+维空间。这通过获得反向循环网络的第一个实例,并将其投射到
+``decoder_size`` 维空间完成:
+
+.. code:: sourcecode
+
+ # 定义源语句的数据层
+ src_word_id = data_layer(name='source_language_word', size=source_dict_dim)
+ # 计算每个词的词向量
+ src_embedding = embedding_layer(
+ input=src_word_id,
+ size=word_vector_dim,
+ param_attr=ParamAttr(name='_source_language_embedding'))
+ # 应用前向循环神经网络
+ src_forward = grumemory(input=src_embedding, size=encoder_size)
+ # 应用反向递归神经网络(reverse=True表示反向循环神经网络)
+ src_backward = grumemory(input=src_embedding,
+ size=encoder_size,
+ reverse=True)
+ # 将循环神经网络的前向和反向部分混合在一起
+ encoded_vector = concat_layer(input=[src_forward, src_backward])
+
+ # 投射编码向量到 decoder_size
+ encoder_proj = mixed_layer(input = [full_matrix_projection(encoded_vector)],
+ size = decoder_size)
+
+ # 计算反向RNN的第一个实例
+ backward_first = first_seq(input=src_backward)
+
+ # 投射反向RNN的第一个实例到 decoder size
+ decoder_boot = mixed_layer(input=[full_matrix_projection(backward_first)], size=decoder_size, act=TanhActivation())
+
+解码器使用 ``recurrent_group`` 来定义循环神经网络。单步函数和输出函数在
+``gru_decoder_with_attention`` 中定义:
+
+.. code:: sourcecode
+
+ group_inputs=[StaticInput(input=encoded_vector,is_seq=True),
+ StaticInput(input=encoded_proj,is_seq=True)]
+ trg_embedding = embedding_layer(
+ input=data_layer(name='target_language_word',
+ size=target_dict_dim),
+ size=word_vector_dim,
+ param_attr=ParamAttr(name='_target_language_embedding'))
+ group_inputs.append(trg_embedding)
+
+ # 对于配备有注意力机制的解码器,在训练中,
+ # 目标向量(groudtruth)是数据输入,
+ # 而源序列的编码向量可以被无边界的memory访问
+ # StaticInput 意味着不同时间步的输入都是相同的值,
+ # 否则它以一个序列输入,不同时间步的输入是不同的。
+ # 所有输入序列应该有相同的长度。
+ decoder = recurrent_group(name=decoder_group_name,
+ step=gru_decoder_with_attention,
+ input=group_inputs)
+
+单步函数的实现如下所示。首先,它定义解码网络的\ **Memory**\ 。然后定义
+attention,门控循环单元单步函数和输出函数:
+
+.. code:: sourcecode
+
+ def gru_decoder_with_attention(enc_vec, enc_proj, current_word):
+ # 定义解码器的Memory
+ # Memory的输出定义在 gru_step 内
+ # 注意 gru_step 应该与它的Memory名字相同
+ decoder_mem = memory(name='gru_decoder',
+ size=decoder_size,
+ boot_layer=decoder_boot)
+ # 计算 attention 加权编码向量
+ context = simple_attention(encoded_sequence=enc_vec,
+ encoded_proj=enc_proj,
+ decoder_state=decoder_mem)
+ # 混合当前词向量和attention加权编码向量
+ decoder_inputs = mixed_layer(inputs = [full_matrix_projection(context),
+ full_matrix_projection(current_word)],
+ size = decoder_size * 3)
+ # 定义门控循环单元循环神经网络单步函数
+ gru_step = gru_step_layer(name='gru_decoder',
+ input=decoder_inputs,
+ output_mem=decoder_mem,
+ size=decoder_size)
+ # 定义输出函数
+ out = mixed_layer(input=[full_matrix_projection(input=gru_step)],
+ size=target_dict_dim,
+ bias_attr=True,
+ act=SoftmaxActivation())
+ return out
+
+生成序列
+--------
+
+训练模型后,我们可以使用它来生成序列。通常的做法是使用\ **beam search**
+生成序列。以下代码片段定义 beam search 算法。注意,\ ``beam_search``
+函数假设 ``step`` 的输出函数返回的是下一个时刻输出词的 softmax
+归一化概率向量。我们对模型进行了以下更改。
+
+- 使用 ``GeneratedInput`` 来表示 trg\_embedding。 ``GeneratedInput``
+ 将上一时间步所生成的词的向量来作为当前时间步的输入。
+- 使用 ``beam_search`` 函数。这个函数需要设置:
+
+ - ``bos_id``: 开始标记。每个句子都以开始标记开头。
+ - ``eos_id``: 结束标记。每个句子都以结束标记结尾。
+ - ``beam_size``: beam search 算法中的beam大小。
+ - ``max_length``: 生成序列的最大长度。
+
+- 使用 ``seqtext_printer_evaluator``
+ 根据索引矩阵和字典打印文本。这个函数需要设置:
+
+ - ``id_input``: 数据的整数ID,用于标识生成的文件中的相应输出。
+ - ``dict_file``: 用于将词ID转换为词的字典文件。
+ - ``result_file``: 生成结果文件的路径。
+
+代码如下:
+
+.. code:: sourcecode
+
+ group_inputs=[StaticInput(input=encoded_vector,is_seq=True),
+ StaticInput(input=encoded_proj,is_seq=True)]
+ # 在生成时,解码器基于编码源序列和最后生成的目标词预测下一目标词。
+ # 编码源序列(编码器输出)必须由只读Memory的 StaticInput 指定。
+ # 这里, GeneratedInputs 自动获取上一个生成的词,并在最开始初始化为起始词,如 。
+ trg_embedding = GeneratedInput(
+ size=target_dict_dim,
+ embedding_name='_target_language_embedding',
+ embedding_size=word_vector_dim)
+ group_inputs.append(trg_embedding)
+ beam_gen = beam_search(name=decoder_group_name,
+ step=gru_decoder_with_attention,
+ input=group_inputs,
+ bos_id=0, # Beginnning token.
+ eos_id=1, # End of sentence token.
+ beam_size=beam_size,
+ max_length=max_length)
+
+ seqtext_printer_evaluator(input=beam_gen,
+ id_input=data_layer(name="sent_id", size=1),
+ dict_file=trg_dict_path,
+ result_file=gen_trans_file)
+ outputs(beam_gen)
+
+注意,这种生成技术只用于类似解码器的生成过程。如果你正在处理序列标记任务,请参阅
+`Semantic Role Labeling
+Demo <../../demo/semantic_role_labeling/index.html>`__
+了解更多详细信息。
+
+完整的配置文件在\ ``demo/seqToseq/seqToseq_net.py``\ 。
diff --git a/paddle/CMakeLists.txt b/paddle/CMakeLists.txt
index fb3af8ea92fee..2daea052b01ad 100644
--- a/paddle/CMakeLists.txt
+++ b/paddle/CMakeLists.txt
@@ -1,4 +1,5 @@
add_subdirectory(cuda)
+add_subdirectory(function)
add_subdirectory(utils)
add_subdirectory(math)
add_subdirectory(parameter)
diff --git a/paddle/api/CMakeLists.txt b/paddle/api/CMakeLists.txt
index a7f17e186bf6b..da6dad10cd807 100644
--- a/paddle/api/CMakeLists.txt
+++ b/paddle/api/CMakeLists.txt
@@ -48,6 +48,7 @@ add_custom_command(OUTPUT ${PROJ_ROOT}/paddle/dist/.timestamp
WORKING_DIRECTORY ${PROJ_ROOT}/paddle
DEPENDS python_swig_sources
paddle_parameter
+ paddle_function
paddle_math
paddle_utils
paddle_gserver
diff --git a/paddle/api/paddle_ld_flags.py b/paddle/api/paddle_ld_flags.py
index 51d7dfee58b78..7c8206e3fe097 100644
--- a/paddle/api/paddle_ld_flags.py
+++ b/paddle/api/paddle_ld_flags.py
@@ -30,8 +30,8 @@
whole_end = ""
LIB_DIRS = [
- "math", 'utils', 'parameter', "gserver", "api", "cuda", "pserver",
- "trainer"
+ "math", 'function', 'utils', 'parameter', "gserver", "api", "cuda",
+ "pserver", "trainer"
]
PARENT_LIB_DIRS = ['proto']
@@ -75,6 +75,7 @@ def libs_str(self):
libs = [
whole_start,
"-lpaddle_gserver",
+ "-lpaddle_function",
whole_end,
"-lpaddle_pserver",
"-lpaddle_trainer_lib",
diff --git a/paddle/cuda/include/hl_cnn.h b/paddle/cuda/include/hl_cnn.h
index 06ee3b3654b57..c5787630abbe1 100644
--- a/paddle/cuda/include/hl_cnn.h
+++ b/paddle/cuda/include/hl_cnn.h
@@ -240,62 +240,6 @@ extern void hl_avgpool_backward(const int frameCnt,
real* backGrad,
const int outStride);
-/**
- * @brief Cross-map-respose normalize forward.
- *
- * @param[in] frameCnt batch size of input image.
- * @param[in] in input data.
- * @param[in] scale buffer.
- * @param[out] out output data.
- * @param[in] channels number of channel.
- * @param[in] height image height.
- * @param[in] width image width.
- * @param[in] sizeX size.
- * @param[in] alpha scale.
- * @param[in] beta scale.
- *
- */
-extern void hl_CMRNorm_forward(size_t frameCnt,
- const real* in,
- real* scale,
- real* out,
- size_t channels,
- size_t height,
- size_t width,
- size_t sizeX,
- real alpha,
- real beta);
-
-/**
- * @brief Cross-map-respose normalize backward.
- *
- * @param[in] frameCnt batch size of input image.
- * @param[in] inV input data.
- * @param[in] scale buffer.
- * @param[out] outV output value.
- * @param[out] outDiff output grad.
- * @param[out] inDiff input grad.
- * @param[in] channels number of channel.
- * @param[in] height image height.
- * @param[in] width image width.
- * @param[in] sizeX size.
- * @param[in] alpha scale.
- * @param[in] beta scale.
- *
- */
-extern void hl_CMRNorm_backward(size_t frameCnt,
- const real* inV,
- const real* scale,
- const real* outV,
- const real* outDiff,
- real* inDiff,
- size_t channels,
- size_t height,
- size_t width,
- size_t sizeX,
- real alpha,
- real beta);
-
/**
* @brief Bilinear interpolation forward.
*
diff --git a/paddle/cuda/include/stub/hl_cnn_stub.h b/paddle/cuda/include/stub/hl_cnn_stub.h
index 52c978735279e..039551c6cc695 100644
--- a/paddle/cuda/include/stub/hl_cnn_stub.h
+++ b/paddle/cuda/include/stub/hl_cnn_stub.h
@@ -117,30 +117,6 @@ inline void hl_avgpool_backward(const int frameCnt,
real* backGrad,
const int outStride) {}
-inline void hl_CMRNorm_forward(size_t frameCnt,
- const real* in,
- real* scale,
- real* out,
- size_t channels,
- size_t height,
- size_t width,
- size_t sizeX,
- real alpha,
- real beta) {}
-
-inline void hl_CMRNorm_backward(size_t frameCnt,
- const real* inV,
- const real* scale,
- const real* outV,
- const real* outDiff,
- real* inDiff,
- size_t channels,
- size_t height,
- size_t width,
- size_t sizeX,
- real alpha,
- real beta) {}
-
inline void hl_bilinear_forward(const real* inData,
const size_t inImgH,
const size_t inImgW,
diff --git a/paddle/cuda/src/hl_cuda_cnn.cu b/paddle/cuda/src/hl_cuda_cnn.cu
index 0992286f360fb..b94f4d8fe4a25 100644
--- a/paddle/cuda/src/hl_cuda_cnn.cu
+++ b/paddle/cuda/src/hl_cuda_cnn.cu
@@ -381,164 +381,6 @@ void hl_avgpool_backward(const int frameCnt, const real* outGrad,
CHECK_SYNC("hl_avgpool_backward failed");
}
-__global__ void KeCMRNormFillScale(size_t nthreads, const real* in,
- real* scale, size_t channels,
- size_t height, size_t width, size_t size,
- real alpha) {
- size_t index = threadIdx.x + blockIdx.x * blockDim.x;
- if (index < nthreads) {
- // find out the local offset
- size_t w = index % width;
- size_t h = (index / width) % height;
- size_t n = index / width / height;
- size_t offset = (n * channels * height + h) * width + w;
- size_t step = height * width;
- in += offset;
- scale += offset;
- size_t head = 0;
- size_t pre_pad = (size - 1) / 2;
- size_t post_pad = size - pre_pad - 1;
- real accum_scale = 0;
- // fill the scale at [n, :, h, w]
- // accumulate values
- while (head < post_pad) {
- accum_scale += in[head * step] * in[head * step];
- ++head;
- }
- // until we reach size, nothing needs to be subtracted
- while (head < size) {
- accum_scale += in[head * step] * in[head * step];
- scale[(head - post_pad) * step] = 1. + accum_scale * alpha;
- ++head;
- }
- // both add and subtract
- while (head < channels) {
- accum_scale += in[head * step] * in[head * step];
- accum_scale -= in[(head - size) * step] * in[(head - size) * step];
- scale[(head - post_pad) * step] = 1. + accum_scale * alpha;
- ++head;
- }
- // subtract only
- while (head < channels + post_pad) {
- accum_scale -= in[(head - size) * step] * in[(head - size) * step];
- scale[(head - post_pad) * step] = 1. + accum_scale * alpha;
- ++head;
- }
- }
-}
-
- __global__ void KeCMRNormOutput(size_t nthreads, const real* in,
- const real* scale, real negative_beta,
- real* out) {
- size_t index = threadIdx.x + blockIdx.x * blockDim.x;
- if (index < nthreads) {
- out[index] = in[index] * pow(scale[index], negative_beta);
- }
-}
-
-void hl_CMRNorm_forward(size_t frameCnt, const real* in, real* scale,
- real* out, size_t channels,
- size_t height, size_t width, size_t sizeX,
- real alpha, real beta) {
- size_t threadsNum = frameCnt * height * width;
- size_t blocksX = (threadsNum + 1024 - 1) / 1024;
- size_t blocksY = 1;
- dim3 threads(1024, 1);
- dim3 grid(blocksX, blocksY);
-
- KeCMRNormFillScale<<>>
- (threadsNum, in, scale, channels, height, width, sizeX, alpha);
-
- threadsNum = frameCnt * height * width *channels;
- blocksX = (threadsNum + 1024 -1) / 1024;
- dim3 threads2(1024, 1);
- dim3 grid2(blocksX, blocksY);
- KeCMRNormOutput<<>>
- (threadsNum, in, scale, beta, out);
- CHECK_SYNC("hl_CMRNorm_forward");
-}
-
-__global__ void KeCMRNormDiff(size_t nthreads, const real* bottom_data,
- const real* top_data, const real* scale,
- const real* top_diff, size_t channels,
- size_t height, size_t width, size_t size,
- real negative_beta, real cache_ratio,
- real* bottom_diff ) {
- int index = threadIdx.x + blockIdx.x * blockDim.x;
- if (index < nthreads) {
- // find out the local offset
- size_t w = index % width;
- size_t h = (index / width) % height;
- size_t n = index / width / height;
- size_t offset = (n * channels * height + h) * width + w;
- size_t step = height * width;
- bottom_data += offset;
- top_data += offset;
- scale += offset;
- top_diff += offset;
- bottom_diff += offset;
- int head = 0;
- int pre_pad = size - (size + 1) / 2;
- int post_pad = size - pre_pad - 1;
- real accum_ratio = 0;
- // accumulate values
- while (head < post_pad) {
- accum_ratio += top_diff[head * step] *
- top_data[head * step] / scale[head * step];
- ++head;
- }
- // until we reach size, nothing needs to be subtracted
- while (head < size) {
- accum_ratio += top_diff[head * step] *
- top_data[head * step] / scale[head * step];
- bottom_diff[(head - post_pad) * step] +=
- top_diff[(head - post_pad) * step] *
- pow(scale[(head - post_pad) * step], negative_beta) - cache_ratio *
- bottom_data[(head - post_pad) * step] * accum_ratio;
- ++head;
- }
- // both add and subtract
- while (head < channels) {
- accum_ratio += top_diff[head * step] * top_data[head * step] /
- scale[head * step];
- accum_ratio -= top_diff[(head - size) * step] *
- top_data[(head - size) * step] / scale[(head - size) * step];
- bottom_diff[(head - post_pad) * step] +=
- top_diff[(head - post_pad) * step] *
- pow(scale[(head - post_pad) * step], negative_beta) - cache_ratio *
- bottom_data[(head - post_pad) * step] * accum_ratio;
- ++head;
- }
- // subtract only
- while (head < channels + post_pad) {
- accum_ratio -= top_diff[(head - size) * step] *
- top_data[(head - size) * step] / scale[(head - size) * step];
- bottom_diff[(head - post_pad) * step] +=
- top_diff[(head - post_pad) * step] *
- pow(scale[(head - post_pad) * step], negative_beta) - cache_ratio *
- bottom_data[(head - post_pad) * step] * accum_ratio;
- ++head;
- }
- }
-}
-
-void hl_CMRNorm_backward(size_t frameCnt, const real* inV,
- const real* scale,
- const real* outV, const real* outDiff,
- real *inDiff, size_t channels,
- size_t height, size_t width, size_t sizeX,
- real alpha, real beta) {
- size_t threadsNum = frameCnt * height * width;
- size_t blocksX = (threadsNum + 1024 - 1) / 1024;
- size_t blocksY = 1;
- dim3 threads(1024, 1);
- dim3 grid(blocksX, blocksY);
- KeCMRNormDiff <<>>
- (threadsNum, inV, outV, scale, outDiff, channels,
- height, width, sizeX, alpha, beta, inDiff);
- CHECK_SYNC("hl_CMRNorm_backward");
-}
-
__global__ void KeBilinearInterpFw(const real* in,
const size_t inImgH,
const size_t inImgW,
diff --git a/paddle/function/CMakeLists.txt b/paddle/function/CMakeLists.txt
new file mode 100644
index 0000000000000..0697842bbef62
--- /dev/null
+++ b/paddle/function/CMakeLists.txt
@@ -0,0 +1,27 @@
+file(GLOB h_files . *_op.h)
+file(GLOB cpp_files . *_op.cpp)
+
+list(APPEND h_files Function.h)
+list(APPEND cpp_files Function.cpp)
+
+if(WITH_GPU)
+ file(GLOB cu_files . *_op_gpu.cu)
+ cuda_compile(cu_objs ${cu_files})
+endif()
+
+add_library(paddle_function STATIC ${cpp_files} ${cu_objs})
+
+add_library(paddle_test_main STATIC TestMain.cpp)
+
+if(WITH_GPU)
+ # TODO:
+ # file(GLOB test_files . *_op_test.cpp)
+ # add_executable(${test_bin} EXCLUDE_FROM_ALL ${test_files})
+ add_simple_unittest(cross_map_normal_op_test)
+endif()
+
+add_style_check_target(paddle_function ${h_files})
+add_style_check_target(paddle_function ${cpp_files})
+if(WITH_GPU)
+ add_style_check_target(paddle_function ${cu_files})
+endif()
diff --git a/paddle/function/Function.cpp b/paddle/function/Function.cpp
new file mode 100644
index 0000000000000..02880e5ea1acb
--- /dev/null
+++ b/paddle/function/Function.cpp
@@ -0,0 +1,49 @@
+/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
+
+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. */
+
+#include "Function.h"
+
+namespace paddle {
+
+template <>
+size_t FuncConfig::get(const std::string& key) const {
+ auto it = valueMap_.find(key);
+ CHECK(it != valueMap_.end()) << "Cannot find value: '" << key << "'";
+ return it->second.s;
+}
+
+template <>
+real FuncConfig::get(const std::string& key) const {
+ auto it = valueMap_.find(key);
+ CHECK(it != valueMap_.end()) << "Cannot find value: '" << key << "'";
+ return it->second.r;
+}
+
+template <>
+FuncConfig& FuncConfig::set(const std::string& key, size_t v) {
+ CHECK(valueMap_.count(key) == 0) << "Duplicated value: " << key;
+ valueMap_[key].s = v;
+ return *this;
+}
+
+template <>
+FuncConfig& FuncConfig::set(const std::string& key, real v) {
+ CHECK(valueMap_.count(key) == 0) << "Duplicated value: " << key;
+ valueMap_[key].r = v;
+ return *this;
+}
+
+ClassRegistrar FunctionBase::funcRegistrar_;
+
+} // namespace paddle
diff --git a/paddle/function/Function.h b/paddle/function/Function.h
new file mode 100644
index 0000000000000..095584c0b19f7
--- /dev/null
+++ b/paddle/function/Function.h
@@ -0,0 +1,96 @@
+/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
+
+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. */
+
+#pragma once
+
+#include