diff --git a/.gitignore b/.gitignore
index 020d3f0c30..ac56a3320e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,4 @@ cmake_install.cmake
paddle/.timestamp
python/paddlepaddle.egg-info/
paddle/pybind/pybind.h
+python/paddle/version.py
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6aeef23330..b309ff37e5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,6 +22,8 @@ SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG")
include(system)
project(paddle CXX C Go)
+message(STATUS "CXX compiler: " ${CMAKE_CXX_COMPILER} ", version: " ${CMAKE_CXX_COMPILER_VERSION})
+message(STATUS "C compiler: " ${CMAKE_C_COMPILER} ", version: " ${CMAKE_C_COMPILER_VERSION})
find_package(Sphinx)
if(NOT CMAKE_CROSSCOMPILING)
@@ -58,6 +60,7 @@ option(GLIDE_INSTALL "Download and install go dependencies " ON)
option(USE_NNPACK "Compile PaddlePaddle with NNPACK library" OFF)
option(WITH_DISTRIBUTE "Compile with grpc distributed support" OFF)
option(USE_EIGEN_FOR_BLAS "Use matrix multiplication in Eigen" OFF)
+option(WITH_ARM_FP16 "Use half precision support on armv8.2-a cpu" OFF)
# CMAKE_BUILD_TYPE
if(NOT CMAKE_BUILD_TYPE)
diff --git a/RELEASE.cn.md b/RELEASE.cn.md
index 5deaf230a8..494c59730d 100644
--- a/RELEASE.cn.md
+++ b/RELEASE.cn.md
@@ -1,3 +1,62 @@
+# v0.11.0版本
+
+## PaddlePaddle Fluid
+
+- PaddlePaddle发布版本v0.11.0包含一个新的特性*PaddlePaddle Fluid*. Fluid 是设计用来让用户像Pytorch和Tensorflow Eager Execution一样执行程序。在这些系统中,不再有*模型*这个概念,应用也不再包含一个用于描述Operator图或者一系列层的符号描述,而是像通用程序那样描述训练或者预测的过程。而Fluid与PyTorch或Eager Execution的区别在于Fluid不依赖Python提供的控制流,例如 if-else-then或者for,而是提供了基于C++实现的控制流并暴露了对应的用with语法实现的Python接口。例如:
+
+ https://github.com/PaddlePaddle/Paddle/blob/3df78ed2a98d37f7ae6725894cc7514effd5664b/python/paddle/v2/fluid/tests/test_while_op.py#L36-L44
+
+- 在v0.11.0版本中,我们提供了一个C++类`Executor`用于运行一个Fluid程序。Executor类似一个解释器。在未来的版本中,我们将提升和优化Executor成为一个调试器,就像GDB。并可能提供一些编译器,这个编译器会读取一个上文所描述的应用然后编译成一个等价的
+源代码,这个源代码可以被nvcc编译成可以使用CUDA的二进制,或者被icc编译成可以充分利用Intel CPU的二进制。
+
+
+## 新特点
+
+* 发布 `PaddlePaddle Fluid`。
+* 增加了用于模型预测的C-API。
+* 用Fluid API实现了一个简单的GAN的例子。
+* 增加了关于性能调优的文档。
+* 为`paddle.v2.dataset`下载数据集提供了重试机制.
+* C++中使用protobuf-lite替换protobuf减少了二进制的大小。
+* 发布了新特性 [Elastic Deep Learning (EDL)](https://github.com/PaddlePaddle/cloud/tree/develop/doc/autoscale/experiment).
+* 基于Bazel API利用cmake实现了一个的新的构建系统函数库。
+* 当使用编译选项`WITH_MKL=ON`时自动下载和编译Intel® [MKLML](https://github.com/01org/mkl-dnn/releases/download/v0.11/mklml_lnx_2018.0.1.20171007.tgz) 函数库.
+* [Intel® MKL-DNN on PaddlePaddle](https://github.com/PaddlePaddle/Paddle/tree/develop/doc/design/mkldnn):
+ - 完成了 11个 MKL-DNN 层: Convolution, Fully connectivity, Pooling, ReLU, Tanh, ELU, Softmax, BatchNorm, AddTo, Concat, LRN。
+ - 完成了 3个 MKL-DNN 网络: VGG-19, ResNet-50, GoogleNet
+ - 基于Intel Skylake 6148 CPU的[性能测试](https://github.com/PaddlePaddle/Paddle/blob/develop/benchmark/IntelOptimizedPaddle.md) : 相对于MKLML有2~3倍的训练加速。
+* 增加 [softsign activation](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/activation.html#softsign)
+* 增加 [dot product layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#dot-prod)
+* 增加 [L2 distance layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#l2-distance)
+* 增加 [sub-nested sequence layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#sub-nested-seq)
+* 增加 [kmax sequence score layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#kmax-sequence-score)
+* 增加 [sequence slice layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#seq-slice)
+* 增加 [row convolution layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#row-conv)
+* 增加移动端友好的网页
+
+## 改进
+
+* 使用一个Python`whl`包即可安装.
+* [V2 API可以实现用户定制化评估](https://github.com/PaddlePaddle/models/tree/develop/ltr#训练过程中输出自定义评估指标)。
+* 将 `PADDLE_ONLY_CPU` 改为 `PADDLE_WITH_GPU`, 因为我们会支持多种设备。
+* 删除了有一些bug的BarrierStat。
+* 清理和删除了paddle::Parameter中未使用的函数。
+* 删除了ProtoDataProvider。
+* Huber loss同时支持回归和分类。
+* 为sequence pooling 层增加`stride`参数。
+* v2 API自动使用cudnn batch normalization。
+* 可以使用一个固定的参数名共享BN层的参数。
+* 2D convolution operation支持variable-dimension input特性。
+* 重构cmake中关于CUDA的部分并实现自动检测GPU架构的功能。
+* 优化网页导航。
+
+## 错误修复
+
+* 修复ROI pooling的Bug. cc9a761
+* 修复当label是dense vector是AUC变成0的问题. #5274
+* 修复WarpCTC 层的Bug.
+
+
# v0.10.0版本
我们非常高兴发布了PaddlePaddle V0.10.0版,并开发了新的[Python API](http://research.baidu.com/paddlepaddles-new-api-simplifies-deep-learning-programs/)。
diff --git a/RELEASE.md b/RELEASE.md
index 146f7afa7d..5a62c95513 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -1,3 +1,75 @@
+# Release v0.11.0
+
+## PaddlePaddle Fluid
+
+- Release 0.11.0 includes a new feature *PaddlePaddle Fluid*. Fluid is
+ designed to allow users to program like PyTorch and TensorFlow Eager Execution.
+ In these systems, there is no longer the concept *model* and applications
+ do not include a symbolic description of a graph of operators nor a sequence
+ of layers. Instead, applications look exactly like a usual program that
+ describes a process of training or inference. The difference between
+ Fluid and PyTorch or Eager Execution is that Fluid doesn't rely on Python's
+ control-flow, `if-then-else` nor `for`. Instead, Fluid provides its
+ C++ implementations and their Python binding using the `with` statement. For an example
+
+ https://github.com/PaddlePaddle/Paddle/blob/3df78ed2a98d37f7ae6725894cc7514effd5664b/python/paddle/v2/fluid/tests/test_while_op.py#L36-L44
+
+- In 0.11.0, we provides a C++ class `Executor` to run a Fluid program.
+Executor works like an interpreter. In future version, we will improve
+`Executor` into a debugger like GDB, and we might provide some compilers,
+which, for example, takes an application like the above one, and outputs
+an equivalent C++ source program, which can be compiled using
+[`nvcc`](http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html)
+to generate binaries that use CUDA, or using
+[`icc`](https://software.intel.com/en-us/c-compilers) to generate binaries
+that make full use of Intel CPUs.
+
+## New Features
+
+* Release `PaddlePaddle Fluid`.
+* Add C-API for model inference
+* Use fluid API to create a simple GAN demo.
+* Add develop guide about performance tunning.
+* Add retry when download `paddle.v2.dataset`.
+* Linking protobuf-lite not protobuf in C++. Reduce the binary size.
+* Feature [Elastic Deep Learning (EDL)](https://github.com/PaddlePaddle/cloud/tree/develop/doc/autoscale/experiment) released.
+* A new style cmake functions for Paddle. It is based on Bazel API.
+* Automatically download and compile with Intel® [MKLML](https://github.com/01org/mkl-dnn/releases/download/v0.11/mklml_lnx_2018.0.1.20171007.tgz) library as CBLAS when build `WITH_MKL=ON`.
+* [Intel® MKL-DNN on PaddlePaddle](https://github.com/PaddlePaddle/Paddle/tree/develop/doc/design/mkldnn):
+ - Complete 11 MKL-DNN layers: Convolution, Fully connectivity, Pooling, ReLU, Tanh, ELU, Softmax, BatchNorm, AddTo, Concat, LRN.
+ - Complete 3 MKL-DNN networks: VGG-19, ResNet-50, GoogleNet
+ - [Benchmark](https://github.com/PaddlePaddle/Paddle/blob/develop/benchmark/IntelOptimizedPaddle.md) on Intel Skylake 6148 CPU: 2~3x training speedup compared with MKLML.
+* Add the [`softsign` activation](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/activation.html#softsign).
+* Add the [dot product layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#dot-prod).
+* Add the [L2 distance layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#l2-distance).
+* Add the [sub-nested sequence layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#sub-nested-seq).
+* Add the [kmax sequence score layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#kmax-sequence-score).
+* Add the [sequence slice layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#seq-slice).
+* Add the [row convolution layer](http://www.paddlepaddle.org/docs/develop/documentation/zh/api/v2/config/layer.html#row-conv)
+* Add mobile friendly webpages.
+
+## Improvements
+
+* Build and install using a single `whl` package.
+* [Custom evaluating in V2 API](https://github.com/PaddlePaddle/models/tree/develop/ltr#训练过程中输出自定义评估指标).
+* Change `PADDLE_ONLY_CPU` to `PADDLE_WITH_GPU`, since we will support many kinds of devices.
+* Remove buggy BarrierStat.
+* Clean and remove unused functions in paddle::Parameter.
+* Remove ProtoDataProvider.
+* Huber loss supports both regression and classification.
+* Add the `stride` parameter for sequence pooling layers.
+* Enable v2 API use cudnn batch normalization automatically.
+* The BN layer's parameter can be shared by a fixed the parameter name.
+* Support variable-dimension input feature for 2D convolution operation.
+* Refine cmake about CUDA to automatically detect GPU architecture.
+* Improved website navigation.
+
+## Bug Fixes
+
+* Fix bug in ROI pooling. cc9a761
+* Fix AUC is zero when label is dense vector. #5274
+* Fix bug in WarpCTC layer.
+
# Release v0.10.0
We are glad to release version 0.10.0. In this version, we are happy to release the new
diff --git a/benchmark/IntelOptimizedPaddle.md b/benchmark/IntelOptimizedPaddle.md
index 16c2390fd3..8ee7fd28c5 100644
--- a/benchmark/IntelOptimizedPaddle.md
+++ b/benchmark/IntelOptimizedPaddle.md
@@ -2,27 +2,25 @@
Machine:
-- Server
- - Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz, 2 Sockets, 20 Cores per socket
-- Laptop
- - DELL XPS15-9560-R1745: i7-7700HQ 8G 256GSSD
- - i5 MacBook Pro (Retina, 13-inch, Early 2015)
-- Desktop
- - i7-6700k
+- Server: Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz, 2 Sockets, 20 Cores per socket
+- Laptop: TBD
System: CentOS release 6.3 (Final), Docker 1.12.1.
-PaddlePaddle: paddlepaddle/paddle:latest (for MKLML and MKL-DNN), paddlepaddle/paddle:latest-openblas (for OpenBLAS)
-- MKL-DNN tag v0.11
-- MKLML 2018.0.1.20171007
-- OpenBLAS v0.2.20
-(TODO: will rerun after 0.11.0)
+PaddlePaddle: (TODO: will rerun after 0.11.0)
+- paddlepaddle/paddle:latest (for MKLML and MKL-DNN)
+ - MKL-DNN tag v0.11
+ - MKLML 2018.0.1.20171007
+- paddlepaddle/paddle:latest-openblas (for OpenBLAS)
+ - OpenBLAS v0.2.20
On each machine, we will test and compare the performance of training on single node using MKL-DNN / MKLML / OpenBLAS respectively.
## Benchmark Model
### Server
+
+#### Training
Test on batch size 64, 128, 256 on Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz
Input image size - 3 * 224 * 224, Time: images/second
@@ -35,9 +33,7 @@ Input image size - 3 * 224 * 224, Time: images/second
| MKLML | 12.12 | 13.70 | 16.18 |
| MKL-DNN | 28.46 | 29.83 | 30.44 |
-
-chart on batch size 128
-TBD
+
- ResNet-50
@@ -47,9 +43,7 @@ TBD
| MKLML | 32.52 | 31.89 | 33.12 |
| MKL-DNN | 81.69 | 82.35 | 84.08 |
-
-chart on batch size 128
-TBD
+
- GoogLeNet
@@ -59,10 +53,35 @@ TBD
| MKLML | 128.46| 137.89| 158.63 |
| MKL-DNN | 250.46| 264.83| 269.50 |
-chart on batch size 128
-TBD
+
+
+#### Inference
+Test on batch size 1, 2, 4, 8, 16 on Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz
+- VGG-19
+
+| BatchSize | 1 | 2 | 4 | 8 | 16 |
+|-----------|-------|-------|-------|-------|-------|
+| OpenBLAS | 1.07 | 1.08 | 1.06 | 0.88 | 0.65 |
+| MKLML | 5.58 | 9.80 | 15.15 | 21.21 | 28.67 |
+| MKL-DNN | 75.07 | 88.64 | 82.58 | 92.29 | 96.75 |
+
+- ResNet-50
+
+| BatchSize | 1 | 2 | 4 | 8 | 16 |
+|-----------|-------|--------|--------|--------|--------|
+| OpenBLAS | 3.35 | 3.19 | 3.09 | 2.55 | 1.96 |
+| MKLML | 6.33 | 12.02 | 22.88 | 40.53 | 63.09 |
+| MKL-DNN | 107.83| 148.84 | 177.78 | 189.35 | 217.69 |
+
+
+- GoogLeNet
+
+| BatchSize | 1 | 2 | 4 | 8 | 16 |
+|-----------|--------|--------|--------|--------|--------|
+| OpenBLAS | 12.04 | 11.31 | 10.00 | 9.07 | 4.34 |
+| MKLML | 22.74 | 41.56 | 81.22 | 133.47 | 210.53 |
+| MKL-DNN | 175.10 | 272.92 | 450.70 | 512.00 | 600.94 |
+
### Laptop
TBD
-### Desktop
-TBD
diff --git a/benchmark/figs/googlenet-cpu-train.png b/benchmark/figs/googlenet-cpu-train.png
new file mode 100644
index 0000000000..c3f67faf09
Binary files /dev/null and b/benchmark/figs/googlenet-cpu-train.png differ
diff --git a/benchmark/figs/resnet-cpu-train.png b/benchmark/figs/resnet-cpu-train.png
new file mode 100644
index 0000000000..b96ecd5ff9
Binary files /dev/null and b/benchmark/figs/resnet-cpu-train.png differ
diff --git a/benchmark/figs/vgg-cpu-train.png b/benchmark/figs/vgg-cpu-train.png
new file mode 100644
index 0000000000..f830ca6a87
Binary files /dev/null and b/benchmark/figs/vgg-cpu-train.png differ
diff --git a/cmake/cblas.cmake b/cmake/cblas.cmake
index b21fc43904..13294c0548 100644
--- a/cmake/cblas.cmake
+++ b/cmake/cblas.cmake
@@ -17,7 +17,7 @@ if(WITH_MKLML AND MKLML_INC_DIR AND MKLML_LIB)
set(CBLAS_INC_DIR ${MKLML_INC_DIR})
set(CBLAS_LIBRARIES ${MKLML_LIB})
- add_definitions(-DPADDLE_USE_MKLML)
+ add_definitions(-DPADDLE_WITH_MKLML)
add_definitions(-DLAPACK_FOUND)
message(STATUS "Found cblas and lapack in MKLML "
diff --git a/cmake/configure.cmake b/cmake/configure.cmake
index e550ec2856..5c6bcfde76 100644
--- a/cmake/configure.cmake
+++ b/cmake/configure.cmake
@@ -24,6 +24,11 @@ if(WITH_DOUBLE)
add_definitions(-DPADDLE_TYPE_DOUBLE)
endif(WITH_DOUBLE)
+if(WITH_ARM_FP16)
+ add_definitions(-DPADDLE_ARM_FP16)
+ add_definitions("-march=armv8.2-a+fp16+simd")
+endif(WITH_ARM_FP16)
+
if(WITH_TESTING)
add_definitions(-DPADDLE_WITH_TESTING)
endif(WITH_TESTING)
diff --git a/cmake/external/cares.cmake b/cmake/external/cares.cmake
index ac456933bd..aec51410b3 100644
--- a/cmake/external/cares.cmake
+++ b/cmake/external/cares.cmake
@@ -33,7 +33,7 @@ ExternalProject_Add(
UPDATE_COMMAND ""
CONFIGURE_COMMAND ./buildconf && ./configure --disable-shared --prefix=${CARES_INSTALL_DIR}
BUILD_IN_SOURCE 1
- BUILD_COMMAND make
+ BUILD_COMMAND make -j8
INSTALL_COMMAND make install
)
diff --git a/cmake/external/mkldnn.cmake b/cmake/external/mkldnn.cmake
index fc52d339d7..5d24caebdc 100644
--- a/cmake/external/mkldnn.cmake
+++ b/cmake/external/mkldnn.cmake
@@ -67,5 +67,5 @@ ADD_LIBRARY(mkldnn SHARED IMPORTED GLOBAL)
SET_PROPERTY(TARGET mkldnn PROPERTY IMPORTED_LOCATION ${MKLDNN_LIB})
ADD_DEPENDENCIES(mkldnn ${MKLDNN_PROJECT})
MESSAGE(STATUS "MKLDNN library: ${MKLDNN_LIB}")
-add_definitions(-DPADDLE_USE_MKLDNN)
+add_definitions(-DPADDLE_WITH_MKLDNN)
LIST(APPEND external_project_dependencies mkldnn)
diff --git a/cmake/external/openblas.cmake b/cmake/external/openblas.cmake
index 4c4f59656d..97857a686b 100644
--- a/cmake/external/openblas.cmake
+++ b/cmake/external/openblas.cmake
@@ -114,11 +114,7 @@ INCLUDE_DIRECTORIES(${CBLAS_INC_DIR})
# linear algebra libraries for cc_library(xxx SRCS xxx.c DEPS cblas)
SET(dummyfile ${CMAKE_CURRENT_BINARY_DIR}/cblas_dummy.c)
FILE(WRITE ${dummyfile} "const char * dummy = \"${dummyfile}\";")
-IF("${CBLAS_PROVIDER}" STREQUAL "MKLML")
- ADD_LIBRARY(cblas SHARED ${dummyfile})
-ELSE()
- ADD_LIBRARY(cblas STATIC ${dummyfile})
-ENDIF()
+ADD_LIBRARY(cblas STATIC ${dummyfile})
TARGET_LINK_LIBRARIES(cblas ${CBLAS_LIBRARIES})
IF(NOT ${CBLAS_FOUND})
diff --git a/doc/api/v2/config/activation.rst b/doc/api/v2/config/activation.rst
index eca3ce03bc..5317e66b64 100644
--- a/doc/api/v2/config/activation.rst
+++ b/doc/api/v2/config/activation.rst
@@ -99,3 +99,10 @@ STanh
.. automodule:: paddle.v2.activation
:members: STanh
:noindex:
+
+SoftSign
+========
+
+.. automodule:: paddle.v2.activation
+ :members: SoftSign
+ :noindex:
diff --git a/doc/design/refactor/distributed_architecture.md b/doc/design/refactor/distributed_architecture.md
index 2b4f921ae9..d9fe7d6bbb 100644
--- a/doc/design/refactor/distributed_architecture.md
+++ b/doc/design/refactor/distributed_architecture.md
@@ -53,7 +53,7 @@ The IR for PaddlePaddle after refactoring is called a `Block`, it specifies the
The user can not directly specify the parameter update rule for the parameter server in the Python module, since the parameter server does not use the same computation definition as the trainer. Instead, the update rule is baked inside the parameter server. The user can not specify the update rule explicitly.
This could be fixed by making the parameter server run the same computation definition as the trainer (the user's Python module). For a detailed explanation, refer to this document -
-[Design Doc: Operation Graph Based Parameter Server](./dist_train.md)
+[Design Doc: Operation Graph Based Parameter Server](./parameter_server.md)
## Distributed Training Architecture
diff --git a/doc/design/releasing_process.md b/doc/design/releasing_process.md
index 62ff8f3229..14c081ea84 100644
--- a/doc/design/releasing_process.md
+++ b/doc/design/releasing_process.md
@@ -5,8 +5,9 @@ PaddlePaddle使用git-flow branching model做分支管理,使用[Semantic Vers
PaddlePaddle每次发新的版本,遵循以下流程:
1. 从`develop`分支派生出新的分支,分支名为`release/版本号`。例如,`release/0.10.0`
-2. 将新分支的版本打上tag,tag为`版本号rc.Patch号`。第一个tag为`0.10.0rc1`,第二个为`0.10.0rc2`,依次类推。
-3. 对这个版本的提交,做如下几个操作:
+1. 将新分支的版本打上tag,tag为`版本号rc.Patch号`。第一个tag为`0.10.0rc1`,第二个为`0.10.0rc2`,依次类推。
+1. 对这个版本的提交,做如下几个操作:
+ * 修改`python/setup.py.in`中的版本信息,并将`istaged`字段设为`True`。
* 编译这个版本的Docker发行镜像,发布到dockerhub。如果失败,修复Docker编译镜像问题,Patch号加一,返回第二步
* 编译这个版本的Ubuntu Deb包。如果失败,修复Ubuntu Deb包编译问题,Patch号加一,返回第二步。
* 使用Regression Test List作为检查列表,测试Docker镜像/ubuntu安装包的功能正确性
@@ -20,9 +21,9 @@ PaddlePaddle每次发新的版本,遵循以下流程:
pip install twine
twine upload dist/[package to upload]
```
-4. 第三步完成后,将`release/版本号`分支合入master分支,并删除`release/版本号`分支。将master分支的合入commit打上tag,tag为`版本号`。同时再将`master`分支合入`develop`分支。最后删除`release/版本号`分支。
-5. 编译master分支的Docker发行镜像,发布到dockerhub。编译ubuntu的deb包,发布到github release页面
-6. 协同完成Release Note的书写
+1. 第三步完成后,将`release/版本号`分支合入master分支,并删除`release/版本号`分支。将master分支的合入commit打上tag,tag为`版本号`。同时再将`master`分支合入`develop`分支。最后删除`release/版本号`分支。
+1. 编译master分支的Docker发行镜像,发布到dockerhub。编译ubuntu的deb包,发布到github release页面
+1. 协同完成Release Note的书写
需要注意的是:
@@ -30,7 +31,7 @@ PaddlePaddle每次发新的版本,遵循以下流程:
* `release/版本号`分支一旦建立,一般不允许再从`develop`分支合入`release/版本号`。这样保证`release/版本号`分支功能的封闭,方便测试人员测试PaddlePaddle的行为。
* 在`release/版本号`分支存在的时候,如果有bugfix的行为,需要将bugfix的分支同时merge到`master`, `develop`和`release/版本号`这三个分支。
-# PaddlePaddle 分支规范
+## PaddlePaddle 分支规范
PaddlePaddle开发过程使用[git-flow](http://nvie.com/posts/a-successful-git-branching-model/)分支规范,并适应github的特性做了一些区别。
@@ -47,11 +48,11 @@ PaddlePaddle开发过程使用[git-flow](http://nvie.com/posts/a-successful-git-
* BugFix分支也是在开发者自己的fork版本库维护,与功能分支不同的是,BugFix分支需要分别给主版本库的`master`、`develop`与可能有的`release/版本号`分支,同时提起`Pull Request`。
-# PaddlePaddle回归测试列表
+## PaddlePaddle回归测试列表
本列表说明PaddlePaddle发版之前需要测试的功能点。
-## PaddlePaddle Book中所有章节
+### PaddlePaddle Book中所有章节
PaddlePaddle每次发版本首先要保证PaddlePaddle Book中所有章节功能的正确性。功能的正确性包括验证PaddlePaddle目前的`paddle_trainer`训练和纯使用`Python`训练模型正确性。
diff --git a/doc/getstarted/build_and_install/build_from_source_cn.rst b/doc/getstarted/build_and_install/build_from_source_cn.rst
index 3c525bdad6..c875c807b8 100644
--- a/doc/getstarted/build_and_install/build_from_source_cn.rst
+++ b/doc/getstarted/build_and_install/build_from_source_cn.rst
@@ -19,7 +19,7 @@ PaddlePaddle主要使用 `CMake `_ 以及GCC, G++作为编译
git clone https://github.com/PaddlePaddle/Paddle.git
cd Paddle
# 如果使用Docker编译环境,执行下面的命令编译CPU-Only的二进制
- docker run -it -v $PWD:/paddle -e "WITH_GPU=OFF" -e "WITH_TESTING=OFF" paddlepaddle/paddle_manylinux_devel:cuda8.0_cudnn5 bash -x paddle/scripts/docker/build.sh
+ docker run -it -v $PWD:/paddle -e "WITH_GPU=OFF" -e "WITH_TESTING=OFF" paddlepaddle/paddle_manylinux_devel:cuda8.0_cudnn5 bash -x /paddle/paddle/scripts/docker/build.sh
# 如果不使用Docker编译环境,执行下面的命令
mkdir build
cd build
@@ -30,7 +30,7 @@ PaddlePaddle主要使用 `CMake `_ 以及GCC, G++作为编译
.. code-block:: bash
- pip install python/dist/*.whl
+ pip install build/python/dist/*.whl
.. _run_test:
@@ -45,7 +45,7 @@ PaddlePaddle主要使用 `CMake `_ 以及GCC, G++作为编译
.. code-block:: bash
- docker run -it -v $PWD:/paddle -e "WITH_GPU=OFF" -e "WITH_TESTING=ON" -e "RUN_TEST=ON" paddlepaddle/paddle_manylinux_devel:cuda8.0_cudnn5 bash -x paddle/scripts/docker/build.sh
+ docker run -it -v $PWD:/paddle -e "WITH_GPU=OFF" -e "WITH_TESTING=ON" -e "RUN_TEST=ON" paddlepaddle/paddle_manylinux_devel:cuda8.0_cudnn5 bash -x /paddle/paddle/scripts/docker/build.sh
如果不使用Docker,可以执行ctest命令即可:
diff --git a/doc/getstarted/build_and_install/build_from_source_en.rst b/doc/getstarted/build_and_install/build_from_source_en.rst
index 76fbc43de2..f194f84ce7 100644
--- a/doc/getstarted/build_and_install/build_from_source_en.rst
+++ b/doc/getstarted/build_and_install/build_from_source_en.rst
@@ -21,7 +21,7 @@ Then run:
git clone https://github.com/PaddlePaddle/Paddle.git
cd Paddle
# run the following command to build a CPU-Only binaries if you are using docker
- docker run -it -v $PWD:/paddle -e "WITH_GPU=OFF" -e "WITH_TESTING=OFF" paddlepaddle/paddle_manylinux_devel:cuda8.0_cudnn5 bash -x paddle/scripts/docker/build.sh
+ docker run -it -v $PWD:/paddle -e "WITH_GPU=OFF" -e "WITH_TESTING=OFF" paddlepaddle/paddle_manylinux_devel:cuda8.0_cudnn5 bash -x /paddle/paddle/scripts/docker/build.sh
# else run these commands
mkdir build
cd build
@@ -34,7 +34,7 @@ machine or copy it to the target machine.
.. code-block:: bash
- pip install python/dist/*.whl
+ pip install build/python/dist/*.whl
.. _run_test:
@@ -49,7 +49,7 @@ Set :code:`WITH_GPU=ON` Can also run tests on GPU.
.. code-block:: bash
- docker run -it -v $PWD:/paddle -e "WITH_GPU=OFF" -e "WITH_TESTING=ON" -e "RUN_TEST=ON" paddlepaddle/paddle_manylinux_devel:cuda8.0_cudnn5 bash -x paddle/scripts/docker/build.sh
+ docker run -it -v $PWD:/paddle -e "WITH_GPU=OFF" -e "WITH_TESTING=ON" -e "RUN_TEST=ON" paddlepaddle/paddle_manylinux_devel:cuda8.0_cudnn5 bash -x paddle/paddle/scripts/docker/build.sh
If you don't use Docker, just run ctest will start the tests:
@@ -117,7 +117,7 @@ You can add :code:`-D` argument to pass such options, like:
"WITH_PYTHON", "Build with integrated Python interpreter", "ON"
"WITH_STYLE_CHECK", "Check code style when building", "ON"
"WITH_TESTING", "Build unit tests", "ON"
- "WITH_DOC", "Build documentaions", "OFF"
+ "WITH_DOC", "Build documentations", "OFF"
"WITH_SWIG_PY", "Build Python SWIG interface for V2 API", "Auto"
"WITH_GOLANG", "Build fault-tolerant parameter server written in go", "ON"
"WITH_MKL", "Use MKL as BLAS library, else use OpenBLAS", "ON"
diff --git a/doc/getstarted/build_and_install/index_cn.rst b/doc/getstarted/build_and_install/index_cn.rst
index 88c5142dde..c9ba84c842 100644
--- a/doc/getstarted/build_and_install/index_cn.rst
+++ b/doc/getstarted/build_and_install/index_cn.rst
@@ -13,7 +13,7 @@ PaddlePaddle提供pip和Docker的安装方式:
pip_install_cn.rst
docker_install_cn.rst
-
+ ../../howto/dev/build_cn.md
编译流程
++++++++
diff --git a/doc/getstarted/build_and_install/index_en.rst b/doc/getstarted/build_and_install/index_en.rst
index c8b60d0357..32d66d63dd 100644
--- a/doc/getstarted/build_and_install/index_en.rst
+++ b/doc/getstarted/build_and_install/index_en.rst
@@ -13,6 +13,7 @@ You can choose either pip or Docker to complete your install:
pip_install_en.rst
docker_install_en.rst
+ ../../howto/dev/build_en.md
Build from Source
diff --git a/doc/howto/dev/build_cn.md b/doc/howto/dev/build_cn.md
index 0b911f7b75..4a80a52451 100644
--- a/doc/howto/dev/build_cn.md
+++ b/doc/howto/dev/build_cn.md
@@ -1,4 +1,4 @@
-# 编译PaddlePaddle和运行单元测试
+# 用Docker编译和测试PaddlePaddle
## 需要的软硬件
diff --git a/doc/howto/dev/build_en.md b/doc/howto/dev/build_en.md
index d0048e3714..91c41ef8ce 100644
--- a/doc/howto/dev/build_en.md
+++ b/doc/howto/dev/build_en.md
@@ -1,4 +1,4 @@
-# Build PaddlePaddle from Source Code and Run Unit Test
+# Build using Docker
## What Developers Need
diff --git a/doc/howto/dev/new_op_cn.md b/doc/howto/dev/new_op_cn.md
index 6cfc9536f2..44dbeecbbd 100644
--- a/doc/howto/dev/new_op_cn.md
+++ b/doc/howto/dev/new_op_cn.md
@@ -30,8 +30,8 @@
-------------- | :----------------------
OpProtoMake定义 | `.cc`文件,Backward Op不需要定义OpProtoMake
Op定义 | `.cc`文件
-Kernel实现 | CPU、GPU共享Kernel实现在`.h`文件中,否则,CPU 实现在`.cc`文件中,GPU 实现在`.cu`文件中。
-注册Op | Op注册实现在`.cc`文件;Kernel注册CPU实现在`.cc`文件中,GPU实现在`.cu`文件中
+Kernel实现 | CPU、CUDA共享Kernel实现在`.h`文件中,否则,CPU 实现在`.cc`文件中,CUDA 实现在`.cu`文件中。
+注册Op | Op注册实现在`.cc`文件;Kernel注册CPU实现在`.cc`文件中,CUDA实现在`.cu`文件中
实现新的op都添加至目录[paddle/operators](https://github.com/PaddlePaddle/Paddle/tree/develop/paddle/operators)下,文件命名以`*_op.h`(如有) 、 `*_op.cc` 、`*_op.cu`(如有)结尾。**系统会根据文件名自动构建op和其对应的Python扩展。**
@@ -153,7 +153,7 @@ MulOp(const std::string &type, const framework::VariableNameMap &inputs,
`MulKernel`继承自`framework::OpKernel`,带有下面两个模板参数:
-- `typename Place`: 表示设备类型,不同设备(CPU、GPU)共享同一个Kernel时,需加该模板参数,不共享则不加,一个不共享的例子是[`OnehotCrossEntropyOpKernel`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/cross_entropy_op.h#L43)。
+- `typename DeviceContext`: 表示设备类型,不同设备(CPU、CUDA)共享同一个Kernel时,需加该模板参数,不共享则不加,一个不共享的例子是[`OnehotCrossEntropyOpKernel`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/cross_entropy_op.h#L43)。
- `typename T` : 表示数据类型,如`float`, `double`等。
@@ -165,7 +165,7 @@ MulOp(const std::string &type, const framework::VariableNameMap &inputs,
下面是 `MulKernel` `Compute`的实现:
```cpp
- template
+ template
class MulKernel : public framework::OpKernel {
public:
void Compute(const framework::ExecutionContext& context) const override {
@@ -173,18 +173,16 @@ MulOp(const std::string &type, const framework::VariableNameMap &inputs,
auto* Y = context.Input("Y");
auto* Z = context.Output("Out");
Z->mutable_data(context.GetPlace());
- auto* device_context =
- const_cast(context.device_context_);
- math::matmul(*X, false, *Y, false, 1, Z, 0, device_context);
+ auto& device_context = context.template device_context();
+ math::matmul(*X, false, *Y, false, 1, Z, 0, device_context);
}
};
- ```
-需要注意:**不同设备(CPU、GPU)共享一个Op定义,是否则共享同一个`OpKernel`,取决于`Compute`调用的函数是否支持不同设备。**
+需要注意:**不同设备(CPU、CUDA)共享一个Op定义,是否则共享同一个`OpKernel`,取决于`Compute`调用的函数是否支持不同设备。**
-`MulOp`的CPU、GPU实现共享同一个`Kernel`。`OpKernel`不共享的例子可以参考:[`OnehotCrossEntropyOpKernel`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/cross_entropy_op.h#L43)。
+`MulOp`的CPU、CUDA实现共享同一个`Kernel`。`OpKernel`不共享的例子可以参考:[`OnehotCrossEntropyOpKernel`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/cross_entropy_op.h#L43)。
-为了使`OpKernel`的计算过程书写更加简单,并且CPU、GPU的代码可以复用,我们通常借助 Eigen unsupported Tensor模块来实现`Compute`接口。关于在PaddlePaddle中如何使用Eigen库,请参考[使用文档](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/howto/dev/use_eigen_cn.md)。
+为了使`OpKernel`的计算过程书写更加简单,并且CPU、CUDA的代码可以复用,我们通常借助 Eigen unsupported Tensor模块来实现`Compute`接口。关于在PaddlePaddle中如何使用Eigen库,请参考[使用文档](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/howto/dev/use_eigen_cn.md)。
到此,前向Op实现完成。接下来,需要在`.cc`文件中注册该op和kernel。
@@ -197,9 +195,9 @@ MulOp(const std::string &type, const framework::VariableNameMap &inputs,
```cpp
namespace ops = paddle::operators;
REGISTER_OP(mul, ops::MulOp, ops::MulOpMaker, mul_grad, ops::MulOpGrad);
- REGISTER_OP_CPU_KERNEL(mul, ops::MulKernel);
+ REGISTER_OP_CPU_KERNEL(mul, ops::MulKernel);
REGISTER_OP_CPU_KERNEL(mul_grad,
- ops::MulGradKernel);
+ ops::MulGradKernel);
```
在上面的代码中:
@@ -209,17 +207,17 @@ MulOp(const std::string &type, const framework::VariableNameMap &inputs,
- `REGISTER_OP_CPU_KERNEL` :注册`ops::MulKernel`类,并特化模板参数为`paddle::platform::CPUPlace`和`float`类型,同理,注册`ops::MulGradKernel`类。
-- 在 `.cu`文件中注册GPU Kernel。
- - 请注意,如果GPU Kernel的实现基于Eigen unsupported模块,那么在 `.cu`的开始请加上宏定义 `#define EIGEN_USE_GPU`,代码示例如下:
+- 在 `.cu`文件中注册CUDA Kernel。
+ - 请注意,如果CUDA Kernel的实现基于Eigen unsupported模块,那么在 `.cu`的开始请加上宏定义 `#define EIGEN_USE_GPU`,代码示例如下:
```cpp
// if use Eigen unsupported module before include head files
- // #define EIGEN_USE_GPU
+ #define EIGEN_USE_GPU
namespace ops = paddle::operators;
- REGISTER_OP_GPU_KERNEL(mul, ops::MulKernel);
- REGISTER_OP_GPU_KERNEL(mul_grad,
- ops::MulGradKernel);
+ REGISTER_OP_CUDA_KERNEL(mul, ops::MulKernel);
+ REGISTER_OP_CUDA_KERNEL(mul_grad,
+ ops::MulGradKernel);
```
### 5. 编译
@@ -236,71 +234,55 @@ make mul_op
## 实现单元测试
-单测包括对比前向Op不同设备(CPU、GPU)的实现、对比反向OP不同设备(CPU、GPU)的实现、反向Op的梯度测试。下面介绍介绍[`MulOp`的单元测试](https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/v2/framework/tests/test_mul_op.py)。
+单测包括对比前向Op不同设备(CPU、CUDA)的实现、对比反向OP不同设备(CPU、CUDA)的实现、反向Op的梯度测试。下面介绍介绍[`MulOp`的单元测试](https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/v2/framework/tests/test_mul_op.py)。
-### 前向Operator单元测试
-前向Op单元测试继承自`unittest.TestCase`,并定义元类`__metaclass__ = OpTestMeta`。各项更加具体的单元测试在`OpTestMeta`里完成。测试前向Operator,需要:
+Op单元测试继承自`OpTest`。各项更加具体的单元测试在`TestMulOp`里完成。测试Operator,需要:
1. 在`setUp`函数定义输入、输出,以及相关的属性参数。
2. 生成随机的输入数据。
3. 在Python脚本中实现与前向operator相同的计算逻辑,得到输出值,与operator前向计算的输出进行对比。
+4. 反向计算已经自动集成进测试框架,直接调用相应接口即可。
```python
import unittest
import numpy as np
- from gradient_checker import GradientChecker, create_op
- from op_test_util import OpTestMeta
+ from op_test import OpTest
- class TestMulOp(unittest.TestCase):
- __metaclass__ = OpTestMeta
+ class TestMulOp(OpTest):
def setUp(self):
- self.type = "mul"
+ self.op_type = "mul"
self.inputs = {
'X': np.random.random((32, 84)).astype("float32"),
'Y': np.random.random((84, 100)).astype("float32")
}
self.outputs = {'Out': np.dot(self.inputs['X'], self.inputs['Y'])}
- ```
-上面的代码首先导入依赖的包,下面是对`setUp`函数中操作的重要变量的详细解释:
-
-- `self.type = "mul" ` : 定义类型,与operator注册时注册的类型一致。
-- `self.inputs` : 定义输入,类型为`numpy.array`,并初始化。
-- `self.outputs` : 定义输出,并在Python脚本中完成与operator同样的计算逻辑,返回Python端的计算结果。
-
-
-### 反向Operator单元测试
+ def test_check_output(self):
+ self.check_output()
-反向Op单元测试继承自`GradientChecker`,而`GradientChecker`继承自`unittest.TestCase`,因此,**反向单元测试函数需要以`test_`开头**。
+ def test_check_grad_normal(self):
+ self.check_grad(['X', 'Y'], 'Out', max_relative_error=0.5)
-```python
-class TestMulGradOp(GradientChecker):
- def setUp(self):
- self.op = create_op("mul")
- self.inputs = {
- 'X': np.random.random((32, 84)).astype("float32"),
- 'Y': np.random.random((84, 100)).astype("float32")
- }
+ def test_check_grad_ingore_x(self):
+ self.check_grad(
+ ['Y'], 'Out', max_relative_error=0.5, no_grad_set=set("X"))
- def test_check_grad_normal(self):
- # mul op will enlarge the relative error
- self.check_grad(['X', 'Y'], 'Out', max_relative_error=0.5)
+ def test_check_grad_ingore_y(self):
+ self.check_grad(
+ ['X'], 'Out', max_relative_error=0.5, no_grad_set=set('Y'))
- def test_check_grad_ingore_x(self):
- self.check_grad(
- ['Y'], 'Out', max_relative_error=0.5, no_grad_set=set("X"))
+ ```
- def test_check_grad_ingore_y(self):
- self.check_grad(
- ['X'], 'Out', max_relative_error=0.5, no_grad_set=set('Y'))
-```
+上面的代码首先导入依赖的包,下面是对`setUp`函数中操作的重要变量的详细解释:
-下面解释代码中一些关键的地方:
+- `self.op_type = "mul" ` : 定义类型,与operator注册时注册的类型一致。
+- `self.inputs` : 定义输入,类型为`numpy.array`,并初始化。
+- `self.outputs` : 定义输出,并在Python脚本中完成与operator同样的计算逻辑,返回Python端的计算结果。
-- 调用`create_op("mul")`创建反向Op对应的前向Op。
+而反向测试中:
- `test_check_grad_normal`中调用`check_grad`使用数值法检测梯度正确性和稳定性。
- 第一个参数`["X", "Y"]` : 指定对输入变量`X`、`Y`做梯度检测。
- 第二个参数`"Out"` : 指定前向网络最终的输出目标变量`Out`。
@@ -328,5 +310,5 @@ ctest -R test_mul_op
- 为每个Op创建单独的`*_op.h`(如有)、`*_op.cc`和`*_op.cu`(如有)。不允许一个文件中包含多个Op,这将会导致编译出错。
- 注册Op时的类型名,需要和该Op的名字一样。即不允许在`A_op.cc`里面,注册`REGISTER_OP(B, ...)`等,这将会导致单元测试出错。
-- 如果Op没有实现GPU Kernel,请不要创建空的`*_op.cu`,这将会导致单元测试出错。
+- 如果Op没有实现CUDA Kernel,请不要创建空的`*_op.cu`,这将会导致单元测试出错。
- 如果多个Op依赖一些共用的函数,可以创建非`*_op.*`格式的文件来存放,如`gather.h`文件。
diff --git a/doc/howto/dev/new_op_en.md b/doc/howto/dev/new_op_en.md
index 1e88e1f5b4..510233306c 100644
--- a/doc/howto/dev/new_op_en.md
+++ b/doc/howto/dev/new_op_en.md
@@ -28,8 +28,8 @@ An operator can be differentiated by whether in has kernel methods. An operator
-------------- | :----------------------
OpProtoMake definition | `.cc`files, Backward Op does not need an OpProtoMake interface.
Op definition | `.cc` files
-Kernel implementation | The kernel methods shared between CPU and GPU are defined in `.h` files. CPU-specific kernels live in `.cc` files, while GPU-specific kernels are implemented in `.cu`files.
-Registering the Op | Ops are registered in `.cc` files; For Kernel registration, `.cc` files contain the CPU implementation, while `.cu` files contain the GPU implementation.
+Kernel implementation | The kernel methods shared between CPU and CUDA are defined in `.h` files. CPU-specific kernels live in `.cc` files, while CUDA-specific kernels are implemented in `.cu`files.
+Registering the Op | Ops are registered in `.cc` files; For Kernel registration, `.cc` files contain the CPU implementation, while `.cu` files contain the CUDA implementation.
New Operator implementations are added to the list [paddle/operators](https://github.com/PaddlePaddle/Paddle/tree/develop/paddle/operators), with file names in the format `*_op.h` (if applicable), `*_op.cc`, `*_op.cu` (if applicable).** The system will use the naming scheme to automatically build operators and their corresponding Python extensions. **
@@ -151,7 +151,7 @@ Usually `OpProtoMaker` and `Op`'s type definitions are written in `.cc` files, w
`MulKernel` inherits `framework::OpKernel`, which includes the following templates:
-- `typename Place` denotes device type. When different devices, namely the CPU and the GPU, share the same kernel, this template needs to be added. If they don't share kernels, this must not be added. An example of a non-sharing kernel is [`OnehotCrossEntropyOpKernel`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/cross_entropy_op.h#L43).
+- `typename DeviceContext` denotes device context type. When different devices, namely the CPUDeviceContext and the CUDADeviceContext, share the same kernel, this template needs to be added. If they don't share kernels, this must not be added. An example of a non-sharing kernel is [`OnehotCrossEntropyOpKernel`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/cross_entropy_op.h#L43).
- `typename T` denotes data type, such as `float` or `double`.
@@ -163,7 +163,7 @@ Usually `OpProtoMaker` and `Op`'s type definitions are written in `.cc` files, w
`MulKernel`'s implementation of `Compute` is as follows:
```cpp
- template
+ template
class MulKernel : public framework::OpKernel {
public:
void Compute(const framework::ExecutionContext& context) const override {
@@ -171,16 +171,15 @@ Usually `OpProtoMaker` and `Op`'s type definitions are written in `.cc` files, w
auto* Y = context.Input("Y");
auto* Z = context.Output("Out");
Z->mutable_data(context.GetPlace());
- auto* device_context =
- const_cast(context.device_context_);
- math::matmul(*X, false, *Y, false, 1, Z, 0, device_context);
+ auto& device_context = context.template device_context();
+ math::matmul(*X, false, *Y, false, 1, Z, 0, device_context);
}
};
```
-Note that **different devices (CPU, GPU)share an Op definition; whether or not they share the same `OpKernel` depends on whether `Compute` calls functions that support both devices.**
+Note that **different devices (CPU, CUDA)share an Op definition; whether or not they share the same `OpKernel` depends on whether `Compute` calls functions that support both devices.**
-`MulOp`'s CPU and GPU share the same `Kernel`. A non-sharing `OpKernel` example can be seen in [`OnehotCrossEntropyOpKernel`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/cross_entropy_op.h#L43).
+`MulOp`'s CPU and CUDA share the same `Kernel`. A non-sharing `OpKernel` example can be seen in [`OnehotCrossEntropyOpKernel`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/cross_entropy_op.h#L43).
To ease the writing of `OpKernel` compute, and for reusing code cross-device, [`Eigen-unsupported Tensor`](https://bitbucket.org/eigen/eigen/src/default/unsupported/Eigen/CXX11/src/Tensor/README.md?fileviewer=file-view-default) module is used to implement `Compute` interface. To learn about how the Eigen library is used in PaddlePaddle, please see [usage document](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/howto/dev/use_eigen_cn.md).
@@ -196,9 +195,9 @@ The definition of its corresponding backward operator, if applicable, is similar
```cpp
namespace ops = paddle::operators;
REGISTER_OP(mul, ops::MulOp, ops::MulOpMaker, mul_grad, ops::MulOpGrad);
- REGISTER_OP_CPU_KERNEL(mul, ops::MulKernel);
+ REGISTER_OP_CPU_KERNEL(mul, ops::MulKernel);
REGISTER_OP_CPU_KERNEL(mul_grad,
- ops::MulGradKernel);
+ ops::MulGradKernel);
```
In that code block,
@@ -208,17 +207,17 @@ The definition of its corresponding backward operator, if applicable, is similar
- `REGISTER_OP_CPU_KERNEL` registers `ops::MulKernel` class and specialized template types `paddle::platform::CPUPlace` and `float`, which also registers `ops::MulGradKernel`.
-- Registering GPU Kernel in `.cu` files
- - Note that if GPU Kernel is implemented using the `Eigen unsupported` module, then on top of `.cu`, a macro definition `#define EIGEN_USE_GPU` is needed, such as
+- Registering CUDA Kernel in `.cu` files
+ - Note that if CUDA Kernel is implemented using the `Eigen unsupported` module, then on top of `.cu`, a macro definition `#define EIGEN_USE_GPU` is needed, such as
```cpp
// if use Eigen unsupported module before include head files
#define EIGEN_USE_GPU
namespace ops = paddle::operators;
- REGISTER_OP_GPU_KERNEL(mul, ops::MulKernel);
- REGISTER_OP_GPU_KERNEL(mul_grad,
- ops::MulGradKernel);
+ REGISTER_OP_CUDA_KERNEL(mul, ops::MulKernel);
+ REGISTER_OP_CUDA_KERNEL(mul_grad,
+ ops::MulGradKernel);
```
### 5. Compilation
@@ -253,62 +252,50 @@ A forward operator unit test inherits `unittest.TestCase` and defines metaclass
2. Generating random input data.
-3. Implementing the same computation logic in a Python script:
+3. Implementing the same computation logic in a Python script.
+
+4. Call check gradient function to check the backward operator.
```python
import unittest
import numpy as np
- from gradient_checker import GradientChecker, create_op
- from op_test_util import OpTestMeta
+ from op_test import OpTest
- class TestMulOp(unittest.TestCase):
- __metaclass__ = OpTestMeta
+ class TestMulOp(OpTest):
def setUp(self):
- self.type = "mul"
+ self.op_type = "mul"
self.inputs = {
'X': np.random.random((32, 84)).astype("float32"),
'Y': np.random.random((84, 100)).astype("float32")
}
self.outputs = {'Out': np.dot(self.inputs['X'], self.inputs['Y'])}
- ```
-Get its output, and compare it with the forward operator's own output.
-
-The code above first loads required packages. In addition, we have
-
-- `self.type = "mul" ` defines the type that is identical to what the operator's registered type.
-- `self.inputs` defines input, with type `numpy.array` and initializes it.
-- `self.outputs` defines output and completes the same operator computation in the Python script, and returns its result from the Python script.
-### Testing Backward Operators
+ def test_check_output(self):
+ self.check_output()
+
+ def test_check_grad_normal(self):
+ self.check_grad(['X', 'Y'], 'Out', max_relative_error=0.5)
-A backward operator unit test inherits `GradientChecker`, which inherits `unittest.TestCase`. As a result, **a backward operator unit test needs to be have the prefix `test_`**.
+ def test_check_grad_ingore_x(self):
+ self.check_grad(
+ ['Y'], 'Out', max_relative_error=0.5, no_grad_set=set("X"))
-```python
-class TestMulGradOp(GradientChecker):
- def setUp(self):
- self.op = create_op("mul")
- self.inputs = {
- 'X': np.random.random((32, 84)).astype("float32"),
- 'Y': np.random.random((84, 100)).astype("float32")
- }
+ def test_check_grad_ingore_y(self):
+ self.check_grad(
+ ['X'], 'Out', max_relative_error=0.5, no_grad_set=set('Y'))
- def test_check_grad_normal(self):
- # mul op will enlarge the relative error
- self.check_grad(['X', 'Y'], 'Out', max_relative_error=0.5)
+ ```
+Get its output, and compare it with the forward operator's own output.
- def test_check_grad_ingore_x(self):
- self.check_grad(
- ['Y'], 'Out', max_relative_error=0.5, no_grad_set=set("X"))
+The code above first loads required packages. In addition, we have
- def test_check_grad_ingore_y(self):
- self.check_grad(
- ['X'], 'Out', max_relative_error=0.5, no_grad_set=set('Y'))
-```
+- `self.op_type = "mul" ` defines the type that is identical to what the operator's registered type.
+- `self.inputs` defines input, with type `numpy.array` and initializes it.
+- `self.outputs` defines output and completes the same operator computation in the Python script, and returns its result from the Python script.
-Some key points in the code above include:
+Some key points in checking gradient above include:
-- `create_op("mul")` creates the backward operator's corresponding forward operator.
- `test_normal` calls `check_grad` to validate scaling tests' correctness and stability through numeric methods.
- The first variable `["X", "Y"]` appoints `X` and `Y` to be scale tested.
- The second variable `"Out"` points to the network's final output target `Out`.
@@ -338,5 +325,5 @@ ctest -R test_mul_op
- Every `*_op.h` (if applicable), `*_op.cc`, and `*_op.cu` (if applicable) must be created for a unique Op. Compiling will fail if multiple operators are included per file.
- The type with which an operator is registered needs to be identical to the Op's name. Registering `REGISTER_OP(B, ...)` in `A_op.cc` will cause unit testing failures.
-- If the operator does not implement a GPU kernel, please refrain from creating an empty `*_op.cu` file, or else unit tests will fail.
+- If the operator does not implement a CUDA kernel, please refrain from creating an empty `*_op.cu` file, or else unit tests will fail.
- If multiple operators rely on some shared methods, a file NOT named `*_op.*` can be created to store them, such as `gather.h`.
diff --git a/paddle/api/CMakeLists.txt b/paddle/api/CMakeLists.txt
index d6b8464100..cf84568ecd 100644
--- a/paddle/api/CMakeLists.txt
+++ b/paddle/api/CMakeLists.txt
@@ -25,8 +25,18 @@ FILE(GLOB PY_PADDLE_PYTHON_FILES ${PADDLE_SOURCE_DIR}/paddle/py_paddle/*.py)
SET_SOURCE_FILES_PROPERTIES(Paddle.i PROPERTIES CPLUSPLUS ON)
+SET(SWIG_NEED_FLAGS
+ -ftls-model=global-dynamic
+ -Wno-parentheses-equality
+ -Wno-self-assign
+ -Wno-maybe-uninitialized
+ -Wno-missing-field-initializers)
+ FOREACH(flag ${SWIG_NEED_FLAGS})
+ safe_set_cxxflag(SWIG_CXX_FLAGS ${flag})
+ENDFOREACH()
+
SET(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR})
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-parentheses-equality -Wno-missing-field-initializers -Wno-self-assign -ftls-model=global-dynamic")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SWIG_CXX_FLAGS}")
SET(SWIG_MODULE_swig_paddle_EXTRA_DEPS
paddle_parameter
diff --git a/paddle/capi/Main.cpp b/paddle/capi/Main.cpp
index bb8249a551..c038789340 100644
--- a/paddle/capi/Main.cpp
+++ b/paddle/capi/Main.cpp
@@ -43,4 +43,11 @@ paddle_error paddle_init(int argc, char** argv) {
isInit = true;
return kPD_NO_ERROR;
}
+
+paddle_error paddle_init_thread() {
+ if (FLAGS_use_gpu) {
+ hl_init(FLAGS_gpu_id);
+ }
+ return kPD_NO_ERROR;
+}
}
diff --git a/paddle/capi/Matrix.cpp b/paddle/capi/Matrix.cpp
index 30f3a766f0..cbacd1fb71 100644
--- a/paddle/capi/Matrix.cpp
+++ b/paddle/capi/Matrix.cpp
@@ -40,7 +40,7 @@ paddle_error paddle_matrix_destroy(paddle_matrix mat) {
paddle_error paddle_matrix_set_row(paddle_matrix mat,
uint64_t rowID,
paddle_real* rowArray) {
- if (mat == nullptr) return kPD_NULLPTR;
+ if (mat == nullptr || rowArray == nullptr) return kPD_NULLPTR;
auto ptr = cast(mat);
if (ptr->mat == nullptr) return kPD_NULLPTR;
if (rowID >= ptr->mat->getHeight()) return kPD_OUT_OF_RANGE;
diff --git a/paddle/capi/error.cpp b/paddle/capi/error.cpp
new file mode 100644
index 0000000000..169b65f921
--- /dev/null
+++ b/paddle/capi/error.cpp
@@ -0,0 +1,32 @@
+/* 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 "error.h"
+
+const char* paddle_error_string(paddle_error err) {
+ switch (err) {
+ case kPD_NULLPTR:
+ return "nullptr error";
+ case kPD_OUT_OF_RANGE:
+ return "out of range error";
+ case kPD_PROTOBUF_ERROR:
+ return "protobuf error";
+ case kPD_NOT_SUPPORTED:
+ return "not supported error";
+ case kPD_UNDEFINED_ERROR:
+ return "undefined error";
+ default:
+ return "";
+ }
+}
diff --git a/paddle/capi/error.h b/paddle/capi/error.h
index 44d8c2040d..9d9d0ed63a 100644
--- a/paddle/capi/error.h
+++ b/paddle/capi/error.h
@@ -15,6 +15,8 @@ limitations under the License. */
#ifndef __PADDLE_CAPI_ERROR_H__
#define __PADDLE_CAPI_ERROR_H__
+#include "config.h"
+
/**
* Error Type for Paddle API.
*/
@@ -27,4 +29,9 @@ typedef enum {
kPD_UNDEFINED_ERROR = -1,
} paddle_error;
+/**
+ * Error string for Paddle API.
+ */
+PD_API const char* paddle_error_string(paddle_error err);
+
#endif
diff --git a/paddle/capi/examples/model_inference/multi_thread/CMakeLists.txt b/paddle/capi/examples/model_inference/multi_thread/CMakeLists.txt
index 98e411ddc0..2fc8debdde 100644
--- a/paddle/capi/examples/model_inference/multi_thread/CMakeLists.txt
+++ b/paddle/capi/examples/model_inference/multi_thread/CMakeLists.txt
@@ -1,8 +1,29 @@
project(multi_thread)
cmake_minimum_required(VERSION 2.8)
-aux_source_directory(. SRC_LIST)
-add_executable(${PROJECT_NAME} ${SRC_LIST})
+
find_package (Threads)
+
+if(NOT PADDLE_ROOT)
+ set(PADDLE_ROOT $ENV{PADDLE_ROOT} CACHE PATH "Paddle Path")
+endif()
+if(PADDLE_ROOT)
+ include_directories(${PADDLE_ROOT}/include)
+ link_directories(${PADDLE_ROOT}/lib)
+endif()
+
+set(CPU_SRCS main.c)
+add_executable(${PROJECT_NAME} ${CPU_SRCS})
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99)
-target_link_libraries(${PROJECT_NAME} -lpaddle_capi_shared
- ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(${PROJECT_NAME}
+ -lpaddle_capi_shared
+ ${CMAKE_THREAD_LIBS_INIT})
+
+find_package(CUDA QUIET)
+if(CUDA_FOUND)
+ set(GPU_SRCS main_gpu.c)
+ cuda_add_executable(${PROJECT_NAME}_gpu ${GPU_SRCS})
+ set_property(TARGET ${PROJECT_NAME}_gpu PROPERTY C_STANDARD 99)
+ target_link_libraries(${PROJECT_NAME}_gpu
+ -lpaddle_capi_shared
+ ${CMAKE_THREAD_LIBS_INIT})
+endif(CUDA_FOUND)
diff --git a/paddle/capi/examples/model_inference/multi_thread/main_gpu.c b/paddle/capi/examples/model_inference/multi_thread/main_gpu.c
new file mode 100644
index 0000000000..6fd376e0d1
--- /dev/null
+++ b/paddle/capi/examples/model_inference/multi_thread/main_gpu.c
@@ -0,0 +1,113 @@
+#include
+#include
+#include
+#include "../common/common.h"
+
+#define CONFIG_BIN "./trainer_config.bin"
+#define NUM_THREAD 4
+#define NUM_ITER 1000
+
+pthread_mutex_t mutex;
+
+/*
+ * @brief It is an simple inference example that runs multi-threads on a GPU.
+ * Each thread holds it own local gradient_machine but shares the same
+ * parameters.
+ * If you want to run on different GPUs, you need to launch
+ * multi-processes or set trainer_count > 1.
+ */
+void* thread_main(void* gm_ptr) {
+ // Initialize the thread environment of Paddle.
+ CHECK(paddle_init_thread());
+
+ paddle_gradient_machine machine = (paddle_gradient_machine)(gm_ptr);
+ // Create input arguments.
+ paddle_arguments in_args = paddle_arguments_create_none();
+ // Create input matrix.
+ paddle_matrix mat = paddle_matrix_create(/* sample_num */ 1,
+ /* size */ 784,
+ /* useGPU */ true);
+ // Create output arguments.
+ paddle_arguments out_args = paddle_arguments_create_none();
+ // Create output matrix.
+ paddle_matrix prob = paddle_matrix_create_none();
+
+ // CPU buffer to cache the input and output.
+ paddle_real* cpu_input = (paddle_real*)malloc(784 * sizeof(paddle_real));
+ paddle_real* cpu_output = (paddle_real*)malloc(10 * sizeof(paddle_real));
+ for (int iter = 0; iter < NUM_ITER; ++iter) {
+ // There is only one input layer of this network.
+ CHECK(paddle_arguments_resize(in_args, 1));
+ CHECK(paddle_arguments_set_value(in_args, 0, mat));
+
+ for (int i = 0; i < 784; ++i) {
+ cpu_input[i] = rand() / ((float)RAND_MAX);
+ }
+ CHECK(paddle_matrix_set_value(mat, cpu_input));
+
+ CHECK(paddle_gradient_machine_forward(machine,
+ in_args,
+ out_args,
+ /* isTrain */ false));
+
+ CHECK(paddle_arguments_get_value(out_args, 0, prob));
+ CHECK(paddle_matrix_get_value(prob, cpu_output));
+
+ pthread_mutex_lock(&mutex);
+ printf("Prob: ");
+ for (int i = 0; i < 10; ++i) {
+ printf("%.2f ", cpu_output[i]);
+ }
+ printf("\n");
+ pthread_mutex_unlock(&mutex);
+ }
+
+ CHECK(paddle_matrix_destroy(prob));
+ CHECK(paddle_arguments_destroy(out_args));
+ CHECK(paddle_matrix_destroy(mat));
+ CHECK(paddle_arguments_destroy(in_args));
+ CHECK(paddle_gradient_machine_destroy(machine));
+
+ free(cpu_input);
+ free(cpu_output);
+
+ return NULL;
+}
+
+int main() {
+ // Initalize Paddle
+ char* argv[] = {"--use_gpu=True"};
+ CHECK(paddle_init(1, (char**)argv));
+
+ // Reading config binary file. It is generated by `convert_protobin.sh`
+ long size;
+ void* buf = read_config(CONFIG_BIN, &size);
+
+ // Create a gradient machine for inference.
+ paddle_gradient_machine machine;
+ CHECK(paddle_gradient_machine_create_for_inference(&machine, buf, (int)size));
+ CHECK(paddle_gradient_machine_randomize_param(machine));
+
+ // Loading parameter. Uncomment the following line and change the directory.
+ // CHECK(paddle_gradient_machine_load_parameter_from_disk(machine,
+ // "./some_where_to_params"));
+ srand(time(0));
+ pthread_mutex_init(&mutex, NULL);
+
+ pthread_t threads[NUM_THREAD];
+
+ for (int i = 0; i < NUM_THREAD; ++i) {
+ paddle_gradient_machine thread_local_machine;
+ CHECK(paddle_gradient_machine_create_shared_param(
+ machine, buf, size, &thread_local_machine));
+ pthread_create(&threads[i], NULL, thread_main, thread_local_machine);
+ }
+
+ for (int i = 0; i < NUM_THREAD; ++i) {
+ pthread_join(threads[i], NULL);
+ }
+
+ pthread_mutex_destroy(&mutex);
+
+ return 0;
+}
diff --git a/paddle/capi/main.h b/paddle/capi/main.h
index 893ebcbd58..99c4e8428d 100644
--- a/paddle/capi/main.h
+++ b/paddle/capi/main.h
@@ -26,6 +26,13 @@ extern "C" {
*/
PD_API paddle_error paddle_init(int argc, char** argv);
+/**
+ * Initialize the thread environment of Paddle.
+ * @note it is requisite for GPU runs but optional for CPU runs.
+ * For GPU runs, all threads will run on the same GPU devices.
+ */
+PD_API paddle_error paddle_init_thread();
+
#ifdef __cplusplus
}
#endif
diff --git a/paddle/cuda/include/hl_cnn.h b/paddle/cuda/include/hl_cnn.h
index 89c1f48eda..8841806292 100644
--- a/paddle/cuda/include/hl_cnn.h
+++ b/paddle/cuda/include/hl_cnn.h
@@ -116,6 +116,7 @@ extern void hl_maxpool_backward(const int frameCnt,
* @param[in] paddingW padding width.
* @param[out] tgtData output data.
* @param[in] tgtStride stride between output data samples.
+ * @param[in] excludeMode whether to consider paddings for size.
*
*/
extern void hl_avgpool_forward(const int frameCnt,
@@ -132,7 +133,8 @@ extern void hl_avgpool_forward(const int frameCnt,
const int paddingH,
const int paddingW,
real* tgtData,
- const int tgtStride);
+ const int tgtStride,
+ bool excludeMode);
/**
* @brief Maximum pool backward.
@@ -154,6 +156,7 @@ extern void hl_avgpool_forward(const int frameCnt,
* @param[in] scaleB scale.
* @param[out] backGrad output grad.
* @param[in] outStride stride between output data samples.
+ * @param[in] excludeMode whether to consider paddings for size.
*
*/
extern void hl_avgpool_backward(const int frameCnt,
@@ -172,7 +175,8 @@ extern void hl_avgpool_backward(const int frameCnt,
real scaleA,
real scaleB,
real* backGrad,
- const int outStride);
+ const int outStride,
+ bool excludeMode);
extern void hl_maxpool3D_forward(const int frameCnt,
const real* inputData,
diff --git a/paddle/cuda/include/stub/hl_cnn_stub.h b/paddle/cuda/include/stub/hl_cnn_stub.h
index 968ed4840f..706cc59a8e 100644
--- a/paddle/cuda/include/stub/hl_cnn_stub.h
+++ b/paddle/cuda/include/stub/hl_cnn_stub.h
@@ -68,7 +68,8 @@ inline void hl_avgpool_forward(const int frameCnt,
const int paddingH,
const int paddingW,
real* tgtData,
- const int tgtStride) {}
+ const int tgtStride,
+ const bool excludeMode) {}
inline void hl_avgpool_backward(const int frameCnt,
const real* outGrad,
@@ -86,7 +87,8 @@ inline void hl_avgpool_backward(const int frameCnt,
real scaleA,
real scaleB,
real* backGrad,
- const int outStride) {}
+ const int outStride,
+ const bool excludeMode) {}
inline void hl_maxpool3D_forward(const int frameCnt,
const real* inputData,
diff --git a/paddle/cuda/src/hl_cuda_cnn.cu b/paddle/cuda/src/hl_cuda_cnn.cu
index 3699b1e8ae..2d1bc4f6d5 100644
--- a/paddle/cuda/src/hl_cuda_cnn.cu
+++ b/paddle/cuda/src/hl_cuda_cnn.cu
@@ -210,7 +210,8 @@ __global__ void KeAvgPoolForward(const int nthreads,
const int padH,
const int padW,
real* tgtData,
- const int tgtStride) {
+ const int tgtStride,
+ const bool excludeMode) {
int index = blockIdx.x * blockDim.x + threadIdx.x;
if (index < nthreads) {
int pw = index % pooledW;
@@ -224,7 +225,8 @@ __global__ void KeAvgPoolForward(const int nthreads,
int wend = min(wstart + sizeX, width);
hstart = max(hstart, 0);
wstart = max(wstart, 0);
- int pool_size = (hend - hstart) * (wend - wstart);
+ int poolSize =
+ excludeMode ? (hend - hstart) * (wend - wstart) : sizeY * sizeX;
real aveval = 0;
inputData += (frameNum * channels + c) * height * width;
@@ -235,7 +237,7 @@ __global__ void KeAvgPoolForward(const int nthreads,
}
int tgtIndex =
index % (pooledW * pooledH * channels) + frameNum * tgtStride;
- tgtData[tgtIndex] = aveval / pool_size;
+ tgtData[tgtIndex] = aveval / poolSize;
}
}
@@ -253,7 +255,8 @@ void hl_avgpool_forward(const int frameCnt,
const int paddingH,
const int paddingW,
real* tgtData,
- const int tgtStride) {
+ const int tgtStride,
+ const bool excludeMode) {
int num_kernels = pooledH * pooledW * channels * frameCnt;
int blocks = (num_kernels + 1024 - 1) / 1024;
KeAvgPoolForward<<>>(num_kernels,
@@ -270,7 +273,8 @@ void hl_avgpool_forward(const int frameCnt,
paddingH,
paddingW,
tgtData,
- tgtStride);
+ tgtStride,
+ excludeMode);
CHECK_SYNC("hl_avgpool_forward failed");
}
@@ -290,7 +294,8 @@ __global__ void KeAvgPoolBackward(const int nthreads,
real scaleA,
real scaleB,
real* tgtGrad,
- const int outStride) {
+ const int outStride,
+ const bool excludeMode) {
int index = blockIdx.x * blockDim.x + threadIdx.x;
if (index < nthreads) {
int offsetW = index % width + padW;
@@ -314,8 +319,9 @@ __global__ void KeAvgPoolBackward(const int nthreads,
int wstart = pw * strideW - padW;
int wend = min(wstart + sizeX, width);
wstart = max(wstart, 0);
- int poolsize = (hend - hstart) * (wend - wstart);
- gradient += outGrad[ph * pooledW + pw] / poolsize;
+ int poolSize =
+ excludeMode ? (hend - hstart) * (wend - wstart) : sizeY * sizeX;
+ gradient += outGrad[ph * pooledW + pw] / poolSize;
}
}
tgtGrad[index] = scaleB * tgtGrad[index] + scaleA * gradient;
@@ -338,7 +344,8 @@ void hl_avgpool_backward(const int frameCnt,
real scaleA,
real scaleB,
real* backGrad,
- const int outStride) {
+ const int outStride,
+ const bool excludeMode) {
int num_kernels = height * width * channels * frameCnt;
int blocks = (num_kernels + 1024 - 1) / 1024;
@@ -358,7 +365,8 @@ void hl_avgpool_backward(const int frameCnt,
scaleA,
scaleB,
backGrad,
- outStride);
+ outStride,
+ excludeMode);
CHECK_SYNC("hl_avgpool_backward failed");
}
diff --git a/paddle/framework/backward.cc b/paddle/framework/backward.cc
index c8b85caaca..a17036c652 100644
--- a/paddle/framework/backward.cc
+++ b/paddle/framework/backward.cc
@@ -33,8 +33,8 @@ static std::unordered_set* g_ctrl_flow_ops_ = nullptr;
// We should design a better way to backward CtrlFlowOps.
static std::unordered_set& CtrlFlowOps() {
if (g_ctrl_flow_ops_ == nullptr) {
- g_ctrl_flow_ops_ =
- new std::unordered_set{"increment", "lod_rank_table"};
+ g_ctrl_flow_ops_ = new std::unordered_set{
+ "increment", "lod_rank_table", "less_than"};
}
return *g_ctrl_flow_ops_;
}
@@ -190,8 +190,9 @@ static std::unique_ptr BackwardRecursive(
// collect all the offset for each alias,
// insert a sum operator to add all aliases to output
insert_position.push_back(
- {dup_op.back(), OpRegistry::CreateOp("sum", {{"X", dup_outputs}},
- {{"Out", {name}}}, {})});
+ {dup_op.back(),
+ OpRegistry::CreateOp("sum", {{"X", dup_outputs}}, {{"Out", {name}}},
+ AttributeMap{})});
}
// make sure the inserted `sum` ops follow the BFS order.
@@ -216,7 +217,8 @@ static std::unique_ptr BackwardRecursive(
// If part of input gradient of that operator is not calculated, fill
// zero variables to that input gradient.
net->AppendOp(OpRegistry::CreateOp("fill_zeros_like", {{"X", {prefix}}},
- {{"Y", {grad_input}}}, {}));
+ {{"Y", {grad_input}}},
+ AttributeMap{}));
}
return false;
});
@@ -392,8 +394,9 @@ std::vector> MakeOpGrad(
0, in_name.size() - sizeof(kGradVarSuffix) / sizeof(char) + 1);
std::string new_name = prefix + kZeroVarSuffix;
desc->Rename(in_name, new_name);
- std::unique_ptr fill_zeros_op(new OpDescBind(
- "fill_zeros_like", {{"X", {prefix}}}, {{"Y", {new_name}}}, {}));
+ std::unique_ptr fill_zeros_op(
+ new OpDescBind("fill_zeros_like", {{"X", {prefix}}},
+ {{"Y", {new_name}}}, AttributeMap{}));
pending_fill_zeros_ops.push_back(std::move(fill_zeros_op));
}
}
@@ -483,8 +486,9 @@ std::vector> MakeBlockBackward(
sum_op_inputs.emplace_back(new_name);
next_g_name = sum_op_inputs.back();
}
- std::unique_ptr sum_op(new OpDescBind(
- "sum", {{"X", sum_op_inputs}}, {{"Out", {out_name}}}, {}));
+ std::unique_ptr sum_op(
+ new OpDescBind("sum", {{"X", sum_op_inputs}}, {{"Out", {out_name}}},
+ AttributeMap{}));
pending_sum_ops.push_back({dup_op.back(), std::move(sum_op)});
}
}
diff --git a/paddle/framework/backward_test.cc b/paddle/framework/backward_test.cc
index 2b858f5ea0..9fe49881d5 100644
--- a/paddle/framework/backward_test.cc
+++ b/paddle/framework/backward_test.cc
@@ -106,15 +106,15 @@ class FcOp : public operators::NetOp {
FcOp(const std::string &type, const VariableNameMap &inputs,
const VariableNameMap &outputs, const AttributeMap &attrs)
: NetOp(type, inputs, outputs, attrs) {
- AppendOp(OpRegistry::CreateOp("mul",
- {{"X", {Input("X")}}, {"Y", {Input("W")}}},
- {{"Out", {Output("mul_result")}}}, {}));
+ AppendOp(OpRegistry::CreateOp(
+ "mul", {{"X", {Input("X")}}, {"Y", {Input("W")}}},
+ {{"Out", {Output("mul_result")}}}, AttributeMap{}));
auto input_b = Inputs("b");
std::string before_act = "mul_result";
if (input_b.size() != 0) {
AppendOp(OpRegistry::CreateOp(
"rowwise_add", {{"X", {Output("mul_result")}}, {"b", {input_b[0]}}},
- {{"Out", {Output("add_result")}}}, {}));
+ {{"Out", {Output("add_result")}}}, AttributeMap{}));
before_act = "add_result";
} else {
auto out_varname = Output("add_result");
@@ -124,7 +124,7 @@ class FcOp : public operators::NetOp {
}
AppendOp(OpRegistry::CreateOp("sigmoid", {{"X", {Output(before_act)}}},
- {{"Out", {Output("Out")}}}, {}));
+ {{"Out", {Output("Out")}}}, AttributeMap{}));
CompleteAddOp(false);
}
};
@@ -278,8 +278,9 @@ REGISTER_OPERATOR(scale, f::NoneOp);
REGISTER_OP_CPU_KERNEL(scale, f::NoneKernel);
TEST(Backward, simple_op_not_need_grad) {
- auto fwd = f::OpRegistry::CreateOp(
- "rowwise_add", {{"X", {"x"}}, {"b", {"b"}}}, {{"Out", {"out"}}}, {});
+ auto fwd =
+ f::OpRegistry::CreateOp("rowwise_add", {{"X", {"x"}}, {"b", {"b"}}},
+ {{"Out", {"out"}}}, f::AttributeMap{});
ASSERT_NE(fwd, nullptr);
auto gop = f::Backward(*fwd, {"x"});
ASSERT_EQ(gop->Output(f::GradVarName("X")), f::kEmptyVarName);
@@ -296,9 +297,10 @@ TEST(Backward, net_fc_backward_normal) {
{{"mul_result", {"mul_res"}},
{"add_result", {"add_re"}},
{"Out", {"out"}}},
- {});
+ f::AttributeMap{});
ASSERT_NE(fwd, nullptr);
- std::shared_ptr gop = f::Backward(*fwd, {});
+ std::shared_ptr gop =
+ f::Backward(*fwd, std::unordered_set{});
ASSERT_TRUE(gop->IsNetOp());
auto net = static_cast(gop.get());
@@ -322,9 +324,10 @@ TEST(Backward, net_fc_backward_not_have_b) {
{{"mul_result", {"mul_res"}},
{"add_result", {"add_res"}},
{"Out", {"tmp"}}},
- {});
+ f::AttributeMap{});
ASSERT_NE(fwd, nullptr);
- std::shared_ptr gop = f::Backward(*fwd, {});
+ std::shared_ptr gop =
+ f::Backward(*fwd, std::unordered_set{});
ASSERT_TRUE(gop->IsNetOp());
auto net = static_cast(gop.get());
@@ -346,13 +349,13 @@ TEST(Backward, net_input_of_network_not_need_grad) {
{{"mul_result", {"mul_tmp_0"}},
{"add_result", {"add_tmp_0"}},
{"Out", {"hidden0"}}},
- {}));
+ f::AttributeMap{}));
net.AppendOp(f::OpRegistry::CreateOp(
"fc", {{"X", {"hidden0"}}, {"W", {"W2"}}, {"b", {"b2"}}},
{{"mul_result", {"mul_tmp_1"}},
{"add_result", {"add_tmp_1"}},
{"Out", {"hidden1"}}},
- {}));
+ f::AttributeMap{}));
net.CompleteAddOp();
auto bwd = Backward(net, {"x"}); // x@GRAD is not need.
ASSERT_TRUE(bwd->IsNetOp());
@@ -381,12 +384,13 @@ TEST(Backward, net_input_of_network_not_need_grad) {
TEST(Backward, net_shared_weight) {
ops::NetOp net;
net.AppendOp(f::OpRegistry::CreateOp("mul", {{"X", {"x"}}, {"Y", {"w"}}},
- {{"Out", {"out"}}}, {}));
+ {{"Out", {"out"}}}, f::AttributeMap{}));
net.AppendOp(f::OpRegistry::CreateOp("mul", {{"X", {"out"}}, {"Y", {"w"}}},
- {{"Out", {"FinalOut"}}}, {}));
+ {{"Out", {"FinalOut"}}},
+ f::AttributeMap{}));
net.CompleteAddOp();
- auto bwd = f::Backward(net, {});
+ auto bwd = f::Backward(net, std::unordered_set{});
ASSERT_TRUE(bwd->IsNetOp());
auto bwd_net = static_cast(bwd.get());
ASSERT_EQ(3UL, bwd_net->ops_.size());
@@ -394,8 +398,9 @@ TEST(Backward, net_shared_weight) {
}
TEST(Backward, op_all_input_are_not_need) {
- auto fwd = f::OpRegistry::CreateOp(
- "rowwise_add", {{"X", {"x"}}, {"b", {"b"}}}, {{"Out", {"out"}}}, {});
+ auto fwd =
+ f::OpRegistry::CreateOp("rowwise_add", {{"X", {"x"}}, {"b", {"b"}}},
+ {{"Out", {"out"}}}, f::AttributeMap{});
auto backward = f::Backward(*fwd, {"x", "b"});
ASSERT_TRUE(backward->IsNetOp());
auto net = static_cast(backward.get());
@@ -403,8 +408,9 @@ TEST(Backward, op_all_input_are_not_need) {
}
TEST(Backward, op_all_output_are_not_need) {
- auto fwd = f::OpRegistry::CreateOp(
- "rowwise_add", {{"X", {"x"}}, {"b", {"b"}}}, {{"Out", {"out"}}}, {});
+ auto fwd =
+ f::OpRegistry::CreateOp("rowwise_add", {{"X", {"x"}}, {"b", {"b"}}},
+ {{"Out", {"out"}}}, f::AttributeMap{});
auto backward = f::Backward(*fwd, {"out"});
ASSERT_TRUE(backward->IsNetOp());
auto net = static_cast(backward.get());
@@ -412,8 +418,9 @@ TEST(Backward, op_all_output_are_not_need) {
}
TEST(Backward, op_part_of_output_are_not_need) {
- auto fwd = f::OpRegistry::CreateOp("many_output_op", {{"x", {"X"}}},
- {{"y", {"Y"}}, {"z", {"Z"}}}, {});
+ auto fwd =
+ f::OpRegistry::CreateOp("many_output_op", {{"x", {"X"}}},
+ {{"y", {"Y"}}, {"z", {"Z"}}}, f::AttributeMap{});
auto backward = f::Backward(*fwd, {"Z"});
ASSERT_TRUE(backward->IsNetOp());
auto net = static_cast(backward.get());
@@ -437,7 +444,7 @@ TEST(Backward, op_part_of_output_are_not_need) {
TEST(Backward, op_part_of_input_are_not_need) {
auto fwd = f::OpRegistry::CreateOp("mul", {{"X", {"a"}}, {"Y", {"b"}}},
- {{"Out", {"out"}}}, {});
+ {{"Out", {"out"}}}, f::AttributeMap{});
auto backward = f::Backward(*fwd, {"a"});
auto &grad_mul = *backward;
ASSERT_EQ(grad_mul.Type(), "mul_grad");
@@ -458,19 +465,19 @@ TEST(Backward, linear_net_intermediate_variable_has_no_grad) {
{{"mul_result", {"mul_out1"}},
{"add_result", {"add_out1"}},
{"Out", {"out1"}}},
- {}));
+ f::AttributeMap{}));
net.AppendOp(f::OpRegistry::CreateOp(
"fc", {{"X", {"out1"}}, {"W", {"w2"}}, {"b", {"b2"}}},
{{"mul_result", {"mul_out2"}},
{"add_result", {"tmp_out2"}},
{"Out", {"out2"}}},
- {}));
+ f::AttributeMap{}));
net.AppendOp(f::OpRegistry::CreateOp(
"fc", {{"X", {"out2"}}, {"W", {"w3"}}, {"b", {"b3"}}},
{{"mul_result", {"mul_out3"}},
{"add_result", {"tmp_out3"}},
{"Out", {"out3"}}},
- {}));
+ f::AttributeMap{}));
net.CompleteAddOp();
auto backward = f::Backward(net, {"mul_out2", "tmp_out2", "out2"});
@@ -509,7 +516,8 @@ TEST(Backward, simple_single_op) {
auto target = f::VarDescBind("out");
target.SetShape({1});
- auto var_to_grad = AppendBackward(program, target, {});
+ auto var_to_grad =
+ AppendBackward(program, target, std::unordered_set{});
ASSERT_EQ(block->AllOps().size(), 3UL);
f::OpDescBind *fill_op = block->AllOps()[1];
@@ -546,7 +554,7 @@ TEST(Backward, default_attribute) {
auto target = f::VarDescBind("out");
target.SetShape({1});
- AppendBackward(program, target, {});
+ AppendBackward(program, target, std::unordered_set{});
ASSERT_EQ(block->AllOps().size(), 3UL);
EXPECT_EQ(boost::get(op->GetAttr("x_num_col_dims")), 1);
@@ -585,7 +593,8 @@ TEST(Backward, simple_mult_op) {
auto target = f::VarDescBind("out3");
target.SetShape({1});
size_t forward_len = block->AllOps().size();
- auto var_to_grad = AppendBackward(program, target, {});
+ auto var_to_grad =
+ AppendBackward(program, target, std::unordered_set{});
ASSERT_EQ(block->AllOps().size(), 6UL + 1);
f::OpDescBind *fill_op = block->AllOps()[forward_len];
@@ -817,7 +826,8 @@ TEST(Backward, shared_var) {
auto target = f::VarDescBind("out3");
target.SetShape({1});
size_t forward_len = block->AllOps().size();
- auto var_to_grad = AppendBackward(program, target, {});
+ auto var_to_grad =
+ AppendBackward(program, target, std::unordered_set{});
ASSERT_EQ(block->AllOps().size(), 8UL);
f::OpDescBind *fill_op = block->AllOps()[forward_len];
diff --git a/paddle/framework/op_desc.cc b/paddle/framework/op_desc.cc
index 2281d93df9..7ba1e3e4e3 100644
--- a/paddle/framework/op_desc.cc
+++ b/paddle/framework/op_desc.cc
@@ -59,7 +59,7 @@ class CompileTimeInferShapeContext : public InferShapeContext {
auto *in_var = block_.FindVarRecursive(Inputs(in)[i]);
auto *out_var = block_.FindVarRecursive(Outputs(out)[j]);
if (in_var->GetType() != VarDesc::LOD_TENSOR) {
- VLOG(3) << "input " << in << "is not LodTensor";
+ VLOG(3) << "input " << in << " is not LodTensor";
return;
}
PADDLE_ENFORCE_EQ(in_var->GetType(), VarDesc::LOD_TENSOR,
@@ -316,8 +316,8 @@ static void InitInferShapeFuncs() {
for (auto &kern_pair : OperatorWithKernel::AllOpKernels()) {
auto op_type = kern_pair.first;
auto &op_info = info_map.at(op_type);
- auto op =
- static_cast(op_info.Creator()("", {}, {}, {}));
+ auto op = static_cast(op_info.Creator()(
+ "", VariableNameMap{}, VariableNameMap{}, AttributeMap{}));
if (op_info.infer_shape_) { // infer_shape has been registered.
continue;
}
diff --git a/paddle/framework/op_registry.h b/paddle/framework/op_registry.h
index daade439e5..b29238432b 100644
--- a/paddle/framework/op_registry.h
+++ b/paddle/framework/op_registry.h
@@ -181,8 +181,8 @@ class OpKernelRegistrar : public Registrar {
return 0; \
}
-#define REGISTER_OP_GPU_KERNEL(op_type, ...) \
- REGISTER_OP_KERNEL(op_type, GPU, ::paddle::platform::GPUPlace, __VA_ARGS__)
+#define REGISTER_OP_CUDA_KERNEL(op_type, ...) \
+ REGISTER_OP_KERNEL(op_type, CUDA, ::paddle::platform::GPUPlace, __VA_ARGS__)
#define REGISTER_OP_CPU_KERNEL(op_type, ...) \
REGISTER_OP_KERNEL(op_type, CPU, ::paddle::platform::CPUPlace, __VA_ARGS__)
@@ -217,7 +217,7 @@ class OpKernelRegistrar : public Registrar {
#else
#define USE_OP_KERNEL(op_type) \
USE_OP_DEVICE_KERNEL(op_type, CPU); \
- USE_OP_DEVICE_KERNEL(op_type, GPU)
+ USE_OP_DEVICE_KERNEL(op_type, CUDA)
#endif
#define USE_NO_KERNEL_OP(op_type) USE_OP_ITSELF(op_type);
@@ -226,9 +226,9 @@ class OpKernelRegistrar : public Registrar {
USE_OP_ITSELF(op_type); \
USE_OP_DEVICE_KERNEL(op_type, CPU);
-#define USE_GPU_ONLY_OP(op_type) \
- USE_OP_ITSELF(op_type); \
- USE_OP_DEVICE_KERNEL(op_type, GPU)
+#define USE_CUDA_ONLY_OP(op_type) \
+ USE_OP_ITSELF(op_type); \
+ USE_OP_DEVICE_KERNEL(op_type, CUDA)
#define USE_OP(op_type) \
USE_OP_ITSELF(op_type); \
diff --git a/paddle/framework/operator.cc b/paddle/framework/operator.cc
index 93467ab8ac..e83d754783 100644
--- a/paddle/framework/operator.cc
+++ b/paddle/framework/operator.cc
@@ -22,20 +22,6 @@ limitations under the License. */
namespace paddle {
namespace framework {
-template <>
-Eigen::DefaultDevice& ExecutionContext::GetEigenDevice<
- platform::CPUPlace, Eigen::DefaultDevice>() const {
- return *device_context_.GetEigenDevice();
-}
-
-#ifdef PADDLE_WITH_CUDA
-template <>
-Eigen::GpuDevice&
-ExecutionContext::GetEigenDevice() const {
- return *device_context_.GetEigenDevice();
-}
-#endif
-
std::string OperatorBase::Input(const std::string& name) const {
auto& ins = Inputs(name);
PADDLE_ENFORCE_LE(ins.size(), 1UL,
@@ -426,13 +412,10 @@ void OperatorWithKernel::Run(const Scope& scope,
}
kernel_iter->second->Compute(ctx);
-
- // throws errors if have.
- dev_ctx.Finish();
}
OpKernelType OperatorWithKernel::GetKernelType(
const ExecutionContext& ctx) const {
- return OpKernelType(IndicateDataType(ctx), ctx.device_context());
+ return OpKernelType(IndicateDataType(ctx), ctx.GetPlace());
}
DataType OperatorWithKernel::IndicateDataType(
const ExecutionContext& ctx) const {
diff --git a/paddle/framework/operator.h b/paddle/framework/operator.h
index 60861d9293..e60dbfc313 100644
--- a/paddle/framework/operator.h
+++ b/paddle/framework/operator.h
@@ -276,17 +276,25 @@ class ExecutionContext {
out_tensor->set_lod(in_tensor.lod());
}
- template ::EigenDeviceType>
- DeviceType& GetEigenDevice() const;
-
platform::Place GetPlace() const { return device_context_.GetPlace(); }
+ template
+ const DeviceContextType& device_context() const {
+ return *reinterpret_cast(&device_context_);
+ }
+
const platform::DeviceContext& device_context() const {
return device_context_;
}
+#ifdef PADDLE_WITH_CUDA
+ const inline platform::CUDADeviceContext& cuda_device_context() const {
+ PADDLE_ENFORCE(platform::is_gpu_place(device_context_.GetPlace()));
+ return *reinterpret_cast(
+ &device_context_);
+ }
+#endif
+
//! Get actual name vector for this input.
const std::vector& Inputs(const std::string& name) const {
return op_.Inputs(name);
@@ -297,14 +305,6 @@ class ExecutionContext {
return op_.Outputs(name);
}
-#ifdef PADDLE_WITH_CUDA
- const inline platform::CUDADeviceContext& cuda_device_context() const {
- PADDLE_ENFORCE(platform::is_gpu_place(device_context_.GetPlace()));
- return *reinterpret_cast(
- &device_context_);
- }
-#endif
-
private:
const OperatorBase& op_;
const Scope& scope_;
diff --git a/paddle/framework/operator_test.cc b/paddle/framework/operator_test.cc
index 1e19f82b34..b678178454 100644
--- a/paddle/framework/operator_test.cc
+++ b/paddle/framework/operator_test.cc
@@ -115,7 +115,7 @@ class OpWithKernelTest : public OperatorWithKernel {
protected:
void InferShape(framework::InferShapeContext* ctx) const override {}
OpKernelType GetKernelType(const ExecutionContext& ctx) const override {
- return OpKernelType(DataType::FP32, ctx.device_context());
+ return OpKernelType(DataType::FP32, ctx.GetPlace());
}
};
@@ -261,7 +261,9 @@ class OperatorClone : public paddle::framework::OperatorBase {
};
TEST(Operator, Clone) {
- OperatorClone a("ABC", {}, {}, {});
+ OperatorClone a("ABC", paddle::framework::VariableNameMap{},
+ paddle::framework::VariableNameMap{},
+ paddle::framework::AttributeMap{});
auto b = a.Clone();
ASSERT_EQ(a.Type(), b->Type());
}
diff --git a/paddle/framework/prune_test.cc b/paddle/framework/prune_test.cc
index 5988874809..f21df37a29 100644
--- a/paddle/framework/prune_test.cc
+++ b/paddle/framework/prune_test.cc
@@ -54,7 +54,8 @@ TEST(Prune, one_operator) {
f::ProgramDescBind program;
f::BlockDescBind *block = program.MutableBlock(0);
- AddOp("one_one", {{"input", {"a"}}}, {{"output", {"b"}}}, {}, block);
+ AddOp("one_one", {{"input", {"a"}}}, {{"output", {"b"}}}, f::AttributeMap{},
+ block);
f::ProgramDesc *pdesc = program.Proto();
f::ProgramDesc pruned;
@@ -71,10 +72,14 @@ TEST(Prune, forward) {
f::ProgramDescBind program;
f::BlockDescBind *block = program.MutableBlock(0);
- AddOp("one_one", {{"input", {"a"}}}, {{"output", {"b"}}}, {}, block);
- AddOp("one_one", {{"input", {"b"}}}, {{"output", {"c"}}}, {}, block);
- AddOp("one_one", {{"input", {"c"}}}, {{"output", {"d"}}}, {}, block);
- AddOp("one_one", {{"input", {"d"}}}, {{"output", {"e"}}}, {}, block);
+ AddOp("one_one", {{"input", {"a"}}}, {{"output", {"b"}}}, f::AttributeMap{},
+ block);
+ AddOp("one_one", {{"input", {"b"}}}, {{"output", {"c"}}}, f::AttributeMap{},
+ block);
+ AddOp("one_one", {{"input", {"c"}}}, {{"output", {"d"}}}, f::AttributeMap{},
+ block);
+ AddOp("one_one", {{"input", {"d"}}}, {{"output", {"e"}}}, f::AttributeMap{},
+ block);
f::ProgramDesc *pdesc = program.Proto();
@@ -90,11 +95,14 @@ TEST(Prune, multi_input_op) {
f::ProgramDescBind program;
f::BlockDescBind *block = program.MutableBlock(0);
- AddOp("one_one", {{"input", {"a0"}}}, {{"output", {"b0"}}}, {}, block);
- AddOp("one_one", {{"input", {"a1"}}}, {{"output", {"b1"}}}, {}, block);
- AddOp("one_one", {{"input", {"a2"}}}, {{"output", {"b2"}}}, {}, block);
- AddOp("three_one", {{"input", {"b0", "b1", "b2"}}}, {{"output", {"c"}}}, {},
+ AddOp("one_one", {{"input", {"a0"}}}, {{"output", {"b0"}}}, f::AttributeMap{},
+ block);
+ AddOp("one_one", {{"input", {"a1"}}}, {{"output", {"b1"}}}, f::AttributeMap{},
block);
+ AddOp("one_one", {{"input", {"a2"}}}, {{"output", {"b2"}}}, f::AttributeMap{},
+ block);
+ AddOp("three_one", {{"input", {"b0", "b1", "b2"}}}, {{"output", {"c"}}},
+ f::AttributeMap{}, block);
f::ProgramDesc *pdesc = program.Proto();
pdesc->mutable_blocks(0)->mutable_ops(3)->set_is_target(true);
@@ -108,9 +116,12 @@ TEST(Prune, multi_output_op) {
f::ProgramDescBind program;
f::BlockDescBind *block = program.MutableBlock(0);
- AddOp("one_two", {{"input", {"a"}}}, {{"output", {"b", "c"}}}, {}, block);
- AddOp("one_one", {{"input", {"b"}}}, {{"output", {"b1"}}}, {}, block);
- AddOp("one_one", {{"input", {"c"}}}, {{"output", {"c1"}}}, {}, block);
+ AddOp("one_two", {{"input", {"a"}}}, {{"output", {"b", "c"}}},
+ f::AttributeMap{}, block);
+ AddOp("one_one", {{"input", {"b"}}}, {{"output", {"b1"}}}, f::AttributeMap{},
+ block);
+ AddOp("one_one", {{"input", {"c"}}}, {{"output", {"c1"}}}, f::AttributeMap{},
+ block);
f::ProgramDesc *pdesc = program.Proto();
pdesc->mutable_blocks(0)->mutable_ops(2)->set_is_target(true);
@@ -124,9 +135,12 @@ TEST(Prune, multi_target) {
f::ProgramDescBind program;
f::BlockDescBind *block = program.MutableBlock(0);
- AddOp("one_two", {{"input", {"a"}}}, {{"output", {"b", "c"}}}, {}, block);
- AddOp("one_one", {{"input", {"b"}}}, {{"output", {"b1"}}}, {}, block);
- AddOp("one_one", {{"input", {"c"}}}, {{"output", {"c1"}}}, {}, block);
+ AddOp("one_two", {{"input", {"a"}}}, {{"output", {"b", "c"}}},
+ f::AttributeMap{}, block);
+ AddOp("one_one", {{"input", {"b"}}}, {{"output", {"b1"}}}, f::AttributeMap{},
+ block);
+ AddOp("one_one", {{"input", {"c"}}}, {{"output", {"c1"}}}, f::AttributeMap{},
+ block);
f::ProgramDesc *pdesc = program.Proto();
pdesc->mutable_blocks(0)->mutable_ops(1)->set_is_target(true);
diff --git a/paddle/gserver/activations/ActivationFunction.cpp b/paddle/gserver/activations/ActivationFunction.cpp
index f5a41b66bf..57c890e488 100644
--- a/paddle/gserver/activations/ActivationFunction.cpp
+++ b/paddle/gserver/activations/ActivationFunction.cpp
@@ -24,7 +24,7 @@ limitations under the License. */
#include "paddle/utils/ClassRegistrar.h"
#include "paddle/utils/Logging.h"
-#ifdef PADDLE_USE_MKLDNN
+#ifdef PADDLE_WITH_MKLDNN
#include "MKLDNNActivation.h"
#endif
@@ -490,7 +490,7 @@ Error __must_check backward(Argument& act) {
END_DEFINE_ACTIVATION(log)
ActivationFunction* ActivationFunction::create(const std::string& type) {
-#ifdef PADDLE_USE_MKLDNN
+#ifdef PADDLE_WITH_MKLDNN
if (!type.empty() && type.compare(0, 7, "mkldnn_") == 0) {
return MKLDNNActivation::create(type);
}
diff --git a/paddle/gserver/gradientmachines/NeuralNetwork.cpp b/paddle/gserver/gradientmachines/NeuralNetwork.cpp
index be112b4123..68bf37d59d 100644
--- a/paddle/gserver/gradientmachines/NeuralNetwork.cpp
+++ b/paddle/gserver/gradientmachines/NeuralNetwork.cpp
@@ -20,7 +20,7 @@ limitations under the License. */
#include "paddle/utils/Logging.h"
#include "paddle/utils/Stat.h"
-#ifdef PADDLE_USE_MKLDNN
+#ifdef PADDLE_WITH_MKLDNN
#include "paddle/gserver/layers/MKLDNNLayer.h"
#endif
@@ -307,7 +307,7 @@ void NeuralNetwork::backward(const UpdateCallback& callback) {
}
void NeuralNetwork::finish() {
-#ifdef PADDLE_USE_MKLDNN
+#ifdef PADDLE_WITH_MKLDNN
FOR_EACH_R(layer, layers_) {
MKLDNNLayerPtr dnnLayer = std::dynamic_pointer_cast(*layer);
if (dnnLayer) {
diff --git a/paddle/gserver/layers/ConvTransProjection.cpp b/paddle/gserver/layers/ConvTransProjection.cpp
index 48132a3ce4..e7f081c023 100644
--- a/paddle/gserver/layers/ConvTransProjection.cpp
+++ b/paddle/gserver/layers/ConvTransProjection.cpp
@@ -24,13 +24,13 @@ size_t ConvTransProjection::calOutputSize() {
if (outputH_ == 0) outputH_ = configOutH_;
if (outputW_ == 0) outputW_ = configOutW_;
imageH_ = imageSize(outputH_,
- filterH_,
+ (filterH_ - 1) * dilationH_ + 1,
paddingH_,
strideH_,
/* caffeMode */ true);
imageW_ = imageSize(outputW_,
- filterW_,
+ (filterW_ - 1) * dilationW_ + 1,
paddingW_,
strideW_,
/* caffeMode */ true);
diff --git a/paddle/gserver/layers/MKLDNNLRNLayer.cpp b/paddle/gserver/layers/MKLDNNLRNLayer.cpp
new file mode 100644
index 0000000000..741984bb68
--- /dev/null
+++ b/paddle/gserver/layers/MKLDNNLRNLayer.cpp
@@ -0,0 +1,163 @@
+/* Copyright (c) 2017 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 "MKLDNNLRNLayer.h"
+#include "paddle/utils/Logging.h"
+
+using namespace mkldnn; // NOLINT
+typedef memory::format format;
+
+namespace paddle {
+
+REGISTER_LAYER(mkldnn_lrn, MKLDNNLRNLayer);
+
+bool MKLDNNLRNLayer::init(const LayerMap& layerMap,
+ const ParameterMap& parameterMap) {
+ if (!MKLDNNLayer::init(layerMap, parameterMap)) {
+ return false;
+ }
+
+ /* the size of inputs for norm-layer is 1 */
+ CHECK_EQ(config_.inputs_size(), 1UL);
+ const NormConfig& conf = config_.inputs(0).norm_conf();
+ localSize_ = conf.size();
+ alpha_ = conf.scale();
+ beta_ = conf.pow();
+
+ ic_ = conf.channels();
+ oc_ = ic_;
+ iw_ = conf.img_size();
+ ow_ = conf.output_x();
+ ih_ = conf.has_img_size_y() ? conf.img_size_y() : conf.img_size();
+ oh_ = conf.has_output_y() ? conf.output_y() : conf.output_x();
+ CHECK_EQ(iw_, ow_);
+ CHECK_EQ(ih_, oh_);
+ return true;
+}
+
+void MKLDNNLRNLayer::reshape(
+ int& bs, int& ic, int& ih, int& iw, int& oc, int& oh, int& ow) {
+ CHECK_EQ(inputLayers_.size(), 1UL);
+ reshapeInput(bs, ih, iw);
+ // ic_ and oc can not be changed
+ CHECK_EQ((size_t)ic,
+ inputLayers_[0]->getOutputValue()->getElementCnt() / bs / ih / iw)
+ << "Input channel can not be changed";
+ oh = ih;
+ ow = iw;
+ reshapeOutput(oh, ow);
+ resizeOutput(bs, oc * oh * ow);
+}
+
+void MKLDNNLRNLayer::resetFwd(std::vector& pipeline,
+ std::vector& inputs,
+ MKLDNNMatrixPtr& out) {
+ resetFwdBuffers(inputs[0], out);
+
+ resetFwdPD(fwdPD_, inputs[0], out);
+
+ resetFwdPipeline(pipeline, fwdPD_, inputs[0], out);
+}
+
+void MKLDNNLRNLayer::resetBwd(std::vector& pipeline,
+ std::vector& inputs,
+ MKLDNNMatrixPtr& out) {
+ std::shared_ptr pd;
+
+ resetBwdBuffers(inputs[0], out);
+
+ resetBwdPD(pd, inputs[0], out);
+
+ resetBwdPipeline(pipeline, pd, inputs[0], out);
+}
+
+void MKLDNNLRNLayer::resetFwdBuffers(MKLDNNMatrixPtr& in,
+ MKLDNNMatrixPtr& out) {
+ resetInValue(in);
+ CHECK(in);
+ resetOutValue(out, in->getPrimitiveDesc());
+}
+
+void MKLDNNLRNLayer::resetFwdPD(std::shared_ptr& pd,
+ MKLDNNMatrixPtr in,
+ MKLDNNMatrixPtr out) {
+ prop_kind pk = passType_ == PASS_TEST ? prop_kind::forward_scoring
+ : prop_kind::forward_training;
+ auto fwdDesc = lrn_fwd::desc(pk,
+ algorithm::lrn_across_channels,
+ in->getMemoryDesc(),
+ localSize_,
+ alpha_,
+ beta_,
+ 1.0f);
+ pd.reset(new lrn_fwd::primitive_desc(fwdDesc, engine_));
+ // prepare workspace if necessary
+ workspace_ =
+ passType_ != PASS_TEST
+ ? std::make_shared(memory(pd->workspace_primitive_desc()))
+ : nullptr;
+}
+
+void MKLDNNLRNLayer::resetFwdPipeline(
+ std::vector& pipeline,
+ std::shared_ptr& pd,
+ MKLDNNMatrixPtr& in,
+ MKLDNNMatrixPtr& out) {
+ fwd_ = workspace_
+ ? std::make_shared(lrn_fwd(*pd, *in, *workspace_, *out))
+ : std::make_shared(lrn_fwd(*pd, *in, *out));
+ pipeline.push_back(*fwd_);
+}
+
+void MKLDNNLRNLayer::resetBwdBuffers(MKLDNNMatrixPtr& in,
+ MKLDNNMatrixPtr& out) {
+ CHECK(inVals_[0] && outVal_);
+ resetOutGrad(out, outVal_->getPrimitiveDesc());
+ resetInGrad(in, inVals_[0]->getPrimitiveDesc());
+}
+
+void MKLDNNLRNLayer::resetBwdPD(std::shared_ptr& pd,
+ MKLDNNMatrixPtr& in,
+ MKLDNNMatrixPtr& out) {
+ pd = nullptr;
+ if (in == nullptr) {
+ return;
+ }
+ CHECK(out);
+ auto bwdDesc = lrn_bwd::desc(algorithm::lrn_across_channels,
+ in->getMemoryDesc(),
+ out->getMemoryDesc(),
+ localSize_,
+ alpha_,
+ beta_,
+ 1.0f);
+ pd.reset(new lrn_bwd::primitive_desc(bwdDesc, engine_, *fwdPD_));
+}
+
+void MKLDNNLRNLayer::resetBwdPipeline(
+ std::vector& pipeline,
+ std::shared_ptr& pd,
+ MKLDNNMatrixPtr& in,
+ MKLDNNMatrixPtr& out) {
+ if (pd == nullptr) {
+ return;
+ }
+ CHECK(inVals_[0]);
+ CHECK(workspace_);
+ bwdData_ = std::make_shared(
+ lrn_bwd(*pd, *inVals_[0], *out, *workspace_, *in));
+ pipeline.push_back(*bwdData_);
+}
+
+} // namespace paddle
diff --git a/paddle/gserver/layers/MKLDNNLRNLayer.h b/paddle/gserver/layers/MKLDNNLRNLayer.h
new file mode 100644
index 0000000000..cfe5621252
--- /dev/null
+++ b/paddle/gserver/layers/MKLDNNLRNLayer.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2017 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 "MKLDNNLayer.h"
+#include "mkldnn.hpp"
+
+namespace paddle {
+typedef mkldnn::lrn_forward lrn_fwd;
+typedef mkldnn::lrn_backward lrn_bwd;
+
+/**
+ * @brief A subclass of MKLDNNLayer LRN(Local Response Norm) layer.
+ *
+ * The config file api is mkldnn_lrn
+ */
+class MKLDNNLRNLayer : public MKLDNNLayer {
+protected:
+ // save forward primitive_desc, which can be used in backward
+ std::shared_ptr fwdPD_;
+ // according to https://github.com/01org/mkl-dnn/blob/master/tests/gtests/
+ // test_lrn_backward.cpp, lrn need workspace for backward
+ std::shared_ptr workspace_;
+
+ int localSize_;
+ float alpha_, beta_; // scale and pow in paddle
+
+public:
+ explicit MKLDNNLRNLayer(const LayerConfig& config) : MKLDNNLayer(config) {}
+
+ ~MKLDNNLRNLayer() {}
+
+ bool init(const LayerMap& layerMap,
+ const ParameterMap& parameterMap) override;
+
+ void reshape(
+ int& bs, int& ic, int& ih, int& iw, int& oc, int& oh, int& ow) override;
+
+ void resetFwd(std::vector& pipeline,
+ std::vector& inputs,
+ MKLDNNMatrixPtr& out) override;
+
+ void resetBwd(std::vector& pipeline,
+ std::vector& inputs,
+ MKLDNNMatrixPtr& out) override;
+
+protected:
+ void resetFwdBuffers(MKLDNNMatrixPtr& in, MKLDNNMatrixPtr& out);
+ void resetFwdPD(std::shared_ptr& pd,
+ MKLDNNMatrixPtr in,
+ MKLDNNMatrixPtr out);
+ void resetFwdPipeline(std::vector& pipeline,
+ std::shared_ptr& pd,
+ MKLDNNMatrixPtr& in,
+ MKLDNNMatrixPtr& out);
+ void resetBwdBuffers(MKLDNNMatrixPtr& in, MKLDNNMatrixPtr& out);
+ void resetBwdPD(std::shared_ptr& pd,
+ MKLDNNMatrixPtr& in,
+ MKLDNNMatrixPtr& out);
+ void resetBwdPipeline(std::vector& pipeline,
+ std::shared_ptr& pd,
+ MKLDNNMatrixPtr& in,
+ MKLDNNMatrixPtr& out);
+};
+
+} // namespace paddle
diff --git a/paddle/gserver/layers/PoolLayer.cpp b/paddle/gserver/layers/PoolLayer.cpp
index 87613a96c5..fceb389d06 100644
--- a/paddle/gserver/layers/PoolLayer.cpp
+++ b/paddle/gserver/layers/PoolLayer.cpp
@@ -45,6 +45,8 @@ bool PoolLayer::init(const LayerMap& layerMap,
strideY_ = conf.has_stride_y() ? conf.stride_y() : conf.stride();
confPaddingY_ = conf.has_padding_y() ? conf.padding_y() : conf.padding();
outputY_ = conf.has_output_y() ? conf.output_y() : conf.output_x();
+
+ excludeMode_ = conf.has_exclude_mode() ? conf.exclude_mode() : true;
return true;
}
diff --git a/paddle/gserver/layers/PoolLayer.h b/paddle/gserver/layers/PoolLayer.h
index d43292ad2d..9df672a935 100644
--- a/paddle/gserver/layers/PoolLayer.h
+++ b/paddle/gserver/layers/PoolLayer.h
@@ -38,6 +38,8 @@ protected:
std::string poolType_;
+ bool excludeMode_;
+
public:
explicit PoolLayer(const LayerConfig& config) : Layer(config) {}
diff --git a/paddle/gserver/layers/PoolProjection.cpp b/paddle/gserver/layers/PoolProjection.cpp
index d90b438448..6a9de394ce 100644
--- a/paddle/gserver/layers/PoolProjection.cpp
+++ b/paddle/gserver/layers/PoolProjection.cpp
@@ -36,6 +36,8 @@ PoolProjection::PoolProjection(const ProjectionConfig& config,
strideY_ = conf.has_stride_y() ? conf.stride_y() : conf.stride();
confPaddingY_ = conf.has_padding_y() ? conf.padding_y() : conf.padding();
outputY_ = conf.has_output_y() ? conf.output_y() : conf.output_x();
+
+ excludeMode_ = conf.has_exclude_mode() ? conf.exclude_mode() : true;
}
size_t PoolProjection::getSize() {
@@ -141,7 +143,8 @@ void AvgPoolProjection::forward() {
outputY_,
outputX_,
confPaddingY_,
- confPadding_);
+ confPadding_,
+ excludeMode_);
}
void AvgPoolProjection::backward(const UpdateCallback& callback) {
@@ -166,6 +169,7 @@ void AvgPoolProjection::backward(const UpdateCallback& callback) {
1,
1,
confPaddingY_,
- confPadding_);
+ confPadding_,
+ excludeMode_);
}
} // namespace paddle
diff --git a/paddle/gserver/layers/PoolProjection.h b/paddle/gserver/layers/PoolProjection.h
index 9a75f465f6..a0412714bc 100644
--- a/paddle/gserver/layers/PoolProjection.h
+++ b/paddle/gserver/layers/PoolProjection.h
@@ -28,6 +28,7 @@ protected:
int confPaddingY_, confPadding_;
size_t channels_;
std::string poolType_;
+ bool excludeMode_;
public:
PoolProjection(const ProjectionConfig& config,
diff --git a/paddle/gserver/tests/mkldnn_simple_net.conf b/paddle/gserver/tests/mkldnn_simple_net.conf
index 8bbe91e56d..0e9d6b31fa 100644
--- a/paddle/gserver/tests/mkldnn_simple_net.conf
+++ b/paddle/gserver/tests/mkldnn_simple_net.conf
@@ -51,6 +51,8 @@ tmp = img_pool_layer(input=tmp,
padding=1,
pool_type=MaxPooling())
+tmp = img_cmrnorm_layer(input=tmp, size=5, scale=0.0001, power=0.75)
+
tmp = fc_layer(input=tmp,
size=channels,
bias_attr=False,
diff --git a/paddle/gserver/tests/test_LayerGrad.cpp b/paddle/gserver/tests/test_LayerGrad.cpp
index c5359f272b..a2f07937b8 100644
--- a/paddle/gserver/tests/test_LayerGrad.cpp
+++ b/paddle/gserver/tests/test_LayerGrad.cpp
@@ -238,9 +238,24 @@ void testProjectionConv(size_t groups, bool isDeconv) {
/* caffeMode */ true);
conv->set_output_x(output_x);
conv->set_output_y(output_y);
+ LOG(INFO) << "DILATION:" << DILATION << "; output_x: " << output_x
+ << "; output_y: " << output_y;
if (isDeconv) {
+ int deconv_image_x = imageSize(output_x,
+ (conv->filter_size() - 1) * DILATION + 1,
+ conv->padding(),
+ conv->stride(),
+ /* caffeMode */ true);
+ int deconv_image_y = imageSize(output_y,
+ (conv->filter_size_y() - 1) * DILATION + 1,
+ conv->padding_y(),
+ conv->stride_y(),
+ /* caffeMode */ true);
+
+ LOG(INFO) << " deconv_image_x: " << deconv_image_x
+ << "; deconv_image_y: " << deconv_image_y;
conf.set_input_size(output_x * output_y * CHANNELS);
- conf.set_output_size(IMAGE_SIZE * IMAGE_SIZE * NUM_FILTERS);
+ conf.set_output_size(deconv_image_x * deconv_image_y * NUM_FILTERS);
} else {
conf.set_input_size(IMAGE_SIZE * IMAGE_SIZE * CHANNELS);
conf.set_output_size(output_x * output_y * NUM_FILTERS);
@@ -1211,7 +1226,10 @@ void setPoolConfig(TestConfig* config,
pool->set_output_y(oh);
}
-void testPoolLayer(const string& poolType, bool trans, bool useGpu) {
+void testPoolLayer(const string& poolType,
+ bool trans,
+ bool useGpu,
+ bool excludeMode = true) {
TestConfig config;
config.inputDefs.push_back({INPUT_DATA, "layer_0", 3136, 0});
LayerInputConfig* input = config.layerConfig.add_inputs();
@@ -1219,6 +1237,7 @@ void testPoolLayer(const string& poolType, bool trans, bool useGpu) {
pool->set_img_size(14);
pool->set_img_size_y(14);
+ pool->set_exclude_mode(excludeMode);
setPoolConfig(&config, pool, poolType);
config.layerConfig.set_size(pool->output_x() * pool->output_y() *
pool->channels());
@@ -1250,16 +1269,26 @@ void testPoolLayer2(const string& poolType, bool trans, bool useGpu) {
TEST(Layer, PoolLayer) {
testPoolLayer("avg-projection", /* trans= */ false, /* useGpu= */ false);
+ testPoolLayer("avg-projection",
+ /* trans= */ false,
+ /* useGpu= */ false,
+ /* excludeMode= */ false);
testPoolLayer("max-projection", /* trans= */ false, /* useGpu= */ false);
testPoolLayer("max-pool-with-mask", /* trans= */ false, /* useGpu= */ false);
#ifdef PADDLE_WITH_CUDA
testPoolLayer("avg-projection", /* trans= */ false, /* useGpu= */ true);
+ testPoolLayer("avg-projection",
+ /* trans= */ false,
+ /* useGpu= */ true,
+ /* excludeMode= */ false);
testPoolLayer("max-projection", /* trans= */ false, /* useGpu= */ true);
testPoolLayer("cudnn-max-pool", /* trans= */ false, /* useGpu= */ true);
testPoolLayer("cudnn-avg-pool", /* trans= */ false, /* useGpu= */ true);
testPoolLayer2("cudnn-max-pool", /* trans= */ false, /* useGpu= */ true);
testPoolLayer2("cudnn-avg-pool", /* trans= */ false, /* useGpu= */ true);
+ testPoolLayer2(
+ "cudnn-avg-incl-pad-pool", /* trans= */ false, /* useGpu= */ true);
testPoolLayer("max-pool-with-mask", /* trans= */ false, /* useGpu= */ true);
#endif
}
diff --git a/paddle/gserver/tests/test_MKLDNN.cpp b/paddle/gserver/tests/test_MKLDNN.cpp
index 56b523f220..ad1dbc3ee2 100644
--- a/paddle/gserver/tests/test_MKLDNN.cpp
+++ b/paddle/gserver/tests/test_MKLDNN.cpp
@@ -272,6 +272,51 @@ TEST(MKLDNNLayer, BatchNormLayer) {
testBatchNormLayer({4, 16, 8, 10});
}
+struct testLRNDesc {
+ int bs, ic, ih, iw;
+ float scale, pow;
+ int localSize;
+};
+
+void getMKLDNNLRNConfig(TestConfig& cfg, const testLRNDesc& pm) {
+ cfg.layerConfig.set_type("mkldnn_lrn");
+ cfg.layerConfig.set_active_type("relu");
+ size_t layerSize = pm.ic * pm.ih * pm.iw;
+ cfg.inputDefs.push_back({INPUT_DATA, "layer_0", layerSize, 0});
+ LayerInputConfig* input = cfg.layerConfig.add_inputs();
+ NormConfig* norm = input->mutable_norm_conf();
+ norm->set_channels(pm.ic);
+ norm->set_size(pm.localSize);
+ norm->set_scale(pm.scale);
+ norm->set_pow(pm.pow);
+ norm->set_blocked(0);
+ norm->set_img_size(pm.iw);
+ norm->set_img_size_y(pm.ih);
+ norm->set_output_x(norm->img_size());
+ norm->set_output_y(norm->img_size_y());
+ cfg.layerConfig.set_size(layerSize);
+ cfg.biasSize = 0;
+}
+
+void testLRNLayer(const testLRNDesc& pm) {
+ TestConfig dnnConfig;
+ getMKLDNNLRNConfig(dnnConfig, pm);
+ // mkldnn_lrn <==> norm with cmrnorm-projection type
+ TestConfig refConfig = dnnConfig;
+ refConfig.layerConfig.set_type("norm");
+ LayerInputConfig* input = refConfig.layerConfig.mutable_inputs(0);
+ NormConfig* norm = input->mutable_norm_conf();
+ norm->set_norm_type("cmrnorm-projection");
+ norm->set_scale(norm->scale() / norm->size());
+ RUN_MKLDNN_TEST(dnnConfig, refConfig, pm)
+}
+
+TEST(MKLDNNLayer, LRNLayer) {
+ testLRNLayer({4, 10, 12, 12, 0.001f, 0.75f, 5});
+ testLRNLayer({2, 32, 6, 6, 0.001f, 0.75f, 5});
+ testLRNLayer({4, 16, 8, 10, 0.01f, 0.5f, 5});
+}
+
struct testImageDesc {
int bs, ic, ih, iw;
};
diff --git a/paddle/math/Allocator.h b/paddle/math/Allocator.h
index 94ef561f06..17563bf5e1 100644
--- a/paddle/math/Allocator.h
+++ b/paddle/math/Allocator.h
@@ -48,7 +48,7 @@ public:
*/
virtual void* alloc(size_t size) {
void* ptr;
-#ifdef PADDLE_USE_MKLDNN
+#ifdef PADDLE_WITH_MKLDNN
// refer to https://github.com/01org/mkl-dnn/blob/master/include/mkldnn.hpp
// memory alignment
CHECK_EQ(posix_memalign(&ptr, 4096ul, size), 0);
diff --git a/paddle/math/MathFunctions.cpp b/paddle/math/MathFunctions.cpp
index ba86eacbb5..28ab54b450 100644
--- a/paddle/math/MathFunctions.cpp
+++ b/paddle/math/MathFunctions.cpp
@@ -206,7 +206,7 @@ double dotProduct(const int n, const double* x, const double* y) {
}
#endif
-#if defined(PADDLE_USE_MKLML)
+#if defined(PADDLE_WITH_MKLML)
template <>
void vExp(const int n, const float* a, float* r) {
diff --git a/paddle/math/MathFunctions.h b/paddle/math/MathFunctions.h
index f6e77029bd..29fe36e3a4 100644
--- a/paddle/math/MathFunctions.h
+++ b/paddle/math/MathFunctions.h
@@ -15,7 +15,7 @@ limitations under the License. */
#ifndef MATHFUNCTIONS_H_
#define MATHFUNCTIONS_H_
-#ifdef PADDLE_USE_MKLML
+#ifdef PADDLE_WITH_MKLML
#include
#include
#include
diff --git a/paddle/math/Matrix.cpp b/paddle/math/Matrix.cpp
index 88e9180690..1ec4336cab 100644
--- a/paddle/math/Matrix.cpp
+++ b/paddle/math/Matrix.cpp
@@ -28,6 +28,7 @@ limitations under the License. */
#include "hl_top_k.h"
#include "paddle/utils/Logging.h"
+#include "NEONFunctions.h"
#include "paddle/function/GemmFunctor.h"
#include "paddle/utils/ThreadLocal.h"
@@ -1130,7 +1131,8 @@ void GpuMatrix::avgPoolForward(Matrix& inputMat,
size_t outputH,
size_t outputW,
size_t paddingH,
- size_t paddingW) {
+ size_t paddingW,
+ bool excludeMode) {
CHECK(inputMat.useGpu_ == true) << "Matrix type are not equal";
real* inputData = inputMat.getData();
@@ -1153,7 +1155,8 @@ void GpuMatrix::avgPoolForward(Matrix& inputMat,
paddingH,
paddingW,
data_,
- getStride());
+ getStride(),
+ excludeMode);
}
void GpuMatrix::avgPoolBackward(Matrix& outGrad,
@@ -1168,7 +1171,8 @@ void GpuMatrix::avgPoolBackward(Matrix& outGrad,
real scaleTargets,
real scaleOutput,
size_t paddingH,
- size_t paddingW) {
+ size_t paddingW,
+ bool excludeMode) {
CHECK(outGrad.useGpu_ == true) << "Matrix type are not equal";
real* outDiff = outGrad.getData();
@@ -1194,7 +1198,8 @@ void GpuMatrix::avgPoolBackward(Matrix& outGrad,
scaleTargets,
scaleOutput,
data_,
- outGrad.getStride());
+ outGrad.getStride(),
+ excludeMode);
}
void GpuMatrix::maxPool3DForward(Matrix& inputMat,
@@ -2136,7 +2141,8 @@ void CpuMatrix::avgPoolForward(Matrix& input,
size_t outputH,
size_t outputW,
size_t paddingH,
- size_t paddingW) {
+ size_t paddingW,
+ bool excludeMode) {
// The main loop
size_t num = input.getHeight();
size_t inLength = imgSizeH * imgSizeW;
@@ -2165,7 +2171,8 @@ void CpuMatrix::avgPoolForward(Matrix& input,
tgtData[ph * outputW + pw] += inData[h * imgSizeW + w];
}
}
- int poolSize = (hend - hstart) * (wend - wstart);
+ int poolSize =
+ excludeMode ? (hend - hstart) * (wend - wstart) : sizeY * sizeX;
CHECK(poolSize);
tgtData[ph * outputW + pw] /= poolSize;
}
@@ -2189,7 +2196,8 @@ void CpuMatrix::avgPoolBackward(Matrix& input,
real scaleTargets,
real scaleOutput,
size_t paddingH,
- size_t paddingW) {
+ size_t paddingW,
+ bool excludeMode) {
size_t num = input.getHeight();
size_t channels = input.getWidth() / outputH / outputW;
size_t inLength = imgSizeH * imgSizeW;
@@ -2211,7 +2219,8 @@ void CpuMatrix::avgPoolBackward(Matrix& input,
int wstart = pw * strideW - paddingW;
int wend = std::min(wstart + sizeX, imgSizeW);
wstart = std::max(wstart, 0);
- int poolSize = (hend - hstart) * (wend - wstart);
+ int poolSize =
+ excludeMode ? (hend - hstart) * (wend - wstart) : sizeY * sizeX;
CHECK(poolSize);
for (int h = hstart; h < hend; ++h) {
@@ -4157,16 +4166,36 @@ void CpuMatrix::print(std::ostream& os) const {
void CpuMatrix::paramReluForward(Matrix& data, Matrix& W) {
real* input = data.getData();
real* w = W.getData();
+ real* output = data_;
size_t numElements = data.getWidth();
size_t numSamples = data.getHeight();
size_t paraSize = W.getHeight() * W.getWidth();
CHECK(!(numElements % paraSize)); // this check from ParameterReluLayer::init
+
size_t partial_sum = numElements / paraSize;
+ if (paraSize == numElements) {
+ for (size_t n = 0; n < numSamples * numElements; ++n) {
+ output[n] = input[n] > 0 ? input[n] : input[n] * w[n % numElements];
+ }
+ return;
+ }
+
+#if defined(__ARM_NEON__) || defined(__ARM_NEON)
+ for (size_t n = 0; n < numSamples; ++n) {
+ for (size_t i = 0; i < paraSize; i++) {
+ neon::prelu(
+ input + i * partial_sum, w[i], output + i * partial_sum, partial_sum);
+ }
+ input = input + numElements;
+ output = output + numElements;
+ }
+#else
for (size_t n = 0, k = 0; n < numSamples; ++n) {
for (size_t i = 0; i < numElements; ++i, ++k) {
- data_[k] = input[k] > 0 ? input[k] : input[k] * w[i / partial_sum];
+ output[k] = input[k] > 0 ? input[k] : input[k] * w[i / partial_sum];
}
}
+#endif
}
void CpuMatrix::paramReluBackwardW(Matrix& oGrad, Matrix& data) {
diff --git a/paddle/math/Matrix.h b/paddle/math/Matrix.h
index e273f11236..c8e690e642 100644
--- a/paddle/math/Matrix.h
+++ b/paddle/math/Matrix.h
@@ -911,7 +911,8 @@ public:
size_t outputH,
size_t outputW,
size_t paddingH,
- size_t paddingW) {
+ size_t paddingW,
+ bool excludeMode = true) {
LOG(FATAL) << "Not implemeted";
}
@@ -927,9 +928,11 @@ public:
real scaleTargets,
real scaleOutput,
size_t paddingH,
- size_t paddingW) {
+ size_t paddingW,
+ bool excludeMode = true) {
LOG(FATAL) << "Not implemeted";
}
+
/**
* Pooling 3D forward operation, pick out the largest element
* in the sizeX of value
@@ -1458,7 +1461,8 @@ public:
size_t outputH,
size_t outputW,
size_t paddingH,
- size_t paddingW);
+ size_t paddingW,
+ bool excludeMode = true);
void avgPoolBackward(Matrix& input,
size_t imgSizeH,
@@ -1472,7 +1476,8 @@ public:
real scaleTargets,
real scaleOutput,
size_t paddingH,
- size_t paddingW);
+ size_t paddingW,
+ bool excludeMode = true);
void maxPool3DForward(Matrix& inputMat,
Matrix& maxPoolIdx,
@@ -1730,7 +1735,8 @@ public:
size_t outputH,
size_t outputW,
size_t paddingH,
- size_t paddingW);
+ size_t paddingW,
+ bool excludeMode = true);
void avgPoolBackward(Matrix& input,
size_t imgSizeH,
@@ -1744,7 +1750,8 @@ public:
real scaleTargets,
real scaleOutput,
size_t paddingH,
- size_t paddingW);
+ size_t paddingW,
+ bool excludeMode = true);
void maxPool3DForward(Matrix& inputMat,
Matrix& maxPoolIdx,
diff --git a/paddle/math/NEONFunctions.cpp b/paddle/math/NEONFunctions.cpp
index 3bf47901f1..0f83149422 100644
--- a/paddle/math/NEONFunctions.cpp
+++ b/paddle/math/NEONFunctions.cpp
@@ -49,6 +49,46 @@ void relu(const float* a, float* b, int len) {
}
}
+// b[i] = a[i] > 0.0f ? a[i] : a[i] * w
+void prelu(const float* a, float w, float* b, int len) {
+ int offset = len % 16;
+ float32x4_t ma0, ma1, ma2, ma3;
+
+ float32x4_t zero = vdupq_n_f32(0.f);
+ float32x4_t vw = vdupq_n_f32(w);
+
+ for (int k = 0; k < len / 16; k++, a += 16, b += 16) {
+ ma0 = vld1q_f32(a);
+ ma1 = vld1q_f32(a + 4);
+ ma2 = vld1q_f32(a + 8);
+ ma3 = vld1q_f32(a + 12);
+
+ uint32x4_t flag0 = vcgtq_f32(ma0, zero);
+ uint32x4_t flag1 = vcgtq_f32(ma1, zero);
+ uint32x4_t flag2 = vcgtq_f32(ma2, zero);
+ uint32x4_t flag3 = vcgtq_f32(ma3, zero);
+
+ float32x4_t mul0 = vmulq_f32(ma0, vw);
+ float32x4_t mul1 = vmulq_f32(ma1, vw);
+ float32x4_t mul2 = vmulq_f32(ma2, vw);
+ float32x4_t mul3 = vmulq_f32(ma3, vw);
+
+ ma0 = vbslq_f32(flag0, ma0, mul0);
+ ma1 = vbslq_f32(flag1, ma1, mul1);
+ ma2 = vbslq_f32(flag2, ma2, mul2);
+ ma3 = vbslq_f32(flag3, ma3, mul3);
+
+ vst1q_f32(b, ma0);
+ vst1q_f32(b + 4, ma1);
+ vst1q_f32(b + 8, ma2);
+ vst1q_f32(b + 12, ma3);
+ }
+
+ for (int i = 0; i < offset; i++) {
+ b[i] = a[i] > 0.0f ? a[i] : a[i] * w;
+ }
+}
+
} // namespace neon
} // namespace paddle
diff --git a/paddle/math/NEONFunctions.h b/paddle/math/NEONFunctions.h
index 69085e3335..d67b2f47a8 100644
--- a/paddle/math/NEONFunctions.h
+++ b/paddle/math/NEONFunctions.h
@@ -18,6 +18,7 @@ namespace paddle {
namespace neon {
void relu(const float* a, float* b, int len);
+void prelu(const float* a, float w, float* b, int len);
} // namespace neon
} // namespace paddle
diff --git a/paddle/math/float16.h b/paddle/math/float16.h
new file mode 100644
index 0000000000..76ad3a0123
--- /dev/null
+++ b/paddle/math/float16.h
@@ -0,0 +1,739 @@
+/* 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
+
+#ifdef PADDLE_WITH_CUDA
+#include
+#endif // PADDLE_WITH_CUDA
+
+#include "unsupported/Eigen/CXX11/Tensor"
+
+#include "paddle/platform/hostdevice.h"
+
+#ifdef __GNUC__
+#define PADDLE_GNUC_VER (__GNUC__ * 10 + __GNUC_MINOR__)
+#else
+#define PADDLE_GNUC_VER 0
+#endif // __GNUC__
+
+#ifdef __clang__
+#define PADDLE_CLANG_VER (__clang_major__ * 10 + __clang_minor__)
+#else
+#define PADDLE_CLANG_VER 0
+#endif // __clang__
+
+#if defined(__CUDACC__) && CUDA_VERSION >= 7050
+#define PADDLE_CUDA_FP16
+#include
+#endif
+
+#if defined(__arm__) || defined(__aarch64__)
+#define PADDLE_ARM
+#endif
+
+#if defined(__ARM_NEON) || defined(__ARM_NEON__)
+#define PADDLE_NEON
+#include
+#endif
+
+#if defined(PADDLE_NEON) && defined(PADDLE_ARM_FP16) && \
+ (PADDLE_GNUC_VER >= 62 || PADDLE_CLANG_VER >= 37)
+#define PADDLE_WITH_NATIVE_FP16
+#endif
+
+#ifndef PADDLE_ARM
+#include
+#endif // PADDLE_ARM
+
+#define PADDLE_ALIGN(x) __attribute__((aligned(x)))
+
+namespace paddle {
+
+// Use PADDLE_ALIGNED(2) to ensure that each float16 will be allocated
+// and aligned at least on a 2-byte boundary, which leads to efficient
+// memory access of float16 struct and also makes float16 compatible
+// with CUDA half, ARM float16_t, and Eigen::half data types.
+struct PADDLE_ALIGN(2) float16 {
+public:
+ uint16_t x;
+
+ // Constructors
+ HOSTDEVICE inline float16() : x(0) {}
+
+ HOSTDEVICE inline float16(const float16& h) : x(h.x) {}
+
+#ifdef PADDLE_CUDA_FP16
+ HOSTDEVICE inline explicit float16(const half& h) {
+#if CUDA_VERSION >= 9000
+ x = reinterpret_cast<__half_raw*>(&h)->x;
+#else
+ x = h.x;
+#endif // CUDA_VERSION >= 9000
+ }
+#endif // PADDLE_CUDA_FP16
+
+ HOSTDEVICE inline explicit float16(const Eigen::half& h) : x(h.x) {}
+
+#ifdef PADDLE_WITH_NATIVE_FP16
+ // __fp16 is a native half precision data type for arm cpu,
+ // float16_t is an alias for __fp16
+ HOSTDEVICE inline explicit float16(const float16_t& h) {
+ x = *reinterpret_cast(&h);
+ }
+#endif
+
+ HOSTDEVICE inline explicit float16(float val) {
+#if defined(PADDLE_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300
+ half tmp = __float2half(val);
+ x = *reinterpret_cast(&tmp);
+
+#elif defined(PADDLE_WITH_NATIVE_FP16)
+ float32x4_t tmp = vld1q_dup_f32(&val);
+ float16_t res = vget_lane_f16(vcvt_f16_f32(tmp), 0);
+ x = *reinterpret_cast(&res);
+
+#elif defined(__F16C__)
+ x = _cvtss_sh(val, 0);
+
+#else
+ // Conversion routine adapted from
+ // http://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion
+ Bits v, s;
+ v.f = val;
+ uint32_t sign = v.si & sigN;
+ v.si ^= sign;
+ sign >>= shiftSign; // logical shift
+ s.si = mulN;
+ s.si = s.f * v.f; // correct subnormals
+ v.si ^= (s.si ^ v.si) & -(minN > v.si);
+ v.si ^= (infN ^ v.si) & -((infN > v.si) & (v.si > maxN));
+ v.si ^= (nanN ^ v.si) & -((nanN > v.si) & (v.si > infN));
+ v.ui >>= shift; // logical shift
+ v.si ^= ((v.si - maxD) ^ v.si) & -(v.si > maxC);
+ v.si ^= ((v.si - minD) ^ v.si) & -(v.si > subC);
+ x = v.ui | sign;
+
+#endif
+ }
+
+ HOSTDEVICE inline explicit float16(bool b) : x(b ? 0x3c00 : 0) {}
+
+ template
+ HOSTDEVICE inline explicit float16(const T& val)
+ : x(float16(static_cast(val)).x) {}
+
+ HOSTDEVICE inline float16& operator=(const float16& rhs) {
+ x = rhs.x;
+ return *this;
+ }
+
+// Assignment operators
+#ifdef PADDLE_CUDA_FP16
+ HOSTDEVICE inline float16& operator=(const half& rhs) {
+#if CUDA_VERSION >= 9000
+ x = reinterpret_cast<__half_raw*>(&rhs)->x;
+#else
+ x = rhs.x;
+#endif
+ return *this;
+ }
+#endif
+
+ HOSTDEVICE inline float16& operator=(const Eigen::half& rhs) {
+ x = rhs.x;
+ return *this;
+ }
+
+#ifdef PADDLE_WITH_NATIVE_FP16
+ HOSTDEVICE inline float16& operator=(const float16_t& rhs) {
+ x = *reinterpret_cast(&rhs);
+ return *this;
+ }
+#endif
+
+ HOSTDEVICE inline float16& operator=(bool b) {
+ x = b ? 0x3c00 : 0;
+ return *this;
+ }
+
+ HOSTDEVICE inline float16& operator=(int8_t val) {
+ x = float16(val).x;
+ return *this;
+ }
+
+ HOSTDEVICE inline float16& operator=(uint8_t val) {
+ x = float16(val).x;
+ return *this;
+ }
+
+ HOSTDEVICE inline float16& operator=(int16_t val) {
+ x = float16(val).x;
+ return *this;
+ }
+
+ HOSTDEVICE inline float16& operator=(uint16_t val) {
+ x = float16(val).x;
+ return *this;
+ }
+
+ HOSTDEVICE inline float16& operator=(int32_t val) {
+ x = float16(val).x;
+ return *this;
+ }
+
+ HOSTDEVICE inline float16& operator=(uint32_t val) {
+ x = float16(val).x;
+ return *this;
+ }
+
+ HOSTDEVICE inline float16& operator=(int64_t val) {
+ x = float16(val).x;
+ return *this;
+ }
+
+ HOSTDEVICE inline float16& operator=(uint64_t val) {
+ x = float16(val).x;
+ return *this;
+ }
+
+ HOSTDEVICE inline float16& operator=(float val) {
+ x = float16(val).x;
+ return *this;
+ }
+
+ HOSTDEVICE inline float16& operator=(double val) {
+ x = float16(val).x;
+ return *this;
+ }
+
+// Conversion opertors
+#ifdef PADDLE_CUDA_FP16
+ HOSTDEVICE inline explicit operator half() const {
+#if CUDA_VERSION >= 9000
+ __half_raw h;
+ h.x = x;
+ return half(h);
+#else
+ half h;
+ h.x = x;
+ return h;
+#endif // CUDA_VERSION >= 9000
+ }
+#endif // PADDLE_CUDA_FP16
+
+ HOSTDEVICE inline explicit operator Eigen::half() const {
+ Eigen::half h;
+ h.x = x;
+ return h;
+ }
+
+#ifdef PADDLE_WITH_NATIVE_FP16
+ HOSTDEVICE inline explicit operator float16_t() const {
+ return *reinterpret_cast(this);
+ }
+#endif
+
+ HOSTDEVICE inline explicit operator float() const {
+#if defined(PADDLE_CUDA_FP16) && defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300
+ half tmp = *reinterpret_cast(this);
+ return __half2float(tmp);
+
+#elif defined(PADDLE_WITH_NATIVE_FP16)
+ float16x4_t res = vld1_dup_f16(reinterpret_cast(this));
+ return vgetq_lane_f32(vcvt_f32_f16(res), 0);
+
+#elif defined(__F16C__)
+ return _cvtsh_ss(this->x);
+
+#else
+ // Conversion routine adapted from
+ // http://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion
+ Bits v;
+ v.ui = this->x;
+ int32_t sign = v.si & sigC;
+ v.si ^= sign;
+ sign <<= shiftSign;
+ v.si ^= ((v.si + minD) ^ v.si) & -(v.si > subC);
+ v.si ^= ((v.si + maxD) ^ v.si) & -(v.si > maxC);
+ Bits s;
+ s.si = mulC;
+ s.f *= v.si;
+ int32_t mask = -(norC > v.si);
+ v.si <<= shift;
+ v.si ^= (s.si ^ v.si) & mask;
+ v.si |= sign;
+ return v.f;
+
+#endif
+ }
+
+ HOSTDEVICE inline explicit operator bool() const { return (x & 0x7fff) != 0; }
+
+ HOSTDEVICE inline explicit operator int8_t() const {
+ return static_cast(float(*this));
+ }
+
+ HOSTDEVICE inline explicit operator uint8_t() const {
+ return static_cast(float(*this));
+ }
+
+ HOSTDEVICE inline explicit operator int16_t() const {
+ return static_cast(float(*this));
+ }
+
+ HOSTDEVICE inline explicit operator uint16_t() const {
+ return static_cast(float(*this));
+ }
+
+ HOSTDEVICE inline explicit operator int32_t() const {
+ return static_cast(float(*this));
+ }
+
+ HOSTDEVICE inline explicit operator uint32_t() const {
+ return static_cast(float(*this));
+ }
+
+ HOSTDEVICE inline explicit operator int64_t() const {
+ return static_cast(float(*this));
+ }
+
+ HOSTDEVICE inline explicit operator uint64_t() const {
+ return static_cast(float(*this));
+ }
+
+ HOSTDEVICE inline explicit operator double() const {
+ return static_cast(float(*this));
+ }
+
+private:
+ union Bits {
+ float f;
+ int32_t si;
+ uint32_t ui;
+ };
+
+ static const int shift = 13;
+ static const int shiftSign = 16;
+
+ static const int32_t infN = 0x7F800000;
+ static const int32_t maxN = 0x477FE000; // max flt16 as flt32
+ static const int32_t minN = 0x38800000; // min flt16 normal as flt32
+ static const int32_t sigN = 0x80000000; // sign bit
+
+ static constexpr int32_t infC = infN >> shift;
+ static constexpr int32_t nanN = (infC + 1)
+ << shift; // minimum flt16 nan as float32
+ static constexpr int32_t maxC = maxN >> shift;
+ static constexpr int32_t minC = minN >> shift;
+ static constexpr int32_t sigC = sigN >> shiftSign;
+
+ static const int32_t mulN = 0x52000000; // (1 << 23) / minN
+ static const int32_t mulC = 0x33800000; // minN / (1 << (23 - shift))
+ static const int32_t subC = 0x003FF; // max flt32 subnormal downshifted
+ static const int32_t norC = 0x00400; // min flt32 normal downshifted
+
+ static constexpr int32_t maxD = infC - maxC - 1;
+ static constexpr int32_t minD = minC - subC - 1;
+};
+
+// Arithmetic operators on GPU
+// CUDA 9.0 provides built-in arithmetic operators for half while
+// CUDA 7.5 and 8.0 do not. The arithmetic operators defined here are
+// for users to write similar CUDA code in CUDA 7.5 and 8.0 as in
+// CUDA 9.0 regarding the half data type.
+#if defined(PADDLE_CUDA_FP16) && CUDA_VERSION < 9000
+
+DEVICE inline half operator+(const half& a, const half& b) {
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
+ return __hadd(a, b);
+#else
+ float res = float(float16(a)) + float(float16(b));
+ return half(float16(res));
+#endif
+}
+
+DEVICE inline half operator-(const half& a, const half& b) {
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
+ return __hsub(a, b);
+#else
+ float res = float(float16(a)) - float(float16(b));
+ return half(float16(res));
+#endif
+}
+
+DEVICE inline half operator*(const half& a, const half& b) {
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
+ return __hmul(a, b);
+#else
+ float res = float(float16(a)) * float(float16(b));
+ return half(float16(res));
+#endif
+}
+
+DEVICE inline half operator/(const half& a, const half& b) {
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 300
+ float num = __half2float(a);
+ float denom = __half2float(b);
+ return __float2half(num / denom);
+#else
+ float res = float(float16(a)) / float(float16(b));
+ return half(float16(res));
+#endif
+}
+
+DEVICE inline half operator-(const half& a) {
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
+ return __hneg(a);
+#else
+ float res = -float(float16(a));
+ return half(float16(res));
+#endif
+}
+
+DEVICE inline half& operator+=(half& a, const half& b) {
+ a = a + b;
+ return a;
+}
+
+DEVICE inline half& operator-=(half& a, const half& b) {
+ a = a - b;
+ return a;
+}
+
+DEVICE inline half& operator*=(half& a, const half& b) {
+ a = a * b;
+ return a;
+}
+
+DEVICE inline half& operator/=(half& a, const half& b) {
+ a = a / b;
+ return a;
+}
+
+DEVICE inline bool operator==(const half& a, const half& b) {
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
+ return __heq(a, b);
+#else
+ return float(float16(a)) == float(float16(b));
+#endif
+}
+
+DEVICE inline bool operator!=(const half& a, const half& b) {
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
+ return __hne(a, b);
+#else
+ return float(float16(a)) != float(float16(b));
+#endif
+}
+
+DEVICE inline bool operator<(const half& a, const half& b) {
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
+ return __hlt(a, b);
+#else
+ return float(float16(a)) < float(float16(b));
+#endif
+}
+
+DEVICE inline bool operator<=(const half& a, const half& b) {
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
+ return __hle(a, b);
+#else
+ return float(float16(a)) <= float(float16(b));
+#endif
+}
+
+DEVICE inline bool operator>(const half& a, const half& b) {
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
+ return __hgt(a, b);
+#else
+ return float(float16(a)) > float(float16(b));
+#endif
+}
+
+DEVICE inline bool operator>=(const half& a, const half& b) {
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 530
+ return __hge(a, b);
+#else
+ return float(float16(a)) >= float(float16(b));
+#endif
+}
+
+#endif // PADDLE_CUDA_FP16
+
+// Arithmetic operators on ARMv8.2-A CPU
+#if defined(PADDLE_WITH_NATIVE_FP16)
+HOST inline float16 operator+(const float16& a, const float16& b) {
+ float16 res;
+ asm volatile(
+ "ld1 {v0.h}[0], [%[a_ptr]]\n"
+ "ld1 {v1.h}[0], [%[b_ptr]]\n"
+ "fadd h0, h0, h1\n"
+ "st1 {v0.h}[0], [%[res_ptr]]\n"
+ : // outputs
+ : // inputs
+ [a_ptr] "r"(&(a.x)),
+ [b_ptr] "r"(&(b.x)),
+ [res_ptr] "r"(&(res.x))
+ : // clobbers
+ "memory", "v0", "v1");
+ return res;
+}
+
+HOST inline float16 operator-(const float16& a, const float16& b) {
+ float16 res;
+ asm volatile(
+ "ld1 {v0.h}[0], [%[a_ptr]]\n"
+ "ld1 {v1.h}[0], [%[b_ptr]]\n"
+ "fsub h0, h0, h1\n"
+ "st1 {v0.h}[0], [%[res_ptr]]\n"
+ : // outputs
+ : // inputs
+ [a_ptr] "r"(&(a.x)),
+ [b_ptr] "r"(&(b.x)),
+ [res_ptr] "r"(&(res.x))
+ : // clobbers
+ "memory", "v0", "v1");
+ return res;
+}
+
+HOST inline float16 operator*(const float16& a, const float16& b) {
+ float16 res;
+ asm volatile(
+ "ld1 {v0.h}[0], [%[a_ptr]]\n"
+ "ld1 {v1.h}[0], [%[b_ptr]]\n"
+ "fmul h0, h0, h1\n"
+ "st1 {v0.h}[0], [%[res_ptr]]\n"
+ : // outputs
+ : // inputs
+ [a_ptr] "r"(&(a.x)),
+ [b_ptr] "r"(&(b.x)),
+ [res_ptr] "r"(&(res.x))
+ : // clobbers
+ "memory", "v0", "v1");
+ return res;
+}
+
+HOST inline float16 operator/(const float16& a, const float16& b) {
+ float16 res;
+ asm volatile(
+ "ld1 {v0.h}[0], [%[a_ptr]]\n"
+ "ld1 {v1.h}[0], [%[b_ptr]]\n"
+ "fdiv h0, h0, h1\n"
+ "st1 {v0.h}[0], [%[res_ptr]]\n"
+ : // outputs
+ : // inputs
+ [a_ptr] "r"(&(a.x)),
+ [b_ptr] "r"(&(b.x)),
+ [res_ptr] "r"(&(res.x))
+ : // clobbers
+ "memory", "v0", "v1");
+ return res;
+}
+
+HOST inline float16 operator-(const float16& a) {
+ float16 res;
+ asm volatile(
+ "ld1 {v0.h}[0], [%[a_ptr]]\n"
+ "fneg h0, h0\n"
+ "st1 {v0.h}[0], [%[res_ptr]]\n"
+ : // outputs
+ : // inputs
+ [a_ptr] "r"(&(a.x)),
+ [res_ptr] "r"(&(res.x))
+ : // clobbers
+ "memory", "v0");
+ return res;
+}
+
+HOST inline float16& operator+=(float16& a, const float16& b) {
+ a = a + b;
+ return a;
+}
+
+HOST inline float16& operator-=(float16& a, const float16& b) {
+ a = a - b;
+ return a;
+}
+
+HOST inline float16& operator*=(float16& a, const float16& b) {
+ a = a * b;
+ return a;
+}
+
+HOST inline float16& operator/=(float16& a, const float16& b) {
+ a = a / b;
+ return a;
+}
+
+HOST inline bool operator==(const float16& a, const float16& b) {
+ uint16_t res;
+ asm volatile(
+ "ld1 {v0.h}[0], [%[a_ptr]]\n"
+ "ld1 {v1.h}[0], [%[b_ptr]]\n"
+ "fcmeq h0, h0, h1\n"
+ "st1 {v0.h}[0], [%[res_ptr]]\n"
+ : // outputs
+ : // inputs
+ [a_ptr] "r"(&(a.x)),
+ [b_ptr] "r"(&(b.x)),
+ [res_ptr] "r"(&res)
+ : // clobbers
+ "memory", "v0", "v1");
+ return (res & 0xffff) != 0;
+}
+
+HOST inline bool operator!=(const float16& a, const float16& b) {
+ return !(a == b);
+}
+
+HOST inline bool operator<(const float16& a, const float16& b) {
+ uint16_t res;
+ asm volatile(
+ "ld1 {v1.h}[0], [%[a_ptr]]\n"
+ "ld1 {v0.h}[0], [%[b_ptr]]\n"
+ "fcmgt h0, h0, h1\n"
+ "st1 {v0.h}[0], [%[res_ptr]]\n"
+ : // outputs
+ : // inputs
+ [a_ptr] "r"(&(a.x)),
+ [b_ptr] "r"(&(b.x)),
+ [res_ptr] "r"(&res)
+ : // clobbers
+ "memory", "v0", "v1");
+ return (res & 0xffff) != 0;
+}
+
+HOST inline bool operator<=(const float16& a, const float16& b) {
+ uint16_t res;
+ asm volatile(
+ "ld1 {v1.h}[0], [%[a_ptr]]\n"
+ "ld1 {v0.h}[0], [%[b_ptr]]\n"
+ "fcmge h0, h0, h1\n"
+ "st1 {v0.h}[0], [%[res_ptr]]\n"
+ : // outputs
+ : // inputs
+ [a_ptr] "r"(&(a.x)),
+ [b_ptr] "r"(&(b.x)),
+ [res_ptr] "r"(&res)
+ : // clobbers
+ "memory", "v0", "v1");
+ return (res & 0xffff) != 0;
+}
+
+HOST inline bool operator>(const float16& a, const float16& b) {
+ uint16_t res;
+ asm volatile(
+ "ld1 {v0.h}[0], [%[a_ptr]]\n"
+ "ld1 {v1.h}[0], [%[b_ptr]]\n"
+ "fcmgt h0, h0, h1\n"
+ "st1 {v0.h}[0], [%[res_ptr]]\n"
+ : // outputs
+ : // inputs
+ [a_ptr] "r"(&(a.x)),
+ [b_ptr] "r"(&(b.x)),
+ [res_ptr] "r"(&res)
+ : // clobbers
+ "memory", "v0", "v1");
+ return (res & 0xffff) != 0;
+}
+
+HOST inline bool operator>=(const float16& a, const float16& b) {
+ uint16_t res;
+ asm volatile(
+ "ld1 {v0.h}[0], [%[a_ptr]]\n"
+ "ld1 {v1.h}[0], [%[b_ptr]]\n"
+ "fcmge h0, h0, h1\n"
+ "st1 {v0.h}[0], [%[res_ptr]]\n"
+ : // outputs
+ : // inputs
+ [a_ptr] "r"(&(a.x)),
+ [b_ptr] "r"(&(b.x)),
+ [res_ptr] "r"(&res)
+ : // clobbers
+ "memory", "v0", "v1");
+ return (res & 0xffff) != 0;
+}
+
+// Arithmetic operators, software emulated on other CPU
+#else
+HOSTDEVICE inline float16 operator+(const float16& a, const float16& b) {
+ return float16(float(a) + float(b));
+}
+
+HOSTDEVICE inline float16 operator-(const float16& a, const float16& b) {
+ return float16(float(a) - float(b));
+}
+
+HOSTDEVICE inline float16 operator*(const float16& a, const float16& b) {
+ return float16(float(a) * float(b));
+}
+
+HOSTDEVICE inline float16 operator/(const float16& a, const float16& b) {
+ return float16(float(a) / float(b));
+}
+
+HOSTDEVICE inline float16 operator-(const float16& a) {
+ float16 res;
+ res.x = a.x ^ 0x8000;
+ return res;
+}
+
+HOSTDEVICE inline float16& operator+=(float16& a, const float16& b) {
+ a = float16(float(a) + float(b));
+ return a;
+}
+
+HOSTDEVICE inline float16& operator-=(float16& a, const float16& b) {
+ a = float16(float(a) - float(b));
+ return a;
+}
+
+HOSTDEVICE inline float16& operator*=(float16& a, const float16& b) {
+ a = float16(float(a) * float(b));
+ return a;
+}
+
+HOSTDEVICE inline float16& operator/=(float16& a, const float16& b) {
+ a = float16(float(a) / float(b));
+ return a;
+}
+
+HOSTDEVICE inline bool operator==(const float16& a, const float16& b) {
+ return float(a) == float(b);
+}
+
+HOSTDEVICE inline bool operator!=(const float16& a, const float16& b) {
+ return float(a) != float(b);
+}
+
+HOSTDEVICE inline bool operator<(const float16& a, const float16& b) {
+ return float(a) < float(b);
+}
+
+HOSTDEVICE inline bool operator<=(const float16& a, const float16& b) {
+ return float(a) <= float(b);
+}
+
+HOSTDEVICE inline bool operator>(const float16& a, const float16& b) {
+ return float(a) > float(b);
+}
+
+HOSTDEVICE inline bool operator>=(const float16& a, const float16& b) {
+ return float(a) >= float(b);
+}
+#endif
+} // namespace paddle
diff --git a/paddle/math/tests/CMakeLists.txt b/paddle/math/tests/CMakeLists.txt
index d8b7f9e3fc..dcd2a34583 100644
--- a/paddle/math/tests/CMakeLists.txt
+++ b/paddle/math/tests/CMakeLists.txt
@@ -22,6 +22,7 @@ if(WITH_GPU)
link_paddle_test(test_Tensor)
CUDA_ADD_EXECUTABLE(test_lazyAssign test_lazyAssign.cu)
link_paddle_test(test_lazyAssign)
+ nv_test(test_float16_gpu SRCS test_float16.cu)
else()
compile_cu_as_cpp(test_Tensor.cu)
add_unittest(test_Tensor test_Tensor.cu)
@@ -33,3 +34,4 @@ add_simple_unittest(test_FPException)
add_simple_unittest(test_GpuProfiler)
add_simple_unittest(test_BaseMatrix)
add_simple_unittest(test_Matrix)
+add_simple_unittest(test_float16)
diff --git a/paddle/math/tests/test_float16.cpp b/paddle/math/tests/test_float16.cpp
new file mode 100644
index 0000000000..74cc55aa37
--- /dev/null
+++ b/paddle/math/tests/test_float16.cpp
@@ -0,0 +1,119 @@
+/* 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/math/float16.h"
+
+#include
+
+namespace paddle {
+
+TEST(float16, conversion_cpu) {
+ // Explicit conversion from Eigen::half
+ EXPECT_EQ(float16(Eigen::half(1.0f)).x, 0x3c00);
+ EXPECT_EQ(float16(Eigen::half(0.5f)).x, 0x3800);
+ EXPECT_EQ(float16(Eigen::half(0.33333f)).x, 0x3555);
+ EXPECT_EQ(float16(Eigen::half(0.0f)).x, 0x0000);
+ EXPECT_EQ(float16(Eigen::half(-0.0f)).x, 0x8000);
+ EXPECT_EQ(float16(Eigen::half(65504.0f)).x, 0x7bff);
+ EXPECT_EQ(float16(Eigen::half(65536.0f)).x, 0x7c00);
+
+ // Conversion from float
+ EXPECT_EQ(float16(1.0f).x, 0x3c00);
+ EXPECT_EQ(float16(0.5f).x, 0x3800);
+ EXPECT_EQ(float16(0.33333f).x, 0x3555);
+ EXPECT_EQ(float16(0.0f).x, 0x0000);
+ EXPECT_EQ(float16(-0.0f).x, 0x8000);
+ EXPECT_EQ(float16(65504.0f).x, 0x7bff);
+ EXPECT_EQ(float16(65536.0f).x, 0x7c00);
+
+ // Conversion from double
+ EXPECT_EQ(float16(1.0).x, 0x3c00);
+ EXPECT_EQ(float16(0.5).x, 0x3800);
+ EXPECT_EQ(float16(0.33333).x, 0x3555);
+ EXPECT_EQ(float16(0.0).x, 0x0000);
+ EXPECT_EQ(float16(-0.0).x, 0x8000);
+ EXPECT_EQ(float16(65504.0).x, 0x7bff);
+ EXPECT_EQ(float16(65536.0).x, 0x7c00);
+
+ // Conversion from int
+ EXPECT_EQ(float16(-1).x, 0xbc00);
+ EXPECT_EQ(float16(0).x, 0x0000);
+ EXPECT_EQ(float16(1).x, 0x3c00);
+ EXPECT_EQ(float16(2).x, 0x4000);
+ EXPECT_EQ(float16(3).x, 0x4200);
+
+ // Conversion from bool
+ EXPECT_EQ(float16(true).x, 0x3c00);
+ EXPECT_EQ(float16(false).x, 0x0000);
+
+ // Default constructor
+ float16 v_def;
+ EXPECT_EQ(v_def.x, 0x0000);
+
+ // Assignment operator
+ float16 v_assign;
+ v_assign = v_def;
+ EXPECT_EQ(v_assign.x, 0x0000);
+ v_assign = Eigen::half(1.0f);
+ EXPECT_EQ(v_assign.x, 0x3c00);
+ v_assign = 0.5f;
+ EXPECT_EQ(v_assign.x, 0x3800);
+ v_assign = 0.33333;
+ EXPECT_EQ(v_assign.x, 0x3555);
+ v_assign = -1;
+ EXPECT_EQ(v_assign.x, 0xbc00);
+ v_assign = true;
+ EXPECT_EQ(v_assign.x, 0x3c00);
+
+ // Conversion operator
+ EXPECT_EQ(Eigen::half(float16(1.0f)).x, 0x3c00);
+ EXPECT_EQ(float(float16(0.5f)), 0.5f);
+ EXPECT_NEAR(double(float16(0.33333)), 0.33333, 0.0001);
+ EXPECT_EQ(int(float16(-1)), -1);
+ EXPECT_EQ(bool(float16(true)), true);
+}
+
+TEST(float16, arithmetic_cpu) {
+ EXPECT_EQ(float(float16(1) + float16(1)), 2);
+ EXPECT_EQ(float(float16(5) + float16(-5)), 0);
+ EXPECT_NEAR(float(float16(0.33333f) + float16(0.66667f)), 1.0f, 0.001);
+ EXPECT_EQ(float(float16(3) - float16(5)), -2);
+ EXPECT_NEAR(float(float16(0.66667f) - float16(0.33333f)), 0.33334f, 0.001);
+ EXPECT_NEAR(float(float16(3.3f) * float16(2.0f)), 6.6f, 0.01);
+ EXPECT_NEAR(float(float16(-2.1f) * float16(-3.0f)), 6.3f, 0.01);
+ EXPECT_NEAR(float(float16(2.0f) / float16(3.0f)), 0.66667f, 0.001);
+ EXPECT_EQ(float(float16(1.0f) / float16(2.0f)), 0.5f);
+ EXPECT_EQ(float(-float16(512.0f)), -512.0f);
+ EXPECT_EQ(float(-float16(-512.0f)), 512.0f);
+}
+
+TEST(float16, comparison_cpu) {
+ EXPECT_TRUE(float16(1.0f) == float16(1.0f));
+ EXPECT_FALSE(float16(-1.0f) == float16(-0.5f));
+ EXPECT_TRUE(float16(1.0f) != float16(0.5f));
+ EXPECT_FALSE(float16(-1.0f) != float16(-1.0f));
+ EXPECT_TRUE(float16(1.0f) < float16(2.0f));
+ EXPECT_FALSE(float16(-1.0f) < float16(-1.0f));
+ EXPECT_TRUE(float16(1.0f) <= float16(1.0f));
+ EXPECT_TRUE(float16(2.0f) > float16(1.0f));
+ EXPECT_FALSE(float16(-2.0f) > float16(-2.0f));
+ EXPECT_TRUE(float16(2.0f) >= float16(2.0f));
+
+ EXPECT_TRUE(float16(0.0f) == float16(-0.0f));
+ EXPECT_TRUE(float16(0.0f) <= float16(-0.0f));
+ EXPECT_TRUE(float16(0.0f) >= float16(-0.0f));
+ EXPECT_FALSE(float16(0.0f) < float16(-0.0f));
+ EXPECT_FALSE(float16(-0.0f) < float16(0.0f));
+ EXPECT_FALSE(float16(0.0f) > float16(-0.0f));
+ EXPECT_FALSE(float16(-0.0f) > float16(0.0f));
+}
+
+} // namespace paddle
diff --git a/paddle/math/tests/test_float16.cu b/paddle/math/tests/test_float16.cu
new file mode 100644
index 0000000000..4b520feaaf
--- /dev/null
+++ b/paddle/math/tests/test_float16.cu
@@ -0,0 +1,213 @@
+/* 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/math/float16.h"
+
+#include
+
+#include "paddle/utils/Logging.h"
+
+#define ARITHMETIC_KERNEL(op_type, sign) \
+ __global__ void op_type(const half* in1, const half* in2, half* out) { \
+ out[0] = in1[0] sign in2[0]; \
+ }
+
+#define COMPOUND_KERNEL(op_type, sign) \
+ __global__ void op_type(half* in1, const half* in2) { in1[0] sign in2[0]; }
+
+#define COMPARISON_KERNEL(op_type, sign) \
+ __global__ void op_type(const half* in1, const half* in2, bool* out) { \
+ out[0] = in1[0] sign in2[0]; \
+ }
+
+#define ARITHMETIC_KERNEL_LAUNCH(op_type) \
+ void Test##op_type(float v_in1, float v_in2, float v_out) { \
+ LOG(INFO) << "Test " << #op_type << " on GPU!"; \
+ half *in1, *in2, *out; \
+ half *d_in1, *d_in2, *d_out; \
+ int size = sizeof(half); \
+ cudaMalloc((void**)&d_in1, size); \
+ cudaMalloc((void**)&d_in2, size); \
+ cudaMalloc((void**)&d_out, size); \
+ in1 = (half*)malloc(size); \
+ in2 = (half*)malloc(size); \
+ out = (half*)malloc(size); \
+ in1[0] = half(float16(v_in1)); \
+ in2[0] = half(float16(v_in2)); \
+ cudaMemcpy(d_in1, in1, size, cudaMemcpyHostToDevice); \
+ cudaMemcpy(d_in2, in2, size, cudaMemcpyHostToDevice); \
+ op_type<<<1, 1>>>(d_in1, d_in2, d_out); \
+ cudaMemcpy(out, d_out, size, cudaMemcpyDeviceToHost); \
+ EXPECT_EQ(float(float16(out[0])), v_out); \
+ free(in1); \
+ free(in2); \
+ free(out); \
+ cudaFree(d_in1); \
+ cudaFree(d_in2); \
+ cudaFree(d_out); \
+ }
+
+#define COMPOUND_KERNEL_LAUNCH(op_type) \
+ void Test##op_type(float v_in1, float v_in2, float v_out) { \
+ LOG(INFO) << "Test " << #op_type << " on GPU!"; \
+ half *in1, *in2; \
+ half *d_in1, *d_in2; \
+ int size = sizeof(half); \
+ cudaMalloc((void**)&d_in1, size); \
+ cudaMalloc((void**)&d_in2, size); \
+ in1 = (half*)malloc(size); \
+ in2 = (half*)malloc(size); \
+ in1[0] = half(float16(v_in1)); \
+ in2[0] = half(float16(v_in2)); \
+ cudaMemcpy(d_in1, in1, size, cudaMemcpyHostToDevice); \
+ cudaMemcpy(d_in2, in2, size, cudaMemcpyHostToDevice); \
+ op_type<<<1, 1>>>(d_in1, d_in2); \
+ cudaMemcpy(in1, d_in1, size, cudaMemcpyDeviceToHost); \
+ EXPECT_EQ(float(float16(in1[0])), v_out); \
+ free(in1); \
+ free(in2); \
+ cudaFree(d_in1); \
+ cudaFree(d_in2); \
+ }
+
+#define COMPARISON_KERNEL_LAUNCH(op_type) \
+ void Test##op_type(float v_in1, float v_in2, bool v_out) { \
+ LOG(INFO) << "Test " << #op_type << " on GPU!"; \
+ half *in1, *in2; \
+ half *d_in1, *d_in2; \
+ bool *out, *d_out; \
+ int size = sizeof(half); \
+ cudaMalloc((void**)&d_in1, size); \
+ cudaMalloc((void**)&d_in2, size); \
+ cudaMalloc((void**)&d_out, 1); \
+ in1 = (half*)malloc(size); \
+ in2 = (half*)malloc(size); \
+ out = (bool*)malloc(1); \
+ in1[0] = half(float16(v_in1)); \
+ in2[0] = half(float16(v_in2)); \
+ cudaMemcpy(d_in1, in1, size, cudaMemcpyHostToDevice); \
+ cudaMemcpy(d_in2, in2, size, cudaMemcpyHostToDevice); \
+ op_type<<<1, 1>>>(d_in1, d_in2, d_out); \
+ cudaMemcpy(out, d_out, 1, cudaMemcpyDeviceToHost); \
+ EXPECT_EQ(out[0], v_out); \
+ free(in1); \
+ free(in2); \
+ free(out); \
+ cudaFree(d_in1); \
+ cudaFree(d_in2); \
+ cudaFree(d_out); \
+ }
+
+#ifdef PADDLE_CUDA_FP16
+namespace paddle {
+
+#if CUDA_VERSION < 9000
+ARITHMETIC_KERNEL(Add, +)
+ARITHMETIC_KERNEL(Sub, -)
+ARITHMETIC_KERNEL(Mul, *)
+ARITHMETIC_KERNEL(Div, /)
+
+ARITHMETIC_KERNEL_LAUNCH(Add)
+ARITHMETIC_KERNEL_LAUNCH(Sub)
+ARITHMETIC_KERNEL_LAUNCH(Mul)
+ARITHMETIC_KERNEL_LAUNCH(Div)
+
+// Negative sign kernel
+__global__ void Neg(half* in) { in[0] = -in[0]; }
+
+void TestNeg(float v_in, float v_out) {
+ LOG(INFO) << "Test Neg on GPU!";
+ half *in, *d_in;
+ int size = sizeof(half);
+ cudaMalloc((void**)&d_in, size);
+ in = (half*)malloc(size);
+ in[0] = half(float16(v_in));
+ cudaMemcpy(d_in, in, size, cudaMemcpyHostToDevice);
+ Neg<<<1, 1>>>(d_in);
+ cudaMemcpy(in, d_in, size, cudaMemcpyDeviceToHost);
+ EXPECT_EQ(float(float16(in[0])), v_out);
+ free(in);
+ cudaFree(d_in);
+}
+
+COMPOUND_KERNEL(AddAssign, +=)
+COMPOUND_KERNEL(SubAssign, -=)
+COMPOUND_KERNEL(MulAssign, *=)
+COMPOUND_KERNEL(DivAssign, /=)
+
+COMPOUND_KERNEL_LAUNCH(AddAssign)
+COMPOUND_KERNEL_LAUNCH(SubAssign)
+COMPOUND_KERNEL_LAUNCH(MulAssign)
+COMPOUND_KERNEL_LAUNCH(DivAssign)
+
+COMPARISON_KERNEL(Equal, ==)
+COMPARISON_KERNEL(NotEqual, !=)
+COMPARISON_KERNEL(Less, <)
+COMPARISON_KERNEL(LessEqual, <=)
+COMPARISON_KERNEL(Greater, >)
+COMPARISON_KERNEL(GreaterEqual, >=)
+
+COMPARISON_KERNEL_LAUNCH(Equal)
+COMPARISON_KERNEL_LAUNCH(NotEqual)
+COMPARISON_KERNEL_LAUNCH(Less)
+COMPARISON_KERNEL_LAUNCH(LessEqual)
+COMPARISON_KERNEL_LAUNCH(Greater)
+COMPARISON_KERNEL_LAUNCH(GreaterEqual)
+
+TEST(float16, arithmetic_on_gpu) {
+ TestAdd(1, 2, 3);
+ TestSub(2, 1, 1);
+ TestMul(2, 3, 6);
+ TestDiv(6, 2, 3);
+ TestNeg(1, -1);
+}
+
+TEST(float16, compound_on_gpu) {
+ TestAddAssign(1, 2, 3);
+ TestSubAssign(2, 1, 1);
+ TestMulAssign(2, 3, 6);
+ TestDivAssign(6, 2, 3);
+}
+
+TEST(float16, comparision_on_gpu) {
+ TestEqual(1, 1, true);
+ TestEqual(1, 2, false);
+ TestNotEqual(2, 3, true);
+ TestNotEqual(2, 2, false);
+ TestLess(3, 4, true);
+ TestLess(3, 3, false);
+ TestLessEqual(3, 3, true);
+ TestLessEqual(3, 2, false);
+ TestGreater(4, 3, true);
+ TestGreater(4, 4, false);
+ TestGreaterEqual(4, 4, true);
+ TestGreaterEqual(4, 5, false);
+}
+#endif // CUDA_VERSION
+
+TEST(float16, conversion_on_gpu) {
+ // Explicit conversion to and from cuda half
+ EXPECT_EQ(float16(half(float16(1.0f))).x, 0x3c00);
+ EXPECT_EQ(float16(half(float16(0.5f))).x, 0x3800);
+ EXPECT_EQ(float16(half(float16(0.33333f))).x, 0x3555);
+ EXPECT_EQ(float16(half(float16(0.0f))).x, 0x0000);
+ EXPECT_EQ(float16(half(float16(-0.0f))).x, 0x8000);
+ EXPECT_EQ(float16(half(float16(65504.0f))).x, 0x7bff);
+ EXPECT_EQ(float16(half(float16(65536.0f))).x, 0x7c00);
+
+ // Assignment operator
+ float16 v_assign;
+ v_assign = half(float16(1.0f));
+ EXPECT_EQ(v_assign.x, 0x3c00);
+}
+
+} // namespace paddle
+#endif // PADDLE_CUDA_FP16
diff --git a/paddle/memory/detail/system_allocator.cc b/paddle/memory/detail/system_allocator.cc
index 6b4e46f56a..6a815a1b57 100644
--- a/paddle/memory/detail/system_allocator.cc
+++ b/paddle/memory/detail/system_allocator.cc
@@ -43,7 +43,7 @@ void* CPUAllocator::Alloc(size_t& index, size_t size) {
void* p;
-#ifdef PADDLE_USE_MKLDNN
+#ifdef PADDLE_WITH_MKLDNN
// refer to https://github.com/01org/mkl-dnn/blob/master/include/mkldnn.hpp
// memory alignment
PADDLE_ENFORCE_EQ(posix_memalign(&p, 4096ul, size), 0);
@@ -83,7 +83,7 @@ void* GPUAllocator::Alloc(size_t& index, size_t size) {
paddle::platform::GpuMemoryUsage(available, capacity);
// Reserve memory for page tables, etc.
- size_t reserving = capacity - paddle::platform::GpuMaxAllocSize();
+ size_t reserving = 0.05 * capacity + paddle::platform::GpuMinChunkSize();
size_t usable = available > reserving ? available - reserving : 0;
// If remaining size no less than expected size, using general
diff --git a/paddle/memory/memory.cc b/paddle/memory/memory.cc
index 95cfe2525e..9cafdfda75 100644
--- a/paddle/memory/memory.cc
+++ b/paddle/memory/memory.cc
@@ -64,19 +64,21 @@ BuddyAllocator* GetGPUBuddyAllocator(int gpu_id) {
int gpu_num = platform::GetCUDADeviceCount();
as = new BuddyAllocator*[gpu_num];
for (int gpu = 0; gpu < gpu_num; gpu++) {
- platform::SetDeviceId(gpu);
- as[gpu] = new BuddyAllocator(new detail::GPUAllocator,
- platform::GpuMinChunkSize(),
- platform::GpuMaxChunkSize());
+ as[gpu] = nullptr;
}
+ }
+ platform::SetDeviceId(gpu_id);
+ if (!as[gpu_id]) {
+ as[gpu_id] = new BuddyAllocator(new detail::GPUAllocator,
+ platform::GpuMinChunkSize(),
+ platform::GpuMaxChunkSize());
VLOG(10) << "\n\nNOTE: each GPU device use "
<< FLAGS_fraction_of_gpu_memory_to_use * 100
<< "% of GPU memory.\n"
- << "You can set environment variable '"
- << platform::kEnvFractionGpuMemoryToUse
+ << "You can set GFlags environment variable '"
+ << "FLAGS_fraction_of_gpu_memory_to_use"
<< "' to change the fraction of GPU usage.\n\n";
}
- platform::SetDeviceId(gpu_id);
return as[gpu_id];
}
diff --git a/paddle/operators/CMakeLists.txt b/paddle/operators/CMakeLists.txt
index 38b89b9eb1..5aaaf99332 100644
--- a/paddle/operators/CMakeLists.txt
+++ b/paddle/operators/CMakeLists.txt
@@ -138,7 +138,7 @@ function(op_library TARGET)
if ("${TARGET}" STREQUAL "nccl_op")
set(pybind_flag 1)
# It's enough to just adding one operator to pybind
- file(APPEND ${pybind_file} "USE_GPU_ONLY_OP(ncclAllReduce);\n")
+ file(APPEND ${pybind_file} "USE_CUDA_ONLY_OP(ncclAllReduce);\n")
endif()
# reduce_op contains several operators
diff --git a/paddle/operators/accuracy_op.cc b/paddle/operators/accuracy_op.cc
index 2785a8c6fb..76da21c472 100644
--- a/paddle/operators/accuracy_op.cc
+++ b/paddle/operators/accuracy_op.cc
@@ -57,7 +57,7 @@ class AccuracyOp : public framework::OperatorWithKernel {
const framework::ExecutionContext &ctx) const override {
return framework::OpKernelType(
framework::ToDataType(ctx.Input("Out")->type()),
- ctx.device_context());
+ ctx.GetPlace());
}
};
diff --git a/paddle/operators/accuracy_op.cu b/paddle/operators/accuracy_op.cu
index d2dcab4e54..539a935302 100644
--- a/paddle/operators/accuracy_op.cu
+++ b/paddle/operators/accuracy_op.cu
@@ -104,5 +104,6 @@ class AccuracyOpCUDAKernel : public framework::OpKernel {
// FIXME(typhoonzero): types of T is for inference data.
// label data is always int64
-REGISTER_OP_GPU_KERNEL(accuracy, paddle::operators::AccuracyOpCUDAKernel,
- paddle::operators::AccuracyOpCUDAKernel);
+REGISTER_OP_CUDA_KERNEL(accuracy,
+ paddle::operators::AccuracyOpCUDAKernel,
+ paddle::operators::AccuracyOpCUDAKernel);
diff --git a/paddle/operators/accuracy_op.h b/paddle/operators/accuracy_op.h
index d060e6eddd..04104a695f 100644
--- a/paddle/operators/accuracy_op.h
+++ b/paddle/operators/accuracy_op.h
@@ -21,7 +21,7 @@ namespace operators {
using Tensor = framework::Tensor;
-template
+template
class AccuracyKernel : public framework::OpKernel {
public:
void Compute(const framework::ExecutionContext& ctx) const override {
diff --git a/paddle/operators/activation_op.cc b/paddle/operators/activation_op.cc
index 154c618e8e..63490f0ec9 100644
--- a/paddle/operators/activation_op.cc
+++ b/paddle/operators/activation_op.cc
@@ -44,9 +44,9 @@ class SigmoidOpMaker : public framework::OpProtoAndCheckerMaker {
AddInput("X", "Input of Sigmoid operator");
AddOutput("Y", "Output of Sigmoid operator");
AddComment(R"DOC(
-Sigmoid Activation Operator.
+Sigmoid Activation Operator
-$y = 1 / (1 + e^{-x})$
+$$y = \frac{1}{1 + e^{-x}}$$
)DOC");
}
@@ -60,9 +60,9 @@ class LogSigmoidOpMaker : public framework::OpProtoAndCheckerMaker {
AddInput("X", "Input of LogSigmoid operator");
AddOutput("Y", "Output of LogSigmoid operator");
AddComment(R"DOC(
-Logsigmoid Activation Operator.
+Logsigmoid Activation Operator
-$y = \log(1 / (1 + e^{-x}))$
+$$y = \log \frac{1}{1 + e^{-x}}$$
)DOC");
}
@@ -506,6 +506,22 @@ It is recommended to use the defaults for this activation.
}
};
+class SwishOpMaker : public framework::OpProtoAndCheckerMaker {
+ public:
+ SwishOpMaker(framework::OpProto *proto, framework::OpAttrChecker *op_checker)
+ : OpProtoAndCheckerMaker(proto, op_checker) {
+ AddInput("X", "Input of Swish operator");
+ AddOutput("Y", "Output of Swish operator");
+ AddAttr("beta", "Constant beta of swish operator").SetDefault(1.0f);
+ AddComment(R"DOC(
+Swish Activation Operator.
+
+$$y = \frac{x}{1 + e^{- \beta x}}$$
+
+)DOC");
+ }
+};
+
} // namespace operators
} // namespace paddle
@@ -592,16 +608,20 @@ REGISTER_OP(thresholded_relu, ops::ActivationOp, ops::ThresholdedReluOpMaker,
REGISTER_OP(hard_sigmoid, ops::ActivationOp, ops::HardSigmoidOpMaker,
hard_sigmoid_grad, ops::ActivationOpGrad);
-#define REGISTER_ACTIVATION_CPU_KERNEL(act_type, functor, grad_functor) \
- REGISTER_OP_CPU_KERNEL( \
- act_type, \
- ops::ActivationKernel>, \
- ops::ActivationKernel>); \
- REGISTER_OP_CPU_KERNEL( \
- act_type##_grad, ops::ActivationGradKernel>, \
- ops::ActivationGradKernel>, \
+ ops::ActivationKernel>); \
+ REGISTER_OP_CPU_KERNEL( \
+ act_type##_grad, \
+ ops::ActivationGradKernel>, \
+ ops::ActivationGradKernel>);
FOR_EACH_KERNEL_FUNCTOR(REGISTER_ACTIVATION_CPU_KERNEL);
diff --git a/paddle/operators/activation_op.cu b/paddle/operators/activation_op.cu
index 97737857ab..856d3fc35d 100644
--- a/paddle/operators/activation_op.cu
+++ b/paddle/operators/activation_op.cu
@@ -17,16 +17,17 @@
namespace ops = paddle::operators;
-#define REGISTER_ACTIVATION_GPU_KERNEL(act_type, functor, grad_functor) \
- REGISTER_OP_GPU_KERNEL( \
- act_type, \
- ops::ActivationKernel>, \
- ops::ActivationKernel>); \
- REGISTER_OP_GPU_KERNEL( \
- act_type##_grad, ops::ActivationGradKernel>, \
- ops::ActivationGradKernel>, \
+ ops::ActivationKernel>); \
+ REGISTER_OP_CUDA_KERNEL( \
+ act_type##_grad, \
+ ops::ActivationGradKernel>, \
+ ops::ActivationGradKernel>);
-FOR_EACH_KERNEL_FUNCTOR(REGISTER_ACTIVATION_GPU_KERNEL);
+FOR_EACH_KERNEL_FUNCTOR(REGISTER_ACTIVATION_CUDA_KERNEL);
diff --git a/paddle/operators/activation_op.h b/paddle/operators/activation_op.h
index 8cd3bfbbd3..75eefca8b8 100644
--- a/paddle/operators/activation_op.h
+++ b/paddle/operators/activation_op.h
@@ -19,7 +19,7 @@
namespace paddle {
namespace operators {
-template
+template
class ActivationKernel
: public framework::OpKernel {
public:
@@ -32,18 +32,19 @@ class ActivationKernel
auto x = framework::EigenVector::Flatten(*X);
auto y = framework::EigenVector::Flatten(*Y);
- auto place = context.GetEigenDevice();
+ auto* place =
+ context.template device_context().eigen_device();
Functor functor;
auto attrs = functor.GetAttrs();
for (auto& attr : attrs) {
*attr.second = context.Attr(attr.first);
}
- functor(place, x, y);
+ functor(*place, x, y);
}
};
-template
+template
class ActivationGradKernel
: public framework::OpKernel {
public:
@@ -59,13 +60,14 @@ class ActivationGradKernel
auto x = framework::EigenVector::Flatten(*X);
auto y = framework::EigenVector::Flatten(*Y);
auto dx = framework::EigenVector::Flatten(*dX);
- auto place = context.GetEigenDevice();
+ auto* place =
+ context.template device_context().eigen_device();
Functor functor;
auto attrs = functor.GetAttrs();
for (auto& attr : attrs) {
*attr.second = context.Attr(attr.first);
}
- functor(place, x, y, dy, dx);
+ functor(*place, x, y, dy, dx);
}
};
@@ -700,6 +702,35 @@ struct HardSigmoidGradFunctor : public BaseActivationFunctor {
}
};
+template
+struct SwishFunctor : public BaseActivationFunctor {
+ float beta;
+ typename BaseActivationFunctor::AttrPair GetAttrs() {
+ return {{"beta", &beta}};
+ }
+
+ template
+ void operator()(Device d, X x, Y y) const {
+ y.device(d) = x / (static_cast(1) + (static_cast(-beta) * x).exp());
+ }
+};
+
+template
+struct SwishGradFunctor : public BaseActivationFunctor {
+ float beta;
+ typename BaseActivationFunctor::AttrPair GetAttrs() {
+ return {{"beta", &beta}};
+ }
+
+ template
+ void operator()(Device d, X x, Y y, dY dy, dX dx) const {
+ auto temp1 = static_cast(1) /
+ (static_cast(1) + (static_cast(-beta) * x).exp());
+ auto temp2 = temp1 * (static_cast(1) - (beta * y));
+ dx.device(d) = dy * ((beta * y) + temp2);
+ }
+};
+
} // namespace operators
} // namespace paddle
@@ -730,4 +761,5 @@ struct HardSigmoidGradFunctor : public BaseActivationFunctor {
__macro(elu, ELUFunctor, ELUGradFunctor); \
__macro(hard_shrink, HardShrinkFunctor, HardShrinkGradFunctor); \
__macro(hard_sigmoid, HardSigmoidFunctor, HardSigmoidGradFunctor); \
+ __macro(swish, SwishFunctor, SwishGradFunctor); \
__macro(thresholded_relu, ThresholdedReluFunctor, ThresholdedReluGradFunctor);
diff --git a/paddle/operators/adadelta_op.cc b/paddle/operators/adadelta_op.cc
index 16a7794d5b..507811e7b5 100644
--- a/paddle/operators/adadelta_op.cc
+++ b/paddle/operators/adadelta_op.cc
@@ -92,12 +92,12 @@ for gradient descent.
Adadelta updates are as follows:
-$$avgSquaredGradOut = \rho * avgSquaredGrad + (1 - \rho) * grad * grad \break
-paramUpdate = - $\sqrt{((avgSquaredUpdate + \epsilon) /
- (avgSquaredGrad_out + \epsilon))}$ * grad \break
-avgSquaredUpdateOut = \rho * avgSquaredUpdate + (1 - \rho) *
- {(paramUpdate)}^2 \break
-paramOut = param + paramUpdate$$
+$$
+avg\_squared\_grad\_out = \rho * avg\_squared\_grad + (1 - \rho) * grad * grad \\
+param\_update = - \sqrt{\frac{avg\_squared\_update + \epsilon}{avg\_squared\_grad\_out + \epsilon}} * grad \\
+avg\_squared\_update\_out = \rho * avg\_squared\_update + (1 - \rho) * {param\_update}^2 \\
+param\_out = param + param\_update
+$$
)DOC");
}
@@ -109,5 +109,5 @@ paramOut = param + paramUpdate$$
namespace ops = paddle::operators;
REGISTER_OP_WITHOUT_GRADIENT(adadelta, ops::AdadeltaOp, ops::AdadeltaOpMaker);
REGISTER_OP_CPU_KERNEL(
- adadelta, ops::AdadeltaOpKernel,
- ops::AdadeltaOpKernel);
+ adadelta, ops::AdadeltaOpKernel,
+ ops::AdadeltaOpKernel);
diff --git a/paddle/operators/adadelta_op.cu b/paddle/operators/adadelta_op.cu
index 9fb6185207..eee2d0a2f5 100644
--- a/paddle/operators/adadelta_op.cu
+++ b/paddle/operators/adadelta_op.cu
@@ -16,6 +16,6 @@
#include "paddle/operators/adadelta_op.h"
namespace ops = paddle::operators;
-REGISTER_OP_GPU_KERNEL(
- adadelta, ops::AdadeltaOpKernel,
- ops::AdadeltaOpKernel);
+REGISTER_OP_CUDA_KERNEL(
+ adadelta, ops::AdadeltaOpKernel,
+ ops::AdadeltaOpKernel);
diff --git a/paddle/operators/adadelta_op.h b/paddle/operators/adadelta_op.h
index a8c5f0c8aa..819d0845db 100644
--- a/paddle/operators/adadelta_op.h
+++ b/paddle/operators/adadelta_op.h
@@ -19,7 +19,7 @@ limitations under the License. */
namespace paddle {
namespace operators {
-template
+template
class AdadeltaOpKernel : public framework::OpKernel {
public:
void Compute(const framework::ExecutionContext& ctx) const override {
@@ -51,7 +51,7 @@ class AdadeltaOpKernel : public framework::OpKernel {
framework::EigenVector::Flatten(*avg_squared_grad_out_tensor);
auto avg_squared_update_out =
framework::EigenVector::Flatten(*avg_squared_update_out_tensor);
- auto place = ctx.GetEigenDevice();
+ auto& place = *ctx.template device_context().eigen_device();
avg_squared_grad_out.device(place) =
rho * avg_squared_grad + (1 - rho) * grad.square();
diff --git a/paddle/operators/adagrad_op.cc b/paddle/operators/adagrad_op.cc
index d6686e3ef3..5d00716316 100644
--- a/paddle/operators/adagrad_op.cc
+++ b/paddle/operators/adagrad_op.cc
@@ -80,8 +80,8 @@ Adaptive Gradient Algorithm (Adagrad).
The update is done as follows:
-$$momentOut = moment + grad * grad \break
-paramOut = param - learningRate * grad / ($\sqrt{momentOut}$ + \epsilon) \break
+$$moment\_out = moment + grad * grad \\
+param\_out = param - \frac{learning\_rate * grad}{\sqrt{moment\_out} + \epsilon}
$$
The original paper(http://www.jmlr.org/papers/volume12/duchi11a/duchi11a.pdf)
@@ -100,8 +100,8 @@ size_t FindPos(const std::vector& rows, int64_t value) {
} // namespace
template
-struct SparseAdagradFunctor {
- void operator()(const platform::DeviceContext& context,
+struct SparseAdagradFunctor {
+ void operator()(const platform::CPUDeviceContext& context,
const framework::SelectedRows& grad,
const framework::Tensor& learning_rate, T epsilon,
framework::Tensor* moment, framework::Tensor* param) {
@@ -120,7 +120,7 @@ struct SparseAdagradFunctor {
{static_cast(merge_rows.size()), grad_width}),
context.GetPlace());
- math::SetConstant constant_functor;
+ math::SetConstant constant_functor;
constant_functor(context, grad_merge->mutable_value(), 0.0);
auto* grad_merge_data = grad_merge->mutable_value()->data();
@@ -144,9 +144,9 @@ struct SparseAdagradFunctor {
auto gs =
framework::EigenVector::Flatten(*(grad_square->mutable_value()));
auto gm = framework::EigenVector::Flatten(grad_merge->value());
- gs.device(*context.GetEigenDevice()) = gm * gm;
+ gs.device(*context.eigen_device()) = gm * gm;
- math::SelectedRowsAddToTensor functor;
+ math::SelectedRowsAddToTensor functor;
functor(context, *grad_square, moment);
// 3. update parameter
@@ -164,13 +164,13 @@ struct SparseAdagradFunctor {
}
};
-template struct SparseAdagradFunctor;
-template struct SparseAdagradFunctor;
+template struct SparseAdagradFunctor;
+template struct SparseAdagradFunctor;
} // namespace operators
} // namespace paddle
namespace ops = paddle::operators;
REGISTER_OP_WITHOUT_GRADIENT(adagrad, ops::AdagradOp, ops::AdagradOpMaker);
REGISTER_OP_CPU_KERNEL(
- adagrad, ops::AdagradOpKernel,
- ops::AdagradOpKernel);
+ adagrad, ops::AdagradOpKernel,
+ ops::AdagradOpKernel);
diff --git a/paddle/operators/adagrad_op.cu b/paddle/operators/adagrad_op.cu
index 1c870214b2..585b2d9289 100644
--- a/paddle/operators/adagrad_op.cu
+++ b/paddle/operators/adagrad_op.cu
@@ -72,8 +72,8 @@ __global__ void SparseAdagradFunctorKernel(const T* grad, const int64_t* rows,
} // namespace
template
-struct SparseAdagradFunctor {
- void operator()(const platform::DeviceContext& context,
+struct SparseAdagradFunctor {
+ void operator()(const platform::CUDADeviceContext& context,
const framework::SelectedRows& grad,
const framework::Tensor& learning_rate, T epsilon,
framework::Tensor* moment, framework::Tensor* param) {
@@ -92,7 +92,7 @@ struct SparseAdagradFunctor {
{static_cast(merge_rows.size()), grad_width}),
context.GetPlace());
- math::SetConstant constant_functor;
+ math::SetConstant constant_functor;
constant_functor(context, grad_merge->mutable_value(), 0.0);
auto* grad_merge_data = grad_merge->mutable_value()->data();
@@ -119,9 +119,9 @@ struct SparseAdagradFunctor {
auto gs =
framework::EigenVector::Flatten(*(grad_square->mutable_value()));
auto gm = framework::EigenVector::Flatten(grad_merge->value());
- gs.device(*context.GetEigenDevice()) = gm * gm;
+ gs.device(*context.eigen_device()) = gm * gm;
- math::SelectedRowsAddToTensor functor;
+ math::SelectedRowsAddToTensor functor;
functor(context, *grad_square, moment);
// 3. update parameter
@@ -139,13 +139,13 @@ struct SparseAdagradFunctor {
}
};
-template struct SparseAdagradFunctor;
-template struct SparseAdagradFunctor