diff --git a/CMakeLists.txt b/CMakeLists.txt index 00996cb7ed5cc573c42b69be6db369c3654d6d1a..f4e7d5c20db5fb95dfd5de05f8209608707b772c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,8 @@ option(WITH_COVERAGE "Compile PaddlePaddle with code coverage" OFF) option(COVERALLS_UPLOAD "Package code coverage data to coveralls" OFF) option(ON_TRAVIS "Exclude special unit test on Travis CI" OFF) option(WITH_C_API "Compile PaddlePaddle with C-API(Prediction)" OFF) +# TODO: Only compile PaddlePaddle fluid version by WITH_FLUID option. +option(WITH_FLUID "Compile PaddlePaddle fluid only(TODO)" ON) option(WITH_GOLANG "Compile PaddlePaddle with GOLANG" OFF) option(GLIDE_INSTALL "Download and install go dependencies " ON) option(USE_NNPACK "Compile PaddlePaddle with NNPACK library" OFF) @@ -107,6 +109,10 @@ if (WITH_C_API AND WITH_PYTHON) "different Python interpreter from compiling.") endif() +if (WITH_C_API) + set(WITH_FLUID OFF CACHE STRING "Disable install fluid when compile the C_API" FORCE) +endif() + if(MOBILE_INFERENCE) set(THIRD_PARTY_BUILD_TYPE MinSizeRel) else() diff --git a/cmake/external/eigen.cmake b/cmake/external/eigen.cmake index c4712f19eb80b34ffbf713d2b13fc0c775312af1..d49c8d601102cf865287c33349bff5eee6a90f6d 100644 --- a/cmake/external/eigen.cmake +++ b/cmake/external/eigen.cmake @@ -1,8 +1,8 @@ INCLUDE(ExternalProject) SET(EIGEN_SOURCE_DIR ${THIRD_PARTY_PATH}/eigen3) - -INCLUDE_DIRECTORIES(${EIGEN_SOURCE_DIR}/src/extern_eigen3) +SET(EIGEN_INCLUDE_DIR ${EIGEN_SOURCE_DIR}/src/extern_eigen3) +INCLUDE_DIRECTORIES(${EIGEN_INCLUDE_DIR}) ExternalProject_Add( extern_eigen3 @@ -28,3 +28,9 @@ endif() add_dependencies(eigen3 extern_eigen3) LIST(APPEND external_project_dependencies eigen3) + +IF(NOT WITH_C_API AND WITH_FLUID) + INSTALL(FILES ${EIGEN_INCLUDE_DIR}/Eigen/Core DESTINATION third_party/eigen3/Eigen) + INSTALL(DIRECTORY ${EIGEN_INCLUDE_DIR}/Eigen/src DESTINATION third_party/eigen3/Eigen) + INSTALL(DIRECTORY ${EIGEN_INCLUDE_DIR}/unsupported/Eigen DESTINATION third_party/eigen3/unsupported) +ENDIF() diff --git a/cmake/external/gflags.cmake b/cmake/external/gflags.cmake index d4f252bb9f64c8db82b841fedf0817f5d8596501..60946304541a20809276c3e665d8524baf209006 100644 --- a/cmake/external/gflags.cmake +++ b/cmake/external/gflags.cmake @@ -52,7 +52,7 @@ ADD_DEPENDENCIES(gflags extern_gflags) LIST(APPEND external_project_dependencies gflags) -IF(WITH_C_API) +IF(WITH_C_API OR WITH_FLUID) INSTALL(DIRECTORY ${GFLAGS_INCLUDE_DIR} DESTINATION third_party/gflags) IF(ANDROID) INSTALL(FILES ${GFLAGS_LIBRARIES} DESTINATION third_party/gflags/lib/${ANDROID_ABI}) diff --git a/cmake/external/glog.cmake b/cmake/external/glog.cmake index 0c6b3aafcb4e990b9d4549820137474e5968a7aa..382fbda3b5cfeba893f03871cf65498d20804f36 100644 --- a/cmake/external/glog.cmake +++ b/cmake/external/glog.cmake @@ -68,7 +68,7 @@ LINK_LIBRARIES(glog gflags) LIST(APPEND external_project_dependencies glog) -IF(WITH_C_API) +IF(WITH_C_API OR WITH_FLUID) INSTALL(DIRECTORY ${GLOG_INCLUDE_DIR} DESTINATION third_party/glog) IF(ANDROID) INSTALL(FILES ${GLOG_LIBRARIES} DESTINATION third_party/glog/lib/${ANDROID_ABI}) diff --git a/cmake/external/protobuf.cmake b/cmake/external/protobuf.cmake index ff5855052dabaa0b63099cd219f3f04e22f1aa85..365a370a9cfb708379bcff18ae6aa0725d420ae1 100644 --- a/cmake/external/protobuf.cmake +++ b/cmake/external/protobuf.cmake @@ -250,7 +250,7 @@ IF(NOT PROTOBUF_FOUND) SET(PROTOBUF_PROTOC_LIBRARY ${extern_protobuf_PROTOC_LIBRARY} CACHE FILEPATH "protoc library." FORCE) - IF(WITH_C_API) + IF(WITH_C_API OR WITH_FLUID) INSTALL(DIRECTORY ${PROTOBUF_INCLUDE_DIR} DESTINATION third_party/protobuf) IF(ANDROID) INSTALL(FILES ${PROTOBUF_LITE_LIBRARY} DESTINATION third_party/protobuf/lib/${ANDROID_ABI}) diff --git a/doc/api/v1/data_provider/dataprovider_cn.rst b/doc/api/v1/data_provider/dataprovider_cn.rst deleted file mode 100644 index d08c6b3efacbc35ae274d5b207fe91e747124e79..0000000000000000000000000000000000000000 --- a/doc/api/v1/data_provider/dataprovider_cn.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. _api_dataprovider: - -DataProvider的介绍 -================== - -DataProvider是PaddlePaddle负责提供数据的模块。其作用是将数据传入内存或显存,让神经网络可以进行训练或预测。用户可以通过简单使用Python接口 :ref:`api_pydataprovider2` ,来自定义传数据的过程。如果有更复杂的使用,或者需要更高的效率,用户也可以在C++端自定义一个 ``DataProvider`` 。 - -PaddlePaddle需要用户在网络配置(trainer_config.py)中定义使用哪种DataProvider,并且在DataProvider中实现如何访问训练文件列表(train.list)或测试文件列表(test.list)。 - -- train.list和test.list存放在本地(推荐直接存放到训练目录,以相对路径引用)。一般情况下,两者均为纯文本文件,其中每一行对应一个数据文件地址: - - - 如果数据文件存于本地磁盘,这个地址则为它的绝对路径或相对路径(相对于PaddlePaddle程序运行时的路径)。 - - 地址也可以为hdfs文件路径,或者数据库连接路径等。 - - 由于这个地址会被DataProvider使用,因此,如何解析该地址也是用户自定义DataProvider时需要考虑的地方。 -- 如果没有设置test.list,或设置为None,那么在训练过程中不会执行测试操作;否则,会根据命令行参数指定的测试方式,在训练过程中进行测试,从而防止过拟合。 diff --git a/doc/api/v1/data_provider/dataprovider_en.rst b/doc/api/v1/data_provider/dataprovider_en.rst deleted file mode 100644 index 96efbb1da959daec561009fdcc95d353b191dec8..0000000000000000000000000000000000000000 --- a/doc/api/v1/data_provider/dataprovider_en.rst +++ /dev/null @@ -1,34 +0,0 @@ -Introduction -============== -DataProvider is a module that loads training or testing data into cpu or gpu -memory for the following triaining or testing process. - -For simple use, users can use Python :code:`PyDataProvider` to dynamically reads -the original data in any format or in any form, and then transfer them into a -data format PaddlePaddle requires. The process is extremly flexible and highly -customized, with sacrificing the efficiency only a little. This is extremly -useful when you have to dynamically generate certain kinds of data according to, -for example, the training performance. - -Besides, users also can customize a C++ :code:`DataProvider` for a more -complex usage, or for a higher efficiency. - -The following parameters are required to define in the PaddlePaddle network -configuration file (trainer_config.py): which DataProvider is chosen to used, -and specific parameters for DataProvider, including training file list -(train.list) and testing file list (test.list). - -Train.list and test.list are simply two plain text files, which defines path -of training or testing data. It is recommended that directly placing them into -the training directory, and reference to them by using a relative path ( -relative to the PaddePaddle program). - -Testing or evaluating will not be performed during training if the test.list is -not set or set to None. Otherwise, PaddlePaddle will evaluate the trained model -by the specified tesing data while training, every testing period (a user -defined command line parameter in PaddlePaddle) to prevent over-fitting. - -Each line of train.list and test.list is an absolute or relative path (relative -to the PaddePaddle program runtime) of data file. Fascinatingly more, each line -can also be a HDFS file path or a SQL connection string. As long as the user -assures how to access each file in DataProvider. diff --git a/doc/api/v1/data_provider/pydataprovider2_cn.rst b/doc/api/v1/data_provider/pydataprovider2_cn.rst deleted file mode 100644 index 8f9db31cfb9946e1d2db3872718bd92787d861f0..0000000000000000000000000000000000000000 --- a/doc/api/v1/data_provider/pydataprovider2_cn.rst +++ /dev/null @@ -1,229 +0,0 @@ -.. _api_pydataprovider2: - -PyDataProvider2的使用 -===================== - -PyDataProvider2是PaddlePaddle使用Python提供数据的推荐接口。该接口使用多线程读取数据,并提供了简单的Cache功能;同时可以使用户只关注如何从文件中读取每一条数据,而不用关心数据如何传输,如何存储等等。 - -.. contents:: - -MNIST的使用场景 ---------------- - -我们以MNIST手写识别为例,来说明PyDataProvider2的简单使用场景。 - -样例数据 -++++++++ - -MNIST是一个包含有70,000张灰度图片的数字分类数据集。样例数据 ``mnist_train.txt`` 如下: - -.. literalinclude:: src/mnist_train.txt - -其中每行数据代表一张图片,行内使用 ``;`` 分成两部分。第一部分是图片的标签,为0-9中的一个数字;第二部分是28*28的图片像素灰度值。 对应的 ``train.list`` 即为这个数据文件的名字: - -.. literalinclude:: src/train.list - -dataprovider的使用 -++++++++++++++++++ - -.. literalinclude:: src/mnist_provider.dict.py - -- 首先,引入PaddlePaddle的PyDataProvider2包。 -- 其次,定义一个Python的 `Decorator `_ `@provider`_ 。用于将下一行的数据输入函数标记成一个PyDataProvider2,同时设置它的input_types属性。 - - - `input_types`_:设置这个PyDataProvider2返回什么样的数据。本例根据网络配置中 ``data_layer`` 的名字,显式指定返回的是一个28*28维的稠密浮点数向量和一个[0-9]的10维整数标签。 - - .. literalinclude:: src/mnist_config.py - :lines: 9-10 - - - 注意:如果用户不显示指定返回数据的对应关系,那么PaddlePaddle会根据layer的声明顺序,来确定对应关系。但这个关系可能不正确,所以推荐使用显式指定的方式来设置input_types。 -- 最后,实现数据输入函数(如本例的 ``process`` 函数)。 - - - 该函数的功能是:打开文本文件,读取每一行,将行中的数据转换成与input_types一致的格式,然后返回给PaddlePaddle进程。注意, - - - 返回的顺序需要和input_types中定义的顺序一致。 - - 返回时,必须使用Python关键词 ``yield`` ,相关概念是 ``generator`` 。 - - 一次yield调用,返回一条完整的样本。如果想为一个数据文件返回多条样本,只需要在函数中调用多次yield即可(本例中使用for循环进行多次调用)。 - - - 该函数具有两个参数: - - - settings:在本例中没有使用,具体可以参考 `init_hook`_ 中的说明。 - - filename:为 ``train.list`` 或 ``test.list`` 中的一行,即若干数据文件路径的某一个。 - -网络配置中的调用 -++++++++++++++++ - -在网络配置里,只需要一行代码就可以调用这个PyDataProvider2,如, - -.. literalinclude:: src/mnist_config.py - :lines: 1-7 - -训练数据是 ``train.list`` ,没有测试数据,调用的PyDataProvider2是 ``mnist_provider`` 模块中的 ``process`` 函数。 - -小结 -+++++ - -至此,简单的PyDataProvider2样例就说明完毕了。对用户来说,仅需要知道如何从 **一个文件** 中读取 **一条样本** ,就可以将数据传送给PaddlePaddle了。而PaddlePaddle则会帮用户做以下工作: - -* 将数据组合成Batch进行训练 -* 对训练数据进行Shuffle -* 多线程的数据读取 -* 缓存训练数据到内存(可选) -* CPU->GPU双缓存 - -是不是很简单呢? - -时序模型的使用场景 ------------------- -样例数据 -++++++++ - -时序模型是指数据的某一维度是一个序列形式,即包含时间步信息。所谓时间步信息,不一定和时间有关系,只是说明数据的顺序是重要的。例如,文本信息就是一个序列数据。 - -本例采用英文情感分类的数据,即将一段英文文本数据,分类成正面情绪和负面情绪两类(用0和1表示)。样例数据 ``sentimental_train.txt`` 如下: - -.. literalinclude:: src/sentimental_train.txt - -dataprovider的使用 -++++++++++++++++++ - -相对MNIST而言,这个dataprovider较复杂,主要原因是增加了初始化机制 `init_hook`_。本例的 ``on_init`` 函数就是根据该机制配置的,它会在dataprovider创建的时候执行。 - -- 其中 ``input_types`` 和在 `@provider`_ 中配置的效果一致。本例中的输入特征是词ID的序列,因此使用 ``integer_value_sequence`` 类型来设置。 -- 将 ``dictionary`` 存入settings对象,在 ``process`` 函数中使用。 dictionary是从网络配置中传入的dict对象,即一个将单词字符串映射到单词ID的字典。 - -.. literalinclude:: src/sentimental_provider.py - -网络配置中的调用 -++++++++++++++++ - -调用这个PyDataProvider2的方法,基本上和MNIST样例一致,除了 - -* 在配置中需要读取外部字典。 -* 在声明DataProvider的时候传入dictionary作为参数。 - -.. literalinclude:: src/sentimental_config.py - :emphasize-lines: 12-14 - -参考(Reference) ---------------- - -@provider -+++++++++ - -``@provider`` 是一个Python的 `Decorator`_ ,可以将某一个函数标记成一个PyDataProvider2。如果不了解 `Decorator`_ 是什么也没关系,只需知道这是一个标记属性的方法就可以了。它包含的属性参数如下: - -* input_types:数据输入格式。具体的格式说明,请参考 `input_types`_ 。 -* should_shuffle:是不是要对数据做Shuffle。训练时默认shuffle,测试时默认不shuffle。 -* min_pool_size:设置内存中最小暂存的数据条数,也是PaddlePaddle所能够保证的shuffle粒度。如果为-1,则会预先读取全部数据到内存中。 -* pool_size: 设置内存中暂存的数据条数。如果为-1(默认),则不在乎内存暂存多少条数据。如果设置,则推荐大于训练时batch size的值,并且在内存足够的情况下越大越好。 -* can_over_batch_size:是否允许暂存略微多余pool_size的数据。由于这样做可以避免很多死锁问题,一般推荐设置成True。 -* calc_batch_size:可以传入一个函数,用于自定义每条数据的batch size(默认为1)。 -* cache: 数据缓存的策略,具体请参考 `cache`_ 。 -* init_hook:初始化时调用的函数,具体请参考 `init_hook`_ 。 -* check:如果为true,会根据input_types检查数据的合法性。 -* check_fail_continue:如果为true,那么当check出数据不合法时,会扔到这条数据,继续训练或预测。(对check=false的情况,没有作用) - -input_types -+++++++++++ - -PaddlePaddle的数据包括四种主要类型,和三种序列模式。 - -四种数据类型: - -* dense_vector:稠密的浮点数向量。 -* sparse_binary_vector:稀疏的01向量,即大部分值为0,但有值的地方必须为1。 -* sparse_float_vector:稀疏的向量,即大部分值为0,但有值的部分可以是任何浮点数。 -* integer:整数标签。 - -三种序列模式: - -* SequenceType.NO_SEQUENCE:不是一条序列 -* SequenceType.SEQUENCE:是一条时间序列 -* SequenceType.SUB_SEQUENCE: 是一条时间序列,且序列的每一个元素还是一个时间序列。 - -不同的数据类型和序列模式返回的格式不同,列表如下: - -+----------------------+---------------------+-----------------------------------+------------------------------------------------+ -| | NO_SEQUENCE | SEQUENCE | SUB_SEQUENCE | -+======================+=====================+===================================+================================================+ -| dense_vector | [f, f, ...] | [[f, ...], [f, ...], ...] | [[[f, ...], ...], [[f, ...], ...],...] | -+----------------------+---------------------+-----------------------------------+------------------------------------------------+ -| sparse_binary_vector | [i, i, ...] | [[i, ...], [i, ...], ...] | [[[i, ...], ...], [[i, ...], ...],...] | -+----------------------+---------------------+-----------------------------------+------------------------------------------------+ -| sparse_float_vector | [(i,f), (i,f), ...] | [[(i,f), ...], [(i,f), ...], ...] | [[[(i,f), ...], ...], [[(i,f), ...], ...],...] | -+----------------------+---------------------+-----------------------------------+------------------------------------------------+ -| integer_value | i | [i, i, ...] | [[i, ...], [i, ...], ...] | -+----------------------+---------------------+-----------------------------------+------------------------------------------------+ - -其中,f代表一个浮点数,i代表一个整数。 - -注意:对sparse_binary_vector和sparse_float_vector,PaddlePaddle存的是有值位置的索引。例如, - -- 对一个5维非序列的稀疏01向量 ``[0, 1, 1, 0, 0]`` ,类型是sparse_binary_vector,返回的是 ``[1, 2]`` 。 -- 对一个5维非序列的稀疏浮点向量 ``[0, 0.5, 0.7, 0, 0]`` ,类型是sparse_float_vector,返回的是 ``[(1, 0.5), (2, 0.7)]`` 。 - -init_hook -+++++++++ - -init_hook可以传入一个函数。该函数在初始化的时候会被调用,其参数如下: - -* 第一个参数是settings对象,它和数据传入函数的第一个参数(如本例中 ``process`` 函数的 ``settings`` 参数)必须一致。该对象具有以下两个属性: - * settings.input_types:数据输入格式,具体请参考 `input_types`_ 。 - * settings.logger:一个logging对象。 -* 其他参数使用 ``kwargs`` (key word arguments)传入,包括以下两种: - * PaddlePaddle定义的参数: 1)is_train:bool型参数,表示用于训练或预测;2)file_list:所有文件列表。 - * 用户定义的参数:使用args在网络配置中设置。 - -注意:PaddlePaddle保留添加参数的权力,因此init_hook尽量使用 ``**kwargs`` 来接受不使用的函数以保证兼容性。 - -cache -+++++ - -PyDataProvider2提供了两种简单的Cache策略: - -* CacheType.NO_CACHE:不缓存任何数据,每次都会从python端读取数据 -* CacheType.CACHE_PASS_IN_MEM:第一个pass会从python端读取数据,剩下的pass会直接从内存里 - 读取数据。 - - -注意事项 --------- - -可能的内存泄露问题 -++++++++++++++++++ - -PaddlePaddle将train.list中的每一行都传递给process函数,从而生成多个generator。当训练数据非常多时,就会生成非常多的generator。 - -虽然每个generator在没有调用的时候,是几乎不占内存的;但当调用过一次后,generator便会存下当前的上下文(Context),而这个Context可能会非常大。并且,generator至少需要调用两次才会知道是否停止。所以,即使process函数里面只有一个yield,也需要两次随机选择到相同generator的时候,才会释放该段内存。 - -.. code-block:: python - - def func(): - yield 0 - - f = func() # 创建generator - tmp = next(f) # 调用一次,返回0 - tmp = next(f) # 调用第二次的时候,才会Stop Iteration - -由于顺序调用这些generator不会出现上述问题,因此有两种解决方案: - -1. **最佳推荐**:将样本的地址放入另一个文本文件,train.list写入那个文本文件的地址。即不要将每一个样本都放入train.list。 -2. 在generator的上下文中尽量留下非常少的变量引用,例如 - -.. code-block:: python - - def real_process(fn): - # ... read from fn - return result # 当函数返回的时候,python可以解除掉内部变量的引用。 - - def process(fn): - yield real_process(fn) - -注意:这个问题是PyDataProvider读数据时候的逻辑问题,很难整体修正。 - -内存不够用的情况 -++++++++++++++++ - -PyDataProvider2会尽可能多的使用内存。因此,对于内存较小的机器,推荐使用 ``pool_size`` 变量来设置内存中暂存的数据条。具体请参考 `@provider`_ 中的说明。 - diff --git a/doc/api/v1/data_provider/pydataprovider2_en.rst b/doc/api/v1/data_provider/pydataprovider2_en.rst deleted file mode 100644 index e8fb6292779790765154502bff319ea10ab1e70b..0000000000000000000000000000000000000000 --- a/doc/api/v1/data_provider/pydataprovider2_en.rst +++ /dev/null @@ -1,249 +0,0 @@ -.. _api_pydataprovider2: - -PyDataProvider2 -=============== - -We highly recommand users to use PyDataProvider2 to provide training or testing -data to PaddlePaddle. The user only needs to focus on how to read a single -sample from the original data file by using PyDataProvider2, leaving all of the -trivial work, including, transfering data into cpu/gpu memory, shuffle, binary -serialization to PyDataProvider2. PyDataProvider2 uses multithreading and a -fanscinating but simple cache strategy to optimize the efficiency of the data -providing process. - -DataProvider for the non-sequential model ------------------------------------------ - -Here we use the MNIST handwriting recognition data as an example to illustrate -how to write a simple PyDataProvider. - -MNIST is a handwriting classification data set. It contains 70,000 digital -grayscale images. Labels of the training sample range from 0 to 9. All the -images have been size-normalized and centered into images with the same size -of 28 x 28 pixels. - -A small part of the original data as an example is shown as below: - -.. literalinclude:: src/mnist_train.txt - -Each line of the data contains two parts, separated by :code:`;`. The first part is -label of an image. The second part contains 28x28 pixel float values. - -Just write path of the above data into train.list. It looks like this: - -.. literalinclude:: src/train.list - -The corresponding dataprovider is shown as below: - -.. literalinclude:: src/mnist_provider.dict.py - -The first line imports PyDataProvider2 package. -The main function is the process function, that has two parameters. -The first parameter is the settings, which is not used in this example. -The second parameter is the filename, that is exactly each line of train.list. -This parameter is passed to the process function by PaddlePaddle. - -:code:`@provider` is a Python -`Decorator `_ . -It sets some properties to DataProvider, and constructs a real PaddlePaddle -DataProvider from a very simple user implemented python function. It does not -matter if you are not familiar with `Decorator`_. You can keep it simple by -just taking :code:`@provider` as a fixed mark above the provider function you -implemented. - -`input_types`_ defines the data format that a DataProvider returns. -In this example, it is set to a 28x28-dimensional dense vector and an integer -scalar, whose value ranges from 0 to 9. -`input_types`_ can be set to several kinds of input formats, please refer to the -document of `input_types`_ for more details. - - -The process method is the core part to construct a real DataProvider in -PaddlePaddle. It implements how to open the text file, how to read one sample -from the original text file, convert them into `input_types`_, and give them -back to PaddlePaddle process at line 23. -Note that data yielded by the process function must follow the same order that -`input_types`_ are defined. - - -With the help of PyDataProvider2, user can focus on how to generate ONE traning -sample by using keywords :code:`yield`. -:code:`yield` is a python keyword, and a concept related to it includes -:code:`generator`. - -Only a few lines of codes need to be added into the training configuration file, -you can take this as an example. - -.. literalinclude:: src/mnist_config.py - -Here we specify training data by :code:`train.list`, and no testing data is specified. -The method which actually provide data is :code:`process`. - -User also can use another style to provide data, which defines the -:code:`data_layer`'s name explicitly when `yield`. For example, -the :code:`dataprovider` is shown as below. - -.. literalinclude:: src/mnist_provider.dict.py - :linenos: - -If user did't give the :code:`data_layer`'s name, PaddlePaddle will use -the order of :code:`data_layer` definition roughly to determine which feature to -which :code:`data_layer`. This order may be not correct, so TO DEFINE THE -:code:`data_layer`'s NAMES EXPLICITLY IS THE RECOMMANDED WAY TO PROVIDER DATA. - -Now, this simple example of using PyDataProvider is finished. -The only thing that the user should know is how to generte **one sample** from -**one data file**. -And PaddlePadle will do all of the rest things\: - -* Form a training batch -* Shuffle the training data -* Read data with multithreading -* Cache the training data (Optional) -* CPU-> GPU double buffering. - -Is this cool? - -.. _api_pydataprovider2_sequential_model: - -DataProvider for the sequential model -------------------------------------- -A sequence model takes sequences as its input. A sequence is made up of several -timesteps. The so-called timestep, is not necessary to have something to do -with time. It can also be explained to that the order of data are taken into -consideration into model design and training. -For example, the sentence can be interpreted as a kind of sequence data in NLP -tasks. - -Here is an example on data proivider for English sentiment classification data. -The original input data are simple English text, labeled into positive or -negative sentiment (marked by 0 and 1 respectively). - -A small part of the original data as an example can be found in the path below: - -.. literalinclude:: src/sentimental_train.txt - -The corresponding data provider can be found in the path below: - -.. literalinclude:: src/sentimental_provider.py - -This data provider for sequential model is a little more complex than that -for MINST dataset. -A new initialization method is introduced here. -The method :code:`on_init` is configured to DataProvider by :code:`@provider`'s -:code:`init_hook` parameter, and it will be invoked once DataProvider is -initialized. The :code:`on_init` function has the following parameters: - -* The first parameter is the settings object. -* The rest parameters are passed by key word arguments. Some of them are passed - by PaddlePaddle, see reference for `init_hook`_. - The :code:`dictionary` object is a python dict object passed from the trainer - configuration file, and it maps word string to word id. - -To pass these parameters into DataProvider, the following lines should be added -into trainer configuration file. - -.. literalinclude:: src/sentimental_config.py - -The definition is basically same as MNIST example, except: -* Load dictionary in this configuration -* Pass it as a parameter to the DataProvider - -The `input_types` is configured in method :code:`on_init`. It has the same -effect to configure them by :code:`@provider`'s :code:`input_types` parameter. -However, the :code:`input_types` is set at runtime, so we can set it to -different types according to the input data. Input of the neural network is a -sequence of word id, so set :code:`seq_type` to :code:`integer_value_sequence`. - -Durning :code:`on_init`, we save :code:`dictionary` variable to -:code:`settings`, and it will be used in :code:`process`. Note the settings -parameter for the process function and for the on_init's function are a same -object. - -The basic processing logic is the same as MNIST's :code:`process` method. Each -sample in the data file is given back to PaddlePaddle process. - -Thus, the basic usage of PyDataProvider is here. -Please refer to the following section reference for details. - -Reference ---------- - -@provider -+++++++++ - -.. autofunction:: paddle.trainer.PyDataProvider2.provider - -input_types -+++++++++++ - -PaddlePaddle has four data types, and three sequence types. -The four data types are: - -* :code:`dense_vector`: dense float vector. -* :code:`sparse_binary_vector`: sparse binary vector, most of the value is 0, and - the non zero elements are fixed to 1. -* :code:`sparse_float_vector`: sparse float vector, most of the value is 0, and some - non zero elements can be any float value. They are given by the user. -* :code:`integer`: an integer scalar, that is especially used for label or word index. - -The three sequence types are: - -* :code:`SequenceType.NO_SEQUENCE` means the sample is not a sequence. -* :code:`SequenceType.SEQUENCE` means the sample is a sequence. -* :code:`SequenceType.SUB_SEQUENCE` means it is a nested sequence, that each timestep of - the input sequence is also a sequence. - -Different input type has a defferenct input format. Their formats are shown -in the above table. - -+----------------------+---------------------+-----------------------------------+------------------------------------------------+ -| | NO_SEQUENCE | SEQUENCE | SUB_SEQUENCE | -+======================+=====================+===================================+================================================+ -| dense_vector | [f, f, ...] | [[f, ...], [f, ...], ...] | [[[f, ...], ...], [[f, ...], ...],...] | -+----------------------+---------------------+-----------------------------------+------------------------------------------------+ -| sparse_binary_vector | [i, i, ...] | [[i, ...], [i, ...], ...] | [[[i, ...], ...], [[i, ...], ...],...] | -+----------------------+---------------------+-----------------------------------+------------------------------------------------+ -| sparse_float_vector | [(i,f), (i,f), ...] | [[(i,f), ...], [(i,f), ...], ...] | [[[(i,f), ...], ...], [[(i,f), ...], ...],...] | -+----------------------+---------------------+-----------------------------------+------------------------------------------------+ -| integer_value | i | [i, i, ...] | [[i, ...], [i, ...], ...] | -+----------------------+---------------------+-----------------------------------+------------------------------------------------+ - -where f represents a float value, i represents an integer value. - -init_hook -+++++++++ - -init_hook is a function that is invoked once the data provoder is initialized. -Its parameters lists as follows: - -* The first parameter is a settings object, which is the same to :code:`settings` - in :code:`process` method. The object contains several attributes, including: - - * :code:`settings.input_types`: the input types. Reference `input_types`_. - * :code:`settings.logger`: a logging object. - -* The rest parameters are the key word arguments. It is made up of PaddpePaddle - pre-defined parameters and user defined parameters. - - * PaddlePaddle-defined parameters including: - - * :code:`is_train` is a bool parameter that indicates the DataProvider is used in - training or testing. - * :code:`file_list` is the list of all files. - - * User-defined parameters args can be set in training configuration. - -Note, PaddlePaddle reserves the right to add pre-defined parameter, so please -use :code:`**kwargs` in init_hook to ensure compatibility by accepting the -parameters which your init_hook does not use. - -cache -+++++ -DataProvider provides two simple cache strategy. They are: - -* :code:`CacheType.NO_CACHE` means do not cache any data, then data is read at runtime by - the user implemented python module every pass. -* :code:`CacheType.CACHE_PASS_IN_MEM` means the first pass reads data by the user - implemented python module, and the rest passes will directly read data from - memory. diff --git a/doc/api/v1/data_provider/src/mnist_config.py b/doc/api/v1/data_provider/src/mnist_config.py deleted file mode 100644 index d2af9d849ec48347d4d56c2b5b6b517671c37518..0000000000000000000000000000000000000000 --- a/doc/api/v1/data_provider/src/mnist_config.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2018 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. - -from paddle.trainer_config_helpers import * - -define_py_data_sources2( - train_list='train.list', - test_list=None, - module='mnist_provider', - obj='process') - -img = data_layer(name='pixel', size=784) -label = data_layer(name='label', size=10) diff --git a/doc/api/v1/data_provider/src/mnist_provider.dict.py b/doc/api/v1/data_provider/src/mnist_provider.dict.py deleted file mode 100644 index 284f7dadb065f8c8a891e949a800280cde9edda9..0000000000000000000000000000000000000000 --- a/doc/api/v1/data_provider/src/mnist_provider.dict.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2018 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. - -from paddle.trainer.PyDataProvider2 import * - - -# Define a py data provider -@provider( - input_types={'pixel': dense_vector(28 * 28), - 'label': integer_value(10)}) -def process(settings, filename): # settings is not used currently. - f = open(filename, 'r') # open one of training file - - for line in f: # read each line - label, pixel = line.split(';') - - # get features and label - pixels_str = pixel.split(' ') - - pixels_float = [] - for each_pixel_str in pixels_str: - pixels_float.append(float(each_pixel_str)) - - # give data to paddle. - yield {"pixel": pixels_float, 'label': int(label)} - - f.close() # close file diff --git a/doc/api/v1/data_provider/src/mnist_train.txt b/doc/api/v1/data_provider/src/mnist_train.txt deleted file mode 100644 index 34be718ad9ea49e7d9aabc34ad70099479df3b31..0000000000000000000000000000000000000000 --- a/doc/api/v1/data_provider/src/mnist_train.txt +++ /dev/null @@ -1,3 +0,0 @@ -5;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.215686 0.533333 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.67451 0.992157 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.070588 0.886275 0.992157 0 0 0 0 0 0 0 0 0 0 0.192157 0.070588 0 0 0 0 0 0 0 0 0 0 0 0 0 0.670588 0.992157 0.992157 0 0 0 0 0 0 0 0 0 0.117647 0.933333 0.858824 0.313725 0 0 0 0 0 0 0 0 0 0 0 0.090196 0.858824 0.992157 0.831373 0 0 0 0 0 0 0 0 0 0.141176 0.992157 0.992157 0.611765 0.054902 0 0 0 0 0 0 0 0 0 0 0.258824 0.992157 0.992157 0.529412 0 0 0 0 0 0 0 0 0 0.368627 0.992157 0.992157 0.419608 0.003922 0 0 0 0 0 0 0 0 0 0.094118 0.835294 0.992157 0.992157 0.517647 0 0 0 0 0 0 0 0 0 0.603922 0.992157 0.992157 0.992157 0.603922 0.545098 0.043137 0 0 0 0 0 0 0 0.447059 0.992157 0.992157 0.956863 0.062745 0 0 0 0 0 0 0 0 0.011765 0.666667 0.992157 0.992157 0.992157 0.992157 0.992157 0.745098 0.137255 0 0 0 0 0 0.152941 0.866667 0.992157 0.992157 0.521569 0 0 0 0 0 0 0 0 0 0.070588 0.992157 0.992157 0.992157 0.803922 0.352941 0.745098 0.992157 0.945098 0.317647 0 0 0 0 0.580392 0.992157 0.992157 0.764706 0.043137 0 0 0 0 0 0 0 0 0 0.070588 0.992157 0.992157 0.776471 0.043137 0 0.007843 0.27451 0.882353 0.941176 0.176471 0 0 0.180392 0.898039 0.992157 0.992157 0.313725 0 0 0 0 0 0 0 0 0 0 0.070588 0.992157 0.992157 0.713725 0 0 0 0 0.627451 0.992157 0.729412 0.062745 0 0.509804 0.992157 0.992157 0.776471 0.035294 0 0 0 0 0 0 0 0 0 0 0.494118 0.992157 0.992157 0.968627 0.168627 0 0 0 0.423529 0.992157 0.992157 0.364706 0 0.717647 0.992157 0.992157 0.317647 0 0 0 0 0 0 0 0 0 0 0 0.533333 0.992157 0.984314 0.945098 0.603922 0 0 0 0.003922 0.466667 0.992157 0.988235 0.976471 0.992157 0.992157 0.788235 0.007843 0 0 0 0 0 0 0 0 0 0 0 0.686275 0.882353 0.364706 0 0 0 0 0 0 0.098039 0.588235 0.992157 0.992157 0.992157 0.980392 0.305882 0 0 0 0 0 0 0 0 0 0 0 0 0.101961 0.67451 0.321569 0 0 0 0 0 0 0 0.105882 0.733333 0.976471 0.811765 0.713725 0 0 0 0 0 0 0 0 0 0 0 0 0 0.65098 0.992157 0.321569 0 0 0 0 0 0 0 0 0 0.25098 0.007843 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0.94902 0.219608 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.968627 0.764706 0.152941 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.498039 0.25098 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; -0;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.298039 0.333333 0.333333 0.333333 0.337255 0.333333 0.333333 0.109804 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.027451 0.223529 0.776471 0.964706 0.988235 0.988235 0.988235 0.992157 0.988235 0.988235 0.780392 0.098039 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.14902 0.698039 0.988235 0.992157 0.988235 0.901961 0.87451 0.568627 0.882353 0.976471 0.988235 0.988235 0.501961 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.188235 0.647059 0.988235 0.988235 0.745098 0.439216 0.098039 0 0 0 0.572549 0.988235 0.988235 0.988235 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0.933333 0.992157 0.941176 0.247059 0 0 0 0 0 0 0.188235 0.898039 0.992157 0.992157 0 0 0 0 0 0 0 0 0 0 0 0.039216 0.639216 0.933333 0.988235 0.913725 0.278431 0 0 0 0 0 0 0 0.113725 0.843137 0.988235 0.988235 0 0 0 0 0 0 0 0 0 0 0 0.235294 0.988235 0.992157 0.988235 0.815686 0.07451 0 0 0 0 0 0 0 0.333333 0.988235 0.988235 0.552941 0 0 0 0 0 0 0 0 0 0 0.211765 0.878431 0.988235 0.992157 0.701961 0.329412 0.109804 0 0 0 0 0 0 0 0.698039 0.988235 0.913725 0.145098 0 0 0 0 0 0 0 0 0 0.188235 0.890196 0.988235 0.988235 0.745098 0.047059 0 0 0 0 0 0 0 0 0 0.882353 0.988235 0.568627 0 0 0 0 0 0 0 0 0 0.2 0.933333 0.992157 0.992157 0.992157 0.447059 0.294118 0 0 0 0 0 0 0 0 0.447059 0.992157 0.768627 0 0 0 0 0 0 0 0 0 0 0.623529 0.988235 0.988235 0.988235 0.988235 0.992157 0.47451 0 0 0 0 0 0 0 0.188235 0.933333 0.87451 0.509804 0 0 0 0 0 0 0 0 0 0 0.992157 0.988235 0.937255 0.792157 0.988235 0.894118 0.082353 0 0 0 0 0 0 0.027451 0.647059 0.992157 0.654902 0 0 0 0 0 0 0 0 0 0 0 0.623529 0.988235 0.913725 0.329412 0.376471 0.184314 0 0 0 0 0 0 0.027451 0.513725 0.988235 0.635294 0.219608 0 0 0 0 0 0 0 0 0 0 0 0.196078 0.929412 0.988235 0.988235 0.741176 0.309804 0 0 0 0 0 0 0.529412 0.988235 0.678431 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.223529 0.992157 0.992157 1 0.992157 0.992157 0.992157 0.992157 1 0.992157 0.992157 0.882353 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.023529 0.478431 0.654902 0.658824 0.952941 0.988235 0.988235 0.988235 0.992157 0.988235 0.729412 0.278431 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.196078 0.647059 0.764706 0.764706 0.768627 0.580392 0.047059 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; -4;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.180392 0.470588 0.623529 0.623529 0.623529 0.588235 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.243137 0.494118 0.862745 0.870588 0.960784 0.996078 0.996078 0.996078 0.996078 0.992157 0.466667 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.317647 0.639216 0.639216 0.639216 0.639216 0.639216 0.470588 0.262745 0.333333 0.929412 0.694118 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.811765 0.694118 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.811765 0.694118 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.811765 0.694118 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.184314 0.992157 0.694118 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.192157 0.996078 0.384314 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.454902 0.980392 0.219608 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.564706 0.941176 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.588235 0.776471 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.945098 0.560784 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.054902 0.952941 0.356863 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.337255 0.917647 0.109804 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.698039 0.701961 0.019608 0.4 0.662745 0.662745 0.662745 0.662745 0.662745 0.662745 0.662745 0.376471 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.090196 0.639216 0.972549 0.945098 0.913725 0.996078 0.996078 0.996078 0.996078 1 0.996078 0.996078 1 0.996078 0 0 0 0 0 0 0 0 0 0 0.007843 0.105882 0.717647 0.776471 0.905882 0.996078 0.996078 0.988235 0.980392 0.862745 0.537255 0.223529 0.223529 0.368627 0.376471 0.6 0.6 0.6 0 0 0 0 0 0 0 0 0.262745 0.470588 0.6 0.996078 0.996078 0.996078 0.996078 0.847059 0.356863 0.156863 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.909804 0.705882 0.823529 0.635294 0.490196 0.219608 0.113725 0.062745 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.152941 0.152941 0.156863 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; diff --git a/doc/api/v1/data_provider/src/sentimental_config.py b/doc/api/v1/data_provider/src/sentimental_config.py deleted file mode 100644 index 56adde13b97b30095729da5246805a2902870676..0000000000000000000000000000000000000000 --- a/doc/api/v1/data_provider/src/sentimental_config.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (c) 2018 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. - -from paddle.trainer_config_helpers import * - -dictionary = dict() -... # read dictionary from outside - -define_py_data_sources2( - train_list='train.list', - test_list=None, - module='sentimental_provider', - obj='process', - # above codes same as mnist sample. - args={ # pass to provider. - 'dictionary': dictionary - }) diff --git a/doc/api/v1/data_provider/src/sentimental_provider.py b/doc/api/v1/data_provider/src/sentimental_provider.py deleted file mode 100644 index 59a2b6f7f5faff847f6fda15827632c4ab236b21..0000000000000000000000000000000000000000 --- a/doc/api/v1/data_provider/src/sentimental_provider.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2018 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. - -from paddle.trainer.PyDataProvider2 import * - - -def on_init(settings, dictionary, **kwargs): - # on_init will invoke when data provider is initialized. The dictionary - # is passed from trainer_config, and is a dict object with type - # (word string => word id). - - # set input types in runtime. It will do the same thing as - # @provider(input_types) will do, but it is set dynamically during runtime. - settings.input_types = { - # The text is a sequence of integer values, and each value is a word id. - # The whole sequence is the sentences that we want to predict its - # sentimental. - 'data': integer_value_sequence(len(dictionary)), # text input - 'label': integer_value(2) # label positive/negative - } - - # save dictionary as settings.dictionary. - # It will be used in process method. - settings.dictionary = dictionary - - -@provider(init_hook=on_init) -def process(settings, filename): - f = open(filename, 'r') - - for line in f: # read each line of file - label, sentence = line.split('\t') # get label and sentence - words = sentence.split(' ') # get words - - # convert word string to word id - # the word not in dictionary will be ignored. - word_ids = [] - - for each_word in words: - if each_word in settings.dictionary: - word_ids.append(settings.dictionary[each_word]) - - # give data to paddle. - yield word_ids, int(label) - - f.close() diff --git a/doc/api/v1/data_provider/src/sentimental_train.txt b/doc/api/v1/data_provider/src/sentimental_train.txt deleted file mode 100644 index 0060ac267c4bf884a8e19553bc4bdea48c89c9b2..0000000000000000000000000000000000000000 --- a/doc/api/v1/data_provider/src/sentimental_train.txt +++ /dev/null @@ -1,3 +0,0 @@ -0 I saw this movie at the AFI Dallas festival . It all takes place at a lake house and it looks wonderful . -1 This documentary makes you travel all around the globe . It contains rare and stunning sequels from the wilderness . -... diff --git a/doc/api/v1/data_provider/src/train.list b/doc/api/v1/data_provider/src/train.list deleted file mode 100644 index 92bdc0a8b4c21b3091341d93afc5c536c3cffe47..0000000000000000000000000000000000000000 --- a/doc/api/v1/data_provider/src/train.list +++ /dev/null @@ -1 +0,0 @@ -mnist_train.txt diff --git a/doc/api/v1/index_cn.rst b/doc/api/v1/index_cn.rst deleted file mode 100644 index cf146dc088e3905a751ff55c26fd82ef0ba02c89..0000000000000000000000000000000000000000 --- a/doc/api/v1/index_cn.rst +++ /dev/null @@ -1,37 +0,0 @@ -API中文手册 -============ - -DataProvider API ----------------- - -.. toctree:: - :maxdepth: 1 - - data_provider/dataprovider_cn.rst - data_provider/pydataprovider2_cn.rst - -.. _api_trainer_config: - -Model Config API ----------------- - -.. toctree:: - :maxdepth: 1 - - trainer_config_helpers/optimizers.rst - trainer_config_helpers/data_sources.rst - trainer_config_helpers/layers.rst - trainer_config_helpers/activations.rst - trainer_config_helpers/poolings.rst - trainer_config_helpers/networks.rst - trainer_config_helpers/evaluators.rst - trainer_config_helpers/attrs.rst - - -Applications API ----------------- - -.. toctree:: - :maxdepth: 1 - - predict/swig_py_paddle_cn.rst diff --git a/doc/api/v1/index_en.rst b/doc/api/v1/index_en.rst deleted file mode 100644 index 10c297a71d6988c002de868e804ed9ee2345fbd7..0000000000000000000000000000000000000000 --- a/doc/api/v1/index_en.rst +++ /dev/null @@ -1,37 +0,0 @@ -API -=== - -DataProvider API ----------------- - -.. toctree:: - :maxdepth: 1 - - data_provider/dataprovider_en.rst - data_provider/pydataprovider2_en.rst - -.. _api_trainer_config: - -Model Config API ----------------- - -.. toctree:: - :maxdepth: 1 - - trainer_config_helpers/optimizers.rst - trainer_config_helpers/data_sources.rst - trainer_config_helpers/layers.rst - trainer_config_helpers/activations.rst - trainer_config_helpers/poolings.rst - trainer_config_helpers/networks.rst - trainer_config_helpers/evaluators.rst - trainer_config_helpers/attrs.rst - - -Applications API ----------------- - -.. toctree:: - :maxdepth: 1 - - predict/swig_py_paddle_en.rst diff --git a/doc/api/v1/predict/src/predict_sample.py b/doc/api/v1/predict/src/predict_sample.py deleted file mode 100644 index 51349250e80ce11e476d952991f0d046f65286b4..0000000000000000000000000000000000000000 --- a/doc/api/v1/predict/src/predict_sample.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved -# -# 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. - -from py_paddle import swig_paddle, DataProviderConverter -from paddle.trainer.PyDataProvider2 import dense_vector -from paddle.trainer.config_parser import parse_config - -TEST_DATA = [[[ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.215686, 0.533333, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.67451, 0.992157, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0.070588, 0.886275, 0.992157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.192157, - 0.070588, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.670588, 0.992157, - 0.992157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.117647, 0.933333, 0.858824, 0.313725, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.090196, 0.858824, 0.992157, 0.831373, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0.141176, 0.992157, 0.992157, 0.611765, 0.054902, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.258824, 0.992157, 0.992157, 0.529412, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0.368627, 0.992157, 0.992157, 0.419608, 0.003922, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0.094118, 0.835294, 0.992157, 0.992157, 0.517647, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0.603922, 0.992157, 0.992157, 0.992157, 0.603922, - 0.545098, 0.043137, 0, 0, 0, 0, 0, 0, 0, 0.447059, 0.992157, 0.992157, - 0.956863, 0.062745, 0, 0, 0, 0, 0, 0, 0, 0, 0.011765, 0.666667, 0.992157, - 0.992157, 0.992157, 0.992157, 0.992157, 0.745098, 0.137255, 0, 0, 0, 0, 0, - 0.152941, 0.866667, 0.992157, 0.992157, 0.521569, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0.070588, 0.992157, 0.992157, 0.992157, 0.803922, 0.352941, 0.745098, - 0.992157, 0.945098, 0.317647, 0, 0, 0, 0, 0.580392, 0.992157, 0.992157, - 0.764706, 0.043137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.070588, 0.992157, 0.992157, - 0.776471, 0.043137, 0, 0.007843, 0.27451, 0.882353, 0.941176, 0.176471, 0, - 0, 0.180392, 0.898039, 0.992157, 0.992157, 0.313725, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0.070588, 0.992157, 0.992157, 0.713725, 0, 0, 0, 0, 0.627451, - 0.992157, 0.729412, 0.062745, 0, 0.509804, 0.992157, 0.992157, 0.776471, - 0.035294, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.494118, 0.992157, 0.992157, - 0.968627, 0.168627, 0, 0, 0, 0.423529, 0.992157, 0.992157, 0.364706, 0, - 0.717647, 0.992157, 0.992157, 0.317647, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0.533333, 0.992157, 0.984314, 0.945098, 0.603922, 0, 0, 0, 0.003922, - 0.466667, 0.992157, 0.988235, 0.976471, 0.992157, 0.992157, 0.788235, - 0.007843, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.686275, 0.882353, 0.364706, 0, - 0, 0, 0, 0, 0, 0.098039, 0.588235, 0.992157, 0.992157, 0.992157, 0.980392, - 0.305882, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.101961, 0.67451, 0.321569, - 0, 0, 0, 0, 0, 0, 0, 0.105882, 0.733333, 0.976471, 0.811765, 0.713725, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.65098, 0.992157, 0.321569, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0.25098, 0.007843, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0.94902, 0.219608, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0.968627, 0.764706, 0.152941, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.498039, 0.25098, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 -]], [[ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0.298039, 0.333333, 0.333333, 0.333333, 0.337255, - 0.333333, 0.333333, 0.109804, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0.027451, 0.223529, 0.776471, 0.964706, 0.988235, 0.988235, 0.988235, - 0.992157, 0.988235, 0.988235, 0.780392, 0.098039, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0.14902, 0.698039, 0.988235, 0.992157, 0.988235, 0.901961, - 0.87451, 0.568627, 0.882353, 0.976471, 0.988235, 0.988235, 0.501961, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.188235, 0.647059, 0.988235, 0.988235, - 0.745098, 0.439216, 0.098039, 0, 0, 0, 0.572549, 0.988235, 0.988235, - 0.988235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2, 0.933333, 0.992157, - 0.941176, 0.247059, 0, 0, 0, 0, 0, 0, 0.188235, 0.898039, 0.992157, - 0.992157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.039216, 0.639216, 0.933333, - 0.988235, 0.913725, 0.278431, 0, 0, 0, 0, 0, 0, 0, 0.113725, 0.843137, - 0.988235, 0.988235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.235294, 0.988235, - 0.992157, 0.988235, 0.815686, 0.07451, 0, 0, 0, 0, 0, 0, 0, 0.333333, - 0.988235, 0.988235, 0.552941, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.211765, - 0.878431, 0.988235, 0.992157, 0.701961, 0.329412, 0.109804, 0, 0, 0, 0, 0, - 0, 0, 0.698039, 0.988235, 0.913725, 0.145098, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0.188235, 0.890196, 0.988235, 0.988235, 0.745098, 0.047059, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0.882353, 0.988235, 0.568627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2, - 0.933333, 0.992157, 0.992157, 0.992157, 0.447059, 0.294118, 0, 0, 0, 0, 0, - 0, 0, 0, 0.447059, 0.992157, 0.768627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0.623529, 0.988235, 0.988235, 0.988235, 0.988235, 0.992157, 0.47451, 0, 0, - 0, 0, 0, 0, 0, 0.188235, 0.933333, 0.87451, 0.509804, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0.992157, 0.988235, 0.937255, 0.792157, 0.988235, 0.894118, - 0.082353, 0, 0, 0, 0, 0, 0, 0.027451, 0.647059, 0.992157, 0.654902, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0.623529, 0.988235, 0.913725, 0.329412, 0.376471, - 0.184314, 0, 0, 0, 0, 0, 0, 0.027451, 0.513725, 0.988235, 0.635294, - 0.219608, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.196078, 0.929412, 0.988235, - 0.988235, 0.741176, 0.309804, 0, 0, 0, 0, 0, 0, 0.529412, 0.988235, - 0.678431, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.223529, 0.992157, - 0.992157, 1, 0.992157, 0.992157, 0.992157, 0.992157, 1, 0.992157, 0.992157, - 0.882353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.023529, - 0.478431, 0.654902, 0.658824, 0.952941, 0.988235, 0.988235, 0.988235, - 0.992157, 0.988235, 0.729412, 0.278431, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0.196078, 0.647059, 0.764706, 0.764706, 0.768627, - 0.580392, 0.047059, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0 -]]] - - -def main(): - conf = parse_config("./mnist_model/trainer_config.py", "") - print conf.data_config.load_data_args - network = swig_paddle.GradientMachine.createFromConfigProto( - conf.model_config) - assert isinstance(network, swig_paddle.GradientMachine) # For code hint. - network.loadParameters("./mnist_model/") - converter = DataProviderConverter([dense_vector(784)]) - inArg = converter(TEST_DATA) - print network.forwardTest(inArg) - - -if __name__ == '__main__': - swig_paddle.initPaddle("--use_gpu=0") - main() diff --git a/doc/api/v1/predict/swig_py_paddle_cn.rst b/doc/api/v1/predict/swig_py_paddle_cn.rst deleted file mode 100644 index 42f333dba2e996e70572b3cda085b83e402ede8e..0000000000000000000000000000000000000000 --- a/doc/api/v1/predict/swig_py_paddle_cn.rst +++ /dev/null @@ -1,58 +0,0 @@ -.. _api_swig_py_paddle: - -基于Python的预测 -================ - -预测流程 --------- - -PaddlePaddle使用swig对常用的预测接口进行了封装,通过编译会生成py_paddle软件包,安装该软件包就可以在python环境下实现模型预测。可以使用python的 ``help()`` 函数查询软件包相关API说明。 - -基于Python的模型预测,主要包括以下五个步骤。 - -1. 初始化PaddlePaddle环境 - - 在程序开始阶段,通过调用 ``swig_paddle.initPaddle()`` 并传入相应的命令行参数初始化PaddlePaddle。 - -2. 解析模型配置文件 - - 初始化之后,可以通过调用 ``parse_config()`` 解析训练模型时用的配置文件。注意预测数据通常不包含label, 同时预测网络通常直接输出最后一层的结果而不是像训练网络一样再接一层cost layer,所以一般需要对训练用的模型配置文件稍作相应修改才能在预测时使用。 - -3. 构造paddle.GradientMachine - - 通过调用 ``swig_paddle.GradientMachine.createFromConfigproto()`` 传入上一步解析出来的模型配置就可以创建一个 ``GradientMachine``。 - -4. 准备预测数据 - - swig_paddle中的预测接口的参数是自定义的C++数据类型,py_paddle里面提供了一个工具类 ``DataProviderConverter`` 可以用于接收和PyDataProvider2一样的输入数据并转换成预测接口所需的数据类型。 - -5. 模型预测 - - 通过调用 ``forwardTest()`` 传入预测数据,直接返回计算结果。 - - -预测Demo --------- - -如下是一段使用mnist model来实现手写识别的预测代码。完整的代码见 ``src_root/doc/ui/predict/predict_sample.py`` 。mnist model可以通过 ``src_root\demo\mnist`` 目录下的demo训练出来。 - -.. literalinclude:: src/predict_sample.py - :language: python - :lines: 15-18,121-136 - - -Demo预测输出如下,其中value即为softmax层的输出。由于TEST_DATA包含两条预测数据,所以输出的value包含两个向量 。 - -.. code-block:: text - - [{'id': None, 'value': array( - [[ 5.53018653e-09, 1.12194102e-05, 1.96644767e-09, - 1.43630644e-02, 1.51111044e-13, 9.85625684e-01, - 2.08823112e-10, 2.32777140e-08, 2.00186201e-09, - 1.15501715e-08], - [ 9.99982715e-01, 1.27787406e-10, 1.72296313e-05, - 1.49316648e-09, 1.36540484e-11, 6.93137714e-10, - 2.70634608e-08, 3.48565123e-08, 5.25639710e-09, - 4.48684503e-08]], dtype=float32)}] - - diff --git a/doc/api/v1/predict/swig_py_paddle_en.rst b/doc/api/v1/predict/swig_py_paddle_en.rst deleted file mode 100644 index 1c628e6971fa5643e6a9ca629488049957686193..0000000000000000000000000000000000000000 --- a/doc/api/v1/predict/swig_py_paddle_en.rst +++ /dev/null @@ -1,59 +0,0 @@ -Python Prediction -================== - -PaddlePaddle offers a set of clean prediction interfaces for python with the help of -SWIG. The main steps of predict values in python are: - -* Parse training configurations -* Construct GradientMachine -* Prepare data -* Predict - -Here is a sample python script that shows the typical prediction process for the -MNIST classification problem. A complete sample code could be found at -:code:`src_root/doc/ui/predict/predict_sample.py`. - -.. literalinclude:: src/predict_sample.py - :language: python - :lines: 15-18,90-100,101-104 - -The module that does the most of the job is py_paddle.swig_paddle, it's -generated by SWIG and has complete documents, for more details you can use -python's :code:`help()` function. Let's walk through the above python script: - -* At the beginning, use :code:`swig_paddle.initPaddle()` to initialize - PaddlePaddle with command line arguments, for more about command line arguments - see :ref:`cmd_detail_introduction` . -* Parse the configuration file that is used in training with :code:`parse_config()`. - Because data to predict with always have no label, and output of prediction work - normally is the output layer rather than the cost layer, so you should modify - the configuration file accordingly before using it in the prediction work. -* Create a neural network with - :code:`swig_paddle.GradientMachine.createFromConfigproto()`, which takes the - parsed configuration :code:`conf.model_config` as argument. Then load the - trained parameters from the model with :code:`network.loadParameters()`. -* Create a data converter object of utility class :code:`DataProviderConverter`. - - Note: As swig_paddle can only accept C++ matrices, we offer a utility - class DataProviderConverter that can accept the same input data with - PyDataProvider2, for more information please refer to document - of :ref:`api_pydataprovider2` . -* Do the prediction with :code:`forwardTest()`, which takes the converted - input data and outputs the activations of the output layer. - -Here is a typical output: - -.. code-block:: text - - [{'id': None, 'value': array([[ 5.53018653e-09, 1.12194102e-05, 1.96644767e-09, - 1.43630644e-02, 1.51111044e-13, 9.85625684e-01, - 2.08823112e-10, 2.32777140e-08, 2.00186201e-09, - 1.15501715e-08], - [ 9.99982715e-01, 1.27787406e-10, 1.72296313e-05, - 1.49316648e-09, 1.36540484e-11, 6.93137714e-10, - 2.70634608e-08, 3.48565123e-08, 5.25639710e-09, - 4.48684503e-08]], dtype=float32)}] - -:code:`value` is the output of the output layer, each row represents result of -the corresponding row in the input data, each element represents activation of -the corresponding neuron in the output layer. - diff --git a/doc/api/v2/fluid/layers.rst b/doc/api/v2/fluid/layers.rst index a82127a36d1fb0726965fe00d3633312b889592c..7c2dd68b184d5ccb3769764882964b98b9af27f1 100644 --- a/doc/api/v2/fluid/layers.rst +++ b/doc/api/v2/fluid/layers.rst @@ -505,6 +505,16 @@ im2sequence .. autofunction:: paddle.v2.fluid.layers.im2sequence :noindex: +edit_distance +--------------- +.. autofunction:: paddle.v2.fluid.layers.edit_distance_error + :noindex: + +ctc_greedy_decoder +--------------- +.. autofunction:: paddle.v2.fluid.layers.ctc_greedy_decoder + :noindex: + l2_normalize ------------ .. autofunction:: paddle.v2.fluid.layers.l2_normalize diff --git a/doc/faq/local/index_cn.rst b/doc/faq/local/index_cn.rst index b331d9d36e6a279881c3b1a5586835e7186957fb..0306b1e5dd25a55545e464ce847291c33576575f 100644 --- a/doc/faq/local/index_cn.rst +++ b/doc/faq/local/index_cn.rst @@ -211,3 +211,49 @@ decoder_inputs = paddle.layer.fc( * list 中元素的个数等于网络中输出层的个数; * list 中每个元素是一个layer的输出结果矩阵,类型是numpy的ndarray; * 每一个layer输出矩阵的高度,在非序列输入时:等于样本数;序列输入时等于:输入序列中元素的总数;宽度等于配置中layer的size; + +6. 如何在训练过程中获得某一个layer的output +----------------------------------------------- + +可以在event_handler中,通过 :code:`event.gm.getLayerOutputs("layer_name")` 获得在模型配置中某一层的name :code:`layer_name` 在当前 +mini-batch forward的output的值。获得的值类型均为 :code:`numpy.ndarray` ,可以通过这个输出来完成自定义的评估指标计算等功能。例如下面代码: + +.. code-block:: python + + def score_diff(right_score, left_score): + return np.average(np.abs(right_score - left_score)) + + def event_handler(event): + if isinstance(event, paddle.event.EndIteration): + if event.batch_id % 25 == 0: + diff = score_diff( + event.gm.getLayerOutputs("right_score")["right_score"][ + "value"], + event.gm.getLayerOutputs("left_score")["left_score"][ + "value"]) + logger.info(("Pass %d Batch %d : Cost %.6f, " + "average absolute diff scores: %.6f") % + (event.pass_id, event.batch_id, event.cost, diff)) + +注意:此方法不能获取 :code:`paddle.layer.recurrent_group` 里step的内容,但可以获取 :code:`paddle.layer.recurrent_group` 的输出。 + +7. 如何在训练过程中获得参数的权重和梯度 +----------------------------------------------- + +在某些情况下,获得当前mini-batch的权重(或称作weights, parameters)有助于在训练时观察具体数值,方便排查以及快速定位问题。 +可以通过在 :code:`event_handler` 中打印其值(注意,需要使用 :code:`paddle.event.EndForwardBackward` 保证使用GPU训练时也可以获得), +示例代码如下: + +.. code-block:: python + + ... + parameters = paddle.parameters.create(cost) + ... + def event_handler(event): + if isinstance(event, paddle.event.EndForwardBackward): + if event.batch_id % 25 == 0: + for p in parameters.keys(): + logger.info("Param %s, Grad %s", + parameters.get(p), parameters.get_grad(p)) + +注意:“在训练过程中获得某一个layer的output”和“在训练过程中获得参数的权重和梯度”都会造成训练中的数据从C++拷贝到numpy,会对训练性能造成影响。不要在注重性能的训练场景下使用。 \ No newline at end of file diff --git a/doc/howto/usage/cluster/fluid_cluster_train_en.md b/doc/howto/usage/cluster/fluid_cluster_train_en.md index a64004a7c4ea12bc0d949d7f11f3e26af62bf912..11904a6f71bb6ce37417aeffb8e408ec65961b12 100644 --- a/doc/howto/usage/cluster/fluid_cluster_train_en.md +++ b/doc/howto/usage/cluster/fluid_cluster_train_en.md @@ -2,27 +2,27 @@ ## Introduction -In this article, we'll explain how to config and run distributed training jobs with PaddlePaddle Fluid in a bare metal cluster. +In this article, we'll explain how to configure and run distributed training jobs with PaddlePaddle Fluid in a bare metal cluster. ## Preparations -### Get your cluster ready +### Getting the cluster ready -Prepare your computer nodes in the cluster. Nodes in this cluster can be of any specification that runs PaddlePaddle, and with a unique IP address assigned to it. Make sure they can communicate with each other. +Prepare the compute nodes in the cluster. Nodes in this cluster can be of any specification that runs PaddlePaddle, and with a unique IP address assigned to it. Make sure they can communicate to each other. ### Have PaddlePaddle installed PaddlePaddle must be installed on all nodes. If you have GPU cards on your nodes, be sure to properly install drivers and CUDA libraries. -PaddlePaddle build and installation guide can be found from [here](http://www.paddlepaddle.org/docs/develop/documentation/en/getstarted/build_and_install/index_en.html). +PaddlePaddle build and installation guide can be found [here](http://www.paddlepaddle.org/docs/develop/documentation/en/getstarted/build_and_install/index_en.html). -### Update training script +### Update the training script #### Non-cluster training script Let's take [Deep Learning 101](http://www.paddlepaddle.org/docs/develop/book/01.fit_a_line/index.html)'s first chapter: "fit a line" as an example. -This demo's non-cluster version with fluid API is as follows: +The non-cluster version of this demo with fluid API is as follows: ``` python import paddle.v2 as paddle @@ -65,25 +65,25 @@ for pass_id in range(PASS_NUM): exit(1) ``` -We created a simple fully connected neural networks training program and handed it to the fluid executor to run for 100 passes. +We created a simple fully-connected neural network training program and handed it to the fluid executor to run for 100 passes. -Now let's try to convert it to a distributed version to run in a cluster. +Now let's try to convert it to a distributed version to run on a cluster. #### Introducing parameter server -As you see from the non-cluster version of training script, there is only one role in it: the trainer, who does the computing as well as holding parameters. In cluster training, since multi-trainers are working on the same task, they need one centralized place to hold and distribute parameters. This centralized place is called the Parameter Server in PaddlePaddle. +As we can see from the non-cluster version of training script, there is only one role in the script: the trainer, that performs the computing as well as holds the parameters. In cluster training, since multi-trainers are working on the same task, they need one centralized place to hold and distribute parameters. This centralized place is called the Parameter Server in PaddlePaddle. -![parameter server architect](src/trainer.png) +![parameter server architecture](src/trainer.png) -Parameter Server in fluid does not only hold parameters but is also assigned with a part of the program. Trainers communicate with parameter servers via send/receive OPs. For more tech detail, please refer to this [document](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/dist_refactor/distributed_architecture.md). +Parameter Server in fluid not only holds the parameters but is also assigned with a part of the program. Trainers communicate with parameter servers via send/receive OPs. For more technical details, please refer to [this document](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/dist_refactor/distributed_architecture.md). -Now we need to create program for both trainers and parameter servers, the question is how? +Now we need to create programs for both: trainers and parameter servers, the question is how? #### Slice the program -Fluid provides a tool called "Distribute Transpiler" to automatically convert the non-cluster program into cluster program. +Fluid provides a tool called "Distributed Transpiler" that automatically converts the non-cluster program into cluster program. -The idea behind this tool is to find optimize OPs and gradient parameters, slice the program into 2 pieces and connect them with send/receive OP. +The idea behind this tool is to find the optimize OPs and gradient parameters, slice the program into 2 pieces and connect them with send/receive OP. Optimize OPs and gradient parameters can be found from the return values of optimizer's minimize function. @@ -94,9 +94,9 @@ To put them together: optimize_ops, params_grads = sgd_optimizer.minimize(avg_cost) #get optimize OPs and gradient parameters -t = fluid.DistributeTranspiler() # create transpiler instance +t = fluid.DistributeTranspiler() # create the transpiler instance # slice the program into 2 pieces with optimizer_ops and gradient parameters list, as well as pserver_endpoints, which is a comma separated list of [IP:PORT] and number of trainers -t.transpile(optimize_ops, params_grads, pservers=pserver_endpoints, trainers=2) +t.transpile(optimize_ops, params_grads, pservers=pserver_endpoints, trainers=2) ... #create executor @@ -119,7 +119,7 @@ for pass_id in range(100): ### E2E demo -Please find the complete demo from [here](https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/v2/fluid/tests/book_distribute/notest_dist_fit_a_line.py). In parameter server node run this in the command line: +Please find the complete demo from [here](https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/v2/fluid/tests/book_distribute/notest_dist_fit_a_line.py). In parameter server node run the following in the command line: ``` bash PSERVERS=192.168.1.2:6174 SERVER_ENDPOINT=192.168.1.2:6174 TRAINING_ROLE=PSERVER python notest_dist_fit_a_line.py @@ -129,12 +129,12 @@ PSERVERS=192.168.1.2:6174 SERVER_ENDPOINT=192.168.1.2:6174 TRAINING_ROLE=PSERVER Wait until the prompt `Server listening on 192.168.1.2:6174` -Then in 2 of your trainer node run this: +Then in 2 of your trainer nodes run this: ``` bash PSERVERS=192.168.1.2:6174 SERVER_ENDPOINT=192.168.1.2:6174 TRAINING_ROLE=TRAINER python notest_dist_fit_a_line.py ``` -*the reason you need to run this command twice in 2 nodes is: in the script we set the trainer count to be 2. You can change this setting on line 50* +*the reason you need to run this command twice in 2 nodes is because: in the script we set the trainer count to be 2. You can change this setting on line 50* Now you have 2 trainers and 1 parameter server up and running. diff --git a/paddle/framework/CMakeLists.txt b/paddle/framework/CMakeLists.txt index afb55bdaaae8e6d46d5791991c92f2b61652ac55..a912d8492fc6c23f88dd675694b805d0eda88335 100644 --- a/paddle/framework/CMakeLists.txt +++ b/paddle/framework/CMakeLists.txt @@ -88,3 +88,10 @@ cc_test(init_test SRCS init_test.cc DEPS init) cc_test(op_kernel_type_test SRCS op_kernel_type_test.cc DEPS place device_context framework_proto) cc_test(cow_ptr_tests SRCS details/cow_ptr_test.cc) + +if(NOT WITH_C_API AND WITH_FLUID) + file(GLOB FRAMEWORK_HEADERS *.h) + install(FILES ${FRAMEWORK_HEADERS} DESTINATION include/paddle/framework) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/framework.pb.h DESTINATION include/paddle/framework) + install(FILES details/cow_ptr.h details/op_registry.h DESTINATION include/paddle/framework/details) +endif() diff --git a/paddle/framework/executor.cc b/paddle/framework/executor.cc index c0418c9266e257bd7567861543e557f354451b17..1382bfca19a674a404916a5c709276ce41219d2f 100644 --- a/paddle/framework/executor.cc +++ b/paddle/framework/executor.cc @@ -23,6 +23,7 @@ limitations under the License. */ #include "paddle/framework/op_registry.h" #include "paddle/platform/place.h" +DECLARE_bool(do_memory_benchmark); DEFINE_bool(check_nan_inf, false, "Checking whether operator produce NAN/INF or not. It will be " "extremely slow so please use this flag wisely."); @@ -117,6 +118,10 @@ void Executor::Run(const ProgramDesc& pdesc, Scope* scope, int block_id, auto op = paddle::framework::OpRegistry::CreateOp(*op_desc); VLOG(3) << op->DebugStringEx(local_scope); op->Run(*local_scope, place_); + if (FLAGS_do_memory_benchmark) { + VLOG(2) << "Memory used after operator " + op->Type() + " running: " + << memory::memory_usage(place_); + } if (FLAGS_check_nan_inf) { for (auto& vname : op->OutputVars(true)) { auto* var = local_scope->FindVar(vname); @@ -130,6 +135,12 @@ void Executor::Run(const ProgramDesc& pdesc, Scope* scope, int block_id, if (create_vars && create_local_scope) { scope->DeleteScope(local_scope); } + if (FLAGS_do_memory_benchmark) { + VLOG(2) << "-------------------------------------------------------"; + VLOG(2) << "Memory used after deleting local scope: " + << memory::memory_usage(place_); + VLOG(2) << "-------------------------------------------------------"; + } } } // namespace framework diff --git a/paddle/framework/scope.cc b/paddle/framework/scope.cc index 2bd0ac8f5a9eb6439a4196dd9c61e13797c1a8e3..a67ff910093d93060d07d849f6e968e5f4ce21cd 100644 --- a/paddle/framework/scope.cc +++ b/paddle/framework/scope.cc @@ -20,6 +20,10 @@ limitations under the License. */ #include "paddle/framework/threadpool.h" #include "paddle/string/printf.h" +DEFINE_bool(do_memory_benchmark, false, + "Doing memory benchmark. It will make deleting scope synchronized, " + "and add some memory usage logs"); + namespace paddle { namespace framework { @@ -88,8 +92,12 @@ void Scope::DeleteScope(Scope* scope) { auto it = std::find(this->kids_.begin(), this->kids_.end(), scope); PADDLE_ENFORCE(it != this->kids_.end(), "Cannot find %p as kid scope", scope); this->kids_.erase(it); - // Make delete async. - Async([scope] { delete scope; }); + // When making memory benchmark on Fluid, we have to delete scope sync. + if (FLAGS_do_memory_benchmark) { + delete scope; + } else { + Async([scope] { delete scope; }); + } } void Scope::Rename(const std::string& origin_name, diff --git a/paddle/gserver/layers/PriorBox.cpp b/paddle/gserver/layers/PriorBox.cpp index 331bc7672ec0d39a7317c39f1d14e8dcadea471a..337b9ba7bc0fc4e4bb80ee7b248d934f111379d5 100644 --- a/paddle/gserver/layers/PriorBox.cpp +++ b/paddle/gserver/layers/PriorBox.cpp @@ -65,14 +65,19 @@ bool PriorBoxLayer::init(const LayerMap& layerMap, std::copy(pbConf.aspect_ratio().begin(), pbConf.aspect_ratio().end(), std::back_inserter(tmp)); - // flip - int inputRatioLength = tmp.size(); - for (int index = 0; index < inputRatioLength; index++) { - aspectRatio_.push_back(tmp[index]); - aspectRatio_.push_back(1 / tmp[index]); + + if (maxSize_.size() > 0) CHECK_EQ(minSize_.size(), maxSize_.size()); + + // flip aspect ratios + for (int index = 0; index < tmp.size(); index++) { + real ar = tmp[index]; + if (fabs(ar - 1.) < 1e-6) continue; + aspectRatio_.push_back(ar); + aspectRatio_.push_back(1. / ar); } - numPriors_ = aspectRatio_.size(); - if (maxSize_.size() > 0) numPriors_++; + + numPriors_ = aspectRatio_.size() * minSize_.size() + maxSize_.size(); + return true; } @@ -99,50 +104,39 @@ void PriorBoxLayer::forward(PassType passType) { for (int w = 0; w < layerWidth; ++w) { real centerX = (w + 0.5) * stepW; real centerY = (h + 0.5) * stepH; - real minSize = 0; for (size_t s = 0; s < minSize_.size(); s++) { - // first prior. - minSize = minSize_[s]; + real minSize = minSize_[s]; real boxWidth = minSize; real boxHeight = minSize; - // xmin, ymin, xmax, ymax. - tmpPtr[idx++] = (centerX - boxWidth / 2.) / imageWidth; - tmpPtr[idx++] = (centerY - boxHeight / 2.) / imageHeight; - tmpPtr[idx++] = (centerX + boxWidth / 2.) / imageWidth; - tmpPtr[idx++] = (centerY + boxHeight / 2.) / imageHeight; - // set the variance. - for (int t = 0; t < 4; t++) tmpPtr[idx++] = variance_[t]; + + // priors with different aspect ratios + for (size_t r = 0; r < aspectRatio_.size(); r++) { + real ar = aspectRatio_[r]; + boxWidth = minSize * sqrt(ar); + boxHeight = minSize / sqrt(ar); + tmpPtr[idx++] = (centerX - boxWidth / 2.) / imageWidth; + tmpPtr[idx++] = (centerY - boxHeight / 2.) / imageHeight; + tmpPtr[idx++] = (centerX + boxWidth / 2.) / imageWidth; + tmpPtr[idx++] = (centerY + boxHeight / 2.) / imageHeight; + // set the variance. + for (int t = 0; t < 4; t++) tmpPtr[idx++] = variance_[t]; + } if (maxSize_.size() > 0) { - CHECK_EQ(minSize_.size(), maxSize_.size()); - // second prior. - for (size_t s = 0; s < maxSize_.size(); s++) { - real maxSize = maxSize_[s]; - boxWidth = boxHeight = sqrt(minSize * maxSize); - tmpPtr[idx++] = (centerX - boxWidth / 2.) / imageWidth; - tmpPtr[idx++] = (centerY - boxHeight / 2.) / imageHeight; - tmpPtr[idx++] = (centerX + boxWidth / 2.) / imageWidth; - tmpPtr[idx++] = (centerY + boxHeight / 2.) / imageHeight; - // set the variance. - for (int t = 0; t < 4; t++) tmpPtr[idx++] = variance_[t]; - } + // square prior with size sqrt(minSize * maxSize) + real maxSize = maxSize_[s]; + boxWidth = boxHeight = sqrt(minSize * maxSize); + tmpPtr[idx++] = (centerX - boxWidth / 2.) / imageWidth; + tmpPtr[idx++] = (centerY - boxHeight / 2.) / imageHeight; + tmpPtr[idx++] = (centerX + boxWidth / 2.) / imageWidth; + tmpPtr[idx++] = (centerY + boxHeight / 2.) / imageHeight; + // set the variance. + for (int t = 0; t < 4; t++) tmpPtr[idx++] = variance_[t]; } } - // rest of priors. - for (size_t r = 0; r < aspectRatio_.size(); r++) { - real ar = aspectRatio_[r]; - if (fabs(ar - 1.) < 1e-6) continue; - real boxWidth = minSize * sqrt(ar); - real boxHeight = minSize / sqrt(ar); - tmpPtr[idx++] = (centerX - boxWidth / 2.) / imageWidth; - tmpPtr[idx++] = (centerY - boxHeight / 2.) / imageHeight; - tmpPtr[idx++] = (centerX + boxWidth / 2.) / imageWidth; - tmpPtr[idx++] = (centerY + boxHeight / 2.) / imageHeight; - // set the variance. - for (int t = 0; t < 4; t++) tmpPtr[idx++] = variance_[t]; - } } } + // clip the prior's coordidate such that it is within [0, 1] for (int d = 0; d < dim * 2; ++d) if ((d % 8) < 4) diff --git a/paddle/inference/CMakeLists.txt b/paddle/inference/CMakeLists.txt index 02ca8a45a851d262eed6962a9a227b5009ef03a5..ae4d3fd2f58daf87a650428e04722581610ed780 100644 --- a/paddle/inference/CMakeLists.txt +++ b/paddle/inference/CMakeLists.txt @@ -1,12 +1,28 @@ -set(FLUID_CORE_MODULES - backward proto_desc paddle_memory executor prune init ${GLOB_OP_LIB}) +set(FLUID_CORE_MODULES proto_desc paddle_memory executor prune init) cc_library(paddle_fluid_api SRCS inference.cc - DEPS ${FLUID_CORE_MODULES}) + DEPS ${FLUID_CORE_MODULES} ${GLOB_OP_LIB}) -# Merge all modules into a simgle static library -cc_library(paddle_fluid DEPS paddle_fluid_api ${FLUID_CORE_MODULES}) +# Merge all modules into a single static library +cc_library(paddle_fluid DEPS paddle_fluid_api ${FLUID_CORE_MODULES} ${GLOB_OP_LIB}) + +# Create shared library +add_library(paddle_fluid_shared SHARED inference.cc) + +target_circle_link_libraries(paddle_fluid_shared + ARCHIVE_START + ${GLOB_OP_LIB} + ARCHIVE_END + ${FLUID_CORE_MODULES}) + +SET_TARGET_PROPERTIES(paddle_fluid_shared PROPERTIES OUTPUT_NAME paddle_fluid) + +# install library & headers +if(NOT WITH_C_API AND WITH_FLUID) + install(FILES inference.h DESTINATION include/paddle/inference) + install(TARGETS paddle_fluid_shared DESTINATION lib) +endif() add_executable(example example.cc) if(APPLE) diff --git a/paddle/memory/CMakeLists.txt b/paddle/memory/CMakeLists.txt index 8841c14ee083fccfd2271efd0c331805919a09d9..061ee1a4d4c97842efe6e64b89f09cfe5c65cd47 100644 --- a/paddle/memory/CMakeLists.txt +++ b/paddle/memory/CMakeLists.txt @@ -14,3 +14,10 @@ cc_library(paddle_memory system_allocator) cc_test(memory_test SRCS memory_test.cc DEPS place paddle_memory) + +if(NOT WITH_C_API AND WITH_FLUID) + file(GLOB MEMORY_HEADERS *.h) + file(GLOB MEMORY_DETAIL_HEADERS detail/*.h) + install(FILES ${MEMORY_HEADERS} DESTINATION include/paddle/memory) + install(FILES ${MEMORY_DETAIL_HEADERS} DESTINATION include/paddle/memory/detail) +endif() diff --git a/paddle/operators/CMakeLists.txt b/paddle/operators/CMakeLists.txt index 6745a8da17723d663913a29f28e5ea9eedc0372a..15f7cb6b560590f55e276fde4900d2e3c0045fb8 100644 --- a/paddle/operators/CMakeLists.txt +++ b/paddle/operators/CMakeLists.txt @@ -156,6 +156,7 @@ op_library(parallel_do_op DEPS executor) # Regist multiple Kernel to pybind if (WITH_GPU) op_library(conv_op SRCS conv_op.cc conv_op.cu.cc conv_cudnn_op.cu.cc DEPS vol2col) +op_library(edit_distance_op SRCS edit_distance_op.cc edit_distance_op.cu DEPS math_function) op_library(pool_op SRCS pool_op.cc pool_op.cu.cc pool_cudnn_op.cu.cc DEPS pooling) op_library(conv_transpose_op SRCS conv_transpose_op.cc conv_transpose_op.cu.cc conv_transpose_cudnn_op.cu.cc DEPS vol2col) diff --git a/paddle/operators/bipartite_match_op.cc b/paddle/operators/bipartite_match_op.cc new file mode 100644 index 0000000000000000000000000000000000000000..b0f7376d272a66e0b01d6b3f7e546372397772f7 --- /dev/null +++ b/paddle/operators/bipartite_match_op.cc @@ -0,0 +1,190 @@ +/* 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 "paddle/framework/op_registry.h" +#include "paddle/operators/math/math_function.h" + +namespace paddle { +namespace operators { + +using Tensor = framework::Tensor; +using LoDTensor = framework::LoDTensor; + +constexpr char kEPS = 1e-6; + +class BipartiteMatchOp : public framework::OperatorWithKernel { + public: + using framework::OperatorWithKernel::OperatorWithKernel; + + void InferShape(framework::InferShapeContext* ctx) const override { + PADDLE_ENFORCE(ctx->HasInput("DistMat"), + "Input(DistMat) of BipartiteMatch should not be null."); + + auto dims = ctx->GetInputDim("DistMat"); + PADDLE_ENFORCE_EQ(dims.size(), 2, "The rank of Input(DistMat) must be 2."); + + ctx->SetOutputDim("ColToRowMatchIndices", dims); + ctx->SetOutputDim("ColToRowMatchDis", dims); + } +}; + +template +class BipartiteMatchKernel : public framework::OpKernel { + public: + // The match_indices must be initialized to -1 at first. + // The match_dist must be initialized to 0 at first. + void BipartiteMatch(const Tensor& dist, int* match_indices, + T* match_dist) const { + PADDLE_ENFORCE_EQ(dist.dims().size(), 2, "The rank of dist must be 2."); + int64_t row = dist.dims()[0]; + int64_t col = dist.dims()[1]; + auto* dist_data = dist.data(); + std::vector row_pool; + for (int i = 0; i < row; ++i) { + row_pool.push_back(i); + } + while (row_pool.size() > 0) { + int max_idx = -1; + int max_row_idx = -1; + T max_dist = -1; + for (int64_t j = 0; j < col; ++j) { + if (match_indices[j] != -1) { + continue; + } + for (size_t k = 0; k < row_pool.size(); ++k) { + int m = row_pool[k]; + // distance is 0 between m-th row and j-th column + if (dist_data[m * col + j] < kEPS) { + continue; + } + if (dist_data[m * col + j] > max_dist) { + max_idx = j; + max_row_idx = m; + max_dist = dist_data[m * col + j]; + } + } + } + if (max_idx == -1) { + // Cannot find good match. + break; + } else { + PADDLE_ENFORCE_EQ(match_indices[max_idx], -1); + match_indices[max_idx] = max_row_idx; + match_dist[max_idx] = max_dist; + // Erase the row index. + row_pool.erase( + std::find(row_pool.begin(), row_pool.end(), max_row_idx)); + } + } + } + + void Compute(const framework::ExecutionContext& context) const override { + auto* dist_mat = context.Input("DistMat"); + auto* match_indices = context.Output("ColToRowMatchIndices"); + auto* match_dist = context.Output("ColToRowMatchDis"); + + auto& dev_ctx = context.device_context(); + + auto col = dist_mat->dims()[1]; + + int64_t n = dist_mat->lod().size() == 0UL + ? 1 + : static_cast(dist_mat->lod().back().size() - 1); + if (dist_mat->lod().size()) { + PADDLE_ENFORCE_EQ(dist_mat->lod().size(), 1UL, + "Only support 1 level of LoD."); + } + match_indices->mutable_data({n, col}, context.GetPlace()); + match_dist->mutable_data({n, col}, context.GetPlace()); + + math::SetConstant iset; + iset(dev_ctx, match_indices, static_cast(-1)); + math::SetConstant tset; + tset(dev_ctx, match_dist, static_cast(0)); + + int* indices = match_indices->data(); + T* dist = match_dist->data(); + if (n == 1) { + BipartiteMatch(*dist_mat, indices, dist); + } else { + auto lod = dist_mat->lod().back(); + for (size_t i = 0; i < lod.size() - 1; ++i) { + Tensor one_ins = dist_mat->Slice(lod[i], lod[i + 1]); + BipartiteMatch(one_ins, indices + i * col, dist + i * col); + } + } + } +}; + +class BipartiteMatchOpMaker : public framework::OpProtoAndCheckerMaker { + public: + BipartiteMatchOpMaker(OpProto* proto, OpAttrChecker* op_checker) + : OpProtoAndCheckerMaker(proto, op_checker) { + AddInput( + "DistMat", + "(LoDTensor or Tensor) this input is a 2-D LoDTensor with shape " + "[K, M]. It is pair-wise distance matrix between the entities " + "represented by each row and each column. For example, assumed one " + "entity is A with shape [K], another entity is B with shape [M]. The " + "DistMat[i][j] is the distance between A[i] and B[j]. The bigger " + "the distance is, the better macthing the pairs are. Please note, " + "This tensor can contain LoD information to represent a batch of " + "inputs. One instance of this batch can contain different numbers of " + "entities."); + AddOutput("ColToRowMatchIndices", + "(Tensor) A 2-D Tensor with shape [N, M] in int type. " + "N is the batch size. If ColToRowMatchIndices[i][j] is -1, it " + "means B[j] does not match any entity in i-th instance. " + "Otherwise, it means B[j] is matched to row " + "ColToRowMatchIndices[i][j] in i-th instance. The row number of " + "i-th instance is saved in ColToRowMatchIndices[i][j]."); + AddOutput("ColToRowMatchDis", + "(Tensor) A 2-D Tensor with shape [N, M] in float type. " + "N is batch size. If ColToRowMatchIndices[i][j] is -1, " + "ColToRowMatchDis[i][j] is also -1.0. Otherwise, assumed " + "ColToRowMatchIndices[i][j] = d, and the row offsets of each " + "instance are called LoD. Then " + "ColToRowMatchDis[i][j] = DistMat[d+LoD[i]][j]"); + AddComment(R"DOC( +This operator is a greedy bipartite matching algorithm, which is used to +obtain the matching with the maximum distance based on the input +distance matrix. For input 2D matrix, the bipartite matching algorithm can +find the matched column for each row, also can find the matched row for +each column. And this operator only calculate matched indices from column +to row. For each instance, the number of matched indices is the number of +of columns of the input ditance matrix. + +There are two outputs to save matched indices and distance. +A simple description, this algothrim matched the best (maximum distance) +row entity to the column entity and the matched indices are not duplicated +in each row of ColToRowMatchIndices. If the column entity is not matched +any row entity, set -1 in ColToRowMatchIndices. + +Please note that the input DistMat can be LoDTensor (with LoD) or Tensor. +If LoDTensor with LoD, the height of ColToRowMatchIndices is batch size. +If Tensor, the height of ColToRowMatchIndices is 1. + +)DOC"); + } +}; + +} // namespace operators +} // namespace paddle + +namespace ops = paddle::operators; +REGISTER_OPERATOR(bipartite_match, ops::BipartiteMatchOp, + ops::BipartiteMatchOpMaker, + paddle::framework::EmptyGradOpMaker); +REGISTER_OP_CPU_KERNEL(bipartite_match, ops::BipartiteMatchKernel, + ops::BipartiteMatchKernel); diff --git a/paddle/operators/compare_op.cc b/paddle/operators/compare_op.cc index daa2c193b48fe216ff284169a3dce1b4cd40a791..930c295a9cb31238954efeb87ff5ac2d3ca7bdc6 100644 --- a/paddle/operators/compare_op.cc +++ b/paddle/operators/compare_op.cc @@ -39,6 +39,11 @@ N-dim tensor. X and Y could be any type. The each element of the Out tensor is calculated by %s )DOC", comment.type, comment.equation)); + AddAttr("axis", + "(int, default -1). The start dimension index " + "for broadcasting Y onto X.") + .SetDefault(-1) + .EqualGreaterThan(-1); } }; @@ -95,11 +100,5 @@ REGISTER_LOGICAL_OP(less_than, "Out = X < Y"); REGISTER_LOGICAL_KERNEL(less_than, CPU, paddle::operators::LessThanFunctor); REGISTER_LOGICAL_OP(less_equal, "Out = X <= Y"); REGISTER_LOGICAL_KERNEL(less_equal, CPU, paddle::operators::LessEqualFunctor); -REGISTER_LOGICAL_OP(greater_than, "Out = X > Y"); -REGISTER_LOGICAL_KERNEL(greater_than, CPU, - paddle::operators::GreaterThanFunctor); -REGISTER_LOGICAL_OP(greater_equal, "Out = X >= Y"); -REGISTER_LOGICAL_KERNEL(greater_equal, CPU, - paddle::operators::GreaterEqualFunctor); REGISTER_LOGICAL_OP(equal, "Out = X == Y"); REGISTER_LOGICAL_KERNEL(equal, CPU, paddle::operators::EqualFunctor); diff --git a/paddle/operators/compare_op.cu b/paddle/operators/compare_op.cu index 26049271befd1fe57001659d1a406e73de0004a7..f625824dbc99d603f1e92700b4ad3d7fa25b471d 100644 --- a/paddle/operators/compare_op.cu +++ b/paddle/operators/compare_op.cu @@ -16,8 +16,4 @@ limitations under the License. */ REGISTER_LOGICAL_KERNEL(less_than, CUDA, paddle::operators::LessThanFunctor); REGISTER_LOGICAL_KERNEL(less_equal, CUDA, paddle::operators::LessEqualFunctor); -REGISTER_LOGICAL_KERNEL(greater_than, CUDA, - paddle::operators::GreaterThanFunctor); -REGISTER_LOGICAL_KERNEL(greater_equal, CUDA, - paddle::operators::GreaterEqualFunctor); REGISTER_LOGICAL_KERNEL(equal, CUDA, paddle::operators::EqualFunctor); diff --git a/paddle/operators/compare_op.h b/paddle/operators/compare_op.h index 567e89c0a727ad0cdd2add8ec8b2a42c86a58007..9c655d6c0d8e5fe04ee6d85f7e9d9da68105230c 100644 --- a/paddle/operators/compare_op.h +++ b/paddle/operators/compare_op.h @@ -16,6 +16,7 @@ limitations under the License. */ #include #include #include "paddle/framework/op_registry.h" +#include "paddle/operators/elementwise_op_function.h" #include "paddle/platform/transform.h" namespace paddle { @@ -33,18 +34,6 @@ struct LessEqualFunctor { HOSTDEVICE bool operator()(const T& a, const T& b) const { return a <= b; } }; -template -struct GreaterThanFunctor { - using ELEM_TYPE = T; - HOSTDEVICE bool operator()(const T& a, const T& b) const { return a > b; } -}; - -template -struct GreaterEqualFunctor { - using ELEM_TYPE = T; - HOSTDEVICE bool operator()(const T& a, const T& b) const { return a >= b; } -}; - template struct EqualFunctor { using ELEM_TYPE = T; @@ -65,14 +54,7 @@ class CompareOpKernel public: void Compute(const framework::ExecutionContext& context) const override { using T = typename Functor::ELEM_TYPE; - auto* x = context.Input("X"); - auto* y = context.Input("Y"); - auto* out = context.Output("Out"); - Functor binary_func; - platform::Transform trans; - trans(context.template device_context(), x->data(), - x->data() + x->numel(), y->data(), - out->mutable_data(context.GetPlace()), binary_func); + ElementwiseComputeEx(context); } }; diff --git a/paddle/operators/edit_distance_op.cc b/paddle/operators/edit_distance_op.cc index 62a1fcebe7b7222ffceafc3ca2bc74e3998225f6..7e7dfc79eba5c9a75366415e5f4b3183653a5cc6 100644 --- a/paddle/operators/edit_distance_op.cc +++ b/paddle/operators/edit_distance_op.cc @@ -25,6 +25,8 @@ class EditDistanceOp : public framework::OperatorWithKernel { PADDLE_ENFORCE(ctx->HasInput("Hyps"), "Input(Hyps) shouldn't be null."); PADDLE_ENFORCE(ctx->HasInput("Refs"), "Input(Refs) shouldn't be null."); PADDLE_ENFORCE(ctx->HasOutput("Out"), "Output(Out) shouldn't be null."); + PADDLE_ENFORCE(ctx->HasOutput("SequenceNum"), + "Output(SequenceNum) shouldn't be null."); auto hyp_dims = ctx->GetInputDim("Hyps"); auto ref_dims = ctx->GetInputDim("Refs"); PADDLE_ENFORCE(hyp_dims.size() == 2 && hyp_dims[1] == 1, @@ -34,6 +36,7 @@ class EditDistanceOp : public framework::OperatorWithKernel { "Input(Refs) must be a 2-D LoDTensor with the 2nd dimension " "equal to 1."); ctx->SetOutputDim("Out", ctx->GetInputDim("Refs")); + ctx->SetOutputDim("SequenceNum", {1}); } protected: @@ -54,6 +57,7 @@ class EditDistanceOpMaker : public framework::OpProtoAndCheckerMaker { AddInput("Refs", "(2-D LoDTensor, 2nd dim. equal to 1) " "The indices for reference strings."); + AddOutput("SequenceNum", "The sequence count of current batch"); AddAttr("normalized", "(bool, default false) Indicated whether to normalize " "the edit distance by the length of reference string.") diff --git a/paddle/operators/edit_distance_op.cu b/paddle/operators/edit_distance_op.cu index 338fd79bcc125b86c7764645c2fd8953d4477d2a..c3e116af086627d576c7a788caebd45667d70017 100644 --- a/paddle/operators/edit_distance_op.cu +++ b/paddle/operators/edit_distance_op.cu @@ -14,6 +14,7 @@ limitations under the License. */ #include #include "paddle/framework/op_registry.h" +#include "paddle/operators/math/math_function.h" #include "paddle/platform/cuda_helper.h" #include "paddle/platform/gpu_info.h" @@ -72,6 +73,8 @@ class EditDistanceGPUKernel : public framework::OpKernel { auto* x1_t = ctx.Input("Hyps"); auto* x2_t = ctx.Input("Refs"); + auto* sequence_num = ctx.Output("SequenceNum"); + sequence_num->mutable_data(ctx.GetPlace()); auto normalized = ctx.Attr("normalized"); auto stream = reinterpret_cast( @@ -88,7 +91,11 @@ class EditDistanceGPUKernel : public framework::OpKernel { "Reference string %d is empty.", i); } - auto num_strs = hyp_lod.size() - 1; + const size_t num_strs = hyp_lod.size() - 1; + math::SetConstant set_constant; + set_constant(ctx.template device_context(), + sequence_num, static_cast(num_strs)); + out_t->Resize({static_cast(num_strs), 1}); out_t->mutable_data(ctx.GetPlace()); auto out = out_t->data(); diff --git a/paddle/operators/edit_distance_op.h b/paddle/operators/edit_distance_op.h index 4c5a29813ce39e42111c0ee5f3c16d5cefac4651..974299e604d22422e9024382e85c843ad831575d 100644 --- a/paddle/operators/edit_distance_op.h +++ b/paddle/operators/edit_distance_op.h @@ -16,7 +16,6 @@ limitations under the License. */ #include #include "paddle/framework/eigen.h" #include "paddle/framework/op_registry.h" - namespace paddle { namespace operators { @@ -28,6 +27,8 @@ class EditDistanceKernel : public framework::OpKernel { auto* x1_t = ctx.Input("Hyps"); auto* x2_t = ctx.Input("Refs"); + auto* sequence_num = ctx.Output("SequenceNum"); + int64_t* seq_num_data = sequence_num->mutable_data(ctx.GetPlace()); auto normalized = ctx.Attr("normalized"); @@ -41,6 +42,7 @@ class EditDistanceKernel : public framework::OpKernel { "Reference string %d is empty.", i); } auto num_strs = hyp_lod.size() - 1; + *seq_num_data = static_cast(num_strs); out_t->Resize({static_cast(num_strs), 1}); out_t->mutable_data(ctx.GetPlace()); diff --git a/paddle/operators/elementwise_op_function.h b/paddle/operators/elementwise_op_function.h index db5d30c1af286913f8decd7ab74058fd732ead65..d749b8e8757d0d433be05876779ccc22b95ca80b 100644 --- a/paddle/operators/elementwise_op_function.h +++ b/paddle/operators/elementwise_op_function.h @@ -176,14 +176,15 @@ class MidWiseTransformIterator }; #endif -template +template class TransformFunctor { public: TransformFunctor(const framework::Tensor* x, const framework::Tensor* y, framework::Tensor* z, const DeviceContext& ctx, Functor func) : x_(x->data()), y_(y->data()), - z_(z->mutable_data(ctx.GetPlace())), + z_(z->mutable_data(ctx.GetPlace())), nx_(x->numel()), ctx_(ctx), func_(func) {} @@ -208,7 +209,7 @@ class TransformFunctor { private: const T* x_; const T* y_; - T* z_; + OutType* z_; int64_t nx_; const DeviceContext& ctx_; Functor func_; @@ -364,15 +365,16 @@ void ElementwiseGradCompute(const framework::ExecutionContext& ctx) { } } -template +template void ElementwiseComputeEx(const framework::ExecutionContext& ctx) { using Tensor = framework::Tensor; auto* x = ctx.Input("X"); auto* y = ctx.Input("Y"); auto* z = ctx.Output("Out"); - z->mutable_data(ctx.GetPlace()); - TransformFunctor functor( + z->mutable_data(ctx.GetPlace()); + TransformFunctor functor( x, y, z, ctx.template device_context(), Functor()); auto x_dims = x->dims(); diff --git a/paddle/operators/im2sequence_op.cc b/paddle/operators/im2sequence_op.cc new file mode 100644 index 0000000000000000000000000000000000000000..31baaedf6914b1a6939fc762491ef35013db4bb6 --- /dev/null +++ b/paddle/operators/im2sequence_op.cc @@ -0,0 +1,157 @@ +/* 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 "paddle/operators/im2sequence_op.h" + +namespace paddle { +namespace operators { + +class Im2SequenceOp : public framework::OperatorWithKernel { + public: + using framework::OperatorWithKernel::OperatorWithKernel; + + protected: + void InferShape(framework::InferShapeContext* ctx) const override { + PADDLE_ENFORCE(ctx->HasInput("X"), + "Input(X) of Im2SequenceOp should not be null."); + PADDLE_ENFORCE(ctx->HasOutput("Out"), + "Output(Out) of Im2SequenceOp op should not be null."); + + auto in_dim = ctx->GetInputDim("X"); + PADDLE_ENFORCE_EQ(in_dim.size(), 4, + "Input(X) format must be 4D tensor, eg., NCHW."); + + auto kernels = ctx->Attrs().Get>("kernels"); + auto strides = ctx->Attrs().Get>("strides"); + auto paddings = ctx->Attrs().Get>("paddings"); + + int batch_size = in_dim[0]; + int img_channels = in_dim[1]; + int img_height = in_dim[2]; + int img_width = in_dim[3]; + + int output_height = OutputSize(img_height, kernels[0], paddings[0], + paddings[2], strides[0]); + int output_width = + OutputSize(img_width, kernels[1], paddings[1], paddings[3], strides[1]); + + ctx->SetOutputDim("Out", {batch_size * output_height * output_width, + img_channels * kernels[0] * kernels[1]}); + } +}; + +class Im2SequenceOpMaker : public framework::OpProtoAndCheckerMaker { + public: + Im2SequenceOpMaker(OpProto* proto, OpAttrChecker* op_checker) + : OpProtoAndCheckerMaker(proto, op_checker) { + AddInput("X", + "(Tensor) The input tensor has NCHW format." + "N: batch size" + "C: channels" + "H: height" + "W: width"); + AddOutput("Out", "(LodTensor) The output data of im2sequence op,"); + AddAttr>("kernels", + "(vector), the " + "kernels(kernel_height, kernel_width)"); + AddAttr>("strides", + "(vector default:{1, 1}), the " + "strides(h_stride, w_stride)") + .SetDefault({1, 1}); + AddAttr>("paddings", + "(vector default:{0, 0, 0, 0}), the " + "paddings(up_pad, left_pad, down_pad, right_pad)") + .SetDefault({0, 0, 0, 0}); + AddComment(R"DOC( +This op uses kernels to scan images and converts these images to sequences. +After expanding, The number of time steps are output_height * output_width +and the dimension of each time step is kernel_height * kernel_width * channels, +in which: + +output_height = + 1 + (padding_height + padding_down + img_height - kernel_height + stride_height - 1) / + stride_height; +output_width = + 1 + (padding_left + padding+right + img_width - kernel_width + stride_width - 1) / + stride_width; + +This op can be used after convolution neural network, and before recurrent neural network. + +Given: + +x = [[[[ 6. 2. 1.] + [ 8. 3. 5.] + [ 0. 2. 6.]] + + [[ 2. 4. 4.] + [ 6. 3. 0.] + [ 6. 4. 7.]]] + + [[[ 6. 7. 1.] + [ 5. 7. 9.] + [ 2. 4. 8.]] + + [[ 1. 2. 1.] + [ 1. 3. 5.] + [ 9. 0. 8.]]]] +x.dims = {2, 2, 3, 3} + +And: + +kernels = [2, 2] +strides = [1, 1] +paddings = [0, 0, 0, 0] + +Then: + +output.data = [[ 6. 2. 8. 3. 2. 4. 6. 3.] + [ 2. 1. 3. 5. 4. 4. 3. 0.] + [ 8. 3. 0. 2. 6. 3. 6. 4.] + [ 3. 5. 2. 6. 3. 0. 4. 7.] + [ 6. 7. 5. 7. 1. 2. 1. 3.] + [ 7. 1. 7. 9. 2. 1. 3. 5.] + [ 5. 7. 2. 4. 1. 3. 9. 0.] + [ 7. 9. 4. 8. 3. 5. 0. 8.]] +output.dims = {8, 9} +output.lod = [[0, 4, 8]] + +)DOC"); + } +}; + +class Im2SequenceGradOp : public framework::OperatorWithKernel { + public: + using framework::OperatorWithKernel::OperatorWithKernel; + + protected: + void InferShape(framework::InferShapeContext* ctx) const override { + PADDLE_ENFORCE(ctx->HasInput("X"), "Input(X) should not be null"); + PADDLE_ENFORCE(ctx->HasInput(framework::GradVarName("Out")), + "Input(Out@GRAD) shouldn't be null."); + ctx->SetOutputDim(framework::GradVarName("X"), ctx->GetInputDim("X")); + } +}; + +} // namespace operators +} // namespace paddle + +namespace ops = paddle::operators; +REGISTER_OP(im2sequence, ops::Im2SequenceOp, ops::Im2SequenceOpMaker, + im2sequence_grad, ops::Im2SequenceGradOp); +REGISTER_OP_CPU_KERNEL( + im2sequence, + ops::Im2SequenceKernel); +REGISTER_OP_CPU_KERNEL( + im2sequence_grad, + ops::Im2SequenceGradKernel); diff --git a/paddle/operators/im2sequence_op.cu b/paddle/operators/im2sequence_op.cu new file mode 100644 index 0000000000000000000000000000000000000000..9db7529112f2710d6ff4af2b444e304543486de3 --- /dev/null +++ b/paddle/operators/im2sequence_op.cu @@ -0,0 +1,25 @@ +/* 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. */ + +#define EIGEN_USE_GPU +#include "paddle/operators/im2sequence_op.h" + +namespace ops = paddle::operators; + +REGISTER_OP_CUDA_KERNEL( + im2sequence, + ops::Im2SequenceKernel); +REGISTER_OP_CUDA_KERNEL( + im2sequence_grad, + ops::Im2SequenceGradKernel); diff --git a/paddle/operators/im2sequence_op.h b/paddle/operators/im2sequence_op.h new file mode 100644 index 0000000000000000000000000000000000000000..aeb810015134babc132909b3e820fa8391233b1c --- /dev/null +++ b/paddle/operators/im2sequence_op.h @@ -0,0 +1,135 @@ +/* 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 "paddle/framework/data_layout.h" +#include "paddle/framework/eigen.h" +#include "paddle/framework/op_registry.h" +#include "paddle/operators/math/im2col.h" +#include "paddle/operators/math/math_function.h" + +namespace paddle { +namespace operators { + +using Tensor = framework::Tensor; +using LoDTensor = framework::LoDTensor; + +inline int OutputSize(int input_size, int filter_size, int padding_0, + int padding_1, int stride) { + const int output_size = + (input_size + padding_0 + padding_1 - filter_size) / stride + 1; + return output_size; +} + +template +class Im2SequenceKernel : public framework::OpKernel { + public: + void Compute(const framework::ExecutionContext& ctx) const override { + const Tensor* in = ctx.Input("X"); + LoDTensor* out = ctx.Output("Out"); + out->mutable_data(ctx.GetPlace()); + // TODO(wanghaoshuang): Add layout checker after 'set_layout' + // being available for python API + // PADDLE_ENFORCE_EQ(in->layout(), framework::DataLayout::kNCHW, + // "Input(X) layout must be NCHW"); + auto in_dim = in->dims(); + int batch_size = in_dim[0]; + int img_channels = in_dim[1]; + int img_height = in_dim[2]; + int img_width = in_dim[3]; + + auto kernels = ctx.Attr>("kernels"); + auto strides = ctx.Attr>("strides"); + auto paddings = ctx.Attr>("paddings"); + int output_height = OutputSize(img_height, kernels[0], paddings[0], + paddings[2], strides[0]); + int output_width = + OutputSize(img_width, kernels[1], paddings[1], paddings[3], strides[1]); + + const std::vector dilations({1, 1}); + + auto out_dims = out->dims(); + out->Resize({batch_size, out->numel() / batch_size}); + for (int i = 0; i < batch_size; i++) { + const Tensor src = + in->Slice(i, i + 1).Resize({img_channels, img_height, img_width}); + Tensor dst = out->Slice(i, i + 1).Resize( + {output_height, output_width, img_channels, kernels[0], kernels[1]}); + + math::Im2ColFunctor f; + auto& dev_ctx = ctx.template device_context(); + f(dev_ctx, src, dilations, strides, paddings, &dst); + } + out->Resize(out_dims); + + // set lod information + // TODO(wanghaoshuang): Move this to InferShape + framework::LoD lod(1); + lod[0].reserve(batch_size + 1); + for (int i = 0, offset = 0; i < batch_size + 1; ++i) { + lod[0][i] = offset; + offset += output_height * output_width; + } + out->set_lod(lod); + } +}; + +template +class Im2SequenceGradKernel : public framework::OpKernel { + public: + void Compute(const framework::ExecutionContext& ctx) const override { + auto* in = ctx.Input("X"); + Tensor* d_out = + const_cast(ctx.Input(framework::GradVarName("Out"))); + auto* d_x = ctx.Output(framework::GradVarName("X")); + d_x->mutable_data(ctx.GetPlace()); + + auto x_v = framework::EigenVector::Flatten(*d_x); + auto& place = *ctx.template device_context().eigen_device(); + x_v.device(place) = x_v.constant(0.0); + + auto in_dim = in->dims(); + int batch_size = in_dim[0]; + int img_channels = in_dim[1]; + int img_height = in_dim[2]; + int img_width = in_dim[3]; + + auto kernels = ctx.Attr>("kernels"); + auto strides = ctx.Attr>("strides"); + auto paddings = ctx.Attr>("paddings"); + int output_height = OutputSize(img_height, kernels[0], paddings[0], + paddings[2], strides[0]); + int output_width = + OutputSize(img_width, kernels[1], paddings[1], paddings[3], strides[1]); + + const std::vector dilations({1, 1}); + + auto d_out_dims = d_out->dims(); + d_out->Resize({batch_size, d_out->numel() / batch_size}); + for (int i = 0; i < batch_size; i++) { + Tensor dst = + d_x->Slice(i, i + 1).Resize({img_channels, img_height, img_width}); + const Tensor src = d_out->Slice(i, i + 1).Resize( + {output_height, output_width, img_channels, kernels[0], kernels[1]}); + math::Col2ImFunctor f; + auto& dev_ctx = ctx.template device_context(); + f(dev_ctx, src, dilations, strides, paddings, &dst); + } + d_out->Resize(d_out_dims); + } +}; + +} // namespace operators +} // namespace paddle diff --git a/paddle/operators/math/sampler.cc b/paddle/operators/math/sampler.cc new file mode 100644 index 0000000000000000000000000000000000000000..4f1cbfe31ac68499a51eda600b38b879f7ca055f --- /dev/null +++ b/paddle/operators/math/sampler.cc @@ -0,0 +1,70 @@ +/* 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 "sampler.h" + +namespace paddle { +namespace random { + +Sampler::~Sampler() {} + +UniformSampler::UniformSampler(int64 range) + : Sampler(range), inv_range_(1.0 / range) { + random_engine_ = std::make_shared(seed_); + dist_ = std::make_shared>(0, range); +} + +UniformSampler::UniformSampler(int64 range, unsigned int seed) + : Sampler(range, seed), inv_range_(1.0 / range) { + random_engine_ = std::make_shared(seed_); + dist_ = std::make_shared>(0, range); +} + +int64 UniformSampler::Sample() const { return (*dist_)(*random_engine_); } + +float UniformSampler::Probability(int64 value) const { return inv_range_; } + +LogUniformSampler::LogUniformSampler(int64 range) + : Sampler(range), log_range_(log(range + 1)) { + random_engine_ = std::make_shared(seed_); + dist_ = std::make_shared>(0, 1); +} + +LogUniformSampler::LogUniformSampler(int64 range, unsigned int seed) + : Sampler(range, seed), log_range_(log(range + 1)) { + random_engine_ = std::make_shared(seed_); + dist_ = std::make_shared>(0, 1); +} +int64 LogUniformSampler::Sample() const { + // Got Log Uniform distribution from uniform distribution by + // inverse_transform_sampling method + // More details: + // https://wanghaoshuang.github.io/2017/11/Log-uniform-distribution-sampler/ + const int64 value = + static_cast(exp((*dist_)(*random_engine_) * log_range_)) - 1; + // Mathematically, value should be <= range_, but might not be due to some + // floating point roundoff, so we mod by range_. + return value % range_; +} + +float LogUniformSampler::Probability(int64 value) const { + // Given f(x) = 1/[(x+1) * log_range_] + // The value's probability is integral of f(x) from value to (value + 1) + // More details: + // https://wanghaoshuang.github.io/2017/11/Log-uniform-distribution-sampler + return (log((value + 2.0) / (value + 1.0))) / log_range_; +} + +} // namespace random +} // namespace paddle diff --git a/paddle/operators/math/sampler.h b/paddle/operators/math/sampler.h new file mode 100644 index 0000000000000000000000000000000000000000..8f82089e7bd9e0ae6282459b650c225d6765faee --- /dev/null +++ b/paddle/operators/math/sampler.h @@ -0,0 +1,100 @@ +/* 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 +#include +typedef long int64; +namespace paddle { +namespace operators { +namespace math { + +// TODO(wanghaoshuang): Support for GPU + +/** +* Sample integers from [0, range). +*/ +class Sampler { + public: + explicit Sampler(int64 range) : range_(range) { + PADDLE_ENFORCE_GT(range, 0); + std::random_device r; + seed_ = r(); + } + explicit Sampler(int64 range, unsigned int seed) + : range_(range), seed_(seed) { + PADDLE_ENFORCE_GT(range, 0); + } + virtual ~Sampler(); + // Sample a single value + virtual int64 Sample() const = 0; + // The probability that a single call to Sample() returns the given value. + virtual float Probability(int64 value) const = 0; + + int64 range() { return range_; }; + + protected: + const int64 range_; + unsigned int seed_; +}; + +/** + * Sample integers from [0, range). + * And the distribution function is: + * P(x) = 1 / range + */ +class UniformSampler : public Sampler { + public: + explicit UniformSampler(int64 range); + + explicit UniformSampler(int64 range, unsigned int seed); + + ~UniformSampler() override {} + + int64 Sample() const override; + + float Probability(int64 value) const override; + + private: + const float inv_range_; + std::shared_ptr random_engine_; + std::shared_ptr> dist_; +}; + +/** + * Sample integers from [0, range). + * And the distribution function is: + * P(x) = (1/ln(range+1)) * ln(1 + 1/(x + 1)) + */ +class LogUniformSampler : public Sampler { + public: + explicit LogUniformSampler(int64 range); + + explicit LogUniformSampler(int64 range, unsigned int seed); + + ~LogUniformSampler() override {} + + int64 Sample() const override; + + float Probability(int64 value) const override; + + private: + const float log_range_; + std::shared_ptr random_engine_; + std::shared_ptr> dist_; +}; + +} // math +} // namespace operators +} // namespace paddle diff --git a/paddle/operators/recv_op.cc b/paddle/operators/recv_op.cc index 60360807351f1cf41c19aa06e30640e5cf473e07..593c35879ae2b3680b93ac5d8443110e61cb99fe 100644 --- a/paddle/operators/recv_op.cc +++ b/paddle/operators/recv_op.cc @@ -49,7 +49,7 @@ static void CreateTensorFromMessageType(framework::Variable *var, var->GetMutable(); } else { PADDLE_THROW( - "VraibleMessage type %d is not in " + "VariableMessage type %d is not in " "[LoDTensor, SelectedRows]", var_type); } @@ -121,17 +121,17 @@ class RecvOp : public framework::OperatorBase { if (it != grad_list.end()) { param_var_name = param_list[it - grad_list.begin()]; } else { - LOG(ERROR) << "grad have no paired param:" << grad_var_name; + LOG(ERROR) << "grad has no paired param:" << grad_var_name; } - VLOG(3) << "recved grad: " << grad_var_name + VLOG(3) << "received grad: " << grad_var_name << " updating param: " << param_var_name; if (fan_in > 1) { grad_var_name = this->GetGradVarNameForTrainer(grad_var_name); } auto *var = recv_scope.FindVar(grad_var_name); if (var == nullptr) { - LOG(ERROR) << "can not find server side var: " << grad_var_name; - PADDLE_THROW("can not find server side var"); + LOG(ERROR) << "Can not find server side var: " << grad_var_name; + PADDLE_THROW("Can not find server side var"); } detail::DeserializeFromMessage(v.second, dev_ctx, var); } @@ -165,7 +165,7 @@ class RecvOpMaker : public framework::OpProtoAndCheckerMaker { AddComment(R"DOC( Recv operator -This operator will recv tensor from send_op +This operator will recieve tensor from send_op )DOC"); AddAttr("endpoint", "(string, default 127.0.0.1:6164)" @@ -176,11 +176,11 @@ This operator will recv tensor from send_op kOptimizeBlock, "Serialized ProgramDesc string for recv to run."); AddAttr>( "ParamList", "type list of string", - "grad->param name mapping to find which param to optimize.") + "grad->param name mapping to find which parameters to optimize.") .SetDefault({}); AddAttr>( "GradList", "type list of string", - "grad->param name mapping to find which param to optimize.") + "grad->param name mapping to find which parameters to optimize.") .SetDefault({}); AddAttr("Fanin", "type int", "Number of trainers in the current cluster job") diff --git a/paddle/operators/reduce_op.cc b/paddle/operators/reduce_op.cc index 09b7091358e65221374a604122b742d763cfbafc..4a06babeda00f2420df80f81f876a0047a3285ef 100644 --- a/paddle/operators/reduce_op.cc +++ b/paddle/operators/reduce_op.cc @@ -190,10 +190,22 @@ REGISTER_OP(reduce_min, ops::ReduceOp, ops::ReduceMinOpMaker, reduce_min_grad, #define REGISTER_REDUCE_CPU_KERNEL(reduce_type, functor, grad_functor) \ REGISTER_OP_CPU_KERNEL(reduce_type, \ ops::ReduceKernel); \ + float, ops::functor>, \ + ops::ReduceKernel, \ + ops::ReduceKernel, \ + ops::ReduceKernel); \ REGISTER_OP_CPU_KERNEL( \ reduce_type##_grad, \ ops::ReduceGradKernel, \ + ops::ReduceGradKernel, \ + ops::ReduceGradKernel, \ + ops::ReduceGradKernel); FOR_EACH_KERNEL_FUNCTOR(REGISTER_REDUCE_CPU_KERNEL); diff --git a/paddle/operators/reduce_op.cu b/paddle/operators/reduce_op.cu index 1dd948ed8a79cce8468f2fe210b5636e7dd1f99e..4ed1e051db4df579afe1c1ca24a06fa1baf3e13a 100644 --- a/paddle/operators/reduce_op.cu +++ b/paddle/operators/reduce_op.cu @@ -20,10 +20,22 @@ namespace ops = paddle::operators; #define REGISTER_REDUCE_GPU_KERNEL(reduce_type, functor, grad_functor) \ REGISTER_OP_CUDA_KERNEL( \ reduce_type, ops::ReduceKernel); \ + float, ops::functor>, \ + ops::ReduceKernel, \ + ops::ReduceKernel, \ + ops::ReduceKernel); \ REGISTER_OP_CUDA_KERNEL( \ reduce_type##_grad, \ ops::ReduceGradKernel, \ + ops::ReduceGradKernel, \ + ops::ReduceGradKernel, \ + ops::ReduceGradKernel); FOR_EACH_KERNEL_FUNCTOR(REGISTER_REDUCE_GPU_KERNEL); diff --git a/paddle/operators/send_op.cc b/paddle/operators/send_op.cc index 807533a6c6129af073c5efa7817bd5ad637fec23..5aa66c20eaf77959089100f8dcee55f2bc83a71a 100644 --- a/paddle/operators/send_op.cc +++ b/paddle/operators/send_op.cc @@ -62,13 +62,13 @@ class SendOpMaker : public framework::OpProtoAndCheckerMaker { public: SendOpMaker(OpProto* proto, OpAttrChecker* op_checker) : OpProtoAndCheckerMaker(proto, op_checker) { - AddInput("X", "(Tensor) Input tensor to be send").AsDuplicable(); - AddOutput("Out", "(Tensor) Output tensor to get from server") + AddInput("X", "(Tensor) Input tensor to be sent").AsDuplicable(); + AddOutput("Out", "(Tensor) Output tensor to be received from server") .AsDuplicable(); AddComment(R"DOC( Send operator -This operator will send tensor to recv_op. +This operator will send tensor to recv_op at the parameter server. )DOC"); AddAttr>("endpoints", "(string vector, default 127.0.0.1:6164)" diff --git a/paddle/operators/transpose_op.cc b/paddle/operators/transpose_op.cc index 11615d806a61b3525d2ed50f5ea5940e8d61c8f8..c7ae162638ca5e929cca14c841cc3eceeea5f64e 100644 --- a/paddle/operators/transpose_op.cc +++ b/paddle/operators/transpose_op.cc @@ -59,44 +59,39 @@ class TransposeOpMaker : public framework::OpProtoAndCheckerMaker { : OpProtoAndCheckerMaker(proto, op_checker) { AddInput( "X", - "(Tensor)The input tensor, tensors with rank at most 6 are supported"); - AddOutput("Out", "(Tensor)The output tensor"); + "(Tensor) The input tensor, tensors with rank up to 6 are supported."); + AddOutput("Out", "(Tensor)The output tensor."); AddAttr>( "axis", - "(vector)A list of values, and the size of the list should be " - "the same with the input tensor rank, the tensor will " - "permute the axes according the the values given"); + "(vector) A list of values, and the size of the list should be " + "the same with the input tensor rank. This operator permutes the input " + "tensor's axes according to the values given."); AddComment(R"DOC( Transpose Operator. -The input tensor will be permuted according to the axis values given. -The op functions is similar to how numpy.transpose works in python. +The input tensor will be permuted according to the axes given. +The behavior of this operator is similar to how `numpy.transpose` works. -For example: +- suppose the input `X` is a 2-D tensor: + $$ + X = \begin{pmatrix} + 0 &1 &2 \\ + 3 &4 &5 + \end{pmatrix}$$ - .. code-block:: text + the given `axes` is: $[1, 0]$, and $Y$ = transpose($X$, axis) - input = numpy.arange(6).reshape((2,3)) + then the output $Y$ is: - the input is: + $$ + Y = \begin{pmatrix} + 0 &3 \\ + 1 &4 \\ + 2 &5 + \end{pmatrix}$$ - array([[0, 1, 2], - [3, 4, 5]]) - - given axis is: - - [1, 0] - - output = input.transpose(axis) - - then the output is: - - array([[0, 3], - [1, 4], - [2, 5]]) - -So, given a input tensor of shape(N, C, H, W) and the axis is {0, 2, 3, 1}, -the output tensor shape will be (N, H, W, C) +- Given a input tensor with shape $(N, C, H, W)$ and the `axes` is +$[0, 2, 3, 1]$, then shape of the output tensor will be: $(N, H, W, C)$. )DOC"); } diff --git a/paddle/platform/CMakeLists.txt b/paddle/platform/CMakeLists.txt index 44f6d85cd1510f309595ca711de2e0f767219580..3742594a504ed728019ac9665c022503748bea01 100644 --- a/paddle/platform/CMakeLists.txt +++ b/paddle/platform/CMakeLists.txt @@ -39,3 +39,11 @@ nv_test(nccl_test SRCS nccl_test.cu DEPS dynload_cuda gpu_info device_context) cc_library(profiler SRCS profiler.cc DEPS device_context) cc_test(profiler_test SRCS profiler_test.cc DEPS profiler) + +if(NOT WITH_C_API AND WITH_FLUID) + file(GLOB PLATFORM_HEADERS *.h) + file(GLOB PLATFORM_dynload_HEADERS dynload/*.h) + install(FILES ${PLATFORM_HEADERS} DESTINATION include/paddle/platform) + install(FILES ${PLATFORM_HEADERS} DESTINATION include/paddle/platform/dynload) + install(FILES details/device_ptr_cast.h DESTINATION include/paddle/platform/details) +endif() diff --git a/paddle/string/CMakeLists.txt b/paddle/string/CMakeLists.txt index 60667b72873f9422aec1807972a81ab680de2e64..751776dbb5c00972c0b6893fcfb2e710f3f082d7 100644 --- a/paddle/string/CMakeLists.txt +++ b/paddle/string/CMakeLists.txt @@ -1,5 +1,10 @@ cc_library(stringpiece SRCS piece.cc) cc_test(stringpiece_test SRCS piece_test.cc DEPS stringpiece glog gflags) - cc_test(stringprintf_test SRCS printf_test.cc DEPS glog gflags) cc_test(to_string_test SRCS to_string_test.cc) + +if(NOT WITH_C_API AND WITH_FLUID) + file(GLOB STRING_HEADERS *.h) + install(FILES ${STRING_HEADERS} DESTINATION include/paddle/string) + install(FILES tinyformat/tinyformat.h DESTINATION include/paddle/string/tinyformat) +endif() diff --git a/python/paddle/v2/dataset/__init__.py b/python/paddle/v2/dataset/__init__.py index 90830515c1e8e6f5260cfca631e02a3a52cedbe5..c1acbecd9c313b02d6d33d2d04fd33fc1a8b026e 100644 --- a/python/paddle/v2/dataset/__init__.py +++ b/python/paddle/v2/dataset/__init__.py @@ -24,11 +24,23 @@ import conll05 import uci_housing import sentiment import wmt14 +import wmt16 import mq2007 import flowers import voc2012 __all__ = [ - 'mnist', 'imikolov', 'imdb', 'cifar', 'movielens', 'conll05', 'sentiment' - 'uci_housing', 'wmt14', 'mq2007', 'flowers', 'voc2012' + 'mnist', + 'imikolov', + 'imdb', + 'cifar', + 'movielens', + 'conll05', + 'sentiment' + 'uci_housing', + 'wmt14', + 'wmt16', + 'mq2007', + 'flowers', + 'voc2012', ] diff --git a/python/paddle/v2/dataset/common.py b/python/paddle/v2/dataset/common.py index fab8a68b0beee8b813bee2a05047e2da526a9c9b..9aba35a6481e3ad3ab37c8d4de0f998c9f0a1f07 100644 --- a/python/paddle/v2/dataset/common.py +++ b/python/paddle/v2/dataset/common.py @@ -25,8 +25,12 @@ import glob import cPickle as pickle __all__ = [ - 'DATA_HOME', 'download', 'md5file', 'split', 'cluster_files_reader', - 'convert' + 'DATA_HOME', + 'download', + 'md5file', + 'split', + 'cluster_files_reader', + 'convert', ] DATA_HOME = os.path.expanduser('~/.cache/paddle/dataset') @@ -58,12 +62,15 @@ def md5file(fname): return hash_md5.hexdigest() -def download(url, module_name, md5sum): +def download(url, module_name, md5sum, save_name=None): dirname = os.path.join(DATA_HOME, module_name) if not os.path.exists(dirname): os.makedirs(dirname) - filename = os.path.join(dirname, url.split('/')[-1]) + filename = os.path.join(dirname, + url.split('/')[-1] + if save_name is None else save_name) + retry = 0 retry_limit = 3 while not (os.path.exists(filename) and md5file(filename) == md5sum): @@ -196,9 +203,11 @@ def convert(output_path, reader, line_count, name_prefix): Convert data from reader to recordio format files. :param output_path: directory in which output files will be saved. - :param reader: a data reader, from which the convert program will read data instances. + :param reader: a data reader, from which the convert program will read + data instances. :param name_prefix: the name prefix of generated files. - :param max_lines_to_shuffle: the max lines numbers to shuffle before writing. + :param max_lines_to_shuffle: the max lines numbers to shuffle before + writing. """ assert line_count >= 1 diff --git a/python/paddle/v2/dataset/tests/wmt16_test.py b/python/paddle/v2/dataset/tests/wmt16_test.py new file mode 100644 index 0000000000000000000000000000000000000000..cef6c3216e7de8d9785a063976e63f88d90b24df --- /dev/null +++ b/python/paddle/v2/dataset/tests/wmt16_test.py @@ -0,0 +1,66 @@ +# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved +# +# 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. + +import paddle.v2.dataset.wmt16 +import unittest + + +class TestWMT16(unittest.TestCase): + def checkout_one_sample(self, sample): + # train data has 3 field: source language word indices, + # target language word indices, and target next word indices. + self.assertEqual(len(sample), 3) + + # test start mark and end mark in source word indices. + self.assertEqual(sample[0][0], 0) + self.assertEqual(sample[0][-1], 1) + + # test start mask in target word indices + self.assertEqual(sample[1][0], 0) + + # test en mask in target next word indices + self.assertEqual(sample[2][-1], 1) + + def test_train(self): + for idx, sample in enumerate( + paddle.v2.dataset.wmt16.train( + src_dict_size=100000, trg_dict_size=100000)()): + if idx >= 10: break + self.checkout_one_sample(sample) + + def test_test(self): + for idx, sample in enumerate( + paddle.v2.dataset.wmt16.test( + src_dict_size=1000, trg_dict_size=1000)()): + if idx >= 10: break + self.checkout_one_sample(sample) + + def test_val(self): + for idx, sample in enumerate( + paddle.v2.dataset.wmt16.validation( + src_dict_size=1000, trg_dict_size=1000)()): + if idx >= 10: break + self.checkout_one_sample(sample) + + def test_get_dict(self): + dict_size = 1000 + word_dict = paddle.v2.dataset.wmt16.get_dict("en", dict_size, True) + self.assertEqual(len(word_dict), dict_size) + self.assertEqual(word_dict[0], "") + self.assertEqual(word_dict[1], "") + self.assertEqual(word_dict[2], "") + + +if __name__ == "__main__": + unittest.main() diff --git a/python/paddle/v2/dataset/wmt14.py b/python/paddle/v2/dataset/wmt14.py index 95a35d97ce9d9503153974cc167ee60829244d5f..5104e29051e4480f3a7eb18421f1b519841b009b 100644 --- a/python/paddle/v2/dataset/wmt14.py +++ b/python/paddle/v2/dataset/wmt14.py @@ -25,12 +25,20 @@ import gzip import paddle.v2.dataset.common from paddle.v2.parameters import Parameters -__all__ = ['train', 'test', 'build_dict', 'convert'] - -URL_DEV_TEST = 'http://www-lium.univ-lemans.fr/~schwenk/cslm_joint_paper/data/dev+test.tgz' +__all__ = [ + 'train', + 'test', + 'get_dict', + 'convert', +] + +URL_DEV_TEST = ('http://www-lium.univ-lemans.fr/~schwenk/' + 'cslm_joint_paper/data/dev+test.tgz') MD5_DEV_TEST = '7d7897317ddd8ba0ae5c5fa7248d3ff5' -# this is a small set of data for test. The original data is too large and will be add later. -URL_TRAIN = 'http://paddlepaddle.cdn.bcebos.com/demo/wmt_shrinked_data/wmt14.tgz' +# this is a small set of data for test. The original data is too large and +# will be add later. +URL_TRAIN = ('http://paddlepaddle.cdn.bcebos.com/demo/' + 'wmt_shrinked_data/wmt14.tgz') MD5_TRAIN = '0791583d57d5beb693b9414c5b36798c' # BLEU of this trained model is 26.92 URL_MODEL = 'http://paddlepaddle.bj.bcebos.com/demo/wmt_14/wmt14_model.tar.gz' @@ -42,8 +50,8 @@ UNK = "" UNK_IDX = 2 -def __read_to_dict__(tar_file, dict_size): - def __to_dict__(fd, size): +def __read_to_dict(tar_file, dict_size): + def __to_dict(fd, size): out_dict = dict() for line_count, line in enumerate(fd): if line_count < size: @@ -58,19 +66,19 @@ def __read_to_dict__(tar_file, dict_size): if each_item.name.endswith("src.dict") ] assert len(names) == 1 - src_dict = __to_dict__(f.extractfile(names[0]), dict_size) + src_dict = __to_dict(f.extractfile(names[0]), dict_size) names = [ each_item.name for each_item in f if each_item.name.endswith("trg.dict") ] assert len(names) == 1 - trg_dict = __to_dict__(f.extractfile(names[0]), dict_size) + trg_dict = __to_dict(f.extractfile(names[0]), dict_size) return src_dict, trg_dict def reader_creator(tar_file, file_name, dict_size): def reader(): - src_dict, trg_dict = __read_to_dict__(tar_file, dict_size) + src_dict, trg_dict = __read_to_dict(tar_file, dict_size) with tarfile.open(tar_file, mode='r') as f: names = [ each_item.name for each_item in f @@ -152,7 +160,7 @@ def get_dict(dict_size, reverse=True): # if reverse = False, return dict = {'a':'001', 'b':'002', ...} # else reverse = true, return dict = {'001':'a', '002':'b', ...} tar_file = paddle.v2.dataset.common.download(URL_TRAIN, 'wmt14', MD5_TRAIN) - src_dict, trg_dict = __read_to_dict__(tar_file, dict_size) + src_dict, trg_dict = __read_to_dict(tar_file, dict_size) if reverse: src_dict = {v: k for k, v in src_dict.items()} trg_dict = {v: k for k, v in trg_dict.items()} diff --git a/python/paddle/v2/dataset/wmt16.py b/python/paddle/v2/dataset/wmt16.py new file mode 100644 index 0000000000000000000000000000000000000000..e2f463be2f7bcd667855f64206d78f387e92ef33 --- /dev/null +++ b/python/paddle/v2/dataset/wmt16.py @@ -0,0 +1,349 @@ +# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved +# +# 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. +""" +ACL2016 Multimodal Machine Translation. Please see this website for more +details: http://www.statmt.org/wmt16/multimodal-task.html#task1 + +If you use the dataset created for your task, please cite the following paper: +Multi30K: Multilingual English-German Image Descriptions. + +@article{elliott-EtAl:2016:VL16, + author = {{Elliott}, D. and {Frank}, S. and {Sima"an}, K. and {Specia}, L.}, + title = {Multi30K: Multilingual English-German Image Descriptions}, + booktitle = {Proceedings of the 6th Workshop on Vision and Language}, + year = {2016}, + pages = {70--74}, + year = 2016 +} +""" + +import os +import tarfile +import gzip +from collections import defaultdict + +import paddle.v2.dataset.common + +__all__ = [ + "train", + "test", + "validation", + "convert", + "fetch", + "get_dict", +] + +DATA_URL = ("http://cloud.dlnel.org/filepub/" + "?uuid=46a0808e-ddd8-427c-bacd-0dbc6d045fed") +DATA_MD5 = "0c38be43600334966403524a40dcd81e" + +TOTAL_EN_WORDS = 11250 +TOTAL_DE_WORDS = 19220 + +START_MARK = "" +END_MARK = "" +UNK_MARK = "" + + +def __build_dict(tar_file, dict_size, save_path, lang): + word_dict = defaultdict(int) + with tarfile.open(tar_file, mode="r") as f: + for line in f.extractfile("wmt16/train"): + line_split = line.strip().split("\t") + if len(line_split) != 2: continue + sen = line_split[0] if lang == "en" else line_split[1] + for w in sen.split(): + word_dict[w] += 1 + + with open(save_path, "w") as fout: + fout.write("%s\n%s\n%s\n" % (START_MARK, END_MARK, UNK_MARK)) + for idx, word in enumerate( + sorted( + word_dict.iteritems(), key=lambda x: x[1], reverse=True)): + if idx + 3 == dict_size: break + fout.write("%s\n" % (word[0])) + + +def __load_dict(tar_file, dict_size, lang, reverse=False): + dict_path = os.path.join(paddle.v2.dataset.common.DATA_HOME, + "wmt16/%s_%d.dict" % (lang, dict_size)) + if not os.path.exists(dict_path) or ( + len(open(dict_path, "r").readlines()) != dict_size): + __build_dict(tar_file, dict_size, dict_path, lang) + + word_dict = {} + with open(dict_path, "r") as fdict: + for idx, line in enumerate(fdict): + if reverse: + word_dict[idx] = line.strip() + else: + word_dict[line.strip()] = idx + return word_dict + + +def __get_dict_size(src_dict_size, trg_dict_size, src_lang): + src_dict_size = min(src_dict_size, (TOTAL_EN_WORDS if src_lang == "en" else + TOTAL_DE_WORDS)) + trg_dict_size = min(trg_dict_size, (TOTAL_DE_WORDS if src_lang == "en" else + TOTAL_ENG_WORDS)) + return src_dict_size, trg_dict_size + + +def reader_creator(tar_file, file_name, src_dict_size, trg_dict_size, src_lang): + def reader(): + src_dict = __load_dict(tar_file, src_dict_size, src_lang) + trg_dict = __load_dict(tar_file, trg_dict_size, + ("de" if src_lang == "en" else "en")) + + # the indice for start mark, end mark, and unk are the same in source + # language and target language. Here uses the source language + # dictionary to determine their indices. + start_id = src_dict[START_MARK] + end_id = src_dict[END_MARK] + unk_id = src_dict[UNK_MARK] + + src_col = 0 if src_lang == "en" else 1 + trg_col = 1 - src_col + + with tarfile.open(tar_file, mode="r") as f: + for line in f.extractfile(file_name): + line_split = line.strip().split("\t") + if len(line_split) != 2: + continue + src_words = line_split[src_col].split() + src_ids = [start_id] + [ + src_dict.get(w, unk_id) for w in src_words + ] + [end_id] + + trg_words = line_split[trg_col].split() + trg_ids = [trg_dict.get(w, unk_id) for w in trg_words] + + trg_ids_next = trg_ids + [end_id] + trg_ids = [start_id] + trg_ids + + yield src_ids, trg_ids, trg_ids_next + + return reader + + +def train(src_dict_size, trg_dict_size, src_lang="en"): + """ + WMT16 train set reader. + + This function returns the reader for train data. Each sample the reader + returns is made up of three fields: the source language word index sequence, + target language word index sequence and next word index sequence. + + + NOTE: + The original like for training data is: + http://www.quest.dcs.shef.ac.uk/wmt16_files_mmt/training.tar.gz + + paddle.dataset.wmt16 provides a tokenized version of the original dataset by + using moses's tokenization script: + https://github.com/moses-smt/mosesdecoder/blob/master/scripts/tokenizer/tokenizer.perl + + Args: + src_dict_size(int): Size of the source language dictionary. Three + special tokens will be added into the dictionary: + for start mark, for end mark, and for + unknown word. + trg_dict_size(int): Size of the target language dictionary. Three + special tokens will be added into the dictionary: + for start mark, for end mark, and for + unknown word. + src_lang(string): A string indicating which language is the source + language. Available options are: "en" for English + and "de" for Germany. + + Returns: + callable: The train reader. + """ + + if src_lang not in ["en", "de"]: + raise ValueError("An error language type. Only support: " + "en (for English); de(for Germany).") + src_dict_size, trg_dict_size = __get_dict_size(src_dict_size, trg_dict_size, + src_lang) + + return reader_creator( + tar_file=paddle.v2.dataset.common.download(DATA_URL, "wmt16", DATA_MD5, + "wmt16.tar.gz"), + file_name="wmt16/train", + src_dict_size=src_dict_size, + trg_dict_size=trg_dict_size, + src_lang=src_lang) + + +def test(src_dict_size, trg_dict_size, src_lang="en"): + """ + WMT16 test set reader. + + This function returns the reader for test data. Each sample the reader + returns is made up of three fields: the source language word index sequence, + target language word index sequence and next word index sequence. + + NOTE: + The original like for test data is: + http://www.quest.dcs.shef.ac.uk/wmt16_files_mmt/mmt16_task1_test.tar.gz + + paddle.dataset.wmt16 provides a tokenized version of the original dataset by + using moses's tokenization script: + https://github.com/moses-smt/mosesdecoder/blob/master/scripts/tokenizer/tokenizer.perl + + Args: + src_dict_size(int): Size of the source language dictionary. Three + special tokens will be added into the dictionary: + for start mark, for end mark, and for + unknown word. + trg_dict_size(int): Size of the target language dictionary. Three + special tokens will be added into the dictionary: + for start mark, for end mark, and for + unknown word. + src_lang(string): A string indicating which language is the source + language. Available options are: "en" for English + and "de" for Germany. + + Returns: + callable: The test reader. + """ + + if src_lang not in ["en", "de"]: + raise ValueError("An error language type. " + "Only support: en (for English); de(for Germany).") + + src_dict_size, trg_dict_size = __get_dict_size(src_dict_size, trg_dict_size, + src_lang) + + return reader_creator( + tar_file=paddle.v2.dataset.common.download(DATA_URL, "wmt16", DATA_MD5, + "wmt16.tar.gz"), + file_name="wmt16/test", + src_dict_size=src_dict_size, + trg_dict_size=trg_dict_size, + src_lang=src_lang) + + +def validation(src_dict_size, trg_dict_size, src_lang="en"): + """ + WMT16 validation set reader. + + This function returns the reader for validation data. Each sample the reader + returns is made up of three fields: the source language word index sequence, + target language word index sequence and next word index sequence. + + NOTE: + The original like for validation data is: + http://www.quest.dcs.shef.ac.uk/wmt16_files_mmt/validation.tar.gz + + paddle.dataset.wmt16 provides a tokenized version of the original dataset by + using moses's tokenization script: + https://github.com/moses-smt/mosesdecoder/blob/master/scripts/tokenizer/tokenizer.perl + + Args: + src_dict_size(int): Size of the source language dictionary. Three + special tokens will be added into the dictionary: + for start mark, for end mark, and for + unknown word. + trg_dict_size(int): Size of the target language dictionary. Three + special tokens will be added into the dictionary: + for start mark, for end mark, and for + unknown word. + src_lang(string): A string indicating which language is the source + language. Available options are: "en" for English + and "de" for Germany. + + Returns: + callable: The validation reader. + """ + if src_lang not in ["en", "de"]: + raise ValueError("An error language type. " + "Only support: en (for English); de(for Germany).") + src_dict_size, trg_dict_size = __get_dict_size(src_dict_size, trg_dict_size, + src_lang) + + return reader_creator( + tar_file=paddle.v2.dataset.common.download(DATA_URL, "wmt16", DATA_MD5, + "wmt16.tar.gz"), + file_name="wmt16/val", + src_dict_size=src_dict_size, + trg_dict_size=trg_dict_size, + src_lang=src_lang) + + +def get_dict(lang, dict_size, reverse=False): + """ + return the word dictionary for the specified language. + + Args: + lang(string): A string indicating which language is the source + language. Available options are: "en" for English + and "de" for Germany. + dict_size(int): Size of the specified language dictionary. + reverse(bool): If reverse is set to False, the returned python + dictionary will use word as key and use index as value. + If reverse is set to True, the returned python + dictionary will use index as key and word as value. + + Returns: + dict: The word dictionary for the specific language. + """ + + if lang == "en": dict_size = min(dict_size, TOTAL_EN_WORDS) + else: dict_size = min(dict_size, TOTAL_DE_WORDS) + + dict_path = os.path.join(paddle.v2.dataset.common.DATA_HOME, + "wmt16/%s_%d.dict" % (lang, dict_size)) + assert (os.path.exists(dict_path), "Word dictionary does not exist. " + "Please invoke paddle.dataset.wmt16.train/test/validation " + "first to build the dictionary.") + tar_file = os.path.join(paddle.v2.dataset.common.DATA_HOME, "wmt16.tar.gz") + return __load_dict(tar_file, dict_size, lang, reverse) + + +def fetch(): + """download the entire dataset. + """ + paddle.v4.dataset.common.download(DATA_URL, "wmt16", DATA_MD5, + "wmt16.tar.gz") + + +def convert(path, src_dict_size, trg_dict_size, src_lang): + """Converts dataset to recordio format. + """ + + paddle.v2.dataset.common.convert( + path, + train( + src_dict_size=src_dict_size, + trg_dict_size=trg_dict_size, + src_lang=src_lang), + 1000, + "wmt16_train") + paddle.v2.dataset.common.convert( + path, + test( + src_dict_size=src_dict_size, + trg_dict_size=trg_dict_size, + src_lang=src_lang), + 1000, + "wmt16_test") + paddle.v2.dataset.common.convert( + path, + validation( + src_dict_size=src_dict_size, + trg_dict_size=trg_dict_size, + src_lang=src_lang), + 1000, + "wmt16_validation") diff --git a/python/paddle/v2/fluid/__init__.py b/python/paddle/v2/fluid/__init__.py index 4ae4165ba4078374c44113371ec4cd84c95c40ee..1f041c74597637a7b74e9690a60b6cd8fdd21cf8 100644 --- a/python/paddle/v2/fluid/__init__.py +++ b/python/paddle/v2/fluid/__init__.py @@ -37,6 +37,7 @@ import clip from memory_optimization_transpiler import memory_optimize Tensor = LoDTensor + __all__ = framework.__all__ + executor.__all__ + [ 'io', 'initializer', @@ -85,7 +86,9 @@ def __bootstrap__(): os.environ['OMP_NUM_THREADS'] = str(num_threads) - read_env_flags = ['use_pinned_memory', 'check_nan_inf'] + read_env_flags = [ + 'use_pinned_memory', 'check_nan_inf', 'do_memory_benchmark' + ] if core.is_compile_gpu(): read_env_flags += ['fraction_of_gpu_memory_to_use', 'op_sync'] core.init_gflags([sys.argv[0]] + @@ -94,4 +97,5 @@ def __bootstrap__(): core.init_devices() +layers.monkey_patch_variable() __bootstrap__() diff --git a/python/paddle/v2/fluid/clip.py b/python/paddle/v2/fluid/clip.py index 5241f4843c0df0314eba6168f8f36335c3f19d0a..3028029e60fde2f481b4348ab1b0a4980ebb2b60 100644 --- a/python/paddle/v2/fluid/clip.py +++ b/python/paddle/v2/fluid/clip.py @@ -12,13 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +import copy + import functools import layers +import framework from . import core __all__ = [ - 'GradientClipByValue', 'ErrorClipByValue', + 'GradientClipByValue', + 'GradientClipByNorm', + 'GradientClipByGlobalNorm', 'append_gradient_clip_ops', 'error_clip_callback', ] @@ -66,7 +71,7 @@ def error_clip_callback(block, context): class BaseGradientClipAttr(object): - def process_context(self, context, p_g): + def process_context(self, context, param, grad): raise NotImplementedError() def create_operators(self, param, grad): @@ -74,7 +79,7 @@ class BaseGradientClipAttr(object): class NullGradientClipAttr(BaseGradientClipAttr): - def process_context(self, context, p_g): + def process_context(self, context, param, grad): pass def create_operators(self, param, grad): @@ -91,7 +96,7 @@ class GradientClipByValue(BaseGradientClipAttr): self.max = max self.min = min - def process_context(self, context, p_g): + def process_context(self, context, param, grad): pass def create_operators(self, param, grad): @@ -99,19 +104,93 @@ class GradientClipByValue(BaseGradientClipAttr): return param, new_grad +class GradientClipByNorm(BaseGradientClipAttr): + def __init__(self, clip_norm): + self.clip_norm = clip_norm + + def process_context(self, context, param, grad): + pass + + def create_operators(self, param, grad): + new_grad = layers.clip_by_norm(x=grad, max_norm=self.clip_norm) + return param, new_grad + + +class GradientClipByGlobalNorm(BaseGradientClipAttr): + def __init__(self, clip_norm, group_name="default_group"): + if not isinstance(group_name, basestring): + raise TypeError("'group_name' must be a basestring.") + + self.clip_norm = clip_norm + self.group_name = group_name + + def process_context(self, context, param, grad): + if self.group_name not in context: + context[self.group_name] = [] + context[self.group_name + "_clip_value"] = self.clip_norm + context[self.group_name + "_clip"] = layers.fill_constant( + shape=[1], dtype="float32", value=self.clip_norm) + else: + if not self.clip_norm == context[self.group_name + "_clip_value"]: + raise ValueError( + "All parameters' 'clip_norm' of a same group should be the same" + ) + + local_norm_var = layers.reduce_sum(input=layers.pow(x=grad, factor=2.0)) + context[self.group_name].append(local_norm_var) + + self.context = context + + def create_operators(self, param, grad): + group_scale_name = self.group_name + "_scale" + if group_scale_name not in self.context: + group_norm_var = layers.sums(input=self.context[self.group_name]) + layers.sqrt(x=group_norm_var, out=group_norm_var) + clip_var = self.context[self.group_name + "_clip"] + group_scale_var = layers.elementwise_div( + x=clip_var, + y=layers.elementwise_max( + x=clip_var, y=group_norm_var)) + assert group_scale_var.shape == (1L, ) + self.context[group_scale_name] = group_scale_var + + new_grad = layers.elementwise_mul( + x=grad, y=self.context[group_scale_name]) + return param, new_grad + + +def set_gradient_clip(clip, param_list=None, program=None): + if not isinstance(clip, BaseGradientClipAttr): + raise TypeError( + "'clip' should be an instance of BaseGradientClipAttr's derived class" + ) + if program is None: + program = framework.default_main_program() + if param_list is None: + param_list = program.block(0).all_parameters() + if all(isinstance(elem, basestring) for elem in param_list): + param_list = [program.block(0).var(elem) for elem in param_list] + if not all(isinstance(elem, framework.Parameter) for elem in param_list): + raise TypeError( + "'param_list' should be a list of Parameter or basestring(parameter's name)." + ) + + for param in param_list: + param.gradient_clip_attr = copy.deepcopy(clip) + + def append_gradient_clip_ops(param_grad): context = dict() create_op_callbacks = [] for p, g in param_grad: - clip_attr = getattr(p, 'clip_attr', NullGradientClipAttr()) + clip_attr = getattr(p, 'gradient_clip_attr', NullGradientClipAttr()) if clip_attr is None: clip_attr = NullGradientClipAttr() if not isinstance(clip_attr, BaseGradientClipAttr): raise TypeError( - "clip attribute should be an instance of BaseGradientClippingAttr" - ) + "clip attribute should be an instance of BaseGradientClipAttr") - clip_attr.process_context(context=context, p_g=param_grad) + clip_attr.process_context(context=context, param=p, grad=g) create_op_callbacks.append( functools.partial( clip_attr.create_operators, param=p, grad=g)) diff --git a/python/paddle/v2/fluid/distribute_transpiler.py b/python/paddle/v2/fluid/distribute_transpiler.py index 573774a2324791c1786e39700aeb27e64e2e8f9a..abcad899bfac9ba3eff20cde825e136d867a4485 100644 --- a/python/paddle/v2/fluid/distribute_transpiler.py +++ b/python/paddle/v2/fluid/distribute_transpiler.py @@ -38,14 +38,14 @@ def split_dense_variable(var_list, min_block_size=1024, max_block_size=1048576): """ - We may need to split dense tensor to one or several blocks and put + We may need to split dense tensor to one or more blocks and put them equally onto parameter server. One block is a sub-tensor aligned by dim[0] of the tensor. - + We need to have a minimal block size so that the calculations in the parameter server side can gain better performance. By default - mininum block size is 1024. The max block size is used to prevent - too large block that may causing send error. + minimum block size is 1024. The max block size is used to prevent + very large blocks that may cause send error. """ blocks = [] for var in var_list: @@ -64,7 +64,7 @@ def split_dense_variable(var_list, remains = block_size % dim1 if remains != 0: block_size += dim1 - remains - # update split_count after align + # update split_count after aligning split_count = int(math.ceil(var_numel / float(block_size))) for block_id in xrange(split_count): curr_block_size = min(block_size, var_numel - ( @@ -83,18 +83,18 @@ class DistributeTranspiler: trainers=1, split_method=round_robin): """ - Transpile the program to a distributed data-parallelism programs. - The main_program will be transform to use a remote parameter server + Transpile the program to distributed data-parallelism programs. + The main_program will be transformed to use a remote parameter server to do parameter optimization. And the optimization graph will be put - in to a parameter server program. + into a parameter server program. - Use different methods to split trainable varialbles to different + Use different methods to split trainable variables to different parameter servers. :param optimize_ops: op list of optimization, should be the return value of Optimizer.minimize :type optimize_ops: list - :param program: program to optimize, default default_main_program + :param program: program to optimize, default is default_main_program :param pservers: parameter server endpoints like "m1:6174,m2:6174" :type pservers: string :return: return a list of programs @@ -106,11 +106,11 @@ class DistributeTranspiler: self.trainers = trainers self.optimize_ops = optimize_ops # steps to transpile: - # 1. split variable to multiple blocks, align by product(dim[1:]) (width). + # 1. split variable to multiple blocks, aligned by product(dim[1:]) (width). # 2. modify trainer program add split_op to each Grad. # 3. append send_op to trainer. # 4. append concat_op to trainer to update local weights. - # 5. create new program as parameter server. + # 5. create new program for parameter server. # 6. create parameter server program by split_method generated endpoint->VarBlock pserver_endpoints = pservers.split(",") @@ -136,10 +136,10 @@ class DistributeTranspiler: for b in param_blocks: varname, block_id, _ = b.split(":") send_outputs.append(param_var_mapping[varname][int(block_id)]) - # let send_op know which endpoint to send which var, eplist is of the same - # order of send_inputs. + # let send_op know which endpoint to send which var to, eplist has the same + # order as send_inputs. eplist = split_method(send_inputs, pserver_endpoints) - # create mapping of endpoint -> splited var to create pserver side program + # create mapping of endpoint -> split var to create pserver side program self.param_grad_ep_mapping = dict() for i, ep in enumerate(eplist): param = send_outputs[i] @@ -149,6 +149,7 @@ class DistributeTranspiler: self.param_grad_ep_mapping[ep]["params"].append(param) self.param_grad_ep_mapping[ep]["grads"].append(grad) + # create send_op send_op = program.global_block().append_op( type="send", inputs={"X": send_inputs}, @@ -167,6 +168,7 @@ class DistributeTranspiler: attrs={"axis": 0}) def _create_vars_from_blocklist(self, program, block_list): + # Create respective variables using the block_list block_map = dict() var_mapping = dict() for block_str in block_list: @@ -207,11 +209,12 @@ class DistributeTranspiler: dtype=var.dtype, type=var.type, lod_level=var.lod_level, - # HACK: let all param in pserver persistable so child + # HACK: let all param in pserver be persistable so the child # program in recv can get them persistable=True) def _append_split_op(self, program, gradblocks): + # Split variables that need to be split and append respective ops var_mapping = self._create_vars_from_blocklist(program, gradblocks) for varname, splited_vars in var_mapping.iteritems(): # variable that don't need to split have empty splited_vars @@ -248,6 +251,7 @@ class DistributeTranspiler: return self.program def _create_var_for_trainers(self, block, var, trainers): + # For each trainer, create the necessary variables var_list = [] for i in xrange(trainers): var_each = block.create_var( @@ -262,7 +266,7 @@ class DistributeTranspiler: param_shape): """ Returns the shape for optimizer inputs that need to be reshaped when - Param and Grad is splited to multiple servers. + Param and Grad is split to multiple servers. """ # HACK(typhoonzero): Should use functions of corresponding optimizer in # optimizer.py to get the shape, do not bind this in the transpiler. @@ -300,7 +304,7 @@ class DistributeTranspiler: else: for n in param_names: if n.startswith(op.inputs["Param"].name+".block") and \ - n != op.inputs["Param"].name: + n != op.inputs["Param"].name: return True return False else: @@ -396,7 +400,7 @@ class DistributeTranspiler: dtype=var.dtype, shape=new_shape) - # change outputs ParamOut variable + # change output's ParamOut variable opt_op.outputs["ParamOut"] = new_inputs["Param"] program.global_block().append_op( type=opt_op.type, @@ -405,6 +409,7 @@ class DistributeTranspiler: attrs=opt_op.attrs) def _append_pserver_non_opt_ops(self, program, pserver_program, opt_op): + # Append the ops for parameters that do not need to be optimized/updated for _, var in opt_op.inputs.iteritems(): program.global_block().create_var( name=var.name, @@ -424,7 +429,7 @@ class DistributeTranspiler: def get_pserver_program(self, endpoint): """ - get pserver side program by endpoint + Get pserver side program using the endpoint NOTE: assume blocks of the same variable is not distributed on the same pserver, only change param/grad varnames for @@ -450,6 +455,7 @@ class DistributeTranspiler: shape=v.shape) # step6 optimize_sub_program = Program() + # Iterate through the ops and append ops as needed for idx, opt_op in enumerate(self.optimize_ops): is_op_on_pserver = self._is_op_on_pserver(endpoint, self.optimize_ops, idx) @@ -461,6 +467,7 @@ class DistributeTranspiler: else: self._append_pserver_non_opt_ops(optimize_sub_program, pserver_program, opt_op) + # Append the recv op pserver_program.global_block().append_op( type="recv", inputs={"RX": self.param_grad_ep_mapping[endpoint]["grads"] @@ -486,7 +493,7 @@ class DistributeTranspiler: """ Get startup program for current parameter server. Modify operator input variables if there are variables that - was splited to several blocks. + were split to several blocks. """ s_prog = Program() orig_s_prog = framework.default_startup_program() diff --git a/python/paddle/v2/fluid/evaluator.py b/python/paddle/v2/fluid/evaluator.py index 396d56fc8b236d95d38517f3513521aa969e47be..2686a5bdfcf0e2d26ce8f58cceff1967b06d835b 100644 --- a/python/paddle/v2/fluid/evaluator.py +++ b/python/paddle/v2/fluid/evaluator.py @@ -205,3 +205,63 @@ class ChunkEvaluator(Evaluator): [precision], dtype='float32'), np.array( [recall], dtype='float32'), np.array( [f1_score], dtype='float32') + + +class EditDistance(Evaluator): + """ + Accumulate edit distance sum and sequence number from mini-batches and + compute the average edit_distance of all batches. + + Args: + input: the sequences predicted by network. + label: the target sequences which must has same sequence count + with input. + ignored_tokens(list of int): Tokens that should be removed before + calculating edit distance. + + Example: + + exe = fluid.executor(place) + distance_evaluator = fluid.Evaluator.EditDistance(input, label) + for epoch in PASS_NUM: + distance_evaluator.reset(exe) + for data in batches: + loss, sum_distance = exe.run(fetch_list=[cost] + distance_evaluator.metrics) + avg_distance = distance_evaluator.eval(exe) + pass_distance = distance_evaluator.eval(exe) + + In the above example: + 'sum_distance' is the sum of the batch's edit distance. + 'avg_distance' is the average of edit distance from the firt batch to the current batch. + 'pass_distance' is the average of edit distance from all the pass. + + """ + + def __init__(self, input, label, ignored_tokens=None, **kwargs): + super(EditDistance, self).__init__("edit_distance", **kwargs) + main_program = self.helper.main_program + if main_program.current_block().idx != 0: + raise ValueError("You can only invoke Evaluator in root block") + + self.total_error = self.create_state( + dtype='float32', shape=[1], suffix='total_error') + self.seq_num = self.create_state( + dtype='int64', shape=[1], suffix='seq_num') + error, seq_num = layers.edit_distance( + input=input, label=label, ignored_tokens=ignored_tokens) + #error = layers.cast(x=error, dtype='float32') + sum_error = layers.reduce_sum(error) + layers.sums(input=[self.total_error, sum_error], out=self.total_error) + layers.sums(input=[self.seq_num, seq_num], out=self.seq_num) + self.metrics.append(sum_error) + + def eval(self, executor, eval_program=None): + if eval_program is None: + eval_program = Program() + block = eval_program.current_block() + with program_guard(main_program=eval_program): + total_error = _clone_var_(block, self.total_error) + seq_num = _clone_var_(block, self.seq_num) + seq_num = layers.cast(x=seq_num, dtype='float32') + out = layers.elementwise_div(x=total_error, y=seq_num) + return np.array(executor.run(eval_program, fetch_list=[out])[0]) diff --git a/python/paddle/v2/fluid/framework.py b/python/paddle/v2/fluid/framework.py index f87666545893884b2664b52be2d1a11b5aa4a244..4d8343e7de9526d527ebe93f334b59108d5ace8e 100644 --- a/python/paddle/v2/fluid/framework.py +++ b/python/paddle/v2/fluid/framework.py @@ -780,7 +780,7 @@ class Block(object): trainable=p.trainable, optimize_attr=p.optimize_attr, regularizer=p.regularizer, - clip_attr=p.clip_attr, + gradient_clip_attr=p.gradient_clip_attr, error_clip=p.error_clip, name=v.name) self.vars[new_p.name] = new_p @@ -948,7 +948,7 @@ class Parameter(Variable): self.regularizer = kwargs.get('regularizer', None) - self.clip_attr = kwargs.get('clip_attr', None) + self.gradient_clip_attr = kwargs.get('gradient_clip_attr', None) # program is a global instance. diff --git a/python/paddle/v2/fluid/layers/__init__.py b/python/paddle/v2/fluid/layers/__init__.py index cc8a1b1ce5677c06afcd742ff94325bec20cdedd..a83dd3db74aed548a324a1c605723c957fca8604 100644 --- a/python/paddle/v2/fluid/layers/__init__.py +++ b/python/paddle/v2/fluid/layers/__init__.py @@ -24,6 +24,8 @@ import control_flow from control_flow import * import device from device import * +import math_op_patch +from math_op_patch import * __all__ = [] __all__ += nn.__all__ @@ -32,3 +34,4 @@ __all__ += tensor.__all__ __all__ += control_flow.__all__ __all__ += ops.__all__ __all__ += device.__all__ +__all__ += math_op_patch.__all__ diff --git a/python/paddle/v2/fluid/layers/control_flow.py b/python/paddle/v2/fluid/layers/control_flow.py index 2f1188c542cc0208a189511a1eef1eddc411007c..5f01fdb076d3bf7d060a805d1431f4973993a843 100644 --- a/python/paddle/v2/fluid/layers/control_flow.py +++ b/python/paddle/v2/fluid/layers/control_flow.py @@ -11,22 +11,41 @@ # 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. +import contextlib -from ..layer_helper import LayerHelper, unique_name -from ..framework import Program, Variable, Operator -from .. import core +from layer_function_generator import autodoc from tensor import assign, fill_constant -import contextlib -from ..registry import autodoc +from .. import core +from ..framework import Program, Variable, Operator +from ..layer_helper import LayerHelper, unique_name __all__ = [ - 'split_lod_tensor', 'merge_lod_tensor', 'BlockGuard', - 'BlockGuardWithCompletion', 'StaticRNNMemoryLink', 'WhileGuard', 'While', - 'lod_rank_table', 'max_sequence_len', 'topk', 'lod_tensor_to_array', - 'array_to_lod_tensor', 'increment', 'array_write', 'create_array', - 'less_than', 'array_read', 'shrink_memory', 'array_length', 'IfElse', - 'DynamicRNN', 'ConditionalBlock', 'StaticRNN', 'reorder_lod_tensor_by_rank', - 'ParallelDo', 'Print' + 'split_lod_tensor', + 'merge_lod_tensor', + 'BlockGuard', + 'BlockGuardWithCompletion', + 'StaticRNNMemoryLink', + 'WhileGuard', + 'While', + 'lod_rank_table', + 'max_sequence_len', + 'topk', + 'lod_tensor_to_array', + 'array_to_lod_tensor', + 'increment', + 'array_write', + 'create_array', + 'less_than', + 'array_read', + 'shrink_memory', + 'array_length', + 'IfElse', + 'DynamicRNN', + 'ConditionalBlock', + 'StaticRNN', + 'reorder_lod_tensor_by_rank', + 'ParallelDo', + 'Print', ] @@ -1458,7 +1477,7 @@ class DynamicRNN(object): method)) -@autodoc +@autodoc() def reorder_lod_tensor_by_rank(x, rank_table): helper = LayerHelper('reorder_lod_tensor_by_rank', **locals()) helper.is_instance('x', Variable) diff --git a/python/paddle/v2/fluid/layers/device.py b/python/paddle/v2/fluid/layers/device.py index 736813d1b109087da367666d90be9e88dad1860e..107511b5f4ab1108610bc1326f30e5d9ab407853 100644 --- a/python/paddle/v2/fluid/layers/device.py +++ b/python/paddle/v2/fluid/layers/device.py @@ -15,14 +15,14 @@ All util layers. """ -from ..layer_helper import LayerHelper +from layer_function_generator import autodoc from ..framework import unique_name -from ..registry import autodoc +from ..layer_helper import LayerHelper __all__ = ['get_places'] -@autodoc +@autodoc() def get_places(device_count=None, device_type=None): helper = LayerHelper('get_places', **locals()) out_places = helper.create_variable(name=unique_name(helper.name + ".out")) diff --git a/python/paddle/v2/fluid/registry.py b/python/paddle/v2/fluid/layers/layer_function_generator.py similarity index 94% rename from python/paddle/v2/fluid/registry.py rename to python/paddle/v2/fluid/layers/layer_function_generator.py index ff10542d40aabaf31897842754d38b7868472b21..b0e4d1635f7b5d0afdfa677e6ec1e8f9245a9d54 100644 --- a/python/paddle/v2/fluid/registry.py +++ b/python/paddle/v2/fluid/layers/layer_function_generator.py @@ -13,17 +13,19 @@ # limitations under the License. import re import cStringIO -import warnings import functools -import inspect +import warnings + +from .. import proto -import proto.framework_pb2 as framework_pb2 -from framework import OpProtoHolder, Variable, Program, Operator -from paddle.v2.fluid.layer_helper import LayerHelper, unique_name +framework_pb2 = proto.framework_pb2 + +from ..framework import OpProtoHolder, Variable +from ..layer_helper import LayerHelper __all__ = [ 'deprecated', - 'register_layer', + 'generate_layer_fn', 'autodoc', ] @@ -96,7 +98,7 @@ def _generate_doc_string_(op_proto): return buf.getvalue() -def register_layer(op_type): +def generate_layer_fn(op_type): """Register the Python layer for an Operator. Args: @@ -207,7 +209,10 @@ def deprecated(func_or_class): return func_wrapper -def autodoc(func): - func.__doc__ = _generate_doc_string_(OpProtoHolder.instance().get_op_proto( - func.__name__)) - return func +def autodoc(comment=""): + def __impl__(func): + func.__doc__ = _generate_doc_string_(OpProtoHolder.instance( + ).get_op_proto(func.__name__)) + comment + return func + + return __impl__ diff --git a/python/paddle/v2/fluid/layers/math_op_patch.py b/python/paddle/v2/fluid/layers/math_op_patch.py new file mode 100644 index 0000000000000000000000000000000000000000..f359e70126f7601b75261e795b5a37bdc241112e --- /dev/null +++ b/python/paddle/v2/fluid/layers/math_op_patch.py @@ -0,0 +1,152 @@ +# Copyright (c) 2018 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. + +from ..framework import Variable, unique_name +from layer_function_generator import OpProtoHolder + +__all__ = ['monkey_patch_variable'] + + +def monkey_patch_variable(): + def unique_tmp_name(): + return unique_name("tmp") + + def safe_get_dtype(var): + try: + dtype = var.dtype + except: + raise ValueError("Cannot get data type from %s", var.name) + return dtype + + def create_tensor(block, value, dtype, shape): + value = float(value) + tmp_name = unique_tmp_name() + var = block.create_var(name=tmp_name, shape=shape, dtype=dtype) + block.append_op( + type="fill_constant", + outputs={'Out': [var]}, + attrs={'dtype': var.dtype, + 'shape': shape, + 'value': value}) + return var + + def create_scalar(block, value, dtype): + return create_tensor(block, value, dtype, shape=[1]) + + def create_tensor_with_batchsize(ref_var, value, dtype): + assert isinstance(ref_var, Variable) + value = float(value) + tmp_name = unique_tmp_name() + var = ref_var.block.create_var(name=tmp_name, dtype=dtype) + ref_var.block.append_op( + type='fill_constant_batch_size_like', + outputs={'Out': [var]}, + inputs={'Input': [ref_var]}, + attrs={'shape': ref_var.shape, + 'value': value}) + return var + + def astype(self, dtype): + """ + Cast a variable to a specified data type. + NOTE: The variable must be a Tensor + Args: + self(Variable): The source variable + dtype: The target dtype + + Returns: + Variable with new dtype + """ + tmp_name = unique_tmp_name() + out = self.block.create_var(name=tmp_name, dtype=dtype) + self.block.append_op( + type="cast", + inputs={"X": [self]}, + outputs={"Out": [out]}, + attrs={"in_dtype": self.dtype, + "out_dtype": out.dtype}) + return out + + def _elemwise_method_creator_(method_name, op_type, reverse=False): + def __impl__(self, other_var): + lhs_dtype = safe_get_dtype(self) + + if not isinstance(other_var, Variable): + if reverse: + has_batch_size = False + for elem in self.shape: + if elem < 0: + has_batch_size = True + break + if not has_batch_size: + other_var = create_tensor( + self.block, + other_var, + dtype=lhs_dtype, + shape=self.shape) + else: + other_var = create_tensor_with_batchsize( + self, other_var, lhs_dtype) + else: + # add fill_op to self.block + other_var = create_scalar( + self.block, value=other_var, dtype=lhs_dtype) + + rhs_dtype = safe_get_dtype(other_var) + if lhs_dtype != rhs_dtype: + other_var = astype(other_var, lhs_dtype) + if reverse: + tmp = self + self = other_var + other_var = tmp + + tmp_name = unique_tmp_name() + out = self.block.create_var(name=tmp_name, dtype=lhs_dtype) + self.block.append_op( + type=op_type, + inputs={'X': [self], + 'Y': [other_var]}, + outputs={'Out': out}) + return out + + comment = OpProtoHolder.instance().get_op_proto(op_type).comment + + __impl__.__doc__ = """ + {0} + Args: + self(Variable): left hand variable + other_var(Variable|float|int): right hand variable + + Returns: + Variable + """.format(comment) + __impl__.__name__ = method_name + return __impl__ + + # inject methods + for method_name, op_type, reverse in ( + ("__add__", "elementwise_add", False), + # a+b == b+a. Do not need to reverse explicitly + ("__radd__", "elementwise_add", False), + ("__sub__", "elementwise_sub", False), + ("__rsub__", "elementwise_sub", True), + ("__mul__", "elementwise_mul", False), + # a*b == b*a. Do not need to reverse explicitly + ("__rmul__", "elementwise_mul", False), + ("__div__", "elementwise_div", False), + ("__rdiv__", "elementwise_div", True)): + setattr(Variable, method_name, + _elemwise_method_creator_(method_name, op_type, reverse)) + + Variable.astype = astype diff --git a/python/paddle/v2/fluid/layers/nn.py b/python/paddle/v2/fluid/layers/nn.py index 070b7472877baad0ebfe310934b79b1a74b86620..bd0404c94d326bd1fff56fec132301c5eae0f10f 100644 --- a/python/paddle/v2/fluid/layers/nn.py +++ b/python/paddle/v2/fluid/layers/nn.py @@ -22,13 +22,42 @@ from ..param_attr import ParamAttr from tensor import concat __all__ = [ - 'fc', 'embedding', 'dynamic_lstm', 'gru_unit', 'linear_chain_crf', - 'crf_decoding', 'cos_sim', 'cross_entropy', 'square_error_cost', 'accuracy', - 'chunk_eval', 'sequence_conv', 'conv2d', 'sequence_pool', 'pool2d', - 'batch_norm', 'beam_search_decode', 'conv2d_transpose', 'sequence_expand', - 'lstm_unit', 'reduce_sum', 'reduce_mean', 'reduce_max', 'reduce_min', - 'sequence_first_step', 'sequence_last_step', 'dropout', 'split', - 'l2_normalize', 'matmul', 'warpctc', 'sequence_reshape', 'im2sequence' + 'fc', + 'embedding', + 'dynamic_lstm', + 'gru_unit', + 'linear_chain_crf', + 'crf_decoding', + 'cos_sim', + 'cross_entropy', + 'square_error_cost', + 'accuracy', + 'chunk_eval', + 'sequence_conv', + 'conv2d', + 'sequence_pool', + 'pool2d', + 'batch_norm', + 'beam_search_decode', + 'conv2d_transpose', + 'sequence_expand', + 'lstm_unit', + 'reduce_sum', + 'reduce_mean', + 'reduce_max', + 'reduce_min', + 'sequence_first_step', + 'sequence_last_step', + 'dropout', + 'split', + 'ctc_greedy_decoder', + 'edit_distance', + 'l2_normalize', + 'matmul', + 'warpctc', + 'sequence_reshape', + 'transpose', + 'im2sequence', ] @@ -43,14 +72,14 @@ def fc(input, **Fully Connected Layer** The fully connected layer can take multiple tensors as its inputs. It - creates a variable (one for each input tensor) called weights for each input - tensor, which represents a fully connected weight matrix from each input - unit to each output unit. The fully connected layer multiplies each input - tensor with its coresponding weight to produce an output Tensor. If - multiple input tensors are given, the results of multiple multiplications - will be sumed up. If bias_attr is not None, a biases variable will be - created and added to the output. Finally, if activation is not None, - it will be applied to the output as well. + creates a variable (one for each input tensor) called weights for each + input tensor, which represents a fully connected weight matrix from + each input unit to each output unit. The fully connected layer + multiplies each input tensor with its coresponding weight to produce + an output Tensor. If multiple input tensors are given, the results of + multiple multiplications will be sumed up. If bias_attr is not None, + a biases variable will be created and added to the output. Finally, + if activation is not None, it will be applied to the output as well. This process can be formulated as follows: @@ -1866,6 +1895,146 @@ def matmul(x, y, transpose_x=False, transpose_y=False, name=None): return out +def edit_distance(input, + label, + normalized=False, + ignored_tokens=None, + name=None): + """ + EditDistance operator computes the edit distances between a batch of hypothesis strings and their references. Edit distance, also called Levenshtein distance, measures how dissimilar two strings are by counting the minimum number of operations to transform one string into anthor. Here the operations include insertion, deletion, and substitution. For example, given hypothesis string A = "kitten" and reference B = "sitting", the edit distance is 3 for A will be transformed into B at least after two substitutions and one insertion: + + "kitten" -> "sitten" -> "sittin" -> "sitting" + + Input(Hyps) is a LoDTensor consisting of all the hypothesis strings with the total number denoted by `batch_size`, and the separation is specified by the LoD information. And the `batch_size` reference strings are arranged in order in the same way in the LoDTensor Input(Refs). + + Output(Out) contains the `batch_size` results and each stands for the edit stance for a pair of strings respectively. If Attr(normalized) is true, the edit distance will be divided by the length of reference string. + + Args: + + input(Variable): The indices for hypothesis strings. + + label(Variable): The indices for reference strings. + + normalized(bool): Indicated whether to normalize the edit distance by the length of reference string. + + ignored_tokens(list of int): Tokens that should be removed before calculating edit distance. + + Returns: + Variable: sequence-to-sequence edit distance in shape [batch_size, 1]. + + Examples: + .. code-block:: python + + x = fluid.layers.data(name='x', shape=[8], dtype='float32') + y = fluid.layers.data(name='y', shape=[7], dtype='float32') + + cost = fluid.layers.edit_distance(input=x,label=y) + """ + helper = LayerHelper("edit_distance", **locals()) + + # remove some tokens from input and labels + if ignored_tokens is not None and len(ignored_tokens) > 0: + erased_input = helper.create_tmp_variable(dtype="int64") + erased_label = helper.create_tmp_variable(dtype="int64") + + helper.append_op( + type="sequence_erase", + inputs={"X": [input]}, + outputs={"Out": [erased_input]}, + attrs={"tokens": ignored_tokens}) + input = erased_input + + helper.append_op( + type="sequence_erase", + inputs={"X": [label]}, + outputs={"Out": [erase_label]}, + attrs={"tokens": ignored_tokens}) + label = erased_label + + # edit distance op + edit_distance_out = helper.create_tmp_variable(dtype="int64") + sequence_num = helper.create_tmp_variable(dtype="int64") + helper.append_op( + type="edit_distance", + inputs={"Hyps": [input], + "Refs": [label]}, + outputs={"Out": [edit_distance_out], + "SequenceNum": [sequence_num]}, + attrs={"normalized": normalized}) + + return edit_distance_out, sequence_num + + +def ctc_greedy_decoder(input, blank, name=None): + """ + This op is used to decode sequences by greedy policy by below steps: + 1. Get the indexes of max value for each row in input. a.k.a. numpy.argmax(input, axis=0). + 2. For each sequence in result of step1, merge repeated tokens between two blanks and delete all blanks. + + A simple example as below: + + .. code-block:: text + + Given: + + input.data = [[0.6, 0.1, 0.3, 0.1], + [0.3, 0.2, 0.4, 0.1], + [0.1, 0.5, 0.1, 0.3], + [0.5, 0.1, 0.3, 0.1], + + [0.5, 0.1, 0.3, 0.1], + [0.2, 0.2, 0.2, 0.4], + [0.2, 0.2, 0.1, 0.5], + [0.5, 0.1, 0.3, 0.1]] + + input.lod = [[0, 4, 8]] + + Then: + + output.data = [[2], + [1], + [3]] + + output.lod = [[0, 2, 3]] + + Args: + + input(Variable): (LoDTensor), the probabilities of variable-length sequences, which is a 2-D Tensor with LoD information. It's shape is [Lp, num_classes + 1], where Lp is the sum of all input sequences' length and num_classes is the true number of classes. (not including the blank label). + + blank(int): the blank label index of Connectionist Temporal Classification (CTC) loss, which is in thehalf-opened interval [0, num_classes + 1). + + Returns: + Variable: CTC greedy decode result. + + Examples: + .. code-block:: python + + x = fluid.layers.data(name='x', shape=[8], dtype='float32') + + cost = fluid.layers.ctc_greedy_decoder(input=x, blank=0) + """ + helper = LayerHelper("ctc_greedy_decoder", **locals()) + # top 1 op + topk_out = helper.create_tmp_variable(dtype=input.dtype) + topk_indices = helper.create_tmp_variable(dtype="int64") + helper.append_op( + type="top_k", + inputs={"X": [input]}, + outputs={"Out": [topk_out], + "Indices": [topk_indices]}, + attrs={"k": 1}) + + # ctc align op + ctc_out = helper.create_tmp_variable(dtype="int64") + helper.append_op( + type="ctc_align", + inputs={"Input": [topk_indices]}, + outputs={"Output": [ctc_out]}, + attrs={"merge_repeated": True, + "blank": blank}) + return ctc_out + + def warpctc(input, label, blank=0, norm_by_times=False, **kwargs): """ An operator integrating the open source Warp-CTC library @@ -1890,7 +2059,7 @@ def warpctc(input, label, blank=0, norm_by_times=False, **kwargs): Temporal Classification (CTC) loss, which is in the half-opened interval [0, num_classes + 1). norm_by_times: (bool, default: false), whether to normalize - the gradients by the number of time-step,which is also the + the gradients by the number of time-step, which is also the sequence's length. There is no need to normalize the gradients if warpctc layer was follewed by a mean_op. @@ -1973,6 +2142,44 @@ def sequence_reshape(input, new_dim): return out +def transpose(x, perm, name=None): + """ + **transpose Layer** + + Permute the dimensions of `input` according to `perm`. + + The `i`-th dimension of the returned tensor will correspond to the + perm[i]-th dimension of `input`. + + Args: + input (Variable): (Tensor), A Tensor. + perm (list): A permutation of the dimensions of `input`. + + Returns: + Variable: A transposed Tensor. + + Examples: + .. code-block:: python + + x = fluid.layers.data(name='x', shape=[5, 10, 15], dtype='float32') + x_transposed = layers.transpose(x, perm=[1, 0, 2]) + """ + + if len(perm) != len(x.shape): + raise ValueError( + "Input(perm) is the permutation of dimensions of Input(input). " + "It's length shoud be equal to Input(input)'s rank.") + + helper = LayerHelper('transpose', **locals()) + out = helper.create_tmp_variable(x.dtype) + helper.append_op( + type='transpose', + inputs={'X': [x]}, + outputs={'Out': [out]}, + attrs={'axis': perm}) + return out + + def im2sequence(input, filter_size=1, stride=1, @@ -2072,7 +2279,7 @@ def im2sequence(input, .. code-block:: python - output = fluid.layers.im2sequence(input=layer, stride=[1, 1], filter=[2, 2]) + output = fluid.layers.im2sequence(input=layer, stride=[1, 1], filter_size=[2, 2]) """ diff --git a/python/paddle/v2/fluid/layers/ops.py b/python/paddle/v2/fluid/layers/ops.py index 7716052a5cae0d8883dd9996f34d39e97f4399ea..022a94cad440f13383a927233195bb008a688843 100644 --- a/python/paddle/v2/fluid/layers/ops.py +++ b/python/paddle/v2/fluid/layers/ops.py @@ -11,8 +11,7 @@ # 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. - -from ..registry import register_layer +from layer_function_generator import generate_layer_fn __activations__ = [ 'sigmoid', @@ -50,7 +49,6 @@ __all__ = [ 'mul', 'reshape', 'scale', - 'transpose', 'sigmoid_cross_entropy_with_logits', 'elementwise_add', 'elementwise_div', @@ -59,8 +57,9 @@ __all__ = [ 'elementwise_max', 'elementwise_min', 'clip', + 'clip_by_norm', 'sequence_softmax', ] + __activations__ for _OP in set(__all__): - globals()[_OP] = register_layer(_OP) + globals()[_OP] = generate_layer_fn(_OP) diff --git a/python/paddle/v2/fluid/param_attr.py b/python/paddle/v2/fluid/param_attr.py index 26e9111f6f31019ab14780cc4bea01e617561fb7..dcca8b6c547d10864ff4cd0af1c217d89e3b522f 100644 --- a/python/paddle/v2/fluid/param_attr.py +++ b/python/paddle/v2/fluid/param_attr.py @@ -25,13 +25,13 @@ class ParamAttr(object): learning_rate=1.0, regularizer=None, trainable=True, - clip=None): + gradient_clip=None): self.name = name self.initializer = initializer self.learning_rate = learning_rate self.regularizer = regularizer self.trainable = trainable - self.clip = clip + self.gradient_clip = gradient_clip def set_default_initializer(self, initializer): if initializer is None: @@ -77,7 +77,7 @@ class ParamAttr(object): }, 'regularizer': self.regularizer, 'trainable': self.trainable, - 'clip_attr': self.clip + 'gradient_clip_attr': self.gradient_clip } if with_initializer: kwargs['initializer'] = self.initializer diff --git a/python/paddle/v2/fluid/tests/CMakeLists.txt b/python/paddle/v2/fluid/tests/CMakeLists.txt index 9a0240cbf65c7a79e29babc2abcb157ada684c5e..83053160820a70bb5e54f721c0d7b881c5765004 100644 --- a/python/paddle/v2/fluid/tests/CMakeLists.txt +++ b/python/paddle/v2/fluid/tests/CMakeLists.txt @@ -6,3 +6,4 @@ endforeach() add_subdirectory(book) add_subdirectory(book_distribute) +add_subdirectory(book_memory_optimization) diff --git a/python/paddle/v2/fluid/tests/book/test_recognize_digits_mlp.py b/python/paddle/v2/fluid/tests/book/test_recognize_digits_mlp.py index be22e97054a16d69cf9e2d1e88629497e519c778..8776a65bf804e93dfeb295ecca34fac0840b0a90 100644 --- a/python/paddle/v2/fluid/tests/book/test_recognize_digits_mlp.py +++ b/python/paddle/v2/fluid/tests/book/test_recognize_digits_mlp.py @@ -27,7 +27,7 @@ hidden1 = fluid.layers.fc(input=image, act='relu', param_attr=fluid.ParamAttr( regularizer=regularizer, - clip=fluid.clip.ClipByValue(10))) + gradient_clip=fluid.clip.ClipByValue(10))) hidden2 = fluid.layers.fc(input=hidden1, size=64, diff --git a/python/paddle/v2/fluid/tests/book/test_understand_sentiment_lstm.py b/python/paddle/v2/fluid/tests/book/test_understand_sentiment_lstm.py index 618191424150eb7c5a24407fc2e106ee8825fedb..117f74c59ad5bf6bb67711801cd7b9a41f39f1f8 100644 --- a/python/paddle/v2/fluid/tests/book/test_understand_sentiment_lstm.py +++ b/python/paddle/v2/fluid/tests/book/test_understand_sentiment_lstm.py @@ -65,13 +65,13 @@ def lstm_net(dict_dim, class_dim=2, emb_dim=32, seq_len=80, batch_size=50): emb = fluid.layers.embedding(input=data, size=[dict_dim, emb_dim]) emb = fluid.layers.reshape(x=emb, shape=[batch_size, seq_len, emb_dim]) - emb = fluid.layers.transpose(x=emb, axis=[1, 0, 2]) + emb = fluid.layers.transpose(x=emb, perm=[1, 0, 2]) c_pre_init = fluid.layers.fill_constant( dtype=emb.dtype, shape=[batch_size, emb_dim], value=0.0) c_pre_init.stop_gradient = False layer_1_out = lstm(emb, c_pre_init=c_pre_init, hidden_dim=emb_dim) - layer_1_out = fluid.layers.transpose(x=layer_1_out, axis=[1, 0, 2]) + layer_1_out = fluid.layers.transpose(x=layer_1_out, perm=[1, 0, 2]) prediction = fluid.layers.fc(input=layer_1_out, size=class_dim, diff --git a/python/paddle/v2/fluid/tests/book_memory_optimization/CMakeLists.txt b/python/paddle/v2/fluid/tests/book_memory_optimization/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..213af5d27f711214feda3d200ced57bf71fbf6c2 --- /dev/null +++ b/python/paddle/v2/fluid/tests/book_memory_optimization/CMakeLists.txt @@ -0,0 +1,11 @@ +file(GLOB TEST_OPS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "test_*.py") +string(REPLACE ".py" "" TEST_OPS "${TEST_OPS}") + +list(REMOVE_ITEM TEST_OPS test_memopt_image_classification_train) +py_test(test_memopt_image_classification_train_resnet SRCS test_memopt_image_classification_train.py ARGS resnet) +py_test(test_memopt_image_classification_train_vgg SRCS test_memopt_image_classification_train.py ARGS vgg) + +# default test +foreach(src ${TEST_OPS}) + py_test(${src} SRCS ${src}.py) +endforeach() diff --git a/python/paddle/v2/fluid/tests/book_memory_optimization/test_memopt_fit_a_line.py b/python/paddle/v2/fluid/tests/book_memory_optimization/test_memopt_fit_a_line.py new file mode 100644 index 0000000000000000000000000000000000000000..cf054bb0fe778d34add4ac456f672a8b47483e84 --- /dev/null +++ b/python/paddle/v2/fluid/tests/book_memory_optimization/test_memopt_fit_a_line.py @@ -0,0 +1,58 @@ +# Copyright (c) 2018 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. + +import numpy as np +import paddle.v2 as paddle +import paddle.v2.fluid as fluid + +x = fluid.layers.data(name='x', shape=[13], dtype='float32') + +y_predict = fluid.layers.fc(input=x, size=1, act=None) + +y = fluid.layers.data(name='y', shape=[1], dtype='float32') + +cost = fluid.layers.square_error_cost(input=y_predict, label=y) +avg_cost = fluid.layers.mean(x=cost) + +sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.1) +sgd_optimizer.minimize(avg_cost) + +# memopt_program = fluid.default_main_program() +memopt_program = fluid.memory_optimize(fluid.default_main_program()) + +BATCH_SIZE = 200 + +train_reader = paddle.batch( + paddle.reader.shuffle( + paddle.dataset.uci_housing.train(), buf_size=500), + batch_size=BATCH_SIZE) + +place = fluid.CPUPlace() +feeder = fluid.DataFeeder(place=place, feed_list=[x, y]) +exe = fluid.Executor(place) + +exe.run(fluid.default_startup_program()) + +PASS_NUM = 100 +for pass_id in range(PASS_NUM): + fluid.io.save_persistables(exe, "./fit_a_line.model/") + fluid.io.load_persistables(exe, "./fit_a_line.model/") + for data in train_reader(): + avg_loss_value, = exe.run(memopt_program, + feed=feeder.feed(data), + fetch_list=[avg_cost]) + + if avg_loss_value[0] < 10.0: + exit(0) # if avg cost less than 10.0, we think our code is good. +exit(1) diff --git a/python/paddle/v2/fluid/tests/book_memory_optimization/test_memopt_image_classification_train.py b/python/paddle/v2/fluid/tests/book_memory_optimization/test_memopt_image_classification_train.py new file mode 100644 index 0000000000000000000000000000000000000000..42b3cb81ce67d38494677f3ecbfb1e07f7c0c3ad --- /dev/null +++ b/python/paddle/v2/fluid/tests/book_memory_optimization/test_memopt_image_classification_train.py @@ -0,0 +1,147 @@ +# Copyright (c) 2018 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. + +from __future__ import print_function + +import sys + +import paddle.v2 as paddle +import paddle.v2.fluid as fluid + + +def resnet_cifar10(input, depth=32): + def conv_bn_layer(input, ch_out, filter_size, stride, padding, act='relu'): + tmp = fluid.layers.conv2d( + input=input, + filter_size=filter_size, + num_filters=ch_out, + stride=stride, + padding=padding, + act=None, + bias_attr=False) + return fluid.layers.batch_norm(input=tmp, act=act) + + def shortcut(input, ch_in, ch_out, stride): + if ch_in != ch_out: + return conv_bn_layer(input, ch_out, 1, stride, 0, None) + else: + return input + + def basicblock(input, ch_in, ch_out, stride): + tmp = conv_bn_layer(input, ch_out, 3, stride, 1) + tmp = conv_bn_layer(tmp, ch_out, 3, 1, 1, act=None) + short = shortcut(input, ch_in, ch_out, stride) + return fluid.layers.elementwise_add(x=tmp, y=short, act='relu') + + def layer_warp(block_func, input, ch_in, ch_out, count, stride): + tmp = block_func(input, ch_in, ch_out, stride) + for i in range(1, count): + tmp = block_func(tmp, ch_out, ch_out, 1) + return tmp + + assert (depth - 2) % 6 == 0 + n = (depth - 2) / 6 + conv1 = conv_bn_layer( + input=input, ch_out=16, filter_size=3, stride=1, padding=1) + res1 = layer_warp(basicblock, conv1, 16, 16, n, 1) + res2 = layer_warp(basicblock, res1, 16, 32, n, 2) + res3 = layer_warp(basicblock, res2, 32, 64, n, 2) + pool = fluid.layers.pool2d( + input=res3, pool_size=8, pool_type='avg', pool_stride=1) + return pool + + +def vgg16_bn_drop(input): + def conv_block(input, num_filter, groups, dropouts): + return fluid.nets.img_conv_group( + input=input, + pool_size=2, + pool_stride=2, + conv_num_filter=[num_filter] * groups, + conv_filter_size=3, + conv_act='relu', + conv_with_batchnorm=True, + conv_batchnorm_drop_rate=dropouts, + pool_type='max') + + conv1 = conv_block(input, 64, 2, [0.3, 0]) + conv2 = conv_block(conv1, 128, 2, [0.4, 0]) + conv3 = conv_block(conv2, 256, 3, [0.4, 0.4, 0]) + conv4 = conv_block(conv3, 512, 3, [0.4, 0.4, 0]) + conv5 = conv_block(conv4, 512, 3, [0.4, 0.4, 0]) + + drop = fluid.layers.dropout(x=conv5, dropout_prob=0.5) + fc1 = fluid.layers.fc(input=drop, size=512, act=None) + bn = fluid.layers.batch_norm(input=fc1, act='relu') + drop2 = fluid.layers.dropout(x=bn, dropout_prob=0.5) + fc2 = fluid.layers.fc(input=drop2, size=512, act=None) + return fc2 + + +classdim = 10 +data_shape = [3, 32, 32] + +images = fluid.layers.data(name='pixel', shape=data_shape, dtype='float32') +label = fluid.layers.data(name='label', shape=[1], dtype='int64') + +net_type = "vgg" +if len(sys.argv) >= 2: + net_type = sys.argv[1] + +if net_type == "vgg": + print("train vgg net") + net = vgg16_bn_drop(images) +elif net_type == "resnet": + print("train resnet") + net = resnet_cifar10(images, 32) +else: + raise ValueError("%s network is not supported" % net_type) + +predict = fluid.layers.fc(input=net, size=classdim, act='softmax') +cost = fluid.layers.cross_entropy(input=predict, label=label) +avg_cost = fluid.layers.mean(x=cost) + +optimizer = fluid.optimizer.Adam(learning_rate=0.001) +opts = optimizer.minimize(avg_cost) + +accuracy = fluid.evaluator.Accuracy(input=predict, label=label) + +# memopt_program = fluid.default_main_program() +memopt_program = fluid.memory_optimize(fluid.default_main_program()) + +BATCH_SIZE = 128 +PASS_NUM = 1 + +train_reader = paddle.batch( + paddle.reader.shuffle( + paddle.dataset.cifar.train10(), buf_size=128 * 10), + batch_size=BATCH_SIZE) + +place = fluid.CPUPlace() +exe = fluid.Executor(place) +feeder = fluid.DataFeeder(place=place, feed_list=[images, label]) +exe.run(fluid.default_startup_program()) + +for pass_id in range(PASS_NUM): + accuracy.reset(exe) + for data in train_reader(): + loss, acc = exe.run(memopt_program, + feed=feeder.feed(data), + fetch_list=[avg_cost] + accuracy.metrics) + pass_acc = accuracy.eval(exe) + print("loss:" + str(loss) + " acc:" + str(acc) + " pass_acc:" + str( + pass_acc)) + # this model is slow, so if we can train two mini batch, we think it works properly. + exit(0) +exit(1) diff --git a/python/paddle/v2/fluid/tests/test_bipartite_match_op.py b/python/paddle/v2/fluid/tests/test_bipartite_match_op.py new file mode 100644 index 0000000000000000000000000000000000000000..34101b1da46d46d0e7a995ba80d8644dc586065d --- /dev/null +++ b/python/paddle/v2/fluid/tests/test_bipartite_match_op.py @@ -0,0 +1,100 @@ +# Copyright (c) 2018 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. +import unittest +import numpy as np +from op_test import OpTest + + +def bipartite_match(distance, match_indices, match_dis): + """Bipartite Matching algorithm. + Arg: + distance (numpy.array) : The distance of two entries with shape [M, N]. + match_indices (numpy.array): the matched indices from column to row + with shape [1, N], it must be initialized to -1. + match_dis (numpy.array): The matched distance from column to row + with shape [1, N], it must be initialized to 0. + """ + match_pair = [] + row, col = distance.shape + for i in range(row): + for j in range(col): + match_pair.append((i, j, distance[i][j])) + + match_sorted = sorted(match_pair, key=lambda tup: tup[2], reverse=True) + + row_indices = -1 * np.ones((row, ), dtype=np.int) + + idx = 0 + for i, j, dis in match_sorted: + if idx >= row: + break + if match_indices[j] == -1 and row_indices[i] == -1 and dis > 0: + match_indices[j] = i + row_indices[i] = j + match_dis[j] = dis + idx += 1 + + +def batch_bipartite_match(distance, lod): + """Bipartite Matching algorithm for batch input. + Arg: + distance (numpy.array) : The distance of two entries with shape [M, N]. + lod (list of int): The offsets of each input in this batch. + """ + n = len(lod) - 1 + m = distance.shape[1] + match_indices = -1 * np.ones((n, m), dtype=np.int) + match_dis = np.zeros((n, m), dtype=np.float32) + for i in range(len(lod) - 1): + bipartite_match(distance[lod[i]:lod[i + 1], :], match_indices[i, :], + match_dis[i, :]) + return match_indices, match_dis + + +class TestBipartiteMatchOpForWithLoD(OpTest): + def setUp(self): + self.op_type = 'bipartite_match' + lod = [[0, 5, 11, 23]] + dis = np.random.random((23, 217)).astype('float32') + match_indices, match_dis = batch_bipartite_match(dis, lod[0]) + + self.inputs = {'DistMat': (dis, lod)} + self.outputs = { + 'ColToRowMatchIndices': (match_indices), + 'ColToRowMatchDis': (match_dis), + } + + def test_check_output(self): + self.check_output() + + +class TestBipartiteMatchOpWithoutLoD(OpTest): + def setUp(self): + self.op_type = 'bipartite_match' + lod = [[0, 8]] + dis = np.random.random((8, 17)).astype('float32') + match_indices, match_dis = batch_bipartite_match(dis, lod[0]) + + self.inputs = {'DistMat': dis} + self.outputs = { + 'ColToRowMatchIndices': (match_indices), + 'ColToRowMatchDis': (match_dis), + } + + def test_check_output(self): + self.check_output() + + +if __name__ == '__main__': + unittest.main() diff --git a/python/paddle/v2/fluid/tests/test_compare_op.py b/python/paddle/v2/fluid/tests/test_compare_op.py index 08ef90b10eb70eb380db2821415184709602b848..c9be80fc45cd3428937998357b9dd9cbde1547cc 100644 --- a/python/paddle/v2/fluid/tests/test_compare_op.py +++ b/python/paddle/v2/fluid/tests/test_compare_op.py @@ -38,8 +38,6 @@ def create_test_class(op_type, typename, callback): for _type_name in {'float32', 'float64', 'int32', 'int64'}: create_test_class('less_than', _type_name, lambda _a, _b: _a < _b) create_test_class('less_equal', _type_name, lambda _a, _b: _a <= _b) - create_test_class('greater_than', _type_name, lambda _a, _b: _a > _b) - create_test_class('greater_equal', _type_name, lambda _a, _b: _a >= _b) create_test_class('equal', _type_name, lambda _a, _b: _a == _b) if __name__ == '__main__': diff --git a/python/paddle/v2/fluid/tests/test_edit_distance_op.py b/python/paddle/v2/fluid/tests/test_edit_distance_op.py index 11cb85a151d1a4e213bcc52592d2f860f69b457f..bebdc5cba36fc96d31162d0d7d43e52064ca8e2d 100644 --- a/python/paddle/v2/fluid/tests/test_edit_distance_op.py +++ b/python/paddle/v2/fluid/tests/test_edit_distance_op.py @@ -61,6 +61,7 @@ class TestEditDistanceOp(OpTest): num_strs = len(x1_lod) - 1 distance = np.zeros((num_strs, 1)).astype("float32") + sequence_num = np.array(2).astype("int64") for i in range(0, num_strs): distance[i] = Levenshtein( hyp=x1[x1_lod[i]:x1_lod[i + 1]], @@ -70,7 +71,7 @@ class TestEditDistanceOp(OpTest): distance[i] = distance[i] / len_ref self.attrs = {'normalized': normalized} self.inputs = {'Hyps': (x1, [x1_lod]), 'Refs': (x2, [x2_lod])} - self.outputs = {'Out': distance} + self.outputs = {'Out': distance, 'SequenceNum': sequence_num} def test_check_output(self): self.check_output() @@ -89,6 +90,7 @@ class TestEditDistanceOpNormalized(OpTest): num_strs = len(x1_lod) - 1 distance = np.zeros((num_strs, 1)).astype("float32") + sequence_num = np.array(3).astype("int64") for i in range(0, num_strs): distance[i] = Levenshtein( hyp=x1[x1_lod[i]:x1_lod[i + 1]], @@ -98,7 +100,7 @@ class TestEditDistanceOpNormalized(OpTest): distance[i] = distance[i] / len_ref self.attrs = {'normalized': normalized} self.inputs = {'Hyps': (x1, [x1_lod]), 'Refs': (x2, [x2_lod])} - self.outputs = {'Out': distance} + self.outputs = {'Out': distance, 'SequenceNum': sequence_num} def test_check_output(self): self.check_output() diff --git a/python/paddle/v2/fluid/tests/test_clip.py b/python/paddle/v2/fluid/tests/test_error_clip.py similarity index 100% rename from python/paddle/v2/fluid/tests/test_clip.py rename to python/paddle/v2/fluid/tests/test_error_clip.py diff --git a/python/paddle/v2/fluid/tests/test_gradient_clip.py b/python/paddle/v2/fluid/tests/test_gradient_clip.py new file mode 100644 index 0000000000000000000000000000000000000000..9337791c21183fd7c2e5d6b9d47c99d762c93d46 --- /dev/null +++ b/python/paddle/v2/fluid/tests/test_gradient_clip.py @@ -0,0 +1,82 @@ +# Copyright (c) 2018 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. + +import numpy as np +import paddle.v2 as paddle +import paddle.v2.fluid as fluid + +BATCH_SIZE = 128 +CLIP = 1 + +prog = fluid.framework.Program() +with fluid.program_guard(main_program=prog): + image = fluid.layers.data(name='x', shape=[784], dtype='float32') + + hidden1 = fluid.layers.fc(input=image, size=128, act='relu') + hidden2 = fluid.layers.fc(input=hidden1, size=64, act='relu') + predict = fluid.layers.fc(input=hidden2, size=10, act='softmax') + + label = fluid.layers.data(name='y', shape=[1], dtype='int64') + + cost = fluid.layers.cross_entropy(input=predict, label=label) + avg_cost = fluid.layers.mean(x=cost) + +prog_clip = prog.clone() + +avg_cost_clip = prog_clip.block(0).var(avg_cost.name) + +p_g = fluid.backward.append_backward(loss=avg_cost) +p_g_clip = fluid.backward.append_backward(loss=avg_cost_clip) + +with fluid.program_guard(main_program=prog_clip): + fluid.clip.set_gradient_clip( + fluid.clip.GradientClipByGlobalNorm(clip_norm=CLIP)) + p_g_clip = fluid.clip.append_gradient_clip_ops(p_g_clip) + +grad_list = [elem[1] for elem in p_g] +grad_clip_list = [elem[1] for elem in p_g_clip] + +train_reader = paddle.batch( + paddle.reader.shuffle( + paddle.dataset.mnist.train(), buf_size=8192), + batch_size=BATCH_SIZE) + +place = fluid.CPUPlace() +exe = fluid.Executor(place) +feeder = fluid.DataFeeder(feed_list=[image, label], place=place) +exe.run(fluid.default_startup_program()) + +count = 0 +for data in train_reader(): + count += 1 + if count > 5: + break + out = exe.run(prog, feed=feeder.feed(data), fetch_list=grad_list) + out_clip = exe.run(prog_clip, + feed=feeder.feed(data), + fetch_list=grad_clip_list) + global_norm = 0 + for v in out[1:]: + global_norm += np.sum(np.power(v, 2)) + global_norm = np.sqrt(global_norm) + + global_norm_clip = 0 + for v in out_clip[1:]: + global_norm_clip += np.sum(np.power(v, 2)) + global_norm_clip = np.sqrt(global_norm_clip) + + if not np.isclose( + a=global_norm_clip, b=np.minimum(global_norm, CLIP), rtol=5e-3): + exit(1) +exit(0) diff --git a/python/paddle/v2/fluid/tests/test_im2sequence_op.py b/python/paddle/v2/fluid/tests/test_im2sequence_op.py new file mode 100644 index 0000000000000000000000000000000000000000..2cab3e31a50034e3b1b362b59690e425aef1c399 --- /dev/null +++ b/python/paddle/v2/fluid/tests/test_im2sequence_op.py @@ -0,0 +1,167 @@ +# Copyright (c) 2018 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. +import unittest +import numpy as np +from op_test import OpTest + + +def get_output_shape(attrs, in_shape): + img_height = in_shape[2] + img_width = in_shape[3] + + paddings = attrs['paddings'] + kernels = attrs['kernels'] + strides = attrs['strides'] + + output_height = \ + 1 + \ + (img_height + paddings[0] + paddings[2] - kernels[0] + strides[0] - 1) / \ + strides[0] + + output_width = \ + 1 + \ + (img_width + paddings[1] + paddings[3] - kernels[1] + strides[1] - 1) / \ + strides[1] + + return output_height, output_width + + +def im2col(attrs, im, col): + """ + im: {CHW} + col: + {outputHeight, outputWidth, inputChannels, filterHeight, filterWidth} + """ + input_channels, input_height, input_width = im.shape + output_height, output_width, _, filter_height, filter_width = col.shape + + stride_height, stride_width = attrs['strides'] + padding_height, padding_width = attrs['paddings'][0:2] + + for col_row_idx in range(0, output_height): + for col_col_idx in range(0, output_width): + for channel in range(0, input_channels): + for filter_row_idx in range(0, filter_height): + for filter_col_idx in range(0, filter_width): + im_row_offset = col_row_idx * stride_height \ + + filter_row_idx - padding_height + + im_col_offset = col_col_idx * stride_width \ + + filter_col_idx - padding_width + + if (im_row_offset < 0 or + im_row_offset >= input_height or + im_col_offset < 0 or + im_col_offset >= input_width): + col[col_row_idx][col_col_idx][channel][\ + filter_row_idx][filter_col_idx] = 0.0 + else: + im_offset = (channel * input_height + im_row_offset \ + ) * input_width + im_col_offset + + col[col_row_idx][col_col_idx][channel][\ + filter_row_idx][filter_col_idx] = im[channel][ \ + im_row_offset][im_col_offset] + + +def Im2Sequence(inputs, attrs): + output_height, output_width = get_output_shape(attrs, inputs.shape) + img_channels = inputs.shape[1] + batch_size = inputs.shape[0] + out = np.zeros([ + batch_size, output_height, output_width, img_channels, + attrs['kernels'][0], attrs['kernels'][1] + ]).astype("float32") + + for i in range(len(inputs)): + im2col(attrs, inputs[i], out[i]) + + out = out.reshape([ + batch_size * output_height * output_width, + img_channels * attrs['kernels'][0] * attrs['kernels'][1] + ]) + return out + + +class TestBlockExpandOp(OpTest): + def config(self): + self.batch_size = 1 + self.img_channels = 3 + self.img_height = 4 + self.img_width = 4 + self.attrs = { + 'kernels': [2, 2], + 'strides': [1, 1], + 'paddings': [1, 1, 1, 1] + } + + def setUp(self): + self.config() + self.op_type = "im2sequence" + x = np.random.uniform(0.1, 1, [ + self.batch_size, self.img_channels, self.img_height, self.img_width + ]).astype("float32") + + out = Im2Sequence(x, self.attrs) + self.inputs = {'X': x} + self.outputs = {'Out': out} + + def test_check_output(self): + self.check_output() + + def test_check_grad_normal(self): + self.check_grad(['X'], 'Out') + + +class TestBlockExpandOpCase2(TestBlockExpandOp): + def config(self): + self.batch_size = 2 + self.img_channels = 3 + self.img_height = 4 + self.img_width = 5 + self.attrs = { + 'kernels': [2, 1], + 'strides': [2, 1], + 'paddings': [2, 1, 2, 1] + } + + +class TestBlockExpandOpCase3(TestBlockExpandOp): + def config(self): + self.batch_size = 3 + self.img_channels = 1 + self.img_height = 4 + self.img_width = 5 + self.attrs = { + 'kernels': [2, 1], + 'strides': [2, 1], + 'paddings': [2, 0, 2, 0] + } + + +class TestBlockExpandOpCase4(TestBlockExpandOp): + def config(self): + self.batch_size = 2 + self.img_channels = 2 + self.img_height = 3 + self.img_width = 3 + self.attrs = { + 'kernels': [2, 2], + 'strides': [1, 1], + 'paddings': [0, 0, 0, 0] + } + + +if __name__ == '__main__': + unittest.main() diff --git a/python/paddle/v2/fluid/tests/test_math_op_patch.py b/python/paddle/v2/fluid/tests/test_math_op_patch.py new file mode 100644 index 0000000000000000000000000000000000000000..2e77639a4c886327cc8dc7053fc6c0f6c6e9dcc9 --- /dev/null +++ b/python/paddle/v2/fluid/tests/test_math_op_patch.py @@ -0,0 +1,181 @@ +# Copyright (c) 2018 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. + +import unittest +import decorators +import paddle.v2.fluid as fluid +import numpy + + +class TestMathOpPatches(unittest.TestCase): + @decorators.prog_scope() + def test_add_scalar(self): + a = fluid.layers.data(name="a", shape=[1]) + b = a + 10 + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + b_np = exe.run(fluid.default_main_program(), + feed={"a": a_np}, + fetch_list=[b]) + self.assertTrue(numpy.allclose(a_np + 10, b_np)) + + @decorators.prog_scope() + def test_radd_scalar(self): + a = fluid.layers.data(name="a", shape=[1]) + b = 10 + a + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + b_np = exe.run(fluid.default_main_program(), + feed={"a": a_np}, + fetch_list=[b]) + self.assertTrue(numpy.allclose(a_np + 10, b_np)) + + @decorators.prog_scope() + def test_sub_scalar(self): + a = fluid.layers.data(name="a", shape=[1]) + b = a - 10 + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + b_np = exe.run(fluid.default_main_program(), + feed={"a": a_np}, + fetch_list=[b]) + self.assertTrue(numpy.allclose(a_np - 10, b_np)) + + @decorators.prog_scope() + def test_radd_scalar(self): + a = fluid.layers.data(name="a", shape=[1]) + b = 10 - a + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + b_np = exe.run(fluid.default_main_program(), + feed={"a": a_np}, + fetch_list=[b]) + self.assertTrue(numpy.allclose(10 - a_np, b_np)) + + @decorators.prog_scope() + def test_mul_scalar(self): + a = fluid.layers.data(name="a", shape=[1]) + b = a * 10 + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + b_np = exe.run(fluid.default_main_program(), + feed={"a": a_np}, + fetch_list=[b]) + self.assertTrue(numpy.allclose(a_np * 10, b_np)) + + @decorators.prog_scope() + def test_rmul_scalar(self): + a = fluid.layers.data(name="a", shape=[1]) + b = 10 * a + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + b_np = exe.run(fluid.default_main_program(), + feed={"a": a_np}, + fetch_list=[b]) + self.assertTrue(numpy.allclose(10 * a_np, b_np)) + + @decorators.prog_scope() + def test_div_scalar(self): + a = fluid.layers.data(name="a", shape=[1]) + b = a / 10 + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + b_np = exe.run(fluid.default_main_program(), + feed={"a": a_np}, + fetch_list=[b]) + self.assertTrue(numpy.allclose(a_np / 10, b_np)) + + @decorators.prog_scope() + def test_rdiv_scalar(self): + a = fluid.layers.data(name="a", shape=[1]) + b = 10 / a + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + 1e-2 + + b_np = exe.run(fluid.default_main_program(), + feed={"a": a_np}, + fetch_list=[b]) + self.assertTrue(numpy.allclose(10 / a_np, b_np)) + + @decorators.prog_scope() + def test_div_two_tensor(self): + a = fluid.layers.data(name="a", shape=[1]) + b = fluid.layers.data(name="b", shape=[1]) + c = a / b + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + b_np = numpy.random.random(size=[10, 1]).astype('float32') + 1e-2 + c_np = exe.run(fluid.default_main_program(), + feed={"a": a_np, + 'b': b_np}, + fetch_list=[c]) + self.assertTrue(numpy.allclose(a_np / b_np, c_np)) + + @decorators.prog_scope() + def test_mul_two_tensor(self): + a = fluid.layers.data(name="a", shape=[1]) + b = fluid.layers.data(name="b", shape=[1]) + c = a * b + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + b_np = numpy.random.random(size=[10, 1]).astype('float32') + c_np = exe.run(fluid.default_main_program(), + feed={"a": a_np, + 'b': b_np}, + fetch_list=[c]) + self.assertTrue(numpy.allclose(a_np * b_np, c_np)) + + @decorators.prog_scope() + def test_add_two_tensor(self): + a = fluid.layers.data(name="a", shape=[1]) + b = fluid.layers.data(name="b", shape=[1]) + c = a + b + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + b_np = numpy.random.random(size=[10, 1]).astype('float32') + c_np = exe.run(fluid.default_main_program(), + feed={"a": a_np, + 'b': b_np}, + fetch_list=[c]) + self.assertTrue(numpy.allclose(a_np + b_np, c_np)) + + @decorators.prog_scope() + def test_sub_two_tensor(self): + a = fluid.layers.data(name="a", shape=[1]) + b = fluid.layers.data(name="b", shape=[1]) + c = a - b + place = fluid.CPUPlace() + exe = fluid.Executor(place) + a_np = numpy.random.random(size=[10, 1]).astype('float32') + b_np = numpy.random.random(size=[10, 1]).astype('float32') + c_np = exe.run(fluid.default_main_program(), + feed={"a": a_np, + 'b': b_np}, + fetch_list=[c]) + self.assertTrue(numpy.allclose(a_np - b_np, c_np)) + + +if __name__ == '__main__': + unittest.main() diff --git a/python/paddle/v2/fluid/tests/test_reduce_op.py b/python/paddle/v2/fluid/tests/test_reduce_op.py index 1a4af39fb9dbc3de7d6746ee92a8e0c232e76c9f..c669f73a7c6de0735b3c580ed4f0ed8ba359a040 100644 --- a/python/paddle/v2/fluid/tests/test_reduce_op.py +++ b/python/paddle/v2/fluid/tests/test_reduce_op.py @@ -20,7 +20,7 @@ from op_test import OpTest class TestSumOp(OpTest): def setUp(self): self.op_type = "reduce_sum" - self.inputs = {'X': np.random.random((5, 6, 10)).astype("float32")} + self.inputs = {'X': np.random.random((5, 6, 10)).astype("float64")} self.outputs = {'Out': self.inputs['X'].sum(axis=0)} def test_check_output(self): @@ -33,7 +33,7 @@ class TestSumOp(OpTest): class TestMeanOp(OpTest): def setUp(self): self.op_type = "reduce_mean" - self.inputs = {'X': np.random.random((5, 6, 2, 10)).astype("float32")} + self.inputs = {'X': np.random.random((5, 6, 2, 10)).astype("float64")} self.attrs = {'dim': 1} self.outputs = {'Out': self.inputs['X'].mean(axis=self.attrs['dim'])} @@ -49,7 +49,7 @@ class TestMaxOp(OpTest): def setUp(self): self.op_type = "reduce_max" - self.inputs = {'X': np.random.random((5, 6, 10)).astype("float32")} + self.inputs = {'X': np.random.random((5, 6, 10)).astype("float64")} self.attrs = {'dim': -1} self.outputs = {'Out': self.inputs['X'].max(axis=self.attrs['dim'])} @@ -62,7 +62,7 @@ class TestMinOp(OpTest): def setUp(self): self.op_type = "reduce_min" - self.inputs = {'X': np.random.random((5, 6, 10)).astype("float32")} + self.inputs = {'X': np.random.random((5, 6, 10)).astype("float64")} self.attrs = {'dim': 2} self.outputs = {'Out': self.inputs['X'].min(axis=self.attrs['dim'])} @@ -73,7 +73,7 @@ class TestMinOp(OpTest): class TestKeepDimReduce(OpTest): def setUp(self): self.op_type = "reduce_sum" - self.inputs = {'X': np.random.random((5, 6, 10)).astype("float32")} + self.inputs = {'X': np.random.random((5, 6, 10)).astype("float64")} self.attrs = {'dim': -2, 'keep_dim': True} self.outputs = { 'Out': self.inputs['X'].sum(axis=self.attrs['dim'], keepdims=True) @@ -89,7 +89,7 @@ class TestKeepDimReduce(OpTest): class Test1DReduce(OpTest): def setUp(self): self.op_type = "reduce_sum" - self.inputs = {'X': np.random.random(20).astype("float32")} + self.inputs = {'X': np.random.random(20).astype("float64")} self.outputs = {'Out': self.inputs['X'].sum(axis=0)} def test_check_output(self): @@ -102,7 +102,7 @@ class Test1DReduce(OpTest): class TestReduceAll(OpTest): def setUp(self): self.op_type = "reduce_sum" - self.inputs = {'X': np.random.random((5, 6, 2, 10)).astype("float32")} + self.inputs = {'X': np.random.random((5, 6, 2, 10)).astype("float64")} self.attrs = {'reduce_all': True} self.outputs = {'Out': self.inputs['X'].sum()} diff --git a/python/paddle/v2/fluid/tests/test_registry.py b/python/paddle/v2/fluid/tests/test_registry.py index 6435e7e243d4e7fa10c99fda48a011523d8cc588..44e50ca55ac609ed2e0a145ff12248fa18479668 100644 --- a/python/paddle/v2/fluid/tests/test_registry.py +++ b/python/paddle/v2/fluid/tests/test_registry.py @@ -11,26 +11,21 @@ # 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. - import unittest -import warnings import paddle.v2.fluid as fluid -import paddle.v2.fluid.framework as framework -import paddle.v2.fluid.layers as layers -import paddle.v2.fluid.registry as registry +import numpy as np +import decorators class TestRegistry(unittest.TestCase): + @decorators.prog_scope() def test_registry_layer(self): - self.layer_type = "mean" - program = framework.Program() - x = fluid.layers.data(name='X', shape=[10, 10], dtype='float32') - output = layers.mean(x) + output = fluid.layers.mean(x=x) + place = fluid.CPUPlace() exe = fluid.Executor(place) - X = np.random.random((10, 10)).astype("float32") - mean_out = exe.run(program, feed={"X": X}, fetch_list=[output]) - self.assertAlmostEqual(np.mean(X), mean_out) + mean_out = exe.run(feed={"X": X}, fetch_list=[output]) + self.assertAlmostEqual(np.mean(X), mean_out[0])