diff --git a/Dockerfile b/Dockerfile index 164fe84904947bfc3cf71132b5fba04744460b26..ea39efd00bb5c0a7deb3f6d57083d83a673b883c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -70,7 +70,7 @@ RUN localedef -i en_US -f UTF-8 en_US.UTF-8 # specify sphinx version as 1.5.6 and remove -U option for [pip install -U # sphinx-rtd-theme] since -U option will cause sphinx being updated to newest # version(1.7.1 for now), which causes building documentation failed. -RUN pip install --upgrade pip==9.0.3 && \ +RUN easy_install -U pip && \ pip install -U wheel && \ pip install -U docopt PyYAML sphinx==1.5.6 && \ pip install sphinx-rtd-theme==0.1.9 recommonmark diff --git a/benchmark/fluid/mnist.py b/benchmark/fluid/mnist.py index 1e2185dfac1072d1f1046f4616a9d53a8fc76061..400200c4745017bd9d160bb9e415fde041c0a6c8 100644 --- a/benchmark/fluid/mnist.py +++ b/benchmark/fluid/mnist.py @@ -159,6 +159,7 @@ def run_benchmark(model, args): paddle.dataset.mnist.train(), batch_size=args.batch_size) accuracy = fluid.metrics.Accuracy() + train_exe = fluid.ParallelExecutor(use_cuda=True, loss_name=avg_cost.name) iters, num_samples, start_time = 0, 0, time.time() for pass_id in range(args.pass_num): accuracy.reset() @@ -175,17 +176,20 @@ def run_benchmark(model, args): y_data = np.array(map(lambda x: x[1], data)).astype("int64") y_data = y_data.reshape([len(y_data), 1]) - outs = exe.run( - fluid.default_main_program(), + outs = train_exe.run( feed={"pixel": img_data, "label": y_data}, - fetch_list=[avg_cost, batch_acc, batch_size_tensor] + fetch_list=[ + avg_cost.name, batch_acc.name, batch_size_tensor.name + ] ) # The accuracy is the accumulation of batches, but not the current batch. - accuracy.update(value=outs[1], weight=outs[2]) + accuracy.update( + value=np.array(np.mean(outs[1])), + weight=np.mean(np.array(outs[2]))) iters += 1 num_samples += len(y_data) - loss = np.array(outs[0]) - acc = np.array(outs[1]) + loss = np.mean(np.array(outs[0])) + acc = np.mean(np.array(outs[1])) train_losses.append(loss) train_accs.append(acc) print("Pass: %d, Iter: %d, Loss: %f, Accuracy: %f" % diff --git a/benchmark/fluid/resnet.py b/benchmark/fluid/resnet.py index 831fa2c019fc2868cd85b1ca7b2c8c76a2f1628c..0fd7258a804e7c93b0b03da140140394bf90004a 100644 --- a/benchmark/fluid/resnet.py +++ b/benchmark/fluid/resnet.py @@ -241,6 +241,7 @@ def run_benchmark(model, args): exe = fluid.Executor(place) exe.run(fluid.default_startup_program()) accuracy = fluid.average.WeightedAverage() + train_exe = fluid.ParallelExecutor(use_cuda=True, loss_name=avg_cost.name) if args.use_fake_data: data = train_reader().next() image = np.array(map(lambda x: x[0].reshape(dshape), data)).astype( @@ -264,14 +265,17 @@ def run_benchmark(model, args): data)).astype('float32') label = np.array(map(lambda x: x[1], data)).astype('int64') label = label.reshape([-1, 1]) - loss, acc, weight = exe.run( - fluid.default_main_program(), + loss, acc, weight = train_exe.run( feed={'data': image, 'label': label}, - fetch_list=[avg_cost, batch_acc, batch_size_tensor]) + fetch_list=[ + avg_cost.name, batch_acc.name, batch_size_tensor.name + ]) iters += 1 num_samples += len(label) - accuracy.add(value=acc, weight=weight) + accuracy.add(value=np.array(np.mean(acc)), weight=np.mean(weight)) + loss = np.mean(np.array(loss)) + acc = np.mean(np.array(acc)) train_losses.append(loss) train_accs.append(acc) print("Pass: %d, Iter: %d, Loss: %f, Accuracy: %f" % diff --git a/benchmark/fluid/vgg.py b/benchmark/fluid/vgg.py index 53e34e0cbd15914791c305db6797f826ebfae34e..2a9566a45c3804183e05db9298cec4f670225a6f 100644 --- a/benchmark/fluid/vgg.py +++ b/benchmark/fluid/vgg.py @@ -169,6 +169,7 @@ def main(): iters, num_samples, start_time = 0, 0, time.time() accuracy = fluid.average.WeightedAverage() + train_exe = fluid.ParallelExecutor(use_cuda=True, loss_name=avg_cost.name) for pass_id in range(args.pass_num): accuracy.reset() train_accs = [] @@ -184,14 +185,17 @@ def main(): y_data = np.array(map(lambda x: x[1], data)).astype("int64") y_data = y_data.reshape([-1, 1]) - loss, acc, weight = exe.run( - fluid.default_main_program(), + loss, acc, weight = train_exe.run( feed={"pixel": img_data, "label": y_data}, - fetch_list=[avg_cost, batch_acc, batch_size_tensor]) - accuracy.add(value=acc, weight=weight) + fetch_list=[ + avg_cost.name, batch_acc.name, batch_size_tensor.name + ]) + accuracy.add(value=np.array(np.mean(acc)), weight=np.mean(weight)) iters += 1 num_samples += len(y_data) + loss = np.mean(np.array(loss)) + acc = np.mean(np.array(acc)) print( "Pass = %d, Iter = %d, Loss = %f, Accuracy = %f" % (pass_id, iters, loss, acc) diff --git a/cmake/external/boost.cmake b/cmake/external/boost.cmake index 10662fc96704685f030a5d76c6857d4bc20a63d9..73713d93d5a52738651dda498fac5ea66e3589d2 100644 --- a/cmake/external/boost.cmake +++ b/cmake/external/boost.cmake @@ -23,8 +23,12 @@ set(BOOST_PROJECT "extern_boost") # checked that the devtools package of CentOS 6 installs boost 1.41.0. # So we use 1.41.0 here. set(BOOST_VER "1.41.0") -set(BOOST_TAR "boost_1_41_0") -set(BOOST_URL "http://paddlepaddledeps.bj.bcebos.com/${BOOST_TAR}.tar.gz") +if((NOT DEFINED BOOST_TAR) OR (NOT DEFINED BOOST_URL)) + message(STATUS "use pre defined download url") + set(BOOST_TAR "boost_1_41_0" CACHE STRING "" FORCE) + set(BOOST_URL "http://paddlepaddledeps.cdn.bcebos.com/${BOOST_TAR}.tar.gz" CACHE STRING "" FORCE) +endif() +MESSAGE(STATUS "BOOST_TAR: ${BOOST_TAR}, BOOST_URL: ${BOOST_URL}") set(BOOST_SOURCES_DIR ${THIRD_PARTY_PATH}/boost) set(BOOST_DOWNLOAD_DIR "${BOOST_SOURCES_DIR}/src/${BOOST_PROJECT}") set(BOOST_INCLUDE_DIR "${BOOST_DOWNLOAD_DIR}/${BOOST_TAR}" CACHE PATH "boost include directory." FORCE) diff --git a/cmake/external/eigen.cmake b/cmake/external/eigen.cmake index edc93c2773f46ec9e0bf898557c55c93274e6a01..e029300eee9b99582f085f6b650e03f7dacc091a 100644 --- a/cmake/external/eigen.cmake +++ b/cmake/external/eigen.cmake @@ -21,11 +21,12 @@ else() ExternalProject_Add( extern_eigen3 ${EXTERNAL_PROJECT_LOG_ARGS} - GIT_REPOSITORY "https://github.com/RLovelett/eigen.git" + GIT_REPOSITORY "https://github.com/eigenteam/eigen-git-mirror" # eigen on cuda9.1 missing header of math_funtions.hpp # https://stackoverflow.com/questions/43113508/math-functions-hpp-not-found-when-using-cuda-with-eigen GIT_TAG 917060c364181f33a735dc023818d5a54f60e54c PREFIX ${EIGEN_SOURCE_DIR} + DOWNLOAD_NAME "eigen" UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" diff --git a/cmake/external/mkldnn.cmake b/cmake/external/mkldnn.cmake index 0332e39d14200da1c1af52675f0ccad2c07de405..25c07850dda7b2f69c2207c37b9d2368632104ec 100644 --- a/cmake/external/mkldnn.cmake +++ b/cmake/external/mkldnn.cmake @@ -53,11 +53,9 @@ ExternalProject_Add( ${EXTERNAL_PROJECT_LOG_ARGS} DEPENDS ${MKLDNN_DEPENDS} GIT_REPOSITORY "https://github.com/01org/mkl-dnn.git" - GIT_TAG "v0.14" + GIT_TAG "db3424ad44901513c03a1ea31ccaacdf633fbe9f" PREFIX ${MKLDNN_SOURCES_DIR} UPDATE_COMMAND "" - # Patch MKLDNN to compile with gcc 4.8, the related issue is in intel/mkl-dnn#237. - PATCH_COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/patches/mkldnn.hpp ${MKLDNN_SOURCES_DIR}/src/extern_mkldnn/include/mkldnn.hpp CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${MKLDNN_INSTALL_DIR} CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} CMAKE_ARGS -DMKLROOT=${MKLML_ROOT} diff --git a/cmake/external/mklml.cmake b/cmake/external/mklml.cmake index cebde2750444c4085ebb7046e8a175cc1cc104d1..82c424fb79d5596c31891bc395699bf9ff4e7e7e 100644 --- a/cmake/external/mklml.cmake +++ b/cmake/external/mklml.cmake @@ -27,8 +27,12 @@ ENDIF() INCLUDE(ExternalProject) SET(MKLML_PROJECT "extern_mklml") -SET(MKLML_VER "mklml_lnx_2018.0.3.20180406") -SET(MKLML_URL "http://paddlepaddledeps.bj.bcebos.com/${MKLML_VER}.tgz") +IF((NOT DEFINED MKLML_VER) OR (NOT DEFINED MKLML_URL)) + MESSAGE(STATUS "use pre defined download url") + SET(MKLML_VER "mklml_lnx_2018.0.3.20180406" CACHE STRING "" FORCE) + SET(MKLML_URL "http://paddlepaddledeps.cdn.bcebos.com/${MKLML_VER}.tgz" CACHE STRING "" FORCE) +ENDIF() +MESSAGE(STATUS "MKLML_VER: ${MKLML_VER}, MKLML_URL: ${MKLML_URL}") SET(MKLML_SOURCE_DIR "${THIRD_PARTY_PATH}/mklml") SET(MKLML_DOWNLOAD_DIR "${MKLML_SOURCE_DIR}/src/${MKLML_PROJECT}") SET(MKLML_DST_DIR "mklml") diff --git a/cmake/external/snappy.cmake b/cmake/external/snappy.cmake index 80282329c6ac65fbd1493a6838efca4bd9cadaad..af09ed4d5d6e21cc50aba5198a7e9ea56f49451a 100644 --- a/cmake/external/snappy.cmake +++ b/cmake/external/snappy.cmake @@ -47,8 +47,6 @@ ExternalProject_Add( -DCMAKE_INSTALL_LIBDIR:PATH=${SNAPPY_INSTALL_DIR}/lib -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON -DCMAKE_BUILD_TYPE:STRING=${THIRD_PARTY_BUILD_TYPE} - BUILD_COMMAND make -j8 - INSTALL_COMMAND make install ) add_library(snappy STATIC IMPORTED GLOBAL) diff --git a/cmake/external/snappystream.cmake b/cmake/external/snappystream.cmake index 20a96430823d07a07d4bb4602e7fc0cfe55c3bf2..6df636d7fa8757ade73892bda03a80ba9767472b 100644 --- a/cmake/external/snappystream.cmake +++ b/cmake/external/snappystream.cmake @@ -46,8 +46,6 @@ ExternalProject_Add( -DCMAKE_INSTALL_PREFIX:PATH=${SNAPPYSTREAM_INSTALL_DIR} -DCMAKE_INSTALL_LIBDIR:PATH=${SNAPPYSTREAM_INSTALL_DIR}/lib -DCMAKE_BUILD_TYPE:STRING=${THIRD_PARTY_BUILD_TYPE} - BUILD_COMMAND make -j8 - INSTALL_COMMAND make install DEPENDS snappy ) diff --git a/cmake/inference_lib.cmake b/cmake/inference_lib.cmake index 06a7ae56827d5afe857ed0a98092210917a52430..7117a3a4f31c88b3c4a81e611146123903659ad5 100644 --- a/cmake/inference_lib.cmake +++ b/cmake/inference_lib.cmake @@ -98,6 +98,14 @@ elseif (WITH_MKLML) ) endif() +if(WITH_MKLDNN) + set(dst_dir "${CMAKE_INSTALL_PREFIX}/third_party/install/mkldnn") + copy(mkldnn_lib + SRCS ${MKLDNN_INC_DIR} ${MKLDNN_SHARED_LIB} + DSTS ${dst_dir} ${dst_dir}/lib + ) +endif() + if(NOT MOBILE_INFERENCE AND NOT RPI) set(dst_dir "${CMAKE_INSTALL_PREFIX}/third_party/install/snappy") copy(snappy_lib @@ -148,4 +156,30 @@ copy(string_lib DSTS ${dst_dir}/${module} ${dst_dir}/${module}/tinyformat ) +set(module "pybind") +copy(pybind_lib + SRCS ${CMAKE_CURRENT_BINARY_DIR}/paddle/fluid/${module}/pybind.h + DSTS ${dst_dir}/${module} +) + +# CMakeCache Info +copy(cmake_cache + SRCS ${CMAKE_CURRENT_BINARY_DIR}/CMakeCache.txt + DSTS ${CMAKE_INSTALL_PREFIX}) + add_custom_target(inference_lib_dist DEPENDS ${inference_lib_dist_dep}) + +# paddle fluid version +execute_process( + COMMAND ${GIT_EXECUTABLE} log --pretty=format:%H -1 + OUTPUT_VARIABLE PADDLE_GIT_COMMIT) +set(version_file ${CMAKE_INSTALL_PREFIX}/version.txt) +file(WRITE ${version_file} + "GIT COMMIT ID: ${PADDLE_GIT_COMMIT}\n" + "WITH_MKL: ${WITH_MKL}\n" + "WITH_GPU: ${WITH_GPU}\n") +if(WITH_GPU) + file(APPEND ${version_file} + "CUDA version: ${CUDA_VERSION}\n" + "CUDNN version: v${CUDNN_MAJOR_VERSION}\n") +endif() diff --git a/doc/fluid/design/concepts/functions_operators_layers.md b/doc/fluid/design/concepts/functions_operators_layers.md index 30bc488a18a28d349645d9d2502aae6691a69931..1f86b99e5197c3e0b85fd76fe704520ef21b06d3 100644 --- a/doc/fluid/design/concepts/functions_operators_layers.md +++ b/doc/fluid/design/concepts/functions_operators_layers.md @@ -40,7 +40,7 @@ template class FCOp : public OperatorBase { public: void Run(...) { - add(mul(Input("X"), Input("W")), Input("b"); + add(mul(Input("X"), Input("W")), Input("b")); } }; REGISTER_OP(FCOp, "fc"); diff --git a/doc/fluid/howto/optimization/cpu_profiling_cn.md b/doc/fluid/howto/optimization/cpu_profiling_cn.md index 8266dec3c6125a09b90ac0ccd4aa5464f5c7db31..198a05a79e19227e90eaafe116217a164cd51a7d 100644 --- a/doc/fluid/howto/optimization/cpu_profiling_cn.md +++ b/doc/fluid/howto/optimization/cpu_profiling_cn.md @@ -1,3 +1,5 @@ +# CPU性能调优 + 此教程会介绍如何使用Python的cProfile包、Python库yep、Google perftools来进行性能分析 (profiling) 与调优(performance tuning)。 Profling 指发现性能瓶颈。系统中的瓶颈可能和程序员开发过程中想象的瓶颈相去甚远。Tuning 指消除瓶颈。性能优化的过程通常是不断重复地 profiling 和 tuning。 @@ -8,7 +10,7 @@ PaddlePaddle 用户一般通过调用 Python API 编写深度学习程序。大 * Python 与 C++ 混合代码的性能分析 -# Python代码的性能分析 +## Python代码的性能分析 ### 生成性能分析文件 diff --git a/doc/fluid/howto/optimization/cpu_profiling_en.md b/doc/fluid/howto/optimization/cpu_profiling_en.md index e95556dd608b7ff0a3eb18873df0015a2da94e7c..216694965b3c878a8a5f3ccd2a0cba8d21d9ce05 100644 --- a/doc/fluid/howto/optimization/cpu_profiling_en.md +++ b/doc/fluid/howto/optimization/cpu_profiling_en.md @@ -1,3 +1,5 @@ +# Tune CPU performance + This tutorial introduces techniques we use to profile and tune the CPU performance of PaddlePaddle. We will use Python packages `cProfile` and `yep`, and Google's `perftools`. @@ -14,7 +16,7 @@ the profiling and tuning of 1. the Python code and 1. the mixture of Python and C++ code. -# Profiling the Python Code +## Profiling the Python Code ### Generate the Performance Profiling File diff --git a/doc/v2/build_and_install/pip_install_cn.rst b/doc/v2/build_and_install/pip_install_cn.rst index b3d882743785e8ee301b71b696230531d2b7ba58..9b84bb6425af1eeb94a4f2f5d6c2b1e28c62e3c8 100644 --- a/doc/v2/build_and_install/pip_install_cn.rst +++ b/doc/v2/build_and_install/pip_install_cn.rst @@ -10,20 +10,38 @@ PaddlePaddle可以使用常用的Python包管理工具 使用pip安装 ------------------------------ - -执行下面的命令即可在当前机器上安装PaddlePaddle的运行时环境,并自动下载安装依赖软件,版本为cpu_avx_openblas。 +执行下面的命令即可在当前机器上安装PaddlePaddle的运行时环境,并自动下载安装依赖软件。 .. code-block:: bash pip install paddlepaddle +当前的默认版本为0.12.0,cpu_avx_openblas,您可以通过指定版本号来安装其它版本,例如: + + .. code-block:: bash + + pip install paddlepaddle==0.11.0 + -如果需要安装支持GPU的版本(cuda7.5_cudnn5_avx_openblas),需要执行: +如果需要安装支持GPU的版本(cuda8.0_cudnn5_avx_openblas),需要执行: .. code-block:: bash pip install paddlepaddle-gpu +当前的默认版本也是0.12.0,PaddlePaddle针对不同需求提供了更多版本的安装包,部分列表如下: + +================================= ======================================== +版本号 版本说明 +================================= ======================================== +paddlepaddle-gpu==0.12.0 使用CUDA 8.0和cuDNN 5编译的0.12.0版本 +paddlepaddle-gpu==0.11.0.post87 使用CUDA 8.0和cuDNN 7编译的0.11.0版本 +paddlepaddle-gpu==0.11.0.post8 使用CUDA 8.0和cuDNN 5编译的0.11.0版本 +paddlepaddle-gpu==0.11.0 使用CUDA 7.5和cuDNN 5编译的0.11.0版本 +================================= ======================================== + +您可以在 `Release History `_ 中找到paddlepaddle-gpu的各个发行版本。 + 如果需要获取并安装最新的(开发分支)PaddlePaddle,可以从我们的CI系统中下载最新的whl安装包和c-api开发包并安装, 您可以从下面的表格中找到需要的版本: @@ -37,12 +55,11 @@ PaddlePaddle可以使用常用的Python包管理工具 :header: "版本说明", "cp27-cp27mu", "cp27-cp27m" :widths: 1, 3, 3 - "cpu_avx_mkl", "`paddlepaddle-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-0.11.0-cp27-cp27m-linux_x86_64.whl `_" - "cpu_avx_openblas", "`paddlepaddle-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-0.11.0-cp27-cp27m-linux_x86_64.whl `_" - "cpu_noavx_openblas", "`paddlepaddle-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-0.11.0-cp27-cp27m-linux_x86_64.whl `_" - "cuda7.5_cudnn5_avx_mkl", "`paddlepaddle_gpu-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle_gpu-0.11.0-cp27-cp27m-linux_x86_64.whl `_" - "cuda8.0_cudnn5_avx_mkl", "`paddlepaddle_gpu-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle_gpu-0.11.0-cp27-cp27m-linux_x86_64.whl `_" - "cuda8.0_cudnn7_avx_mkl", "`paddlepaddle_gpu-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle_gpu-0.11.0-cp27-cp27m-linux_x86_64.whl `_" + "cpu_avx_mkl", "`paddlepaddle-latest-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-latest-cp27-cp27m-linux_x86_64.whl `_" + "cpu_avx_openblas", "`paddlepaddle-latest-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-latest-cp27-cp27m-linux_x86_64.whl `_" + "cpu_noavx_openblas", "`paddlepaddle-latest-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-latest-cp27-cp27m-linux_x86_64.whl `_" + "cuda8.0_cudnn5_avx_mkl", "`paddlepaddle_gpu-latest-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle_gpu-latest-cp27-cp27m-linux_x86_64.whl `_" + "cuda8.0_cudnn7_avx_mkl", "`paddlepaddle_gpu-latest-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle_gpu-latest-cp27-cp27m-linux_x86_64.whl `_" .. _pip_dependency: @@ -69,7 +86,7 @@ PaddlePaddle发布的安装包会尽量对齐 `manylinux1 9.0.0) 才可以安装。可以使用下面的命令更新您的pip: .. code-block:: bash diff --git a/doc/v2/build_and_install/pip_install_en.rst b/doc/v2/build_and_install/pip_install_en.rst index 1e409d86b9775094998f72f92954f4bbc1013ea1..fcac76d6a24eb4905a20f797d614db8f743342d7 100644 --- a/doc/v2/build_and_install/pip_install_en.rst +++ b/doc/v2/build_and_install/pip_install_en.rst @@ -12,20 +12,38 @@ Install using pip ------------------------------ Run the following command to install PaddlePaddle on the current -machine, it will also download requirements, the version is cpu_avx_openblas. +machine, it will also download requirements. .. code-block:: bash pip install paddlepaddle +the default version is 0.12.0, cpu_avx_openblas, you can specify the versions to satisfy your demands, like: -If you wish to install GPU version (cuda7.5_cudnn5_avx_openblas), just run: + .. code-block:: bash + + pip install paddlepaddle==0.11.0 + +If you need to install a GPU-enabled version (cuda8.0_cudnn5_avx_openblas), you need to run: .. code-block:: bash pip install paddlepaddle-gpu -If you wish to install the latest develop branch PaddlePaddle, +The default version is also 0.12.0, PaddlePaddle provides several versions of packages for different needs, as shown in the table: + +================================= ======================================== +版本号 版本说明 +================================= ======================================== +paddlepaddle-gpu==0.12.0 0.12.0 built with CUDA 8.0 and cuDNN 5 +paddlepaddle-gpu==0.11.0.post87 0.11.0 built with CUDA 8.0 and cuDNN 7 +paddlepaddle-gpu==0.11.0.post8 0.11.0 built with CUDA 8.0 and cuDNN 5 +paddlepaddle-gpu==0.11.0 0.11.0 built with CUDA 7.5 and cuDNN 5 +================================= ======================================== + +You can find all versions released of paddlepaddle-gpu in `Release History `_ . + +If you wish to install the latest develop branch PaddlePaddle, you can download the latest whl package from our CI system. Access the below links, log in as guest, then click at the "Artifact" tab, you'll find the download link of whl packages. @@ -40,12 +58,11 @@ If the links below shows up the login form, just click "Log in as guest" to star :header: "version", "cp27-cp27mu", "cp27-cp27m" :widths: 1, 3, 3 - "cpu_avx_mkl", "`paddlepaddle-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-0.11.0-cp27-cp27m-linux_x86_64.whl `_" - "cpu_avx_openblas", "`paddlepaddle-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-0.11.0-cp27-cp27m-linux_x86_64.whl `_" - "cpu_noavx_openblas", "`paddlepaddle-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-0.11.0-cp27-cp27m-linux_x86_64.whl `_" - "cuda7.5_cudnn5_avx_mkl", "`paddlepaddle_gpu-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle_gpu-0.11.0-cp27-cp27m-linux_x86_64.whl `_" - "cuda8.0_cudnn5_avx_mkl", "`paddlepaddle_gpu-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle_gpu-0.11.0-cp27-cp27m-linux_x86_64.whl `_" - "cuda8.0_cudnn7_avx_mkl", "`paddlepaddle_gpu-0.11.0-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle_gpu-0.11.0-cp27-cp27m-linux_x86_64.whl `_" + "cpu_avx_mkl", "`paddlepaddle-latest-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-latest-cp27-cp27m-linux_x86_64.whl `_" + "cpu_avx_openblas", "`paddlepaddle-latest-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-latest-cp27-cp27m-linux_x86_64.whl `_" + "cpu_noavx_openblas", "`paddlepaddle-latest-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle-latest-cp27-cp27m-linux_x86_64.whl `_" + "cuda8.0_cudnn5_avx_mkl", "`paddlepaddle_gpu-latest-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle_gpu-latest-cp27-cp27m-linux_x86_64.whl `_" + "cuda8.0_cudnn7_avx_mkl", "`paddlepaddle_gpu-latest-cp27-cp27mu-linux_x86_64.whl `_", "`paddlepaddle_gpu-latest-cp27-cp27m-linux_x86_64.whl `_" .. _pip_dependency: @@ -79,7 +96,7 @@ FAQ ------------------------------ - paddlepaddle*.whl is not a supported wheel on this platform. - + The main cause of this issue is that your current platform is not supported. Please check that you are using Python 2.7 series. Besides, pypi only supports manylinux1 standard, you'll need to diff --git a/paddle/CMakeLists.txt b/paddle/CMakeLists.txt index 8b1ca5e16548334ed0c9a6d31b88e0805304579e..d722eec1892206ac44c49e7a12d92be0c54df8c0 100644 --- a/paddle/CMakeLists.txt +++ b/paddle/CMakeLists.txt @@ -24,6 +24,6 @@ if(NOT WITH_FLUID_ONLY) endif() add_subdirectory(testing) -if(NOT MOBILE_INFERENCE AND NOT RPI) +if(NOT MOBILE_INFERENCE AND NOT RPI AND NOT WITH_C_API) add_subdirectory(fluid) endif() diff --git a/contrib/float16/.gitignore b/paddle/contrib/float16/.gitignore similarity index 100% rename from contrib/float16/.gitignore rename to paddle/contrib/float16/.gitignore diff --git a/contrib/float16/README.md b/paddle/contrib/float16/README.md similarity index 100% rename from contrib/float16/README.md rename to paddle/contrib/float16/README.md diff --git a/contrib/float16/float16_benchmark.md b/paddle/contrib/float16/float16_benchmark.md similarity index 100% rename from contrib/float16/float16_benchmark.md rename to paddle/contrib/float16/float16_benchmark.md diff --git a/contrib/float16/float16_inference_demo.py b/paddle/contrib/float16/float16_inference_demo.py similarity index 100% rename from contrib/float16/float16_inference_demo.py rename to paddle/contrib/float16/float16_inference_demo.py diff --git a/contrib/float16/float16_transpiler.py b/paddle/contrib/float16/float16_transpiler.py similarity index 100% rename from contrib/float16/float16_transpiler.py rename to paddle/contrib/float16/float16_transpiler.py diff --git a/contrib/float16/run_float16_demo.sh b/paddle/contrib/float16/run_float16_demo.sh similarity index 100% rename from contrib/float16/run_float16_demo.sh rename to paddle/contrib/float16/run_float16_demo.sh diff --git a/contrib/inference/README.md b/paddle/contrib/inference/README.md similarity index 100% rename from contrib/inference/README.md rename to paddle/contrib/inference/README.md diff --git a/contrib/inference/paddle_inference_api.h b/paddle/contrib/inference/paddle_inference_api.h similarity index 100% rename from contrib/inference/paddle_inference_api.h rename to paddle/contrib/inference/paddle_inference_api.h diff --git a/paddle/fluid/framework/data_device_transform.cc b/paddle/fluid/framework/data_device_transform.cc index 85dbb39e6fba735471446b5e5e71a612282c498a..a876725ac0f17838458065c4b4753a03e2812801 100644 --- a/paddle/fluid/framework/data_device_transform.cc +++ b/paddle/fluid/framework/data_device_transform.cc @@ -36,9 +36,11 @@ void TransDataDevice(const Tensor& in, const platform::Place& dst_place, VLOG(3) << "DeviceTransform in, src_place " << in.place() << " dst_place: " << dst_place; auto* dev_ctx = GetDeviceContext(in.place(), dst_place); - dev_ctx->Wait(); + TensorCopy(in, dst_place, *dev_ctx, out); - dev_ctx->Wait(); + if (platform::is_gpu_place(in.place()) && platform::is_cpu_place(dst_place)) { + dev_ctx->Wait(); + } } } // namespace framework diff --git a/paddle/fluid/framework/data_type.cc b/paddle/fluid/framework/data_type.cc index b9c90cb0c32f337ba82ce1eaa5b43199540491ef..b6b93cf422a60c1d8e9cb8b477efd562f9fe4758 100644 --- a/paddle/fluid/framework/data_type.cc +++ b/paddle/fluid/framework/data_type.cc @@ -58,6 +58,7 @@ static DataTypeMap* InitDataTypeMap() { RegType(bool, proto::VarType::BOOL); RegType(size_t, proto::VarType::SIZE_T); RegType(int16_t, proto::VarType::INT16); + RegType(uint8_t, proto::VarType::UINT8); #undef RegType return retv; diff --git a/paddle/fluid/framework/data_type.h b/paddle/fluid/framework/data_type.h index 4b9f572ec5f1cda71c8b8dd8fae54b42e9f16f7a..491413db8c8d66fd907801131e89d9303bdef9f2 100644 --- a/paddle/fluid/framework/data_type.h +++ b/paddle/fluid/framework/data_type.h @@ -47,8 +47,14 @@ inline void VisitDataType(proto::VarType::Type type, Visitor visitor) { case proto::VarType::BOOL: visitor.template operator()(); break; + case proto::VarType::UINT8: + visitor.template operator()(); + break; + case proto::VarType::INT16: + visitor.template operator()(); + break; default: - PADDLE_THROW("Not supported"); + PADDLE_THROW("Not supported %d", type); } } diff --git a/paddle/fluid/framework/data_type_transform.cc b/paddle/fluid/framework/data_type_transform.cc index c0523f3c795b103c0c27081ec5dc717f6a0f11e0..5a57ec20585c26dbcd4251464718fc819148a7a5 100644 --- a/paddle/fluid/framework/data_type_transform.cc +++ b/paddle/fluid/framework/data_type_transform.cc @@ -91,6 +91,12 @@ void TransDataType(const OpKernelType& kernel_type_for_var, case proto::VarType::BOOL: framework::VisitDataType(dst_type, CastDataType(in, out, ctx)); break; + case proto::VarType::INT16: + framework::VisitDataType(dst_type, CastDataType(in, out, ctx)); + break; + case proto::VarType::UINT8: + framework::VisitDataType(dst_type, CastDataType(in, out, ctx)); + break; default: PADDLE_THROW("Not support type %d", src_type); } diff --git a/paddle/fluid/framework/details/fetch_op_handle.cc b/paddle/fluid/framework/details/fetch_op_handle.cc index b1c9dd0d15223f7d1bf6ea44144589f1de927e3e..224e8e1f6efd7a894591ac51c929517cae7539ce 100644 --- a/paddle/fluid/framework/details/fetch_op_handle.cc +++ b/paddle/fluid/framework/details/fetch_op_handle.cc @@ -48,17 +48,18 @@ void FetchOpHandle::RunImpl() { WaitInputVarGenerated(platform::CPUPlace()); tensors_.resize(inputs_.size()); - auto *var_handle = static_cast(inputs_[0]); - auto &var_name = var_handle->name_; platform::CPUPlace cpu; auto &scopes = *local_scopes_; - for (size_t i = 0; i < scopes.size(); ++i) { - auto &scope = scopes[i]; - auto *var = - scope->FindVar(kLocalExecScopeName)->Get()->FindVar(var_name); + for (size_t i = 0; i < inputs_.size(); ++i) { + auto *var_handle = static_cast(inputs_[i]); + auto &scope = scopes.at(var_handle->scope_idx_); + auto *var = scope->FindVar(kLocalExecScopeName) + ->Get() + ->FindVar(var_handle->name_); PADDLE_ENFORCE_NOT_NULL(var, "Cannot find variable %s in execution scope", - var_name); + var_handle->name_); + auto &t = var->Get(); if (platform::is_gpu_place(t.place())) { #ifdef PADDLE_WITH_CUDA diff --git a/paddle/fluid/framework/details/multi_devices_graph_builder.cc b/paddle/fluid/framework/details/multi_devices_graph_builder.cc index 7aae514094cab674511a4e88cc642c1d96df83d7..6506af6520bb35d99770b804e1204c9a437617c7 100644 --- a/paddle/fluid/framework/details/multi_devices_graph_builder.cc +++ b/paddle/fluid/framework/details/multi_devices_graph_builder.cc @@ -98,7 +98,7 @@ bool MultiDevSSAGraphBuilder::IsDistTrainOp(const OpDesc &op, return false; }; - if (op.Type() == "split") { + if (op.Type() == "split" || op.Type() == "split_byref") { return checker(op.OutputArgumentNames(), send_op->InputArgumentNames()); } else if (op.Type() == "concat") { return checker(op.InputArgumentNames(), send_op->OutputArgumentNames()); diff --git a/paddle/fluid/framework/details/op_handle_base.h b/paddle/fluid/framework/details/op_handle_base.h index fe1735d05dde5f09d5c72c68e5002d16f0083eb5..8f94206a87dbae8a81727ca48718886bbabbe25c 100644 --- a/paddle/fluid/framework/details/op_handle_base.h +++ b/paddle/fluid/framework/details/op_handle_base.h @@ -70,6 +70,14 @@ class OpHandleBase { const std::vector &Inputs() const { return inputs_; } + size_t NoDupInputSize() const { + std::unordered_set res; + for (auto *var : inputs_) { + res.emplace(var); + } + return res.size(); + } + const std::vector &Outputs() const { return outputs_; } protected: diff --git a/paddle/fluid/framework/details/threaded_ssa_graph_executor.cc b/paddle/fluid/framework/details/threaded_ssa_graph_executor.cc index ef263d82c5ec93f0673eb0ac70e4fb02904bff13..815f739371e77d953a28be99b38ec1b8ff26506c 100644 --- a/paddle/fluid/framework/details/threaded_ssa_graph_executor.cc +++ b/paddle/fluid/framework/details/threaded_ssa_graph_executor.cc @@ -174,7 +174,7 @@ void ThreadedSSAGraphExecutor::InsertFetchOps( void ThreadedSSAGraphExecutor::InsertPendingOp( std::unordered_map *pending_ops, OpHandleBase *op_instance) const { - pending_ops->insert({op_instance, op_instance->Inputs().size()}); + pending_ops->insert({op_instance, op_instance->NoDupInputSize()}); } void ThreadedSSAGraphExecutor::InsertPendingVar( diff --git a/paddle/fluid/framework/executor.cc b/paddle/fluid/framework/executor.cc index ce91d7a82674364560b8065277b28b51ae1b303a..4e431561f81b2a84c06dff9fcb041317ebc84ae3 100644 --- a/paddle/fluid/framework/executor.cc +++ b/paddle/fluid/framework/executor.cc @@ -228,7 +228,8 @@ static bool has_fetch_operators( void Executor::Run(const ProgramDesc& program, Scope* scope, std::map* feed_targets, std::map* fetch_targets, - bool create_vars, const std::string& feed_holder_name, + bool create_local_scope, bool create_vars, + const std::string& feed_holder_name, const std::string& fetch_holder_name) { platform::RecordBlock b(kProgramId); bool has_feed_ops = @@ -290,8 +291,9 @@ void Executor::Run(const ProgramDesc& program, Scope* scope, } auto ctx = Prepare(*copy_program, 0); - RunPreparedContext(ctx.get(), scope, feed_targets, fetch_targets, create_vars, - feed_holder_name, fetch_holder_name); + RunPreparedContext(ctx.get(), scope, feed_targets, fetch_targets, + create_local_scope, create_vars, feed_holder_name, + fetch_holder_name); } std::unique_ptr Executor::Prepare( @@ -366,8 +368,9 @@ void Executor::RunPreparedContext(ExecutorPrepareContext* ctx, Scope* scope, void Executor::RunPreparedContext( ExecutorPrepareContext* ctx, Scope* scope, std::map* feed_targets, - std::map* fetch_targets, bool create_vars, - const std::string& feed_holder_name, const std::string& fetch_holder_name) { + std::map* fetch_targets, bool create_local_scope, + bool create_vars, const std::string& feed_holder_name, + const std::string& fetch_holder_name) { auto& global_block = ctx->prog_.Block(ctx->block_id_); PADDLE_ENFORCE( @@ -387,7 +390,7 @@ void Executor::RunPreparedContext( } } - RunPreparedContext(ctx, scope, create_vars, create_vars); + RunPreparedContext(ctx, scope, create_local_scope, create_vars); // obtain the data of fetch_targets from fetch_holder for (auto* op : global_block.AllOps()) { diff --git a/paddle/fluid/framework/executor.h b/paddle/fluid/framework/executor.h index 4a3d637e2d79f8cbd83412eea2d73e4b497ef1e7..0c3c23611d95e0da67cabfb8fb2755a4a52c991b 100644 --- a/paddle/fluid/framework/executor.h +++ b/paddle/fluid/framework/executor.h @@ -57,7 +57,7 @@ class Executor { void Run(const ProgramDesc& program, Scope* scope, std::map* feed_targets, std::map* fetch_targets, - bool create_vars = true, + bool create_local_scope = true, bool create_vars = true, const std::string& feed_holder_name = "feed", const std::string& fetch_holder_name = "fetch"); @@ -76,6 +76,7 @@ class Executor { void RunPreparedContext(ExecutorPrepareContext* ctx, Scope* scope, std::map* feed_targets, std::map* fetch_targets, + bool create_local_scope = true, bool create_vars = true, const std::string& feed_holder_name = "feed", const std::string& fetch_holder_name = "fetch"); diff --git a/paddle/fluid/framework/framework.proto b/paddle/fluid/framework/framework.proto index d2558f111f49139b33f921f7260b41830279edc8..d35125fe8c3c8018c38650dc87b2b1474ded6058 100644 --- a/paddle/fluid/framework/framework.proto +++ b/paddle/fluid/framework/framework.proto @@ -103,6 +103,7 @@ message VarType { FP64 = 6; // Tensor is used in C++. SIZE_T = 19; + UINT8 = 20; // Other types that may need additional descriptions LOD_TENSOR = 7; diff --git a/paddle/fluid/framework/lod_tensor_test.cc b/paddle/fluid/framework/lod_tensor_test.cc index 77e5ec4c7dd14b7ebb6d606b8c401ee714259d40..2ceffc93319359683e87e7fec2d18784c9bf02f3 100644 --- a/paddle/fluid/framework/lod_tensor_test.cc +++ b/paddle/fluid/framework/lod_tensor_test.cc @@ -228,11 +228,12 @@ TEST(LoD, CheckAbsLoD) { ASSERT_FALSE(CheckAbsLoD(abs_lod0)); } -TEST(LoDTensor, RecordIO) { +template +static void TestRecordIO() { LoDTensor tensor; - int* tmp = tensor.mutable_data(make_ddim({4, 5}), platform::CPUPlace()); + T* tmp = tensor.mutable_data(make_ddim({4, 5}), platform::CPUPlace()); for (int i = 0; i < 20; ++i) { - tmp[i] = i; + tmp[i] = static_cast(i); } std::stringstream* stream = new std::stringstream(); @@ -247,7 +248,7 @@ TEST(LoDTensor, RecordIO) { auto assert_tensor_ok = [](const LoDTensor& tensor) { for (int i = 0; i < 20; ++i) { - ASSERT_EQ(tensor.data()[i], i); + ASSERT_EQ(tensor.data()[i], static_cast(i)); } }; @@ -265,5 +266,13 @@ TEST(LoDTensor, RecordIO) { } } +TEST(LoDTensor, RecordIO) { + TestRecordIO(); + TestRecordIO(); + TestRecordIO(); + TestRecordIO(); + TestRecordIO(); +} + } // namespace framework } // namespace paddle diff --git a/paddle/fluid/framework/operator.h b/paddle/fluid/framework/operator.h index a4eb6f706edab9479cbce436311eb96da8845646..2f480e00c100d579e100de17d3feb957f5ef6167 100644 --- a/paddle/fluid/framework/operator.h +++ b/paddle/fluid/framework/operator.h @@ -33,7 +33,6 @@ limitations under the License. */ #include "paddle/fluid/framework/tensor.h" #include "paddle/fluid/platform/device_context.h" #include "paddle/fluid/platform/variant.h" -#include "paddle/utils/Error.h" namespace paddle { namespace framework { diff --git a/paddle/fluid/inference/tensorrt/convert/op_converter.h b/paddle/fluid/inference/tensorrt/convert/op_converter.h index abc9ebf472498f6653d5bb1113ae2f3ce7e5a923..1cd3ed9a00acead2599420f88499bd0d74c2974b 100644 --- a/paddle/fluid/inference/tensorrt/convert/op_converter.h +++ b/paddle/fluid/inference/tensorrt/convert/op_converter.h @@ -49,7 +49,7 @@ class OpConverter { // convert fluid block to tensorrt network void ConvertBlock(const framework::proto::BlockDesc& block, TensorRTEngine* engine) { - for (size_t i = 0; i < block.ops_size(); i++) { + for (int i = 0; i < block.ops_size(); i++) { const auto& op = block.ops(i); OpConverter::Run(op, engine); } diff --git a/paddle/fluid/inference/tests/test_helper.h b/paddle/fluid/inference/tests/test_helper.h index b02e5c99f00eaf03c3753e43575cbc67e834774e..cc1589514aab3b973b4909159748bc4223cdce46 100644 --- a/paddle/fluid/inference/tests/test_helper.h +++ b/paddle/fluid/inference/tests/test_helper.h @@ -149,7 +149,7 @@ void TestInference(const std::string& dirname, state = paddle::platform::ProfilerState::kCPU; } else { #ifdef PADDLE_WITH_CUDA - state = paddle::platform::ProfilerState::kCUDA; + state = paddle::platform::ProfilerState::kAll; // The default device_id of paddle::platform::CUDAPlace is 0. // Users can get the device_id using: // int device_id = place.GetDeviceId(); @@ -172,7 +172,7 @@ void TestInference(const std::string& dirname, } // Disable the profiler and print the timing information paddle::platform::DisableProfiler(paddle::platform::EventSortingKey::kDefault, - "load_program_profiler.txt"); + "load_program_profiler"); paddle::platform::ResetProfiler(); // 3. Get the feed_target_names and fetch_target_names @@ -208,10 +208,10 @@ void TestInference(const std::string& dirname, if (PrepareContext) { ctx = executor.Prepare(*inference_program, 0); executor.RunPreparedContext(ctx.get(), scope, &feed_targets, - &fetch_targets, CreateVars); + &fetch_targets, true, CreateVars); } else { executor.Run(*inference_program, scope, &feed_targets, &fetch_targets, - CreateVars); + true, CreateVars); } // Enable the profiler @@ -236,8 +236,7 @@ void TestInference(const std::string& dirname, // Disable the profiler and print the timing information paddle::platform::DisableProfiler( - paddle::platform::EventSortingKey::kDefault, - "run_inference_profiler.txt"); + paddle::platform::EventSortingKey::kDefault, "run_inference_profiler"); paddle::platform::ResetProfiler(); } diff --git a/paddle/fluid/operators/CMakeLists.txt b/paddle/fluid/operators/CMakeLists.txt index d38a9ce58726a1d045d6905354b0b592166c0110..7fce138e3f47e0eb485afb4d5a665eb41f68e286 100644 --- a/paddle/fluid/operators/CMakeLists.txt +++ b/paddle/fluid/operators/CMakeLists.txt @@ -186,11 +186,7 @@ endif() add_subdirectory(detail) if(WITH_DISTRIBUTE) - if(WITH_GPU) - op_library(gen_nccl_id_op DEPS nccl_common) - else() - set(DEPS_OPS ${DEPS_OPS} gen_nccl_id_op) - endif() + set(DISTRIBUTE_DEPS sendrecvop_grpc grpc++_unsecure grpc_unsecure gpr cares zlib protobuf) set(DISTRIBUTE_COMPILE_FLAGS "-Wno-non-virtual-dtor -Wno-error=non-virtual-dtor -Wno-error=delete-non-virtual-dtor") op_library(send_op DEPS ${DISTRIBUTE_DEPS}) @@ -207,7 +203,14 @@ if(WITH_DISTRIBUTE) set_source_files_properties(send_barrier_op.cc PROPERTIES COMPILE_FLAGS ${DISTRIBUTE_COMPILE_FLAGS}) set_source_files_properties(send_recv_op_test.cc PROPERTIES COMPILE_FLAGS ${DISTRIBUTE_COMPILE_FLAGS}) cc_test(test_send_recv SRCS send_recv_op_test.cc DEPS prefetch_op send_op listen_and_serv_op sum_op executor) - cc_test(test_send_nccl_id SRCS test_send_nccl_id.cc DEPS send_op listen_and_serv_op executor) + if(WITH_GPU) + set_source_files_properties(test_send_nccl_id.cc PROPERTIES COMPILE_FLAGS ${DISTRIBUTE_COMPILE_FLAGS}) + cc_test(test_send_nccl_id SRCS test_send_nccl_id.cc DEPS send_op listen_and_serv_op executor) + op_library(gen_nccl_id_op DEPS nccl_common sendrecvop_grpc) + set_source_files_properties(gen_nccl_id_op.cc PROPERTIES COMPILE_FLAGS ${DISTRIBUTE_COMPILE_FLAGS}) + else() + set(DEPS_OPS ${DEPS_OPS} gen_nccl_id_op) + endif() else() set(DEPS_OPS ${DEPS_OPS} send_op prefetch_op recv_op listen_and_serv_op send_vars_op send_barrier_op gen_nccl_id_op) endif() diff --git a/paddle/fluid/operators/activation_mkldnn_op.cc b/paddle/fluid/operators/activation_mkldnn_op.cc index ab7c61227114fe7a0ce2ff2515dd560706058b64..b892ac77d9ed60210ddadaecb1a4f214e5a25180 100644 --- a/paddle/fluid/operators/activation_mkldnn_op.cc +++ b/paddle/fluid/operators/activation_mkldnn_op.cc @@ -15,6 +15,7 @@ #include "mkldnn.hpp" #include "paddle/fluid/operators/activation_op.h" #include "paddle/fluid/operators/mkldnn_activation_op.h" +#include "paddle/fluid/platform/mkldnn_helper.h" namespace paddle { namespace operators { @@ -23,6 +24,18 @@ using paddle::framework::Tensor; using paddle::platform::MKLDNNDeviceContext; namespace { +std::string gethash(const mkldnn::memory::dims &operand_dims, + const mkldnn::algorithm algorithm) { + auto dim2str = [](const mkldnn::memory::dims &operand_dims) { + std::string dstr = ""; + for (size_t i = 0; i < operand_dims.size(); ++i) { + dstr += std::to_string(operand_dims[i]) + "-"; + } + return dstr; + }; + return dim2str(operand_dims) + std::to_string(algorithm); +} + template void eltwise_forward(const ExecContext &ctx, mkldnn::algorithm algorithm, const T alpha = 0, const T beta = 0) { @@ -37,42 +50,70 @@ void eltwise_forward(const ExecContext &ctx, mkldnn::algorithm algorithm, const auto *src_data = src->template data(); auto *dst = ctx.template Output("Out"); - const T *dst_data = dst->template mutable_data(ctx.GetPlace()); + T *dst_data = dst->template mutable_data(ctx.GetPlace()); // get memory dim PADDLE_ENFORCE(src->dims().size() == 2 || src->dims().size() == 4, "Input dim must be with 2 or 4"); std::vector src_tz = framework::vectorize2int(src->dims()); - // create memory description - auto data_md = src_tz.size() == 2 - ? platform::MKLDNNMemDesc(src_tz, mkldnn::memory::f32, - mkldnn::memory::format::nc) - : platform::MKLDNNMemDesc(src_tz, mkldnn::memory::f32, - mkldnn::memory::format::nchw); - - // create memory primitives - auto src_memory = - mkldnn::memory({data_md, mkldnn_engine}, - static_cast(const_cast(src_data))); - auto dst_memory = - mkldnn::memory({data_md, mkldnn_engine}, - static_cast(const_cast(dst_data))); - - auto forward_desc = mkldnn::eltwise_forward::desc( - mkldnn::prop_kind::forward_training, algorithm, data_md, alpha, beta); - - // save prim desc into global device context to be referred in backward path - const std::string key = ctx.op().Output("Out"); - const std::string key_eltwise_pd = key + "@eltwise_pd"; - auto forward_pd = std::make_shared( - forward_desc, mkldnn_engine); - dev_ctx.SetBlob(key_eltwise_pd, forward_pd); - - auto eltwise = mkldnn::eltwise_forward(*forward_pd, src_memory, dst_memory); + const std::string key = gethash(src_tz, algorithm); + const std::string key_src_data = + key + ctx.op().Output("Out") + "@eltwise_fwd_src_data"; + const std::string key_src_mem = key + "@eltwise_fwd_src_mem"; + const std::string key_dst_mem = key + "@eltwise_fwd_dst_mem"; + const std::string key_fwd = key + "@eltwise_fwd"; + + auto p_fwd = std::static_pointer_cast( + dev_ctx.GetBlob(key_fwd)); + + // save input data to be referred in backward path + auto p_src_data = std::make_shared(src_data); + dev_ctx.SetBlob(key_src_data, p_src_data); + + if (p_fwd == nullptr) { + // create memory description + auto data_md = src_tz.size() == 2 + ? platform::MKLDNNMemDesc(src_tz, mkldnn::memory::f32, + mkldnn::memory::format::nc) + : platform::MKLDNNMemDesc(src_tz, mkldnn::memory::f32, + mkldnn::memory::format::nchw); + + // create memory primitives + auto p_src_mem = std::make_shared(mkldnn::memory( + {data_md, mkldnn_engine}, platform::to_void_cast(src_data))); + dev_ctx.SetBlob(key_src_mem, p_src_mem); + + auto p_dst_mem = std::make_shared(mkldnn::memory( + {data_md, mkldnn_engine}, platform::to_void_cast(dst_data))); + dev_ctx.SetBlob(key_dst_mem, p_dst_mem); + + auto fwd_desc = mkldnn::eltwise_forward::desc( + mkldnn::prop_kind::forward_training, algorithm, data_md, alpha, beta); + auto p_fwd_pd = std::make_shared( + fwd_desc, mkldnn_engine); + const std::string key_fwd_pd = key + "eltwise_fwd_pd"; + dev_ctx.SetBlob(key_fwd_pd, p_fwd_pd); + p_fwd = std::make_shared( + *p_fwd_pd, *(p_src_mem.get()), *(p_dst_mem.get())); + dev_ctx.SetBlob(key_fwd, p_fwd); + } else { + // primitives already exist + auto p_src_mem = + std::static_pointer_cast(dev_ctx.GetBlob(key_src_mem)); + PADDLE_ENFORCE(p_src_mem != nullptr, + "Fail to find eltwise p_src_mem in device context."); + auto p_dst_mem = + std::static_pointer_cast(dev_ctx.GetBlob(key_dst_mem)); + PADDLE_ENFORCE(p_dst_mem != nullptr, + "Fail to find eltwise p_src_mem in device context."); + + p_src_mem->set_data_handle(platform::to_void_reinterpret_cast(src_data)); + p_dst_mem->set_data_handle(dst_data); + } // push primitive to stream and wait until it's executed - std::vector pipeline = {eltwise}; + std::vector pipeline = {*(p_fwd.get())}; mkldnn::stream(mkldnn::stream::kind::eager).submit(pipeline).wait(); } @@ -83,8 +124,7 @@ void eltwise_grad(const ExecContext &ctx, mkldnn::algorithm algorithm, const auto &mkldnn_engine = dev_ctx.GetEngine(); // get buffers - const auto *x = ctx.template Input("X"); - const auto *src = x->template data(); + const auto *out = ctx.template Input("Out"); auto *dout = ctx.template Input(framework::GradVarName("Out")); const auto *diff_dst = dout->template data(); @@ -94,45 +134,73 @@ void eltwise_grad(const ExecContext &ctx, mkldnn::algorithm algorithm, const T *diff_src = dx->template mutable_data(ctx.GetPlace()); // get memory dim - std::vector src_tz = framework::vectorize2int(x->dims()); - - // create memory description - auto data_md = src_tz.size() == 2 - ? platform::MKLDNNMemDesc(src_tz, mkldnn::memory::f32, - mkldnn::memory::format::nc) - : platform::MKLDNNMemDesc(src_tz, mkldnn::memory::f32, - mkldnn::memory::format::nchw); - - // create memory primitives - auto src_memory = mkldnn::memory( - {data_md, mkldnn_engine}, static_cast(const_cast(src))); - auto diff_src_memory = - mkldnn::memory({data_md, mkldnn_engine}, - static_cast(const_cast(diff_src))); - auto diff_dst_memory = - mkldnn::memory({data_md, mkldnn_engine}, - static_cast(const_cast(diff_dst))); - - auto backward_desc = - mkldnn::eltwise_backward::desc(algorithm, data_md, data_md, alpha, beta); - - // retrieve eltwise primitive desc from device context - const std::string key = ctx.op().Input("Out"); - const std::string key_eltwise_pd = key + "@eltwise_pd"; - const std::shared_ptr forward_pd = dev_ctx.GetBlob(key_eltwise_pd); - PADDLE_ENFORCE(forward_pd != nullptr, - "Fail to find eltwise_pd in device context"); - auto *p_forward_pd = - static_cast(forward_pd.get()); - - auto eltwise_bwd_prim_desc = mkldnn::eltwise_backward::primitive_desc( - backward_desc, mkldnn_engine, *p_forward_pd); - - auto eltwise_bwd = mkldnn::eltwise_backward(eltwise_bwd_prim_desc, src_memory, - diff_dst_memory, diff_src_memory); + std::vector src_tz = framework::vectorize2int(out->dims()); + + const std::string key = gethash(src_tz, algorithm); + const std::string key_diff_src_mem = key + "@eltwise_diff_src_mem"; + const std::string key_diff_dst_mem = key + "@eltwise_diff_dst_mem"; + const std::string key_grad = key + "@eltwise_grad"; + + const std::string key_src_data = + key + ctx.op().Input("Out") + "@eltwise_fwd_src_data"; + const auto p_src_data = + std::static_pointer_cast(dev_ctx.GetBlob(key_src_data)); + + const std::string key_src_mem = key + "@eltwise_fwd_src_mem"; + auto p_src_mem = + std::static_pointer_cast(dev_ctx.GetBlob(key_src_mem)); + p_src_mem->set_data_handle(*p_src_data.get()); + + auto p_grad = std::static_pointer_cast( + dev_ctx.GetBlob(key_grad)); + + if (p_grad == nullptr) { + // create memory description + auto data_md = src_tz.size() == 2 + ? platform::MKLDNNMemDesc(src_tz, mkldnn::memory::f32, + mkldnn::memory::format::nc) + : platform::MKLDNNMemDesc(src_tz, mkldnn::memory::f32, + mkldnn::memory::format::nchw); + + // create memory primitives + std::shared_ptr p_diff_src_mem = + std::make_shared(mkldnn::memory( + {data_md, mkldnn_engine}, platform::to_void_cast(diff_src))); + dev_ctx.SetBlob(key_diff_src_mem, p_diff_src_mem); + std::shared_ptr p_diff_dst_mem = + std::make_shared(mkldnn::memory( + {data_md, mkldnn_engine}, platform::to_void_cast(diff_dst))); + dev_ctx.SetBlob(key_diff_dst_mem, p_diff_dst_mem); + + auto bwd_desc = mkldnn::eltwise_backward::desc(algorithm, data_md, data_md, + alpha, beta); + + const std::string key_fwd_pd = key + "eltwise_fwd_pd"; + auto *p_fwd_pd = static_cast( + dev_ctx.GetBlob(key_fwd_pd).get()); + + auto eltwise_bwd_prim_desc = mkldnn::eltwise_backward::primitive_desc( + bwd_desc, mkldnn_engine, *p_fwd_pd); + + p_grad = std::make_shared( + eltwise_bwd_prim_desc, *static_cast(p_src_mem.get()), + *(static_cast(p_diff_dst_mem.get())), + *(static_cast(p_diff_src_mem.get()))); + } else { + // primitives already exist + auto p_diff_src_mem = std::static_pointer_cast( + dev_ctx.GetBlob(key_diff_src_mem)); + auto p_diff_dst_mem = std::static_pointer_cast( + dev_ctx.GetBlob(key_diff_dst_mem)); + + p_diff_src_mem->set_data_handle( + platform::to_void_reinterpret_cast(diff_src)); + p_diff_dst_mem->set_data_handle( + platform::to_void_reinterpret_cast(diff_dst)); + } // push primitive to stream and wait until it's executed - std::vector pipeline = {eltwise_bwd}; + std::vector pipeline = {*(p_grad.get())}; mkldnn::stream(mkldnn::stream::kind::eager).submit(pipeline).wait(); } } // anonymous namespace diff --git a/paddle/fluid/operators/activation_op.cc b/paddle/fluid/operators/activation_op.cc index 55482abdf09516077a94ca99140ae7961f0915aa..dd71c66a75a039429f6e4b1771bb31508bb6b56d 100644 --- a/paddle/fluid/operators/activation_op.cc +++ b/paddle/fluid/operators/activation_op.cc @@ -41,7 +41,7 @@ namespace operators { \ protected: \ std::unique_ptr<::paddle::framework::OpDesc> Apply() const override { \ - auto *op = new ::paddle::framework::OpDesc(); \ + auto* op = new ::paddle::framework::OpDesc(); \ op->SetType(#KERNEL_TYPE "_grad"); \ op->SetInput("Out", Output("Out")); \ op->SetInput(::paddle::framework::GradVarName("Out"), \ @@ -54,23 +54,50 @@ namespace operators { } \ } +framework::OpKernelType GetKernelType(const framework::ExecutionContext& ctx, + const framework::OperatorWithKernel& oper, + const std::string& name) { + framework::LibraryType library{framework::LibraryType::kPlain}; +#ifdef PADDLE_WITH_MKLDNN + auto it = oper.Attrs().find("use_mkldnn"); + if (library == framework::LibraryType::kPlain && it != oper.Attrs().end() && + platform::CanMKLDNNBeUsed(ctx)) { + library = framework::LibraryType::kMKLDNN; + } +#endif + framework::DataLayout layout = framework::DataLayout::kAnyLayout; + return framework::OpKernelType( + framework::ToDataType(ctx.Input(name)->type()), + ctx.GetPlace(), layout, library); +} + class ActivationOp : public framework::OperatorWithKernel { public: using framework::OperatorWithKernel::OperatorWithKernel; - void InferShape(framework::InferShapeContext *ctx) const override { + void InferShape(framework::InferShapeContext* ctx) const override { ctx->SetOutputDim("Out", ctx->GetInputDim("X")); ctx->ShareLoD("X", /*->*/ "Out"); } + + framework::OpKernelType GetExpectedKernelType( + const framework::ExecutionContext& ctx) const override { + return GetKernelType(ctx, *this, "X"); + } }; class ActivationOpGrad : public framework::OperatorWithKernel { public: using framework::OperatorWithKernel::OperatorWithKernel; - void InferShape(framework::InferShapeContext *ctx) const override { + void InferShape(framework::InferShapeContext* ctx) const override { ctx->SetOutputDim(framework::GradVarName("X"), ctx->GetInputDim("Out")); } + + framework::OpKernelType GetExpectedKernelType( + const framework::ExecutionContext& ctx) const override { + return GetKernelType(ctx, *this, "Out"); + } }; __attribute__((unused)) constexpr char SigmoidDoc[] = R"DOC( diff --git a/paddle/fluid/operators/beam_search_op.h b/paddle/fluid/operators/beam_search_op.h index 9b51db8a45186c2a90cf8b2eb7966d0aaea04028..46bc4f6f936929050276e8b3b93f1eddd62ac638 100644 --- a/paddle/fluid/operators/beam_search_op.h +++ b/paddle/fluid/operators/beam_search_op.h @@ -14,10 +14,6 @@ limitations under the License. */ #pragma once -#ifdef PADDLE_WITH_TESTING -#include "gtest/gtest.h" -#endif - #include #include #include "paddle/fluid/framework/lod_tensor.h" diff --git a/paddle/fluid/operators/detail/grpc_server.cc b/paddle/fluid/operators/detail/grpc_server.cc index d09f8479b765ad26cc202bfdb2692828213c7956..eb114a47d99541402f748bfffcf6b10fde3e78e2 100644 --- a/paddle/fluid/operators/detail/grpc_server.cc +++ b/paddle/fluid/operators/detail/grpc_server.cc @@ -184,7 +184,7 @@ class RequestPrefetch final : public RequestBase { framework::Scope* local_scope = &scope_->NewScope(); auto* var = local_scope->FindVar(var_name); InitializeVariable(var, var_desc->GetType()); - executor_->RunPreparedContext(prefetch_ctx_, scope_, false, false); + executor_->RunPreparedContext(prefetch_ctx_, scope_); SerializeToByteBuffer(var_name, var, *dev_ctx_, &reply); diff --git a/paddle/fluid/operators/detection_map_op.cc b/paddle/fluid/operators/detection_map_op.cc index 0ccf701b61349274ce0627dfeaf7cfad384215cd..716c8625d35308f98582e6802e90d99d643e188b 100644 --- a/paddle/fluid/operators/detection_map_op.cc +++ b/paddle/fluid/operators/detection_map_op.cc @@ -51,7 +51,8 @@ class DetectionMAPOp : public framework::OperatorWithKernel { PADDLE_ENFORCE_EQ(label_dims.size(), 2, "The rank of Input(Label) must be 2, " "the shape is [N, 6]."); - PADDLE_ENFORCE_EQ(label_dims[1], 6, "The shape is of Input(Label) [N, 6]."); + PADDLE_ENFORCE(label_dims[1] == 6 || label_dims[1] == 5, + "The shape of Input(Label) is [N, 6] or [N, 5]."); if (ctx->HasInput("PosCount")) { PADDLE_ENFORCE(ctx->HasInput("TruePos"), @@ -88,9 +89,10 @@ class DetectionMAPOpMaker : public framework::OpProtoAndCheckerMaker { "offset is N + 1, if LoD[i + 1] - LoD[i] == 0, means there is " "no detected data."); AddInput("Label", - "(LoDTensor) A 2-D LoDTensor with shape[N, 6] represents the" + "(LoDTensor) A 2-D LoDTensor represents the" "Labeled ground-truth data. Each row has 6 values: " - "[label, is_difficult, xmin, ymin, xmax, ymax], N is the total " + "[label, xmin, ymin, xmax, ymax, is_difficult] or 5 values: " + "[label, xmin, ymin, xmax, ymax], where N is the total " "number of ground-truth data in this mini-batch. For each " "instance, the offsets in first dimension are called LoD, " "the number of offset is N + 1, if LoD[i + 1] - LoD[i] == 0, " diff --git a/paddle/fluid/operators/detection_map_op.h b/paddle/fluid/operators/detection_map_op.h index 431812e2bfcf926cadf8d7be6a7d1a79e78c7762..dd1ab85fd8d0c8170afcd9dd2a49ee55c41dc8be 100644 --- a/paddle/fluid/operators/detection_map_op.h +++ b/paddle/fluid/operators/detection_map_op.h @@ -72,7 +72,7 @@ class DetectionMAPOpKernel : public framework::OpKernel { auto* out_false_pos = ctx.Output("AccumFalsePos"); float overlap_threshold = ctx.Attr("overlap_threshold"); - float evaluate_difficult = ctx.Attr("evaluate_difficult"); + bool evaluate_difficult = ctx.Attr("evaluate_difficult"); auto ap_type = GetAPType(ctx.Attr("ap_type")); int class_num = ctx.Attr("class_num"); @@ -175,14 +175,20 @@ class DetectionMAPOpKernel : public framework::OpKernel { for (int n = 0; n < batch_size; ++n) { std::map> boxes; for (size_t i = label_index[n]; i < label_index[n + 1]; ++i) { - Box box(labels(i, 2), labels(i, 3), labels(i, 4), labels(i, 5)); int label = labels(i, 0); - auto is_difficult = labels(i, 1); - if (std::abs(is_difficult - 0.0) < 1e-6) - box.is_difficult = false; - else - box.is_difficult = true; - boxes[label].push_back(box); + if (input_label.dims()[1] == 6) { + Box box(labels(i, 2), labels(i, 3), labels(i, 4), labels(i, 5)); + auto is_difficult = labels(i, 1); + if (std::abs(is_difficult - 0.0) < 1e-6) + box.is_difficult = false; + else + box.is_difficult = true; + boxes[label].push_back(box); + } else { + PADDLE_ENFORCE_EQ(input_label.dims()[1], 5); + Box box(labels(i, 1), labels(i, 2), labels(i, 3), labels(i, 4)); + boxes[label].push_back(box); + } } gt_boxes->push_back(boxes); } diff --git a/paddle/fluid/operators/is_empty_op.cc b/paddle/fluid/operators/is_empty_op.cc index d3f3ad92442cafdd8d4cdc396d89721863d069c2..29b73951bbddd9bfd73c932d7801797590de5e8e 100644 --- a/paddle/fluid/operators/is_empty_op.cc +++ b/paddle/fluid/operators/is_empty_op.cc @@ -12,45 +12,41 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ +#include "paddle/fluid/operators/is_empty_op.h" #include "paddle/fluid/framework/op_registry.h" #include "paddle/fluid/framework/operator.h" namespace paddle { namespace operators { -constexpr char kInput[] = "X"; -constexpr char kOutput[] = "Out"; - -class IsEmptyOp : public framework::OperatorBase { +class IsEmptyOp : public framework::OperatorWithKernel { public: - IsEmptyOp(const std::string &type, const framework::VariableNameMap &inputs, - const framework::VariableNameMap &outputs, - const framework::AttributeMap &attrs) - : OperatorBase(type, inputs, outputs, attrs) {} + using framework::OperatorWithKernel::OperatorWithKernel; - private: - void RunImpl(const framework::Scope &scope, - const platform::Place &place) const override { - // get input - auto *var = scope.FindVar(Input(kInput)); - PADDLE_ENFORCE_NOT_NULL(var); - auto &tensor = var->Get(); - // get output - auto *out = scope.FindVar(Output(kOutput)); - PADDLE_ENFORCE_NOT_NULL(out); - auto *out_tensor = out->GetMutable(); + protected: + void InferShape(framework::InferShapeContext *ctx) const override { + PADDLE_ENFORCE(ctx->HasInput("X"), + "Input(X) of IsEmptyOp should not be null."); + PADDLE_ENFORCE(ctx->HasOutput("Out"), + "Output(Out) of IsEmptyOp should not be null."); + ctx->SetOutputDim("Out", {1}); + } - out_tensor->Resize({1}); - out_tensor->mutable_data(platform::CPUPlace())[0] = - framework::product(tensor.dims()) == 0; + framework::OpKernelType GetExpectedKernelType( + const framework::ExecutionContext &ctx) const override { + framework::OpKernelType kt = framework::OpKernelType( + framework::ToDataType(ctx.Input("X")->type()), + platform::CPUPlace()); + return kt; } }; -class IsEmptyOpProtoMaker : public framework::OpProtoAndCheckerMaker { +class IsEmptyOpMaker : public framework::OpProtoAndCheckerMaker { public: void Make() override { - AddInput(kInput, "(Tensor) Tensor which is to be checked."); - AddOutput(kOutput, "(Tensor) a boolean Tensor that indicate empty or not."); + AddInput("X", "(LoDTensor) Tensor which is to be checked."); + AddOutput("Out", + "(LoDTensor) a boolean Tensor that indicate empty or not."); AddComment(R"DOC( IsEmpty Operator which checks whether a tensor is empty. @@ -62,5 +58,12 @@ It will just return product(tensor.ddims()) > 0; } // namespace operators } // namespace paddle -REGISTER_OP_WITHOUT_GRADIENT(is_empty, paddle::operators::IsEmptyOp, - paddle::operators::IsEmptyOpProtoMaker); +namespace ops = paddle::operators; + +REGISTER_OPERATOR(is_empty, ops::IsEmptyOp, ops::IsEmptyOpMaker, + paddle::framework::EmptyGradOpMaker); +REGISTER_OP_CPU_KERNEL( + is_empty, ops::IsEmptyOpKernel, + ops::IsEmptyOpKernel, + ops::IsEmptyOpKernel, + ops::IsEmptyOpKernel); diff --git a/paddle/fluid/operators/is_empty_op.h b/paddle/fluid/operators/is_empty_op.h new file mode 100644 index 0000000000000000000000000000000000000000..3e3af22fa8d842b6a1e67418446f1a40949e046b --- /dev/null +++ b/paddle/fluid/operators/is_empty_op.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#pragma once +#include "paddle/fluid/framework/op_registry.h" +#include "paddle/fluid/framework/operator.h" + +namespace paddle { +namespace operators { + +template +class IsEmptyOpKernel : public framework::OpKernel { + public: + void Compute(const framework::ExecutionContext& context) const override { + // get input + auto* input_tensor = context.Input("X"); + // get output + auto* output_tensor = context.Output("Out"); + + output_tensor->mutable_data(platform::CPUPlace())[0] = + framework::product(input_tensor->dims()) == 0; + } +}; + +} // namespace operators +} // namespace paddle diff --git a/paddle/fluid/operators/listen_and_serv_op.cc b/paddle/fluid/operators/listen_and_serv_op.cc index abc88d3eb1514e159f4a880f44ecc0c0960a73d9..57eb5d9a0e73a51d9e2cef7ad7539c1b9da2c4ea 100644 --- a/paddle/fluid/operators/listen_and_serv_op.cc +++ b/paddle/fluid/operators/listen_and_serv_op.cc @@ -57,8 +57,7 @@ static void ParallelExecuteBlocks( framework::Async([&executor, &prepared, &program, &scope, idx]() { int run_block = idx; // thread local try { - executor->RunPreparedContext(prepared[run_block].get(), scope, - false, false); + executor->RunPreparedContext(prepared[run_block].get(), scope); } catch (std::exception &e) { LOG(ERROR) << "run sub program error " << e.what(); } @@ -211,8 +210,8 @@ static void AsyncUpdateThread( } auto fs = framework::Async([var_name, &executor, &v, prepared] { try { - executor->RunPreparedContext(prepared, v.second->GetMutableLocalScope(), - false, false); + executor->RunPreparedContext(prepared, + v.second->GetMutableLocalScope()); } catch (std::exception &e) { LOG(ERROR) << "run sub program error " << e.what(); } diff --git a/paddle/fluid/operators/math/math_function.cc b/paddle/fluid/operators/math/math_function.cc index d62ea387cc55c7399973b6f35bace491a49666dc..d39154c6f88d6d17c1719eb9a5b048211f4bb52b 100644 --- a/paddle/fluid/operators/math/math_function.cc +++ b/paddle/fluid/operators/math/math_function.cc @@ -38,7 +38,9 @@ template struct SetConstant; template struct Transpose; \ template struct Transpose; \ template struct Transpose; \ - template struct Transpose; + template struct Transpose; \ + template struct Transpose; \ + template struct Transpose; DEFINE_CPU_TRANS(1); DEFINE_CPU_TRANS(2); diff --git a/paddle/fluid/operators/mkldnn_activation_op.h b/paddle/fluid/operators/mkldnn_activation_op.h index f26a165b5a59f01f864d62bbf798f4cbffa65371..85664623d7330e9473286d995bec67879510dbd7 100644 --- a/paddle/fluid/operators/mkldnn_activation_op.h +++ b/paddle/fluid/operators/mkldnn_activation_op.h @@ -13,6 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. */ #pragma once +#include + #include "paddle/fluid/framework/eigen.h" #include "paddle/fluid/framework/op_registry.h" #include "paddle/fluid/operators/detail/safe_ref.h" @@ -60,52 +62,5 @@ class MKLDNNActivationGradKernel } }; -namespace { // NOLINT -framework::OpKernelType GetKernelType( - const framework::ExecutionContext& ctx, - const framework::OperatorWithKernel& oper) { - framework::LibraryType library{framework::LibraryType::kPlain}; -#ifdef PADDLE_WITH_MKLDNN - if (library == framework::LibraryType::kPlain && - platform::CanMKLDNNBeUsed(ctx)) { - library = framework::LibraryType::kMKLDNN; - } -#endif - framework::DataLayout layout = framework::DataLayout::kAnyLayout; - return framework::OpKernelType( - framework::ToDataType(ctx.Input("X")->type()), - ctx.GetPlace(), layout, library); -} -} // anonymous namespace - -class ActivationWithMKLDNNOp : public framework::OperatorWithKernel { - public: - using framework::OperatorWithKernel::OperatorWithKernel; - - void InferShape(framework::InferShapeContext* ctx) const override { - ctx->SetOutputDim("Out", ctx->GetInputDim("X")); - ctx->ShareLoD("X", /*->*/ "Out"); - } - - framework::OpKernelType GetExpectedKernelType( - const framework::ExecutionContext& ctx) const override { - return GetKernelType(ctx, *this); - } -}; - -class ActivationWithMKLDNNOpGrad : public framework::OperatorWithKernel { - public: - using framework::OperatorWithKernel::OperatorWithKernel; - - void InferShape(framework::InferShapeContext* ctx) const override { - ctx->SetOutputDim(framework::GradVarName("X"), ctx->GetInputDim("Out")); - } - - framework::OpKernelType GetExpectedKernelType( - const framework::ExecutionContext& ctx) const override { - return GetKernelType(ctx, *this); - } -}; - } // namespace operators } // namespace paddle diff --git a/paddle/fluid/operators/pool_mkldnn_op.cc b/paddle/fluid/operators/pool_mkldnn_op.cc index 63eaaedcd5fc3df17902511dc02b25bf43ccd241..60e936298defe7c6ce8a33bdc7de05b52eb950e7 100644 --- a/paddle/fluid/operators/pool_mkldnn_op.cc +++ b/paddle/fluid/operators/pool_mkldnn_op.cc @@ -18,6 +18,26 @@ limitations under the License. */ namespace paddle { namespace operators { +using mkldnn::memory; // Note: paddle has also "memory" namespace +using mkldnn::pooling_forward; +using mkldnn::pooling_backward; + +// Generate keys for storing/retriving primitives for this operator +// TODO(jczaja): Make hashing function more optimial +static std::string gethash(memory::dims& input_dims, std::string& pooling_type, + std::vector& ksize, std::vector& strides, + std::vector& paddings, std::string suffix) { + auto dims2str = [](memory::dims& operand_dims) { + std::string dstr = ""; + for (size_t i = 0; i < operand_dims.size(); ++i) { + dstr += std::to_string(operand_dims[i]) + "-"; + } + return dstr; + }; + return dims2str(input_dims) + dims2str(ksize) + dims2str(strides) + + dims2str(paddings) + pooling_type + suffix; +} + template class PoolMKLDNNOpKernel : public paddle::framework::OpKernel { public: @@ -34,10 +54,6 @@ class PoolMKLDNNOpKernel : public paddle::framework::OpKernel { // Get an unique name from "argument" name of "Out" variable // This name will be used as key when saving info into device context - const std::string key = ctx.op().Output("Out"); - const std::string key_pool_pd = key + "@pool_pd"; - const std::string key_pool_workspace_memory = - key + "@pool_workspace_memory"; std::string pooling_type = ctx.Attr("pooling_type"); std::vector ksize = ctx.Attr>("ksize"); @@ -63,37 +79,71 @@ class PoolMKLDNNOpKernel : public paddle::framework::OpKernel { std::vector src_tz = paddle::framework::vectorize2int(input->dims()); std::vector dst_tz = paddle::framework::vectorize2int(output->dims()); - // TODO(pzelazko-intel): support more formats - auto src_md = platform::MKLDNNMemDesc(src_tz, mkldnn::memory::f32, - mkldnn::memory::format::nchw); - auto dst_md = platform::MKLDNNMemDesc(dst_tz, mkldnn::memory::f32, - mkldnn::memory::format::nchw); - - std::shared_ptr pool_pd = - CreatePrimitiveDesc(src_md, dst_md, strides, paddings, ksize, - pooling_type, mkldnn_engine); - - // save pool_pd into global device context to be referred in backward path - dev_ctx.SetBlob(key_pool_pd, pool_pd); - - std::shared_ptr workspace_memory = - CreateWorkspaceMemory(pool_pd, pooling_type, mkldnn_engine); - - // save pool_workspace_memory to be referred in backward path - dev_ctx.SetBlob(key_pool_workspace_memory, workspace_memory); - - auto src_memory = - mkldnn::memory({src_md, mkldnn_engine}, - static_cast(const_cast(input_data))); - auto dst_memory = - mkldnn::memory({dst_md, mkldnn_engine}, - static_cast(const_cast(output_data))); + const std::string key = gethash(src_tz, pooling_type, ksize, strides, + paddings, ctx.op().Output("Out")); + const std::string key_pool_p = key + "@pool_p"; + const std::string key_pool_pd = key + "@pool_pd"; + const std::string key_pool_src_mem_p = key + "@pool_src_mem_p"; + const std::string key_pool_dst_mem_p = key + "@pool_dst_mem_p"; + const std::string key_pool_workspace_memory = + key + "@pool_workspace_memory"; - auto pool_prim = mkldnn::pooling_forward(*pool_pd, src_memory, dst_memory, - *workspace_memory); + auto pool_p = + std::static_pointer_cast(dev_ctx.GetBlob(key_pool_p)); + if (pool_p == nullptr) { + // TODO(pzelazko-intel): support more formats + + auto src_md = + platform::MKLDNNMemDesc(src_tz, platform::MKLDNNGetDataType(), + mkldnn::memory::format::nchw); + auto dst_md = + platform::MKLDNNMemDesc(dst_tz, platform::MKLDNNGetDataType(), + mkldnn::memory::format::nchw); + + std::shared_ptr pool_pd = + CreatePrimitiveDesc(src_md, dst_md, strides, paddings, ksize, + pooling_type, mkldnn_engine); + + // save pool_pd into global device context to be referred in backward path + dev_ctx.SetBlob(key_pool_pd, pool_pd); + + std::shared_ptr workspace_memory = + CreateWorkspaceMemory(pool_pd, pooling_type, mkldnn_engine); + + // save pool_workspace_memory to be referred in backward path + dev_ctx.SetBlob(key_pool_workspace_memory, workspace_memory); + + auto pool_src_memory_p = std::make_shared( + memory::primitive_desc{src_md, mkldnn_engine}, + static_cast(const_cast(input_data))); + dev_ctx.SetBlob(key_pool_src_mem_p, pool_src_memory_p); + + auto pool_dst_memory_p = std::make_shared( + memory::primitive_desc{dst_md, mkldnn_engine}, + static_cast(output_data)); + dev_ctx.SetBlob(key_pool_dst_mem_p, pool_dst_memory_p); + + pool_p = std::make_shared( + *pool_pd, *(pool_src_memory_p.get()), *(pool_dst_memory_p.get()), + *workspace_memory); + dev_ctx.SetBlob(key_pool_p, pool_p); + } else { + // Primitives already exist + auto pool_src_memory_p = + std::static_pointer_cast(dev_ctx.GetBlob(key_pool_src_mem_p)); + PADDLE_ENFORCE(pool_src_memory_p != nullptr, + "Fail to find pooling src mem_p in device context"); + auto pool_dst_memory_p = + std::static_pointer_cast(dev_ctx.GetBlob(key_pool_dst_mem_p)); + PADDLE_ENFORCE(pool_dst_memory_p != nullptr, + "Fail to find pooling dst mem_p in device context"); + pool_src_memory_p->set_data_handle( + reinterpret_cast(const_cast(input_data))); + pool_dst_memory_p->set_data_handle(output_data); + } // push primitive to stream and wait until it's executed - std::vector pipeline{pool_prim}; + std::vector pipeline{*(pool_p.get())}; mkldnn::stream(mkldnn::stream::kind::eager).submit(pipeline).wait(); } @@ -120,9 +170,10 @@ class PoolMKLDNNOpKernel : public paddle::framework::OpKernel { mkldnn::memory::primitive_desc workspace_md = pooling_type == "max" ? pool_pd->workspace_primitive_desc() - : mkldnn::memory::primitive_desc( - {{}, mkldnn::memory::f32, mkldnn::memory::format::nchw}, - engine); + : mkldnn::memory::primitive_desc({{}, + platform::MKLDNNGetDataType(), + mkldnn::memory::format::nchw}, + engine); auto p_workspace_memory = new mkldnn::memory(workspace_md); return std::unique_ptr(p_workspace_memory); @@ -140,13 +191,6 @@ class PoolMKLDNNGradOpKernel : public paddle::framework::OpKernel { const Tensor* out_grad = ctx.Input(framework::GradVarName("Out")); Tensor* in_x_grad = ctx.Output(framework::GradVarName("X")); - // Get an unique name from "argument" name of "Out" variable - // This name will be used as key when referring info from device context - const std::string key = ctx.op().Input("Out"); - const std::string key_pool_pd = key + "@pool_pd"; - const std::string key_pool_workspace_memory = - key + "@pool_workspace_memory"; - std::string pooling_type = ctx.Attr("pooling_type"); std::vector ksize = ctx.Attr>("ksize"); std::vector strides = ctx.Attr>("strides"); @@ -171,43 +215,76 @@ class PoolMKLDNNGradOpKernel : public paddle::framework::OpKernel { std::vector diff_dst_tz = paddle::framework::vectorize2int(out_grad->dims()); - auto diff_src_md = platform::MKLDNNMemDesc(diff_src_tz, mkldnn::memory::f32, - mkldnn::memory::format::nchw); - auto diff_dst_md = platform::MKLDNNMemDesc(diff_dst_tz, mkldnn::memory::f32, - mkldnn::memory::format::nchw); - - // Retrieve pool_pd/pool_workspace_memory from device context - auto pool_pd = - std::static_pointer_cast( - dev_ctx.GetBlob(key_pool_pd)); - PADDLE_ENFORCE(pool_pd != nullptr, - "Fail to find pool_pd in device context"); - - auto workspace_memory = std::static_pointer_cast( - dev_ctx.GetBlob(key_pool_workspace_memory)); - PADDLE_ENFORCE(workspace_memory != nullptr, - "Fail to find workspace_memory in device context"); - - auto pool_bwd_desc = mkldnn::pooling_backward::desc( - pooling_type == "max" ? mkldnn::algorithm::pooling_max - : mkldnn::algorithm::pooling_avg, - diff_src_md, diff_dst_md, strides, ksize, paddings, paddings, - mkldnn::padding_kind::zero); - auto pool_bwd_pd = mkldnn::pooling_backward::primitive_desc( - pool_bwd_desc, mkldnn_engine, *pool_pd); - - auto diff_src_memory = - mkldnn::memory({diff_src_md, mkldnn_engine}, - static_cast(const_cast(in_x_grad_data))); - auto diff_dst_memory = - mkldnn::memory({diff_dst_md, mkldnn_engine}, - static_cast(const_cast(out_grad_data))); + // Get an unique name from "argument" name of "Out" variable + // This name will be used as key when referring info from device context + const std::string key = gethash(diff_src_tz, pooling_type, ksize, strides, + paddings, ctx.op().Input("Out")); + const std::string key_pool_bwd_p = key + "@pool_bwd_p"; + const std::string key_pool_diff_src_mem_p = key + "@pool_diff_src_mem_p"; + const std::string key_pool_diff_dst_mem_p = key + "@pool_diff_dst_mem_p"; + const std::string key_pool_pd = key + "@pool_pd"; + const std::string key_pool_workspace_memory = + key + "@pool_workspace_memory"; - auto bwd_prim = mkldnn::pooling_backward( - pool_bwd_pd, diff_dst_memory, *workspace_memory, diff_src_memory); + auto pool_bwd_p = std::static_pointer_cast( + dev_ctx.GetBlob(key_pool_bwd_p)); + if (pool_bwd_p == nullptr) { + auto diff_src_md = + platform::MKLDNNMemDesc(diff_src_tz, platform::MKLDNNGetDataType(), + mkldnn::memory::format::nchw); + auto diff_dst_md = + platform::MKLDNNMemDesc(diff_dst_tz, platform::MKLDNNGetDataType(), + mkldnn::memory::format::nchw); + // Retrieve pool_pd/pool_workspace_memory from device context + auto pool_pd = + std::static_pointer_cast( + dev_ctx.GetBlob(key_pool_pd)); + PADDLE_ENFORCE(pool_pd != nullptr, + "Fail to find pool_pd in device context"); + + auto workspace_memory = std::static_pointer_cast( + dev_ctx.GetBlob(key_pool_workspace_memory)); + PADDLE_ENFORCE(workspace_memory != nullptr, + "Fail to find workspace_memory in device context"); + + auto pool_diff_src_memory_p = std::make_shared(memory( + {diff_src_md, mkldnn_engine}, static_cast(in_x_grad_data))); + dev_ctx.SetBlob(key_pool_diff_src_mem_p, pool_diff_src_memory_p); + + auto pool_diff_dst_memory_p = std::make_shared( + memory({diff_dst_md, mkldnn_engine}, + static_cast(const_cast(out_grad_data)))); + dev_ctx.SetBlob(key_pool_diff_dst_mem_p, pool_diff_dst_memory_p); + + auto pool_bwd_desc = mkldnn::pooling_backward::desc( + pooling_type == "max" ? mkldnn::algorithm::pooling_max + : mkldnn::algorithm::pooling_avg, + diff_src_md, diff_dst_md, strides, ksize, paddings, paddings, + mkldnn::padding_kind::zero); + auto pool_bwd_pd = mkldnn::pooling_backward::primitive_desc( + pool_bwd_desc, mkldnn_engine, *pool_pd); + + pool_bwd_p = std::make_shared( + pool_bwd_pd, *(pool_diff_dst_memory_p.get()), *workspace_memory, + *(pool_diff_src_memory_p)); + dev_ctx.SetBlob(key_pool_bwd_p, pool_bwd_p); + } else { + // Primitives already exist + auto pool_diff_src_memory_p = std::static_pointer_cast( + dev_ctx.GetBlob(key_pool_diff_src_mem_p)); + PADDLE_ENFORCE(pool_diff_src_memory_p != nullptr, + "Fail to find pooling src mem_p in device context"); + auto pool_diff_dst_memory_p = std::static_pointer_cast( + dev_ctx.GetBlob(key_pool_diff_dst_mem_p)); + PADDLE_ENFORCE(pool_diff_dst_memory_p != nullptr, + "Fail to find pooling dst mem_p in device context"); + pool_diff_src_memory_p->set_data_handle( + reinterpret_cast(in_x_grad_data)); + pool_diff_dst_memory_p->set_data_handle(const_cast(out_grad_data)); + } // push primitive to stream and wait until it's executed - std::vector pipeline{bwd_prim}; + std::vector pipeline{*(pool_bwd_p.get())}; mkldnn::stream(mkldnn::stream::kind::eager).submit(pipeline).wait(); } // Compute() }; diff --git a/paddle/fluid/operators/roi_pool_op.cu b/paddle/fluid/operators/roi_pool_op.cu index f905d690f984a20622c5fbcbcc813d888dfb19d9..50450b62f7b1c0b2b5abf01a43581a0e2d2cd01e 100644 --- a/paddle/fluid/operators/roi_pool_op.cu +++ b/paddle/fluid/operators/roi_pool_op.cu @@ -38,10 +38,10 @@ __global__ void GPUROIPoolForward( int index = blockIdx.x * blockDim.x + threadIdx.x; int offset = blockDim.x * gridDim.x; for (size_t i = index; i < nthreads; i += offset) { - int pw = index % pooled_width; - int ph = (index / pooled_width) % pooled_height; - int c = (index / pooled_width / pooled_height) % channels; - int n = index / pooled_width / pooled_height / channels; + int pw = i % pooled_width; + int ph = (i / pooled_width) % pooled_height; + int c = (i / pooled_width / pooled_height) % channels; + int n = i / pooled_width / pooled_height / channels; const int64_t* offset_input_rois = input_rois + n * kROISize; int roi_batch_ind = roi_batch_id_data[n]; @@ -52,14 +52,19 @@ __global__ void GPUROIPoolForward( int roi_width = max(roi_end_w - roi_start_w + 1, 1); int roi_height = max(roi_end_h - roi_start_h + 1, 1); - T bin_size_h = static_cast(roi_height) / static_cast(pooled_height); - T bin_size_w = static_cast(roi_width) / static_cast(pooled_width); - - int hstart = static_cast(floor(static_cast(ph) * bin_size_h)); - int wstart = static_cast(floor(static_cast(pw) * bin_size_w)); - int hend = static_cast(ceil(static_cast(ph + 1) * bin_size_h)); - int wend = static_cast(ceil(static_cast(pw + 1) * bin_size_w)); + int hstart = static_cast(floor(static_cast(ph) * + static_cast(roi_height) / + static_cast(pooled_height))); + int wstart = static_cast(floor(static_cast(pw) * + static_cast(roi_width) / + static_cast(pooled_width))); + int hend = static_cast(ceil(static_cast(ph + 1) * + static_cast(roi_height) / + static_cast(pooled_height))); + int wend = static_cast(ceil(static_cast(pw + 1) * + static_cast(roi_width) / + static_cast(pooled_width))); hstart = min(max(hstart + roi_start_h, 0), height); hend = min(max(hend + roi_start_h, 0), height); wstart = min(max(wstart + roi_start_w, 0), width); @@ -79,9 +84,9 @@ __global__ void GPUROIPoolForward( } } } - output_data[index] = maxval; + output_data[i] = maxval; if (argmax_data) { - argmax_data[index] = maxidx; + argmax_data[i] = maxidx; } } } @@ -96,10 +101,10 @@ __global__ void GPUROIPoolBackward( int index = blockIdx.x * blockDim.x + threadIdx.x; int offset = blockDim.x * gridDim.x; for (int i = index; i < nthreads; i += offset) { - int pw = index % pooled_width; - int ph = (index / pooled_width) % pooled_height; - int c = (index / pooled_width / pooled_height) % channels; - int n = index / pooled_width / pooled_height / channels; + int pw = i % pooled_width; + int ph = (i / pooled_width) % pooled_height; + int c = (i / pooled_width / pooled_height) % channels; + int n = i / pooled_width / pooled_height / channels; int roi_batch_ind = roi_batch_id_data[n]; int input_offset = (roi_batch_ind * channels + c) * height * width; @@ -138,6 +143,7 @@ class GPUROIPoolOpKernel : public framework::OpKernel { int width = in_dims[3]; int rois_num = rois->dims()[0]; + if (rois_num == 0) return; int output_size = out->numel(); diff --git a/paddle/fluid/operators/send_recv_op_test.cc b/paddle/fluid/operators/send_recv_op_test.cc index eb51f301bfe2a97c65dd1fec23ff5a44f3843b05..d5303eaf50722234d205264e56892b1723104d53 100644 --- a/paddle/fluid/operators/send_recv_op_test.cc +++ b/paddle/fluid/operators/send_recv_op_test.cc @@ -92,12 +92,16 @@ void InitSelectedRowsInScope(const p::CPUPlace &place, f::Scope *scope) { void AddOp(const std::string &type, const f::VariableNameMap &inputs, const f::VariableNameMap &outputs, f::AttributeMap attrs, - f::BlockDesc *block) { + f::BlockDesc *block, bool is_sparse) { // insert output for (auto kv : outputs) { for (auto v : kv.second) { auto var = block->Var(v); var->SetDataType(f::proto::VarType::FP32); + var->SetPersistable(true); + if (is_sparse) { + var->SetType(f::proto::VarType::SELECTED_ROWS); + } } } @@ -128,7 +132,8 @@ void StartServerNet(bool is_sparse, std::atomic *initialized) { auto *optimize_block = program.AppendBlock(root_block); auto *prefetch_block = program.AppendBlock(root_block); // X for server side tensors, RX for received tensors, must be of same shape. - AddOp("sum", {{"X", {"x0", "x1"}}}, {{"Out", {"Out"}}}, {}, optimize_block); + AddOp("sum", {{"X", {"x0", "x1"}}}, {{"Out", {"Out"}}}, {}, optimize_block, + is_sparse); f::AttributeMap attrs; attrs.insert({"endpoint", std::string("127.0.0.1:0")}); attrs.insert({"Fanin", 1}); diff --git a/paddle/fluid/operators/smooth_l1_loss_op.cc b/paddle/fluid/operators/smooth_l1_loss_op.cc index c44c5f164b2d84616e9a85813e0ee5219b41df28..622420c1c33a62994c81ad9534c4fa37a4a1fa1a 100644 --- a/paddle/fluid/operators/smooth_l1_loss_op.cc +++ b/paddle/fluid/operators/smooth_l1_loss_op.cc @@ -105,7 +105,7 @@ class SmoothL1LossGradOp : public framework::OperatorWithKernel { using framework::OperatorWithKernel::OperatorWithKernel; void InferShape(framework::InferShapeContext* ctx) const override { - auto in_dims = ctx->GetInputDim("X"); + auto in_dims = ctx->GetInputDim("Diff"); auto out_dims = ctx->GetInputDim(framework::GradVarName("Out")); PADDLE_ENFORCE_GE(out_dims.size(), 2, @@ -127,12 +127,33 @@ class SmoothL1LossGradOp : public framework::OperatorWithKernel { } }; +class SmoothL1LossGradMaker : public framework::SingleGradOpDescMaker { + public: + using framework::SingleGradOpDescMaker::SingleGradOpDescMaker; + + protected: + std::unique_ptr Apply() const override { + auto* op = new framework::OpDesc(); + op->SetType("smooth_l1_loss_grad"); + op->SetInput("InsideWeight", Input("InsideWeight")); + op->SetInput("OutsideWeight", Input("OutsideWeight")); + op->SetInput("Diff", Output("Diff")); + op->SetInput(framework::GradVarName("Out"), OutputGrad("Out")); + + op->SetAttrMap(Attrs()); + + op->SetOutput(framework::GradVarName("X"), InputGrad("X")); + op->SetOutput(framework::GradVarName("Y"), InputGrad("Y")); + return std::unique_ptr(op); + } +}; + } // namespace operators } // namespace paddle namespace ops = paddle::operators; REGISTER_OPERATOR(smooth_l1_loss, ops::SmoothL1LossOp, ops::SmoothL1LossOpMaker, - paddle::framework::DefaultGradOpDescMaker); + ops::SmoothL1LossGradMaker); REGISTER_OPERATOR(smooth_l1_loss_grad, ops::SmoothL1LossGradOp); REGISTER_OP_CPU_KERNEL( smooth_l1_loss, diff --git a/paddle/fluid/platform/CMakeLists.txt b/paddle/fluid/platform/CMakeLists.txt index 598fd4d419078a973647f2f8f20e8a12c8115a8b..b29035bafd34fa81dc6b59691142fe74439202b8 100644 --- a/paddle/fluid/platform/CMakeLists.txt +++ b/paddle/fluid/platform/CMakeLists.txt @@ -1,4 +1,4 @@ -proto_library(profiler_proto SRCS profiler.proto) +proto_library(profiler_proto SRCS profiler.proto DEPS framework_proto) py_proto_compile(profiler_py_proto SRCS profiler.proto) add_custom_target(profiler_py_proto_init ALL COMMAND ${CMAKE_COMMAND} -E touch __init__.py) @@ -49,7 +49,7 @@ nv_test(device_context_test SRCS device_context_test.cu DEPS device_context gpu_ nv_test(cudnn_helper_test SRCS cudnn_helper_test.cc DEPS dynload_cuda) nv_test(transform_test SRCS transform_test.cu DEPS memory place device_context) -cc_library(device_tracer SRCS device_tracer.cc DEPS boost profiler_proto ${GPU_CTX_DEPS}) +cc_library(device_tracer SRCS device_tracer.cc DEPS boost profiler_proto framework_proto ${GPU_CTX_DEPS}) cc_library(profiler SRCS profiler.cc DEPS device_context device_tracer) cc_test(profiler_test SRCS profiler_test.cc DEPS profiler) diff --git a/paddle/fluid/platform/mkldnn_helper.h b/paddle/fluid/platform/mkldnn_helper.h index 23f1d615daab91f0e4b353bc7d9a3ca7f5cec5ae..f1187620d81ff3bc1deef2106edb54d6199fa927 100644 --- a/paddle/fluid/platform/mkldnn_helper.h +++ b/paddle/fluid/platform/mkldnn_helper.h @@ -38,6 +38,11 @@ void* to_void_cast(const Type* t) { return static_cast(const_cast(t)); } +template +void* to_void_reinterpret_cast(const Type* t) { + return reinterpret_cast(const_cast(t)); +} + template using tf_desc = typename Type::desc; @@ -71,5 +76,15 @@ inline bool CanMKLDNNBeUsed(const framework::ExecutionContext& ctx) { return use_mkldnn && platform::is_cpu_place(ctx.GetPlace()); } +template +mkldnn::memory::data_type MKLDNNGetDataType() { + return mkldnn::memory::data_undef; +} + +template <> +inline mkldnn::memory::data_type MKLDNNGetDataType() { + return mkldnn::memory::f32; +} + } // namespace platform } // namespace paddle diff --git a/paddle/fluid/platform/profiler.cc b/paddle/fluid/platform/profiler.cc index 50bc0aba6aa0f056dc0b2d49f6b3b745433e0756..2fb5c6dc6b8ad25fa1ad5fcf7c2acfedd5be4a83 100644 --- a/paddle/fluid/platform/profiler.cc +++ b/paddle/fluid/platform/profiler.cc @@ -173,8 +173,9 @@ void PopEvent(const std::string& name, const DeviceContext* dev_ctx) { } RecordEvent::RecordEvent(const std::string& name, const DeviceContext* dev_ctx) - : start_ns_(PosixInNsec()) { + : is_enabled_(false), start_ns_(PosixInNsec()) { if (g_state == ProfilerState::kDisabled) return; + is_enabled_ = true; dev_ctx_ = dev_ctx; name_ = name; PushEvent(name_, dev_ctx_); @@ -183,7 +184,7 @@ RecordEvent::RecordEvent(const std::string& name, const DeviceContext* dev_ctx) } RecordEvent::~RecordEvent() { - if (g_state == ProfilerState::kDisabled) return; + if (g_state == ProfilerState::kDisabled || !is_enabled_) return; DeviceTracer* tracer = GetDeviceTracer(); if (tracer) { tracer->AddCPURecords(CurAnnotation(), start_ns_, PosixInNsec(), @@ -193,14 +194,16 @@ RecordEvent::~RecordEvent() { PopEvent(name_, dev_ctx_); } -RecordBlock::RecordBlock(int block_id) : start_ns_(PosixInNsec()) { +RecordBlock::RecordBlock(int block_id) + : is_enabled_(false), start_ns_(PosixInNsec()) { if (g_state == ProfilerState::kDisabled) return; + is_enabled_ = true; SetCurBlock(block_id); name_ = string::Sprintf("block_%d", block_id); } RecordBlock::~RecordBlock() { - if (g_state == ProfilerState::kDisabled) return; + if (g_state == ProfilerState::kDisabled || !is_enabled_) return; DeviceTracer* tracer = GetDeviceTracer(); if (tracer) { // We try to put all blocks at the same nested depth in the diff --git a/paddle/fluid/platform/profiler.h b/paddle/fluid/platform/profiler.h index 61b98143e41abb9e47d2c717c7876f1bab7f5077..643bb6183d144ec11a4890d9ea1ca970acb08b4c 100644 --- a/paddle/fluid/platform/profiler.h +++ b/paddle/fluid/platform/profiler.h @@ -74,6 +74,7 @@ struct RecordEvent { ~RecordEvent(); + bool is_enabled_; uint64_t start_ns_; // The device context is used by Event to get the current cuda stream. const DeviceContext* dev_ctx_; @@ -89,6 +90,7 @@ struct RecordBlock { ~RecordBlock(); private: + bool is_enabled_; std::string name_; uint64_t start_ns_; }; diff --git a/paddle/fluid/pybind/protobuf.cc b/paddle/fluid/pybind/protobuf.cc index 6471eb3ab7bf05365c0bb2bf68bb74ef9044c527..bcf6d4dd3087060c016e53722cde80704ef2e834 100644 --- a/paddle/fluid/pybind/protobuf.cc +++ b/paddle/fluid/pybind/protobuf.cc @@ -238,6 +238,7 @@ void BindVarDsec(pybind11::module *m) { pybind11::enum_(var_desc, "VarType", "") .value("BOOL", pd::proto::VarType::BOOL) + .value("UINT8", pd::proto::VarType::UINT8) .value("INT16", pd::proto::VarType::INT16) .value("INT32", pd::proto::VarType::INT32) .value("INT64", pd::proto::VarType::INT64) diff --git a/paddle/fluid/train/demo/CMakeLists.txt b/paddle/fluid/train/demo/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..78d6e5ff554b9cd9facae85be166a697e0b75337 --- /dev/null +++ b/paddle/fluid/train/demo/CMakeLists.txt @@ -0,0 +1,66 @@ +cmake_minimum_required(VERSION 3.0) + +project(cpp_train_demo CXX C) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + +if(NOT DEFINED PADDLE_LIB) + message(FATAL_ERROR "please set PADDLE_LIB with -DPADDLE_LIB=/paddle/lib/dir") +endif() + +option(WITH_MKLDNN "Compile PaddlePaddle with MKLDNN" OFF) +option(WITH_MKL "Compile PaddlePaddle with MKL support, default use openblas." OFF) + +include_directories("${PADDLE_LIB}") +include_directories("${PADDLE_LIB}/third_party/install/protobuf/include") +include_directories("${PADDLE_LIB}/third_party/install/glog/include") +include_directories("${PADDLE_LIB}/third_party/install/gflags/include") +include_directories("${PADDLE_LIB}/third_party/install/snappy/include") +include_directories("${PADDLE_LIB}/third_party/install/snappystream/include") +include_directories("${PADDLE_LIB}/third_party/install/zlib/include") + +include_directories("${PADDLE_LIB}/third_party/boost") +include_directories("${PADDLE_LIB}/third_party/eigen3") + +link_directories("${PADDLE_LIB}/third_party/install/snappy/lib") +link_directories("${PADDLE_LIB}/third_party/install/snappystream/lib") +link_directories("${PADDLE_LIB}/third_party/install/protobuf/lib") +link_directories("${PADDLE_LIB}/third_party/install/glog/lib") +link_directories("${PADDLE_LIB}/third_party/install/gflags/lib") +link_directories("${PADDLE_LIB}/third_party/install/zlib/lib") + +add_executable(demo_trainer demo_trainer.cc) + +if(WITH_MKLDNN) + include_directories("${PADDLE_LIB}/third_party/install/mkldnn/include") + set(MKLDNN_LIB ${PADDLE_LIB}/third_party/install/mkldnn/lib/libmkldnn.so.0) +endif() + +if(WITH_MKL) + include_directories("${PADDLE_LIB}/third_party/install/mklml/include") + set(MATH_LIB ${PADDLE_LIB}/third_party/install/mklml/lib/libmklml_intel.so) +else() + if(APPLE) + set(MATH_LIB cblas) + else(APPLE) + set(MATH_LIB ${PADDLE_LIB}/third_party/install/openblas/lib/libopenblas.a) + endif(APPLE) +endif() + +if(APPLE) + set(MACOS_LD_FLAGS "-undefined dynamic_lookup -Wl,-all_load -framework CoreFoundation -framework Security") +else(APPLE) + set(ARCHIVE_START "-Wl,--whole-archive") + set(ARCHIVE_END "-Wl,--no-whole-archive") + set(EXTERNAL_LIB "-lrt -ldl -lpthread") +endif(APPLE) + +target_link_libraries(demo_trainer + ${MACOS_LD_FLAGS} + ${ARCHIVE_START} + ${PADDLE_LIB}/paddle/fluid/inference/libpaddle_fluid.a + ${ARCHIVE_END} + ${MATH_LIB} + ${MKLDNN_LIB} + glog gflags protobuf snappystream snappy z + ${EXTERNAL_LIB}) diff --git a/paddle/fluid/train/demo/README.md b/paddle/fluid/train/demo/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fd80a77b02e60c15ae6c58486ed7cbbb6ffefabc --- /dev/null +++ b/paddle/fluid/train/demo/README.md @@ -0,0 +1,66 @@ + +### step 1. build paddle lib + +``` + +# WITH_MKL=ON|OFF +# WITH_MKLDNN=ON|OFF + +PADDLE_LIB=/paddle/lib/dir +cmake .. -DCMAKE_INSTALL_PREFIX=$PADDLE_LIB \ + -DCMAKE_BUILD_TYPE=Release \ + -DWITH_FLUID_ONLY=ON \ + -DWITH_GPU=OFF \ + -DWITH_STYLE_CHECK=OFF \ + -DWITH_MKL=OFF \ + -DWITH_MKLDNN=OFF +make -j8 +make -j8 inference_lib_dist +``` + +### step 2. generate program desc +``` +# please install paddle before run this scripe +pip install --upgrade paddlepaddle-*.whl +python demo_network.py +``` + +This will generate two program desc files: + - startup_program: used to init all parameters + - main_program: main logic of the network + +### step 3. build demo_trainer and run it. + + +``` +# Make a build dir at the same dir of this README.md document. +# The demo dir can be put anywhere. +mkdir build +cd build + +# WITH_MKL=ON|OFF +# WITH_MKLDNN=ON|OFF +PADDLE_LIB=/paddle/lib/dir + +# PADDLE_LIB is the same with CMAKE_INSTALL_PREFIX when building the lib +cmake .. -DPADDLE_LIB=$PADDLE_LIB \ + -DWITH_MKLDNN=OFF \ + -DWITH_MKL=OFF +make + +# copy startup_program and main_program to this dir +cp ../startup_program . +cp ../main_program . + +# run demo cpp trainer +./demo_trainer + +``` + +The output will be: +``` +step: 0 loss: 1069.02 +step: 1 loss: 1069.02 +step: 2 loss: 1069.02 +.... +``` diff --git a/paddle/fluid/train/demo/demo_network.py b/paddle/fluid/train/demo/demo_network.py new file mode 100644 index 0000000000000000000000000000000000000000..41e98c6a24a750a9300b5c2a6d370303cc0e59c5 --- /dev/null +++ b/paddle/fluid/train/demo/demo_network.py @@ -0,0 +1,47 @@ +# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import paddle.fluid as fluid +import paddle.fluid.framework as framework + + +def train_network(with_optimize): + x = fluid.layers.data(name='x', shape=[13], dtype='float32') + y_predict = fluid.layers.fc(input=x, size=1, act=None) + + y = fluid.layers.data(name='y', shape=[1], dtype='float32') + cost = fluid.layers.square_error_cost(input=y_predict, label=y) + avg_cost = fluid.layers.mean(cost) + + if with_optimize: + sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.00001) + sgd_optimizer.minimize(avg_cost) + else: + fluid.backward.append_backward(avg_cost) + + +def save_program_desc(network_func): + startup_program = framework.Program() + train_program = framework.Program() + + with framework.program_guard(train_program, startup_program): + network_func(with_optimize=False) + + with open("startup_program", "w") as f: + f.write(startup_program.desc.serialize_to_string()) + with open("main_program", "w") as f: + f.write(train_program.desc.serialize_to_string()) + + +save_program_desc(train_network) diff --git a/paddle/fluid/train/demo/demo_trainer.cc b/paddle/fluid/train/demo/demo_trainer.cc new file mode 100644 index 0000000000000000000000000000000000000000..813d8386868558bd62a9d5670d540ddeddb2b77d --- /dev/null +++ b/paddle/fluid/train/demo/demo_trainer.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "paddle/fluid/framework/executor.h" +#include "paddle/fluid/framework/init.h" +#include "paddle/fluid/framework/op_registry.h" +#include "paddle/fluid/framework/program_desc.h" +#include "paddle/fluid/framework/tensor_util.h" +#include "paddle/fluid/platform/device_context.h" +#include "paddle/fluid/platform/place.h" + +namespace paddle { +namespace train { + +void ReadBinaryFile(const std::string& filename, std::string* contents) { + std::ifstream fin(filename, std::ios::in | std::ios::binary); + PADDLE_ENFORCE(static_cast(fin), "Cannot open file %s", filename); + fin.seekg(0, std::ios::end); + contents->clear(); + contents->resize(fin.tellg()); + fin.seekg(0, std::ios::beg); + fin.read(&(contents->at(0)), contents->size()); + fin.close(); +} + +std::unique_ptr Load( + paddle::framework::Executor* executor, const std::string& model_filename) { + VLOG(3) << "loading model from " << model_filename; + std::string program_desc_str; + ReadBinaryFile(model_filename, &program_desc_str); + + std::unique_ptr main_program( + new paddle::framework::ProgramDesc(program_desc_str)); + return main_program; +} + +} // namespace train +} // namespace paddle + +int main() { + paddle::framework::InitDevices(false); + + const auto cpu_place = paddle::platform::CPUPlace(); + + paddle::framework::Executor executor(cpu_place); + paddle::framework::Scope scope; + auto startup_program = paddle::train::Load(&executor, "startup_program"); + auto train_program = paddle::train::Load(&executor, "main_program"); + + std::string loss_name = ""; + for (auto op_desc : train_program->Block(0).AllOps()) { + if (op_desc->Type() == "mean") { + loss_name = op_desc->Output("Out")[0]; + break; + } + } + + PADDLE_ENFORCE_NE(loss_name, "", "loss not found"); + + // init all parameters + executor.Run(*startup_program.get(), &scope, 0); + + // prepare data + auto x_var = scope.Var("x"); + auto x_tensor = x_var->GetMutable(); + x_tensor->Resize({2, 13}); + + auto x_data = x_tensor->mutable_data(cpu_place); + for (int i = 0; i < 2 * 13; ++i) { + x_data[i] = static_cast(i); + } + + auto y_var = scope.Var("y"); + auto y_tensor = y_var->GetMutable(); + y_tensor->Resize({2, 1}); + auto y_data = y_tensor->mutable_data(cpu_place); + for (int i = 0; i < 2 * 1; ++i) { + y_data[i] = static_cast(i); + } + + auto loss_var = scope.Var(loss_name); + + for (int i = 0; i < 10; ++i) { + executor.Run(*train_program.get(), &scope, 0, false, true); + std::cout << "step: " << i << " loss: " + << loss_var->Get().data()[0] + << std::endl; + } + return 0; +} diff --git a/paddle/scripts/docker/build.sh b/paddle/scripts/docker/build.sh index 7e00bd38487902227c3b4521db20cdbe314059be..92b8b90880bc78dbc281a959a7472c2822f76fc3 100755 --- a/paddle/scripts/docker/build.sh +++ b/paddle/scripts/docker/build.sh @@ -198,7 +198,7 @@ EOF # run paddle version to install python packages first RUN apt-get update &&\ ${NCCL_DEPS}\ - apt-get install -y wget python-pip dmidecode python-tk && pip install -U pip==9.0.3 && \ + apt-get install -y wget python-pip dmidecode python-tk && easy_install -U pip && \ pip install /*.whl; apt-get install -f -y && \ apt-get clean -y && \ rm -f /*.whl && \ diff --git a/paddle/scripts/paddle_build.sh b/paddle/scripts/paddle_build.sh index 5bef232cd8fc44ded89ac56a790c8db0955b390a..fbe219a1c9cf85f19ae2ab991ae7e4207858f204 100755 --- a/paddle/scripts/paddle_build.sh +++ b/paddle/scripts/paddle_build.sh @@ -20,19 +20,15 @@ #================================================= function print_usage() { - RED='\033[0;31m' - BLUE='\033[0;34m' - BOLD='\033[1m' - NONE='\033[0m' - echo -e "\n${RED}Usage${NONE}: - ${BOLD}$0${NONE} [OPTION]" + ${BOLD}${SCRIPT_NAME}${NONE} [OPTION]" echo -e "\n${RED}Options${NONE}: ${BLUE}build${NONE}: run build for x86 platform ${BLUE}build_android${NONE}: run build for android platform ${BLUE}build_ios${NONE}: run build for ios platform ${BLUE}test${NONE}: run all unit tests + ${BLUE}single_test${NONE}: run a single unit test ${BLUE}bind_test${NONE}: parallel tests bind to different GPU ${BLUE}doc${NONE}: generate paddle documents ${BLUE}html${NONE}: convert C++ source code into HTML @@ -45,7 +41,15 @@ function print_usage() { } function init() { + RED='\033[0;31m' + BLUE='\033[0;34m' + BOLD='\033[1m' + NONE='\033[0m' + PADDLE_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}")/../../" && pwd )" + if [ -z "${SCRIPT_NAME}" ]; then + SCRIPT_NAME=$0 + fi } function cmake_gen() { @@ -91,7 +95,6 @@ function cmake_gen() { -DWITH_AVX=${WITH_AVX:-OFF} -DWITH_GOLANG=${WITH_GOLANG:-OFF} -DCUDA_ARCH_NAME=${CUDA_ARCH_NAME:-All} - -DWITH_SWIG_PY=ON -DWITH_C_API=${WITH_C_API:-OFF} -DWITH_PYTHON=${WITH_PYTHON:-ON} -DWITH_SWIG_PY=${WITH_SWIG_PY:-ON} @@ -309,6 +312,25 @@ EOF fi } +function single_test() { + TEST_NAME=$1 + if [ -z "${TEST_NAME}" ]; then + echo -e "${RED}Usage:${NONE}" + echo -e "${BOLD}${SCRIPT_NAME}${NONE} ${BLUE}single_test${NONE} [test_name]" + exit 1 + fi + mkdir -p ${PADDLE_ROOT}/build + cd ${PADDLE_ROOT}/build + if [ ${WITH_TESTING:-ON} == "ON" ] ; then + cat < /dev/null - return $? -} - function start_build_docker() { docker pull $IMG - if container_running "${CONTAINER_ID}"; then - docker stop "${CONTAINER_ID}" 1>/dev/null - docker rm -f "${CONTAINER_ID}" 1>/dev/null - fi - apt_mirror='s#http://archive.ubuntu.com/ubuntu#mirror://mirrors.ubuntu.com/mirrors.txt#g' DOCKER_ENV=$(cat < -#include -#include -#include -#include -#include - -#include "mkldnn.h" -#endif - -namespace mkldnn { - -/// @addtogroup cpp_api C++ API -/// @{ - -/// @addtogroup cpp_api_utils Utils -/// @{ - -/// A class that provides the destructor for an Intel(R) MKL-DNN C handle -template -class handle_traits {}; - -/// A class for wrapping an Intel(R) MKL-DNN handle. It is used as the base -/// class for primitive (#mkldnn_primitive_t), engine (#mkldnn_engine_t), and -/// stream (#mkldnn_stream_t) handles. An object of the #mkldnn::handle class -/// can be passed by value. This class enables wrapping: -/// - Newly constructed handles. -/// @n In this case, the constructed handle uses reference counting provided -/// by @p std::shared_ptr with a proper deleter function specified through -/// the @p handle_traits class. -/// - Pre-existing handles returned by the Intel(R) MKL-DNN C API (for -/// example, through #mkldnn_primitive_get_output()). -/// @n In this case, an Intel(R) MKL-DNN C API handle is wrapped without a -/// deleter because it is assumed that the handle wrapper for the original -/// object deletes the handle (this model is similar to @p std::weak_ptr). -template > -class handle { -private: - std::shared_ptr::type> _data; - handle(const handle &&) = delete; - handle &operator=(const handle &&other) = delete; - -protected: - /// Constructs a C handle wrapper. - /// @param t The C handle to wrap. - /// @param weak A flag to specify whether to construct a weak wrapper. - handle(T t = 0, bool weak = false) : _data(0) { reset(t, weak); } - - bool operator==(const T other) const { return other == _data.get(); } - bool operator!=(const T other) const { return !(*this == other); } - -public: - handle(const handle &other) : _data(other._data) {} - handle &operator=(const handle &other) { - _data = other._data; - return *this; - } - /// Resets the value of a C handle. - /// @param t The new value of the C handle. - /// @param weak A flag to specify whether the wrapper should be weak. - void reset(T t, bool weak = false) { - auto dummy_destructor = [](T) { - return decltype(traits::destructor(0))(0); - }; - _data.reset(t, weak ? dummy_destructor : traits::destructor); - } - - /// Returns the value of the underlying C handle. - T get() const { return _data.get(); } - - bool operator==(const handle &other) const { - return other._data.get() == _data.get(); - } - bool operator!=(const handle &other) const { return !(*this == other); } -}; - -#ifndef DOXYGEN_SHOULD_SKIP_THIS -template <> -struct handle_traits { - static constexpr auto destructor = &mkldnn_primitive_desc_destroy; -}; - -template <> -struct handle_traits { - static constexpr auto destructor = &mkldnn_primitive_destroy; -}; -#endif - -/// Base class for all computational primitives. -class primitive : public handle { - friend struct error; - friend struct stream; - friend class primitive_at; - using handle::handle; - -public: - /// A proxy to C primitive kind enum - enum class kind { - undefined_primitive = mkldnn_undefined_primitive, - memory = mkldnn_memory, - view = mkldnn_view, - reorder = mkldnn_reorder, - concat = mkldnn_concat, - concat_inplace = mkldnn_concat_inplace, - sum = mkldnn_sum, - convolution = mkldnn_convolution, - deconvolution = mkldnn_deconvolution, - eltwise = mkldnn_eltwise, - relu = mkldnn_relu, - softmax = mkldnn_softmax, - pooling = mkldnn_pooling, - lrn = mkldnn_lrn, - batch_normalization = mkldnn_batch_normalization, - inner_product = mkldnn_inner_product, - convolution_relu = mkldnn_convolution_relu, - rnn = mkldnn_rnn, - }; - - /// A wrapper structure to specify a particular output of a primitive. - struct at { - /// The underlying C API structure. - mkldnn_primitive_at_t data; - /// Constructs a wrapper specifying @p aprimitive output with index @p - /// at. - /// - /// @param aprimitive The target primitive. - /// @param at The output index. - - at(const primitive &aprimitive, size_t at = 0) - : data(mkldnn_primitive_at(aprimitive.get(), at)) {} - /// Returns the specified output. - inline operator primitive() const; - }; - - /// Returns the descriptor of the underlying C API primitive - inline const_mkldnn_primitive_desc_t get_primitive_desc() const; - // TODO: use the C++ API wrapper structure. -}; - -inline mkldnn_primitive_kind_t convert_to_c(primitive::kind akind) { - return static_cast(akind); -} - -/// Intel(R) MKL-DNN exception class. -/// -/// This class captures the status returned by the failed C API function, error -/// message, and, optionally, handle of the primitive that caused the error. -struct error : public std::exception { - mkldnn_status_t status; - std::string message; - primitive error_primitive; - - /// Constructs an error instance. - /// - /// @param astatus The error status returned by the C API. - /// @param amessage The error message. - /// @param aerror_primitive (optional) A C handle of the primitive that - /// caused the error. - - error(mkldnn_status_t astatus, - std::string amessage, - mkldnn_primitive_t aerror_primitive = 0) - : status(astatus), - message(amessage), - error_primitive(aerror_primitive, true) {} - - /// A convenience function for wrapping calls to the C API. Checks the - /// return status and throws an #error in case of failure. - /// - /// @param status The error status returned by the C API. - /// @param message The error message. - /// @param error_primitive (optional) A C handle of the primitive that - /// caused the error. - - static void wrap_c_api(mkldnn_status_t status, - std::string message, - mkldnn_primitive_t *error_primitive = 0) { - if (status != mkldnn_success) { - if (nullptr != error_primitive) - throw error(status, message, *error_primitive); - else - throw error(status, message, nullptr); - } - } -}; - -inline primitive::at::operator primitive() const { - const_mkldnn_primitive_t output; - error::wrap_c_api( - mkldnn_primitive_get_output(data.primitive, data.output_index, &output), - "could not get an output primitive"); - return primitive(const_cast(output), true); -} - -const_mkldnn_primitive_desc_t primitive::get_primitive_desc() const { - const_mkldnn_primitive_desc_t pd; - error::wrap_c_api(mkldnn_primitive_get_primitive_desc(get(), &pd), - "could not get primitive descriptor by primitive"); - return pd; -} -/// @} - -/// @addtogroup cpp_api_enums Common data types and enumerations -/// @{ - -enum round_mode { - round_nearest = mkldnn_round_nearest, - round_down = mkldnn_round_down, -}; - -inline mkldnn_round_mode_t convert_to_c(round_mode mode) { - return static_cast(mode); -} - -enum padding_kind { zero = mkldnn_padding_zero }; - -inline mkldnn_padding_kind_t convert_to_c(padding_kind kind) { - return static_cast(kind); -} - -enum prop_kind { - forward_training = mkldnn_forward_training, - forward_scoring = mkldnn_forward_scoring, - forward_inference = mkldnn_forward_inference, - forward = mkldnn_forward, - backward = mkldnn_backward, - backward_data = mkldnn_backward_data, - backward_weights = mkldnn_backward_weights, - backward_bias = mkldnn_backward_bias -}; - -inline mkldnn_prop_kind_t convert_to_c(prop_kind kind) { - return static_cast(kind); -} - -enum algorithm { - algorithm_undef = mkldnn_alg_kind_undef, - convolution_direct = mkldnn_convolution_direct, - convolution_winograd = mkldnn_convolution_winograd, - deconvolution_direct = mkldnn_deconvolution_direct, - deconvolution_winograd = mkldnn_deconvolution_winograd, - eltwise_relu = mkldnn_eltwise_relu, - eltwise_tanh = mkldnn_eltwise_tanh, - eltwise_elu = mkldnn_eltwise_elu, - eltwise_square = mkldnn_eltwise_square, - eltwise_abs = mkldnn_eltwise_abs, - eltwise_sqrt = mkldnn_eltwise_sqrt, - eltwise_linear = mkldnn_eltwise_linear, - eltwise_bounded_relu = mkldnn_eltwise_bounded_relu, - eltwise_soft_relu = mkldnn_eltwise_soft_relu, - eltwise_logistic = mkldnn_eltwise_logistic, - lrn_across_channels = mkldnn_lrn_across_channels, - lrn_within_channel = mkldnn_lrn_within_channel, - pooling_max = mkldnn_pooling_max, - pooling_avg = mkldnn_pooling_avg, - pooling_avg_include_padding = mkldnn_pooling_avg_include_padding, - pooling_avg_exclude_padding = mkldnn_pooling_avg_exclude_padding, - vanilla_rnn = mkldnn_vanilla_rnn, - vanilla_lstm = mkldnn_vanilla_lstm, - vanilla_gru = mkldnn_vanilla_gru, -}; - -inline mkldnn_alg_kind_t convert_to_c(algorithm aalgorithm) { - return static_cast(aalgorithm); -} - -enum batch_normalization_flag { - use_global_stats = mkldnn_use_global_stats, - use_scale_shift = mkldnn_use_scaleshift, - omit_stats = mkldnn_omit_stats, - fuse_bn_relu = mkldnn_fuse_bn_relu -}; - -inline mkldnn_batch_normalization_flag_t convert_to_c( - batch_normalization_flag aflag) { - return static_cast(aflag); -} - -enum rnn_direction { - unidirectional_left2right = mkldnn_unidirectional_left2right, - unidirectional_right2left = mkldnn_unidirectional_right2left, - unidirectional = mkldnn_unidirectional, - bidirectional_concat = mkldnn_bidirectional_concat, - bidirectional_sum = mkldnn_bidirectional_sum, -}; - -inline mkldnn_rnn_direction_t convert_to_c(rnn_direction adir) { - return static_cast(adir); -} - -enum query { - undef = mkldnn_query_undef, - - eengine = mkldnn_query_engine, - primitive_kind = mkldnn_query_primitive_kind, - - num_of_inputs_s32 = mkldnn_query_num_of_inputs_s32, - num_of_outputs_s32 = mkldnn_query_num_of_outputs_s32, - - time_estimate_f64 = mkldnn_query_time_estimate_f64, - memory_consumption_s64 = mkldnn_query_memory_consumption_s64, - - impl_info_str = mkldnn_query_impl_info_str, - - memory_d = mkldnn_query_memory_d, - convolution_d = mkldnn_query_convolution_d, - deconvolution_d = mkldnn_query_deconvolution_d, - eltwise_d = mkldnn_query_eltwise_d, - relu_d = mkldnn_query_relu_d, - softmax_d = mkldnn_query_softmax_d, - pooling_d = mkldnn_query_pooling_d, - lrn_d = mkldnn_query_lrn_d, - batch_normalization_d = mkldnn_query_batch_normalization_d, - inner_product_d = mkldnn_query_inner_product_d, - convolution_relu_d = mkldnn_query_convolution_relu_d, - rnn_d = mkldnn_query_rnn_d, - - input_pd = mkldnn_query_input_pd, - output_pd = mkldnn_query_output_pd, - src_pd = mkldnn_query_src_pd, - diff_src_pd = mkldnn_query_diff_src_pd, - weights_pd = mkldnn_query_weights_pd, - diff_weights_pd = mkldnn_query_diff_weights_pd, - dst_pd = mkldnn_query_dst_pd, - diff_dst_pd = mkldnn_query_diff_dst_pd, - workspace_pd = mkldnn_query_workspace_pd, -}; - -inline mkldnn_query_t convert_to_c(query aquery) { - return static_cast(aquery); -} - -/// @} - -/// @addtogroup cpp_api_attr Attributes -/// @{ - -#ifndef DOXYGEN_SHOULD_SKIP_THIS -template <> -struct handle_traits { - static constexpr auto destructor = &mkldnn_post_ops_destroy; -}; -#endif - -struct post_ops : public handle { - post_ops() { - mkldnn_post_ops_t result; - error::wrap_c_api(mkldnn_post_ops_create(&result), - "could not create post operation sequence"); - reset(result); - } - - int len() const { return mkldnn_post_ops_len(get()); } - - primitive::kind kind(int index) const { - error::wrap_c_api(index < len() ? mkldnn_success : mkldnn_invalid_arguments, - "post_ops index is out of range"); - return static_cast(mkldnn_post_ops_get_kind(get(), index)); - } - - void append_sum(float scale = 1.) { - error::wrap_c_api(mkldnn_post_ops_append_sum(get(), scale), - "could not append sum"); - } - - void get_params_sum(int index, float &scale) const { - error::wrap_c_api(mkldnn_post_ops_get_params_sum(get(), index, &scale), - "could not get sum params"); - } - - void append_eltwise(float scale, algorithm alg, float alpha, float beta) { - error::wrap_c_api(mkldnn_post_ops_append_eltwise( - get(), scale, convert_to_c(alg), alpha, beta), - "could not append eltwise"); - } - - void get_params_eltwise(int index, - float &scale, - algorithm &alg, - float &alpha, - float &beta) const { - mkldnn_alg_kind_t c_alg; - error::wrap_c_api(mkldnn_post_ops_get_params_eltwise( - get(), index, &scale, &c_alg, &alpha, &beta), - "could not get eltwise params"); - alg = static_cast(c_alg); - } -}; - -#ifndef DOXYGEN_SHOULD_SKIP_THIS -template <> -struct handle_traits { - static constexpr auto destructor = &mkldnn_primitive_attr_destroy; -}; -#endif - -struct primitive_attr : public handle { - primitive_attr() { - mkldnn_primitive_attr_t result; - error::wrap_c_api(mkldnn_primitive_attr_create(&result), - "could not create a primitive attr"); - reset(result); - } - - round_mode get_int_output_round_mode() const { - mkldnn_round_mode_t result; - error::wrap_c_api( - mkldnn_primitive_attr_get_int_output_round_mode(get(), &result), - "could not get int output round mode"); - return round_mode(result); - } - - void set_int_output_round_mode(round_mode mode) { - error::wrap_c_api(mkldnn_primitive_attr_set_int_output_round_mode( - get(), mkldnn::convert_to_c(mode)), - "could not set int output round mode"); - } - - void get_output_scales(int &mask, std::vector &scales) const { - int count, c_mask; - const float *c_scales; - error::wrap_c_api(mkldnn_primitive_attr_get_output_scales( - get(), &count, &c_mask, &c_scales), - "could not get int output scales"); - scales.resize(count); - - mask = c_mask; - for (int c = 0; c < count; ++c) scales[c] = c_scales[c]; - } - - void set_output_scales(int mask, const std::vector &scales) { - error::wrap_c_api(mkldnn_primitive_attr_set_output_scales( - get(), (int)scales.size(), mask, &scales[0]), - "could not set int output scales"); - } - - const post_ops get_post_ops() const { - post_ops result; - const_mkldnn_post_ops_t c_result; - error::wrap_c_api(mkldnn_primitive_attr_get_post_ops(get(), &c_result), - "could not get post operation sequence"); - result.reset(const_cast(c_result), true); - return result; - } - - void set_post_ops(post_ops ops) { - error::wrap_c_api(mkldnn_primitive_attr_set_post_ops(get(), ops.get()), - "could not set post operation sequence"); - } -}; - -/// @} - -/// @addtogroup cpp_api_engine Engine -/// @{ - -#ifndef DOXYGEN_SHOULD_SKIP_THIS -template <> -struct handle_traits { - static constexpr auto destructor = &mkldnn_engine_destroy; -}; -#endif - -/// An execution engine. -struct engine : public handle { - friend class primitive; - // gcc bug??? using handle::handle; - - /// Kinds of engines - enum kind { - /// An unspecified engine - any = mkldnn_any_engine, - /// CPU engine - cpu = mkldnn_cpu, - }; - - /// Returns the number of engines of a certain kind. - /// - /// @param akind The kind of engines to count. - - static size_t get_count(kind akind) { - return mkldnn_engine_get_count(convert_to_c(akind)); - } - - /// Constructs an engine. - /// - /// @param akind The kind of engine to construct. - /// @param index The index of the engine. Must be less than the value - /// returned by #get_count() for this particular kind of engine. - - engine(kind akind, size_t index) { - mkldnn_engine_t aengine; - error::wrap_c_api( - mkldnn_engine_create(&aengine, convert_to_c(akind), index), - "could not create an engine"); - reset(aengine); - } - - explicit engine(const mkldnn_engine_t &aengine) : handle(aengine, true) {} - - engine(const handle &pd) { - mkldnn_engine_t engine_q; - error::wrap_c_api( - mkldnn_primitive_desc_query( - pd.get(), mkldnn::convert_to_c(eengine), 0, &engine_q), - "could not get engine from primitive_desc"); - reset(engine_q, true); - } - - template - static engine query(const primitive_desc &pd) { - mkldnn_engine_t engine_q; - error::wrap_c_api( - mkldnn_primitive_desc_query( - pd.get(), mkldnn::convert_to_c(eengine), 0, &engine_q), - "could not get engine from primitive_desc"); - - return engine(engine_q); - } - -private: - static mkldnn_engine_kind_t convert_to_c(kind akind) { - return static_cast(akind); - } -}; - -/// @} - -/// @addtogroup cpp_api_primitives Primitives -/// @{ - -/// @addtogroup cpp_api_memory Memory -/// @{ - -/// Memory primitive that describes the data. -struct memory : public primitive { -private: - std::shared_ptr _handle; - -public: - typedef std::vector::type> dims; - - template - static void validate_dims(std::vector v) { - if (v.size() > TENSOR_MAX_DIMS) - throw error(mkldnn_invalid_arguments, "invalid dimensions"); - } - - /// Data type specification. See #mkldnn_data_type_t for a detailed - /// description. - enum data_type { - data_undef = mkldnn_data_type_undef, - f32 = mkldnn_f32, - s32 = mkldnn_s32, - s16 = mkldnn_s16, - s8 = mkldnn_s8, - u8 = mkldnn_u8, - }; - - /// Memory format specification. See #mkldnn_memory_format_t - /// for a detailed description. - enum format { - format_undef = mkldnn_format_undef, - any = mkldnn_any, - blocked = mkldnn_blocked, - x = mkldnn_x, - nc = mkldnn_nc, - nchw = mkldnn_nchw, - nhwc = mkldnn_nhwc, - chwn = mkldnn_chwn, - nChw8c = mkldnn_nChw8c, - nChw16c = mkldnn_nChw16c, - ncdhw = mkldnn_ncdhw, - ndhwc = mkldnn_ndhwc, - nCdhw16c = mkldnn_nCdhw16c, - oi = mkldnn_oi, - io = mkldnn_io, - oihw = mkldnn_oihw, - ihwo = mkldnn_ihwo, - hwio = mkldnn_hwio, - oidhw = mkldnn_oidhw, - OIdhw16i16o = mkldnn_OIdhw16i16o, - OIdhw16o16i = mkldnn_OIdhw16o16i, - Oidhw16o = mkldnn_Oidhw16o, - Odhwi16o = mkldnn_Odhwi16o, - oIhw8i = mkldnn_oIhw8i, - oIhw16i = mkldnn_oIhw16i, - OIhw8i8o = mkldnn_OIhw8i8o, - OIhw16i16o = mkldnn_OIhw16i16o, - OIhw8o8i = mkldnn_OIhw8o8i, - OIhw16o16i = mkldnn_OIhw16o16i, - IOhw16o16i = mkldnn_IOhw16o16i, - OIhw8i16o2i = mkldnn_OIhw8i16o2i, - OIhw8o16i2o = mkldnn_OIhw8o16i2o, - OIhw4i16o4i = mkldnn_OIhw4i16o4i, - Oihw8o = mkldnn_Oihw8o, - Oihw16o = mkldnn_Oihw16o, - Ohwi8o = mkldnn_Ohwi8o, - Ohwi16o = mkldnn_Ohwi16o, - OhIw16o4i = mkldnn_OhIw16o4i, - goihw = mkldnn_goihw, - hwigo = mkldnn_hwigo, - gOIhw8i8o = mkldnn_gOIhw8i8o, - gOIhw16i16o = mkldnn_gOIhw16i16o, - gOIhw8i16o2i = mkldnn_gOIhw8i16o2i, - gOIhw8o16i2o = mkldnn_gOIhw8o16i2o, - gOIhw4i16o4i = mkldnn_gOIhw4i16o4i, - gOihw8o = mkldnn_gOihw8o, - gOihw16o = mkldnn_gOihw16o, - gOhwi8o = mkldnn_gOhwi8o, - gOhwi16o = mkldnn_gOhwi16o, - Goihw8g = mkldnn_Goihw8g, - Goihw16g = mkldnn_Goihw16g, - gOIhw8o8i = mkldnn_gOIhw8o8i, - gOIhw16o16i = mkldnn_gOIhw16o16i, - gIOhw16o16i = mkldnn_gIOhw16o16i, - gOhIw16o4i = mkldnn_gOhIw16o4i, - goidhw = mkldnn_goidhw, - gOIdhw16i16o = mkldnn_gOIdhw16i16o, - gOIdhw16o16i = mkldnn_gOIdhw16o16i, - gOidhw16o = mkldnn_gOidhw16o, - gOdhwi16o = mkldnn_gOdhwi16o, - ntc = mkldnn_ntc, - tnc = mkldnn_tnc, - ldsnc = mkldnn_ldsnc, - ldigo = mkldnn_ldigo, - ldigo_p = mkldnn_ldigo_p, - ldgoi = mkldnn_ldgoi, - ldgoi_p = mkldnn_ldgoi_p, - ldgo = mkldnn_ldgo, - wino_fmt = mkldnn_wino_fmt, - format_last = mkldnn_format_last, - }; - - /// A memory descriptor. - struct desc { - friend struct memory; - /// The underlying C API data structure. - mkldnn_memory_desc_t data; - - /// Constructs a memory descriptor. - /// - /// @param adims Data dimensions - /// @param adata_type Data precision/type. - /// @param aformat Data layout format. - desc(dims adims, data_type adata_type, format aformat) { - validate_dims(adims); - error::wrap_c_api( - mkldnn_memory_desc_init(&data, - (int)adims.size(), - adims.size() == 0 ? nullptr : &adims[0], - convert_to_c(adata_type), - convert_to_c(aformat)), - "could not initialize a memory descriptor"); - } - - /// Constructs a memory descriptor from a C API data structure. - /// - /// @param adata A C API #mkldnn_memory_desc_t structure. - desc(const mkldnn_memory_desc_t &adata) : data(adata) {} - }; - - /// A memory primitive descriptor. - struct primitive_desc : public handle { - friend struct memory; - - // TODO: make private - primitive_desc() {} - - /// Constructs a memory primitive descriptor. - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api(mkldnn_memory_primitive_desc_create( - &result, &adesc.data, aengine.get()), - "could not initialize a memory primitive descriptor"); - reset(result); - } - - /// Returns the memory primitive descriptor. - memory::desc desc() { - auto memory_d = mkldnn_primitive_desc_query_memory_d(get()); - return memory::desc(*memory_d); - } - - /// Returns the number of bytes required to allocate the memory described - /// including the padding area. - size_t get_size() const { - return mkldnn_memory_primitive_desc_get_size(get()); - } - - bool operator==(const primitive_desc &other) const { - return mkldnn_memory_primitive_desc_equal(get(), other.get()); - } - - bool operator!=(const primitive_desc &other) const { - return !operator==(other); - } - - engine get_engine() { return engine::query(*this); } - }; - - /// Constructs a memory primitive from a generic primitive. - /// - /// @param aprimitive The primitive to treat as memory. - memory(const primitive &aprimitive) : primitive(aprimitive) {} - /// Constructs a memory primitive. - /// - /// @param adesc Memory primitive descriptor. - memory(const primitive_desc &adesc) { - mkldnn_primitive_t result; - error::wrap_c_api( - mkldnn_primitive_create(&result, adesc.get(), nullptr, nullptr), - "could not create a memory primitive"); - reset(result); - auto _malloc = [](size_t size, int alignment) { - void *ptr; -#ifdef _WIN32 - ptr = _aligned_malloc(size, alignment); - int rc = ((ptr) ? 0 : errno); -#else - int rc = ::posix_memalign(&ptr, alignment, size); -#endif /* _WIN32 */ - return (rc == 0) ? (char *)ptr : nullptr; - }; - auto _free = [](char *p) { -#ifdef _WIN32 - _aligned_free((void *)p); -#else - ::free((void *)p); -#endif /* _WIN32 */ - }; - _handle.reset(_malloc(adesc.get_size(), 4096), _free); - set_data_handle(_handle.get()); - } - - memory(const primitive_desc &adesc, void *ahandle) { - mkldnn_primitive_t result; - error::wrap_c_api( - mkldnn_primitive_create(&result, adesc.get(), nullptr, nullptr), - "could not create a memory primitive"); - reset(result); - set_data_handle(ahandle); - } - - /// Returns the descriptor of the memory primitive. - primitive_desc get_primitive_desc() const { - primitive_desc adesc; - const_mkldnn_primitive_desc_t cdesc; - error::wrap_c_api( - mkldnn_primitive_get_primitive_desc(get(), &cdesc), - "could not get primitive descriptor from a memory primitive"); - /* FIXME: no const_cast should be here */ - adesc.reset(const_cast(cdesc), true); - return adesc; - } - - /// Returns a handle of the data contained in the memory primitive. On - /// the CPU engine, this is a pointer to the allocated memory. - inline void *get_data_handle() const { - void *handle; - error::wrap_c_api(mkldnn_memory_get_data_handle(get(), &handle), - "could not get native handle"); - return handle; - } - - inline void set_data_handle(void *handle) const { - error::wrap_c_api(mkldnn_memory_set_data_handle(get(), handle), - "could not set native handle"); - } - - // Must go away or be private: - static mkldnn_data_type_t convert_to_c(data_type adata_type) { - return static_cast(adata_type); - } - static mkldnn_memory_format_t convert_to_c(format aformat) { - return static_cast(aformat); - } -}; - -inline memory::desc zero_md() { - mkldnn_memory_desc_t zero; - zero.primitive_kind = mkldnn_memory; - return memory::desc(zero); -} - -inline memory null_memory(engine eng) { - mkldnn::memory::desc zero = zero_md(); - return memory({zero, eng}, nullptr); -} - -inline bool is_null_memory(const const_mkldnn_primitive_t &aprimitive) { - const_mkldnn_primitive_desc_t aprimitive_pd; - mkldnn_primitive_get_primitive_desc(aprimitive, &aprimitive_pd); - const mkldnn_memory_desc_t *aprimitive_md = - mkldnn_primitive_desc_query_memory_d(aprimitive_pd); - - return ((aprimitive_md != nullptr) && (aprimitive_md->ndims == 0)); -} - -inline bool operator==(mkldnn_data_type_t a, memory::data_type b) { - return a == memory::convert_to_c(b); -} -inline bool operator!=(mkldnn_data_type_t a, memory::data_type b) { - return !(a == b); -} -inline bool operator==(memory::data_type a, mkldnn_data_type_t b) { - return b == a; -} -inline bool operator!=(memory::data_type a, mkldnn_data_type_t b) { - return !(a == b); -} - -inline bool operator==(mkldnn_memory_format_t a, memory::format b) { - return a == memory::convert_to_c(b); -} -inline bool operator!=(mkldnn_memory_format_t a, memory::format b) { - return !(a == b); -} -inline bool operator==(memory::format a, mkldnn_memory_format_t b) { - return b == a; -} -inline bool operator!=(memory::format a, mkldnn_memory_format_t b) { - return !(a == b); -} - -/// @} - -/// @addtogroup cpp_api_reorder Reorder -/// @{ - -struct reorder : public primitive { - struct primitive_desc : public handle { - primitive_desc(const memory::primitive_desc &input, - const memory::primitive_desc &output) { - mkldnn_primitive_desc_t result; - error::wrap_c_api(mkldnn_reorder_primitive_desc_create( - &result, input.get(), output.get()), - "could not create a reorder primitive descriptor"); - reset(result); - } - - primitive_desc(const memory::primitive_desc &input, - const memory::primitive_desc &output, - const primitive_attr &aattr) { - mkldnn_primitive_desc_t result; - error::wrap_c_api(mkldnn_reorder_primitive_desc_create_v2( - &result, input.get(), output.get(), aattr.get()), - "could not create a reorder primitive descriptor"); - reset(result); - } - - engine get_engine() { return engine::query(*this); } - }; - - reorder(const primitive_desc &aprimitive_desc, - const primitive::at &input, - const memory &output) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {input.data}; - const_mkldnn_primitive_t outputs[] = {output.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a reorder primitive"); - reset(result); - } - - reorder(const primitive::at &input, const memory &output) { - auto input_mpd = memory(input).get_primitive_desc(); - auto output_mpd = output.get_primitive_desc(); - - auto reorder_d = primitive_desc(input_mpd, output_mpd); - - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {input.data}; - const_mkldnn_primitive_t outputs[] = {output.get()}; - error::wrap_c_api( - mkldnn_primitive_create(&result, reorder_d.get(), inputs, outputs), - "could not create a reorder primitive"); - reset(result); - } -}; - -/// @} - -/// @addtogroup cpp_api_view View -/// @{ - -struct view : public primitive { - struct primitive_desc : public handle { - primitive_desc(const memory::primitive_desc &input, - memory::dims dims, - memory::dims offsets) { - mkldnn_primitive_desc_t result; - - error::wrap_c_api(mkldnn_view_primitive_desc_create( - &result, input.get(), &dims[0], &offsets[0]), - "could not create a view primitive descriptor"); - reset(result); - } - - memory::primitive_desc dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - view(const primitive_desc &view_pd, primitive::at input) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {input.data}; - error::wrap_c_api( - mkldnn_primitive_create(&result, view_pd.get(), inputs, nullptr), - "could not create a view primitive"); - reset(result); - } - - view(memory input, memory::dims dims, memory::dims offsets) { - mkldnn_primitive_t result; - primitive_desc view_pd(input.get_primitive_desc(), dims, offsets); - mkldnn_primitive_at_t inputs[] = {primitive::at(input).data}; - error::wrap_c_api( - mkldnn_primitive_create(&result, view_pd.get(), inputs, nullptr), - "could not create a view primitive"); - reset(result); - } -}; - -/// @} - -/// @addtogroup cpp_api_concat Concat -/// @{ - -struct concat : public primitive { - struct primitive_desc : public handle { - std::vector cpp_to_c( - std::vector inputs) { - std::vector c_api_inputs; - c_api_inputs.reserve(inputs.size()); - auto convert_to_c = [](memory::primitive_desc d) { return d.get(); }; - std::transform(inputs.begin(), - inputs.end(), - std::back_inserter(c_api_inputs), - convert_to_c); - return c_api_inputs; - } - - primitive_desc(const memory::desc &output, - int concat_dimension, - std::vector inputs) { - mkldnn_primitive_desc_t result; - - auto c_api_inputs = cpp_to_c(inputs); - - error::wrap_c_api( - mkldnn_concat_primitive_desc_create(&result, - &output.data, - (int)c_api_inputs.size(), - concat_dimension, - &c_api_inputs[0]), - "could not create a concat primitive descriptor"); - reset(result); - } - - primitive_desc(int concat_dimension, - std::vector inputs) { - mkldnn_primitive_desc_t result; - - auto c_api_inputs = cpp_to_c(inputs); - - error::wrap_c_api( - mkldnn_concat_primitive_desc_create(&result, - nullptr, - (int)c_api_inputs.size(), - concat_dimension, - &c_api_inputs[0]), - "could not create a concat primitive descriptor"); - reset(result); - } - - memory::primitive_desc dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - concat(const primitive_desc &concat_pd, - std::vector &inputs, - const memory &output) { - mkldnn_primitive_t result; - - std::vector p_inputs; - for (size_t i = 0; i < inputs.size(); i++) - p_inputs.push_back(inputs[i].data); - const_mkldnn_primitive_t outputs[] = {output.get()}; - - error::wrap_c_api(mkldnn_primitive_create( - &result, concat_pd.get(), &p_inputs[0], outputs), - "could not create a concat primitive"); - reset(result); - } -}; - -/// @} - -/// @addtogroup cpp_api_sum Sum -/// @{ - -struct sum : public primitive { - struct primitive_desc : public handle { - std::vector cpp_to_c( - std::vector inputs) { - std::vector c_api_inputs; - c_api_inputs.reserve(inputs.size()); - auto convert_to_c = [](memory::primitive_desc d) { return d.get(); }; - std::transform(inputs.begin(), - inputs.end(), - std::back_inserter(c_api_inputs), - convert_to_c); - return c_api_inputs; - } - - primitive_desc(const memory::desc &output, - const std::vector &scales, - std::vector inputs) { - mkldnn_primitive_desc_t result; - - auto c_api_inputs = cpp_to_c(inputs); - - error::wrap_c_api( - mkldnn_sum_primitive_desc_create(&result, - &output.data, - (int)c_api_inputs.size(), - &scales[0], - &c_api_inputs[0]), - "could not create a sum primitive descriptor"); - reset(result); - } - - primitive_desc(const std::vector &scales, - std::vector inputs) { - mkldnn_primitive_desc_t result; - - auto c_api_inputs = cpp_to_c(inputs); - - error::wrap_c_api( - mkldnn_sum_primitive_desc_create(&result, - nullptr, - (int)c_api_inputs.size(), - &scales[0], - &c_api_inputs[0]), - "could not create a sum primitive descriptor"); - reset(result); - } - - /** @deprecated: api backwards compatibility for double scales type */ - MKLDNN_DEPRECATED - primitive_desc(const memory::desc &output, - std::vector scale, - std::vector inputs) { - mkldnn_primitive_desc_t result; - - auto c_api_inputs = cpp_to_c(inputs); - auto scale_f = scale_to_float(scale); - - error::wrap_c_api( - mkldnn_sum_primitive_desc_create(&result, - &output.data, - (int)c_api_inputs.size(), - &scale_f[0], - &c_api_inputs[0]), - "could not create a sum primitive descriptor"); - reset(result); - } - - /** @deprecated: api backwards compatibility for double scales type */ - MKLDNN_DEPRECATED - primitive_desc(std::vector scale, - std::vector inputs) { - mkldnn_primitive_desc_t result; - - auto c_api_inputs = cpp_to_c(inputs); - auto scale_f = scale_to_float(scale); - - error::wrap_c_api( - mkldnn_sum_primitive_desc_create(&result, - nullptr, - (int)c_api_inputs.size(), - &scale_f[0], - &c_api_inputs[0]), - "could not create a sum primitive descriptor"); - reset(result); - } - - memory::primitive_desc dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - sum(const primitive_desc &sum_pd, - std::vector &inputs, - const memory &output) { - mkldnn_primitive_t result; - - std::vector p_inputs; - for (size_t i = 0; i < inputs.size(); i++) - p_inputs.push_back(inputs[i].data); - const_mkldnn_primitive_t outputs[] = {output.get()}; - - error::wrap_c_api( - mkldnn_primitive_create(&result, sum_pd.get(), &p_inputs[0], outputs), - "could not create a sum primitive"); - reset(result); - } - -private: - static std::vector scale_to_float(const std::vector &vd) { - std::vector vf(vd.size()); - std::transform( - vd.begin(), vd.end(), vf.begin(), [=](double x) { return (float)x; }); - return vf; - } -}; - -/// @} - -/// @addtogroup cpp_api_convolution Convolution -/// @{ - -struct convolution_forward : public primitive { - struct desc { - mkldnn_convolution_desc_t data; - desc(prop_kind aprop_kind, - algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &weights_desc, - const memory::desc &bias_desc, - const memory::desc &dst_desc, - const memory::dims strides, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api(mkldnn_convolution_forward_desc_init( - &data, - mkldnn::convert_to_c(aprop_kind), - convert_to_c(aalgorithm), - &src_desc.data, - &weights_desc.data, - &bias_desc.data, - &dst_desc.data, - &strides[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a convolution forward descriptor"); - } - desc(prop_kind aprop_kind, - algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &weights_desc, - const memory::desc &dst_desc, - const memory::dims strides, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api(mkldnn_convolution_forward_desc_init( - &data, - mkldnn::convert_to_c(aprop_kind), - convert_to_c(aalgorithm), - &src_desc.data, - &weights_desc.data, - nullptr, - &dst_desc.data, - &strides[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a convolution forward descriptor"); - } - desc(prop_kind aprop_kind, - algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &weights_desc, - const memory::desc &bias_desc, - const memory::desc &dst_desc, - const memory::dims strides, - const memory::dims dilates, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(dilates); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_dilated_convolution_forward_desc_init( - &data, - mkldnn::convert_to_c(aprop_kind), - convert_to_c(aalgorithm), - &src_desc.data, - &weights_desc.data, - &bias_desc.data, - &dst_desc.data, - &strides[0], - &dilates[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a dilated convolution forward descriptor"); - } - desc(prop_kind aprop_kind, - algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &weights_desc, - const memory::desc &dst_desc, - const memory::dims strides, - const memory::dims dilates, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(dilates); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_dilated_convolution_forward_desc_init( - &data, - mkldnn::convert_to_c(aprop_kind), - convert_to_c(aalgorithm), - &src_desc.data, - &weights_desc.data, - nullptr, - &dst_desc.data, - &strides[0], - &dilates[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a dilated convolution forward descriptor"); - } - }; - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create( - &result, &adesc.data, aengine.get(), nullptr), - "could not create a convolution forward primitive descriptor"); - reset(result); - } - - primitive_desc(const desc &adesc, - const primitive_attr &aattr, - const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create_v2( - &result, &adesc.data, aattr.get(), aengine.get(), nullptr), - "could not create a convolution forward primitive descriptor"); - reset(result); - } - - memory::primitive_desc src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a src primititve descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc bias_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a bias primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - convolution_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &weights, - const primitive::at &bias, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, weights.data, bias.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a convolution forward bias primitive"); - reset(result); - } - - convolution_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &weights, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, weights.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a convolution forward primitive"); - reset(result); - } -}; - -struct convolution_backward_data : public primitive { - struct desc { - mkldnn_convolution_desc_t data; - desc(algorithm aalgorithm, - const memory::desc &diff_src_desc, - const memory::desc &weights_desc, - const memory::desc &diff_dst_desc, - const memory::dims strides, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_convolution_backward_data_desc_init( - &data, - convert_to_c(aalgorithm), - &diff_src_desc.data, - &weights_desc.data, - &diff_dst_desc.data, - &strides[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a convolution backward data descriptor"); - } - desc(algorithm aalgorithm, - const memory::desc &diff_src_desc, - const memory::desc &weights_desc, - const memory::desc &diff_dst_desc, - const memory::dims strides, - const memory::dims dilates, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(dilates); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_dilated_convolution_backward_data_desc_init( - &data, - convert_to_c(aalgorithm), - &diff_src_desc.data, - &weights_desc.data, - &diff_dst_desc.data, - &strides[0], - &dilates[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a convolution backward data descriptor"); - } - }; - struct primitive_desc : public handle { - primitive_desc( - const desc &adesc, - const engine &aengine, - const convolution_forward::primitive_desc &hint_fwd_primitive_desc) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create(&result, - &adesc.data, - aengine.get(), - hint_fwd_primitive_desc.get()), - "could not create a convolution backward data primitive descriptor"); - reset(result); - } - memory::primitive_desc diff_src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_src primititve descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - convolution_backward_data(const primitive_desc &aprimitive_desc, - const primitive::at &diff_dst, - const primitive::at &weights, - const memory &diff_src) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {diff_dst.data, weights.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a convolution backward data primitive"); - reset(result); - } -}; - -struct convolution_backward_weights : public primitive { - struct desc { - mkldnn_convolution_desc_t data; - desc(algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &diff_weights_desc, - const memory::desc &diff_bias_desc, - const memory::desc &diff_dst_desc, - const memory::dims strides, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_convolution_backward_weights_desc_init( - &data, - convert_to_c(aalgorithm), - &src_desc.data, - &diff_weights_desc.data, - &diff_bias_desc.data, - &diff_dst_desc.data, - &strides[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a convolution backward weights descriptor"); - } - desc(algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &diff_weights_desc, - const memory::desc &diff_dst_desc, - const memory::dims strides, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_convolution_backward_weights_desc_init( - &data, - convert_to_c(aalgorithm), - &src_desc.data, - &diff_weights_desc.data, - nullptr, - &diff_dst_desc.data, - &strides[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a convolution backward weights descriptor"); - } - desc(algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &diff_weights_desc, - const memory::desc &diff_bias_desc, - const memory::desc &diff_dst_desc, - const memory::dims strides, - const memory::dims dilates, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(dilates); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_dilated_convolution_backward_weights_desc_init( - &data, - convert_to_c(aalgorithm), - &src_desc.data, - &diff_weights_desc.data, - &diff_bias_desc.data, - &diff_dst_desc.data, - &strides[0], - &dilates[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a convolution backward weights descriptor"); - } - desc(algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &diff_weights_desc, - const memory::desc &diff_dst_desc, - const memory::dims strides, - const memory::dims dilates, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(dilates); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_dilated_convolution_backward_weights_desc_init( - &data, - convert_to_c(aalgorithm), - &src_desc.data, - &diff_weights_desc.data, - nullptr, - &diff_dst_desc.data, - &strides[0], - &dilates[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a convolution backward weights descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc( - const desc &adesc, - const engine &aengine, - const convolution_forward::primitive_desc &hint_fwd_primitive_desc) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create(&result, - &adesc.data, - aengine.get(), - hint_fwd_primitive_desc.get()), - "could not create a convolution backward weights primitive " - "descriptor"); - reset(result); - } - memory::primitive_desc src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a src primititve descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_bias_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_weights_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_bias primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - convolution_backward_weights(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &diff_dst, - const memory &diff_weights, - const memory &diff_bias) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data}; - const_mkldnn_primitive_t outputs[] = {diff_weights.get(), diff_bias.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a convolution backward weights primitive"); - reset(result); - } - convolution_backward_weights(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &diff_dst, - const memory &diff_weights) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data}; - const_mkldnn_primitive_t outputs[] = {diff_weights.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a convolution backward weights primitive"); - reset(result); - } -}; - -struct convolution_relu_forward : public primitive { - struct desc { - mkldnn_convolution_relu_desc_t data; - desc(const convolution_forward::desc conv_desc, - const float negative_slope) { - error::wrap_c_api( - mkldnn_convolution_relu_desc_init( - &data, &conv_desc.data, negative_slope), - "could not create a convolution_relu_forward descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create( - &result, &adesc.data, aengine.get(), nullptr), - "could not create a convolution relu forward descriptor"); - reset(result); - } - - engine get_engine() { return engine::query(*this); } - }; - - convolution_relu_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &weights, - const primitive::at &bias, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, weights.data, bias.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a convolution relu forward primitive"); - reset(result); - } - - convolution_relu_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &weights, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, weights.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a convolution relu forward primitive"); - reset(result); - } -}; - -/// @} -// -/// @addtogroup cpp_api_deconvolution Deconvolution -/// @{ - -struct deconvolution_forward : public primitive { - struct desc { - mkldnn_deconvolution_desc_t data; - desc(prop_kind aprop_kind, - algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &weights_desc, - const memory::desc &bias_desc, - const memory::desc &dst_desc, - const memory::dims strides, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api(mkldnn_deconvolution_forward_desc_init( - &data, - mkldnn::convert_to_c(aprop_kind), - convert_to_c(aalgorithm), - &src_desc.data, - &weights_desc.data, - &bias_desc.data, - &dst_desc.data, - &strides[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a deconvolution forward descriptor"); - } - desc(prop_kind aprop_kind, - algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &weights_desc, - const memory::desc &dst_desc, - const memory::dims strides, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api(mkldnn_deconvolution_forward_desc_init( - &data, - mkldnn::convert_to_c(aprop_kind), - convert_to_c(aalgorithm), - &src_desc.data, - &weights_desc.data, - nullptr, - &dst_desc.data, - &strides[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a deconvolution forward descriptor"); - } - }; - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create( - &result, &adesc.data, aengine.get(), nullptr), - "could not create a deconvolution forward primitive descriptor"); - reset(result); - } - - primitive_desc(const desc &adesc, - const primitive_attr &aattr, - const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create_v2( - &result, &adesc.data, aattr.get(), aengine.get(), nullptr), - "could not create a deconvolution forward primitive descriptor"); - reset(result); - } - - memory::primitive_desc src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a src primititve descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc bias_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a bias primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - deconvolution_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &weights, - const primitive::at &bias, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, weights.data, bias.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a deconvolution forward bias primitive"); - reset(result); - } - - deconvolution_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &weights, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, weights.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a deconvolution forward primitive"); - reset(result); - } -}; - -struct deconvolution_backward_data : public primitive { - struct desc { - mkldnn_deconvolution_desc_t data; - desc(algorithm aalgorithm, - const memory::desc &diff_src_desc, - const memory::desc &weights_desc, - const memory::desc &diff_dst_desc, - const memory::dims strides, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_deconvolution_backward_data_desc_init( - &data, - convert_to_c(aalgorithm), - &diff_src_desc.data, - &weights_desc.data, - &diff_dst_desc.data, - &strides[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a deconvolution backward data descriptor"); - } - }; - struct primitive_desc : public handle { - primitive_desc( - const desc &adesc, - const engine &aengine, - const deconvolution_forward::primitive_desc &hint_fwd_primitive_desc) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create(&result, - &adesc.data, - aengine.get(), - hint_fwd_primitive_desc.get()), - "could not create a deconvolution backward data primitive " - "descriptor"); - reset(result); - } - memory::primitive_desc diff_src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_src primititve descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - deconvolution_backward_data(const primitive_desc &aprimitive_desc, - const primitive::at &diff_dst, - const primitive::at &weights, - const memory &diff_src) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {diff_dst.data, weights.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a deconvolution backward data primitive"); - reset(result); - } -}; - -struct deconvolution_backward_weights : public primitive { - struct desc { - mkldnn_deconvolution_desc_t data; - desc(algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &diff_weights_desc, - const memory::desc &diff_bias_desc, - const memory::desc &diff_dst_desc, - const memory::dims strides, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_deconvolution_backward_weights_desc_init( - &data, - convert_to_c(aalgorithm), - &src_desc.data, - &diff_weights_desc.data, - &diff_bias_desc.data, - &diff_dst_desc.data, - &strides[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a deconvolution backward weights descriptor"); - } - desc(algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &diff_weights_desc, - const memory::desc &diff_dst_desc, - const memory::dims strides, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_deconvolution_backward_weights_desc_init( - &data, - convert_to_c(aalgorithm), - &src_desc.data, - &diff_weights_desc.data, - nullptr, - &diff_dst_desc.data, - &strides[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not create a deconvolution backward weights descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc( - const desc &adesc, - const engine &aengine, - const deconvolution_forward::primitive_desc &hint_fwd_primitive_desc) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create(&result, - &adesc.data, - aengine.get(), - hint_fwd_primitive_desc.get()), - "could not create a deconvolution backward weights primitive " - "descriptor"); - reset(result); - } - memory::primitive_desc src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a src primititve descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_bias_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_weights_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_bias primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - deconvolution_backward_weights(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &diff_dst, - const memory &diff_weights, - const memory &diff_bias) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data}; - const_mkldnn_primitive_t outputs[] = {diff_weights.get(), diff_bias.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a deconvolution backward weights primitive"); - reset(result); - } - deconvolution_backward_weights(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &diff_dst, - const memory &diff_weights) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data}; - const_mkldnn_primitive_t outputs[] = {diff_weights.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a deconvolution backward weights primitive"); - reset(result); - } -}; - -/// @} - -/// @addtogroup cpp_api_lrn LRN -/// @{ - -struct lrn_forward : public primitive { - struct desc { - mkldnn_lrn_desc_t data; - desc(prop_kind aprop_kind, - algorithm aalgorithm, - const memory::desc &src_desc, - int local_size, - float alpha, - float beta, - float k) { - error::wrap_c_api( - mkldnn_lrn_forward_desc_init(&data, - mkldnn::convert_to_c(aprop_kind), - convert_to_c(aalgorithm), - &src_desc.data, - local_size, - alpha, - beta, - k), - "could not create a lrn forward descriptor"); - } - desc(prop_kind aprop_kind, - algorithm aalgorithm, - const memory::desc &src_desc, - int local_size, - float alpha, - float beta) { - error::wrap_c_api( - mkldnn_lrn_forward_desc_init(&data, - mkldnn::convert_to_c(aprop_kind), - convert_to_c(aalgorithm), - &src_desc.data, - local_size, - alpha, - beta, - float(1.0)), - "could not create a lrn forward descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api(mkldnn_primitive_desc_create( - &result, &adesc.data, aengine.get(), nullptr), - "could not create a lrn forward primitive descriptor"); - reset(result); - } - - memory::primitive_desc src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a src primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc workspace_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t ldesc; - const_mkldnn_primitive_desc_t const_ldesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(workspace_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&ldesc, const_ldesc), - "could not clone a workspace primitive descriptor"); - adesc.reset(ldesc); - return adesc; - } - - memory::primitive_desc dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - lrn_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const memory &workspace, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data}; - const_mkldnn_primitive_t outputs[] = {dst.get(), workspace.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a lrn forward primitive"); - reset(result); - } - - lrn_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a lrn forward primitive"); - reset(result); - } -}; - -struct lrn_backward : public primitive { - struct desc { - mkldnn_lrn_desc_t data; - desc(algorithm aalgorithm, - const memory::desc &data_desc, - const memory::desc &diff_data_desc, - int local_size, - float alpha, - float beta, - float k) { - error::wrap_c_api(mkldnn_lrn_backward_desc_init(&data, - convert_to_c(aalgorithm), - &diff_data_desc.data, - &data_desc.data, - local_size, - alpha, - beta, - k), - "could not create a lrn backward descriptor"); - } - desc(algorithm aalgorithm, - const memory::desc &data_desc, - const memory::desc &diff_data_desc, - int local_size, - float alpha, - float beta) { - error::wrap_c_api(mkldnn_lrn_backward_desc_init(&data, - convert_to_c(aalgorithm), - &diff_data_desc.data, - &data_desc.data, - local_size, - alpha, - beta, - float(1.0)), - "could not create a lrn backward descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, - const engine &aengine, - const lrn_forward::primitive_desc &hint_fwd_primitive_desc) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create(&result, - &adesc.data, - aengine.get(), - hint_fwd_primitive_desc.get()), - "could not create a backward lrn primitive descriptor"); - reset(result); - } - - memory::primitive_desc diff_src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_src primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc workspace_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t ldesc; - const_mkldnn_primitive_desc_t const_ldesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(workspace_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&ldesc, const_ldesc), - "could not clone a workspace primitive descriptor"); - adesc.reset(ldesc); - return adesc; - } - - memory::primitive_desc diff_dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff_dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - lrn_backward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &diff_dst, - const primitive::at &workspace, - const memory &diff_src) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data, workspace.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a lrn backward primitive"); - reset(result); - } - - lrn_backward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &diff_dst, - const memory &diff_src) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a lrn backward primitive"); - reset(result); - } -}; - -/// @} - -/// @addtogroup cpp_api_pooling Pooling -/// @{ - -struct pooling_forward : public primitive { - struct desc { - mkldnn_pooling_desc_t data; - desc(prop_kind aprop_kind, - algorithm aalgorithm, - const memory::desc &src_desc, - const memory::desc &dst_desc, - const memory::dims strides, - const memory::dims kernel, - const memory::dims padding_l, - const memory::dims padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(kernel); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api( - mkldnn_pooling_forward_desc_init(&data, - mkldnn::convert_to_c(aprop_kind), - convert_to_c(aalgorithm), - &src_desc.data, - &dst_desc.data, - &strides[0], - &kernel[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not init a forward pooling descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create( - &result, &adesc.data, aengine.get(), nullptr), - "could not create a forward pooling primitive descriptor"); - reset(result); - } - - memory::primitive_desc workspace_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(workspace_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a workspace primititve descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - pooling_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data}; - const_mkldnn_primitive_t outputs[] = {dst.get(), nullptr}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a pooling forward primitive"); - reset(result); - } - - pooling_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const memory &dst, - const memory &workspace) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data}; - const_mkldnn_primitive_t outputs[] = {dst.get(), workspace.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a pooling forward primitive"); - reset(result); - } -}; - -struct pooling_backward : public primitive { - struct desc { - mkldnn_pooling_desc_t data; - desc(algorithm aalgorithm, - const memory::desc &diff_src_desc, - const memory::desc &diff_dst_desc, - const memory::dims &strides, - const memory::dims &kernel, - const memory::dims &padding_l, - const memory::dims &padding_r, - const padding_kind apadding_kind) { - memory::validate_dims(strides); - memory::validate_dims(kernel); - memory::validate_dims(padding_l); - memory::validate_dims(padding_r); - error::wrap_c_api(mkldnn_pooling_backward_desc_init( - &data, - convert_to_c(aalgorithm), - &diff_src_desc.data, - &diff_dst_desc.data, - &strides[0], - &kernel[0], - &padding_l[0], - &padding_r[0], - mkldnn::convert_to_c(apadding_kind)), - "could not init a backward pooling descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc( - const desc &adesc, - const engine &aengine, - const pooling_forward::primitive_desc &hint_fwd_primitive_desc) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create(&result, - &adesc.data, - aengine.get(), - hint_fwd_primitive_desc.get()), - "could not create a backward pooling primitive descriptor"); - reset(result); - } - - memory::primitive_desc diff_src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff src primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - pooling_backward(const primitive_desc &aprimitive_desc, - const primitive::at &diff_dst, - const memory &diff_src) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {diff_dst.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a pooling backward primitive"); - reset(result); - } - - pooling_backward(const primitive_desc &aprimitive_desc, - const primitive::at &diff_dst, - const primitive::at &workspace, - const memory &diff_src) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {diff_dst.data, workspace.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a pooling backward primitive"); - reset(result); - } -}; - -/// @} - -/// @addtogroup cpp_api_eltwise Eltwise -/// @{ - -struct eltwise_forward : public primitive { - struct desc { - mkldnn_eltwise_desc_t data; - template - desc(prop_kind aprop_kind, - algorithm alg_kind, - const memory::desc &src_desc, - T alpha = 0, - T beta = 0) { - error::wrap_c_api( - mkldnn_eltwise_forward_desc_init(&data, - mkldnn::convert_to_c(aprop_kind), - mkldnn::convert_to_c(alg_kind), - &src_desc.data, - static_cast(alpha), - static_cast(beta)), - "could not create a eltwise forward descriptor"); - } - - /** @deprecated: api backward compatibility for relu */ - template - MKLDNN_DEPRECATED desc(prop_kind aprop_kind, - const memory::desc &src_desc, - T negative_slope) - : desc(aprop_kind, eltwise_relu, src_desc, negative_slope) {} - }; - - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create( - &result, &adesc.data, aengine.get(), nullptr), - "could not create a eltwise forward primitive descriptor"); - reset(result); - } - - memory::primitive_desc dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - eltwise_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a eltwise forward primitive"); - reset(result); - } -}; - -typedef eltwise_forward relu_forward; - -struct eltwise_backward : public primitive { - struct desc { - mkldnn_eltwise_desc_t data; - - template - desc(algorithm alg_kind, - const memory::desc &diff_data_desc, - const memory::desc &data_desc, - T alpha = 0, - T beta = 0) { - error::wrap_c_api( - mkldnn_eltwise_backward_desc_init(&data, - mkldnn::convert_to_c(alg_kind), - &diff_data_desc.data, - &data_desc.data, - static_cast(alpha), - static_cast(beta)), - "could not create a eltwise backward descriptor"); - } - - /** @deprecated: api backward compatibility for relu */ - template - MKLDNN_DEPRECATED desc(const memory::desc &diff_data_desc, - const memory::desc &data_desc, - T negative_slope) - : desc(eltwise_relu, diff_data_desc, data_desc, negative_slope) {} - }; - - struct primitive_desc : public handle { - primitive_desc( - const desc &adesc, - const engine &aengine, - const eltwise_forward::primitive_desc &hint_fwd_primitive_desc) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create(&result, - &adesc.data, - aengine.get(), - hint_fwd_primitive_desc.get()), - "could not create a eltwise backward primitive descriptor"); - reset(result); - } - - memory::primitive_desc diff_src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff src primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - eltwise_backward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &diff_dst, - const memory &diff_src) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a eltwise backward primitive"); - reset(result); - } -}; - -typedef eltwise_backward relu_backward; - -/// @} - -/// @addtogroup cpp_api_softmax Softmax -/// @{ - -struct softmax_forward : public primitive { - struct desc { - mkldnn_softmax_desc_t data; - desc(prop_kind aprop_kind, - const memory::desc &data_desc, - int softmax_axis) { - error::wrap_c_api( - mkldnn_softmax_forward_desc_init(&data, - mkldnn::convert_to_c(aprop_kind), - &data_desc.data, - softmax_axis), - "could not create a softmax forward descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create( - &result, &adesc.data, aengine.get(), nullptr), - "could not create a softmax forward primitive descriptor"); - reset(result); - } - - engine get_engine() { return engine::query(*this); } - }; - - softmax_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a softmax forward primitive"); - reset(result); - } -}; - -/// @} - -/// @addtogroup cpp_api_batch_norm Batch normalization -/// @{ - -struct batch_normalization_forward : public primitive { - struct desc { - mkldnn_batch_normalization_desc_t data; - template - desc(prop_kind aprop_kind, - const memory::desc &src_desc, - T epsilon, - unsigned flags) { - error::wrap_c_api( - mkldnn_batch_normalization_forward_desc_init( - &data, - mkldnn::convert_to_c(aprop_kind), - &src_desc.data, - static_cast(epsilon), - flags), - "could not create a batch normalization forward descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api(mkldnn_primitive_desc_create( - &result, &adesc.data, aengine.get(), nullptr), - "could not create a batch normalization forward " - "primitive descriptor"); - reset(result); - } - - primitive_desc(const desc &adesc, - const primitive_attr &aattr, - const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create_v2( - &result, &adesc.data, aattr.get(), aengine.get(), nullptr), - "could not create a batch normalization forward " - "primitive descriptor"); - reset(result); - } - - memory::primitive_desc weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t bndesc; - const_mkldnn_primitive_desc_t const_bndesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc), - "could not clone a weights primitive descriptor"); - adesc.reset(bndesc); - return adesc; - } - - memory::primitive_desc mean_primitive_desc() const { - memory::primitive_desc aprimitive_desc; - mkldnn_primitive_desc_t bndesc; - mkldnn_batch_normalization_desc_t *p; - error::wrap_c_api( - mkldnn_primitive_desc_query( - get(), mkldnn::convert_to_c(batch_normalization_d), 0, &p), - "could not get a batch-normalization descriptor"); - const_mkldnn_primitive_desc_t const_bndesc = - (p->flags & use_global_stats) - ? mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 1) - : mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc), - "could not clone a mean primitive descriptor"); - aprimitive_desc.reset(bndesc); - return aprimitive_desc; - } - - memory::primitive_desc variance_primitive_desc() const { - memory::primitive_desc aprimitive_desc; - mkldnn_primitive_desc_t bndesc; - mkldnn_batch_normalization_desc_t *p; - error::wrap_c_api( - mkldnn_primitive_desc_query( - get(), mkldnn::convert_to_c(batch_normalization_d), 0, &p), - "could not get a batch-normalization descriptor"); - const_mkldnn_primitive_desc_t const_bndesc = - (p->flags & use_global_stats) - ? mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 2) - : mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 2); - error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc), - "could not clone a variance primitive descriptor"); - aprimitive_desc.reset(bndesc); - return aprimitive_desc; - } - - memory::primitive_desc workspace_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(workspace_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a workspace primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - batch_normalization_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &mean, - const primitive::at &variance, - const primitive::at &weights, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = { - src.data, mean.data, variance.data, weights.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization forward primitive"); - reset(result); - } - - batch_normalization_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &mean, - const primitive::at &variance, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, mean.data, variance.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization forward primitive"); - reset(result); - } - - /// @warning batch_normalization_forward has 2 constructors with very - /// similar signatures: - /// - (pd, src, weights, dst, mean, variance) // 2 in, 3 out - /// - (pd, src, dst, mean, variance, workspace) // 1 in, 4 out - /// The only way to distinguish between those is to explicitly - /// cast all input parameters to their type, i.e. to - /// const primitive:at &. - batch_normalization_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &weights, - const memory &dst, - const memory &mean, - const memory &variance) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, weights.data}; - const_mkldnn_primitive_t outputs[] = { - dst.get(), mean.get(), variance.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization forward primitive"); - reset(result); - } - - batch_normalization_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &weights, - const memory &dst, - const memory &mean, - const memory &variance, - const memory &workspace) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, weights.data}; - const_mkldnn_primitive_t outputs[] = { - dst.get(), mean.get(), variance.get(), workspace.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization forward primitive"); - reset(result); - } - - batch_normalization_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const memory &dst, - const memory &mean, - const memory &variance) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data}; - const_mkldnn_primitive_t outputs[] = { - dst.get(), mean.get(), variance.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization forward primitive"); - reset(result); - } - - /// @warning batch_normalization_forward has 2 constructors with very - /// similar signatures: - /// - (pd, src, weights, dst, mean, variance) // 2 in, 3 out - /// - (pd, src, dst, mean, variance, workspace) // 1 in, 4 out - /// The only way to distinguish between those is to explicitly - /// cast all input parameters to their type, i.e. to - /// const primitive:at &. - /// @note to make users' experience a little bit better this constructor - /// checks if whether parameters match corresponding primitive - /// descriptor, and if they are not -- call the other (proper) - /// constructor. Yeah, this is still very ugly... - batch_normalization_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const memory &dst, - const memory &mean, - const memory &variance, - const memory &workspace) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[2] = {src.data}; - const_mkldnn_primitive_t outputs[4] = { - dst.get(), mean.get(), variance.get(), workspace.get()}; - - if (1) { // check whether this is the `wrong` constructor - const int n_inputs_expected = mkldnn_primitive_desc_query_s32( - aprimitive_desc.get(), mkldnn_query_num_of_inputs_s32, 0); - const int n_outputs_expected = mkldnn_primitive_desc_query_s32( - aprimitive_desc.get(), mkldnn_query_num_of_outputs_s32, 0); - if (n_inputs_expected == 2 && n_outputs_expected == 3) { - // shift parameters, get rid of workspace, and add weights... - auto _weights = dst; - inputs[1] = {_weights.get(), 0}; - - auto _dst = mean, _mean = variance, _variance = workspace; - outputs[0] = _dst.get(); - outputs[1] = _mean.get(); - outputs[2] = _variance.get(); - outputs[3] = nullptr; - } - } - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization forward primitive"); - reset(result); - } - - batch_normalization_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &weights, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, weights.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization forward primitive"); - reset(result); - } - - batch_normalization_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization forward primitive"); - reset(result); - } -}; - -struct batch_normalization_backward : public primitive { - struct desc { - mkldnn_batch_normalization_desc_t data; - template - desc(prop_kind aprop_kind, - const memory::desc &diff_data_desc, - const memory::desc &data_desc, - T epsilon, - unsigned flags) { - error::wrap_c_api( - mkldnn_batch_normalization_backward_desc_init( - &data, - mkldnn::convert_to_c(aprop_kind), - &diff_data_desc.data, - &data_desc.data, - static_cast(epsilon), - flags), - "could not create a batch normalization backward descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, - const engine &aengine, - const batch_normalization_forward::primitive_desc - &hint_fwd_primitive_desc) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create(&result, - &adesc.data, - aengine.get(), - hint_fwd_primitive_desc.get()), - "could not create a batch normalization backward primitive " - "descriptor"); - reset(result); - } - - memory::primitive_desc weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t bndesc; - const_mkldnn_primitive_desc_t const_bndesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc), - "could not clone a weights primitive descriptor"); - adesc.reset(bndesc); - return adesc; - } - - memory::primitive_desc diff_weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t bndesc; - const_mkldnn_primitive_desc_t const_bndesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc), - "could not clone a diff_weights primitive descriptor"); - adesc.reset(bndesc); - return adesc; - } - - memory::primitive_desc mean_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t bndesc; - const_mkldnn_primitive_desc_t const_bndesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc), - "could not clone a mean primitive descriptor"); - adesc.reset(bndesc); - return adesc; - } - - memory::primitive_desc variance_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t bndesc; - const_mkldnn_primitive_desc_t const_bndesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 2); - error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc), - "could not clone a variance primitive descriptor"); - adesc.reset(bndesc); - return adesc; - } - - memory::primitive_desc workspace_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(workspace_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a workspace primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - // Prop_kind == backward - batch_normalization_backward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &mean, - const primitive::at &variance, - const primitive::at &diff_dst, - const primitive::at &weights, - const memory &diff_src, - const memory &diff_weights) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = { - src.data, mean.data, variance.data, diff_dst.data, weights.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get(), diff_weights.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization backward primitive"); - reset(result); - } - - // Prop_kind == backward (+ws) - batch_normalization_backward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &mean, - const primitive::at &variance, - const primitive::at &diff_dst, - const primitive::at &weights, - const primitive::at &workspace, - const memory &diff_src, - const memory &diff_weights) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, - mean.data, - variance.data, - diff_dst.data, - weights.data, - workspace.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get(), diff_weights.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization backward primitive"); - reset(result); - } - - // Prop_kind == backward_data (+ws or +weights) - /// @warning This constructor works for backward_data propagation - /// - w/ weights but w/o workspace, or - /// - w/ workspace but w/o weights - batch_normalization_backward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &mean, - const primitive::at &variance, - const primitive::at &diff_dst, - const primitive::at &weights_or_workspace, - const memory &diff_src) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, - mean.data, - variance.data, - diff_dst.data, - weights_or_workspace.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization backward primitive"); - reset(result); - } - - // Prop_kind == backward_data - batch_normalization_backward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at &mean, - const primitive::at &variance, - const primitive::at &diff_dst, - const memory &diff_src) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = { - src.data, mean.data, variance.data, diff_dst.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a batch normalization backward primitive"); - reset(result); - } -}; - -/// @} - -/// @addtogroup cpp_api_inner_product Inner Product -/// @{ - -struct inner_product_forward : public primitive { - struct desc { - mkldnn_inner_product_desc_t data; - desc(prop_kind aprop_kind, - const memory::desc &src_desc, - const memory::desc &weights_desc, - const memory::desc &bias_desc, - const memory::desc &dst_desc) { - error::wrap_c_api(mkldnn_inner_product_forward_desc_init( - &data, - mkldnn::convert_to_c(aprop_kind), - &src_desc.data, - &weights_desc.data, - &bias_desc.data, - &dst_desc.data), - "could not create a inner product forward descriptor"); - } - - desc(prop_kind aprop_kind, - const memory::desc &src_desc, - const memory::desc &weights_desc, - const memory::desc &dst_desc) { - error::wrap_c_api(mkldnn_inner_product_forward_desc_init( - &data, - mkldnn::convert_to_c(aprop_kind), - &src_desc.data, - &weights_desc.data, - nullptr, - &dst_desc.data), - "could not create a inner product forward descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create( - &result, &adesc.data, aengine.get(), nullptr), - "could not create a inner product forward primitive descriptor"); - reset(result); - } - - primitive_desc(const desc &adesc, - const primitive_attr &aattr, - const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create_v2( - &result, &adesc.data, aattr.get(), aengine.get(), nullptr), - "could not create a inner product " - "forward primitive descriptor"); - reset(result); - } - - memory::primitive_desc src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a src primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc bias_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a bias primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - inner_product_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at weights, - const primitive::at &bias, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, weights.data, bias.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a inner product forward primitive"); - reset(result); - } - - inner_product_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at weights, - const memory &dst) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, weights.data}; - const_mkldnn_primitive_t outputs[] = {dst.get()}; - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a inner product forward primitive"); - reset(result); - } -}; - -struct inner_product_backward_data : public primitive { - struct desc { - mkldnn_inner_product_desc_t data; - desc(const memory::desc &diff_src_desc, - const memory::desc &weights_desc, - const memory::desc &diff_dst_desc) { - error::wrap_c_api( - mkldnn_inner_product_backward_data_desc_init(&data, - &diff_src_desc.data, - &weights_desc.data, - &diff_dst_desc.data), - "could not create a inner product backward data descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc( - const desc &adesc, - const engine &aengine, - const inner_product_forward::primitive_desc &hint_fwd_primitive_desc) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create(&result, - &adesc.data, - aengine.get(), - hint_fwd_primitive_desc.get()), - "could not create a inner product backward data primitive " - "descriptor"); - reset(result); - } - - memory::primitive_desc diff_dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff dst primititve descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff src primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - inner_product_backward_data(const primitive_desc &aprimitive_desc, - const primitive::at &diff_dst, - const primitive::at weights, - const memory &diff_src) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {diff_dst.data, weights.data}; - const_mkldnn_primitive_t outputs[] = {diff_src.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a inner product backward data primitive"); - reset(result); - } -}; - -struct inner_product_backward_weights : public primitive { - struct desc { - mkldnn_inner_product_desc_t data; - desc(const memory::desc &src_desc, - const memory::desc &diff_weights_desc, - const memory::desc &diff_bias_desc, - const memory::desc &diff_dst_desc) { - error::wrap_c_api( - mkldnn_inner_product_backward_weights_desc_init( - &data, - &src_desc.data, - &diff_weights_desc.data, - &diff_bias_desc.data, - &diff_dst_desc.data), - "could not create a inner product backward weights descriptor"); - } - desc(const memory::desc &src_desc, - const memory::desc &diff_weights_desc, - const memory::desc &diff_dst_desc) { - error::wrap_c_api( - mkldnn_inner_product_backward_weights_desc_init( - &data, - &src_desc.data, - &diff_weights_desc.data, - nullptr, - &diff_dst_desc.data), - "could not create a inner product backward weights descriptor"); - } - }; - - struct primitive_desc : public handle { - primitive_desc( - const desc &adesc, - const engine &aengine, - const inner_product_forward::primitive_desc &hint_fwd_primitive_desc) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create(&result, - &adesc.data, - aengine.get(), - hint_fwd_primitive_desc.get()), - "could not create a inner product backward weights primitive " - "descriptor"); - reset(result); - } - - memory::primitive_desc diff_dst_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_dst_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff dst primititve descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_weights_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_bias_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_weights_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a diff bias primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc src_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a src primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - inner_product_backward_weights(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at diff_dst, - const memory &diff_weights) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data}; - const_mkldnn_primitive_t outputs[] = {diff_weights.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a inner product backward weights primitive"); - reset(result); - } - - inner_product_backward_weights(const primitive_desc &aprimitive_desc, - const primitive::at &src, - const primitive::at diff_dst, - const memory &diff_weights, - const memory &diff_bias) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data}; - const_mkldnn_primitive_t outputs[] = {diff_weights.get(), diff_bias.get()}; - error::wrap_c_api( - mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create a inner product backward weights primitive"); - reset(result); - } -}; - -/// @} - -/// @addtogroup cpp_api_rnn RNN -/// @{ - -struct rnn_cell { - struct desc { - mkldnn_rnn_cell_desc_t c_rnn_cell_; - - desc(algorithm kind, algorithm activation_f) { - error::wrap_c_api( - mkldnn_rnn_cell_desc_init(&c_rnn_cell_, - mkldnn::convert_to_c(kind), - mkldnn::convert_to_c(activation_f), - 0U, - 0, - 0), - "could not init an rnn cell descriptor"); - } - desc(algorithm kind) : desc(kind, algorithm::algorithm_undef) {} - - operator const mkldnn_rnn_cell_desc_t *() const { return &c_rnn_cell_; } - - algorithm get_cell_kind() const { return algorithm(c_rnn_cell_.cell_kind); } - algorithm get_activation() const { - return algorithm(c_rnn_cell_.activation_kind); - } - - float get_alpha() const { return c_rnn_cell_.alpha; } - void set_alpha(float alpha) { - c_rnn_cell_.flags |= mkldnn_rnn_cell_with_relu; - c_rnn_cell_.alpha = alpha; - } - - float get_clipping() const { return c_rnn_cell_.clipping; } - void set_clipping(float clipping) { - c_rnn_cell_.flags |= mkldnn_rnn_cell_with_clipping; - c_rnn_cell_.clipping = clipping; - } - - int get_gates_count() const { - return mkldnn_rnn_cell_get_gates_count(&c_rnn_cell_); - } - int get_state_count() const { - return mkldnn_rnn_cell_get_states_count(&c_rnn_cell_); - } - }; -}; - -struct rnn_forward : public primitive { - struct desc { - mkldnn_rnn_desc_t data; - desc(prop_kind aprop_kind, - rnn_cell::desc cell, - const rnn_direction direction, - const memory::desc &src_layer_desc, - const memory::desc &src_iter_desc, - const memory::desc &weights_layer_desc, - const memory::desc &weights_iter_desc, - const memory::desc &bias_desc, - const memory::desc &dst_layer_desc, - const memory::desc &dst_iter_desc) { - error::wrap_c_api( - mkldnn_rnn_forward_desc_init(&data, - mkldnn::convert_to_c(aprop_kind), - cell, - mkldnn::convert_to_c(direction), - &src_layer_desc.data, - &src_iter_desc.data, - &weights_layer_desc.data, - &weights_iter_desc.data, - &bias_desc.data, - &dst_layer_desc.data, - &dst_iter_desc.data), - "could not create an RNN forward descriptor"); - } - }; - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api(mkldnn_primitive_desc_create( - &result, &adesc.data, aengine.get(), nullptr), - "could not create an RNN forward primitive descriptor"); - reset(result); - } - - memory::primitive_desc src_layer_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone an src layer primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc src_iter_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a src iter primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc weights_layer_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc weights_src_iter_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc bias_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 2); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a bias primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc workspace_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t ldesc; - const_mkldnn_primitive_desc_t const_ldesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(workspace_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&ldesc, const_ldesc), - "could not clone a workspace primitive descriptor"); - adesc.reset(ldesc); - return adesc; - } - - memory::primitive_desc dst_layer_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api( - mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst last layer primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc dst_iter_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 1); - error::wrap_c_api( - mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst last iteration primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - - rnn_forward(const primitive_desc &aprimitive_desc, - const primitive::at &src_layer, - const primitive::at &src_iter, - const primitive::at &weights_layer, - const primitive::at &weights_iter, - const primitive::at &bias, - const memory &dst_layer, - const memory &dst_iter, - const memory &workspace) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[5]; - const_mkldnn_primitive_t outputs[3]; - int idx = 0; - inputs[idx++] = src_layer.data; - if (!is_null_memory(src_iter.data.primitive)) inputs[idx++] = src_iter.data; - inputs[idx++] = weights_layer.data; - inputs[idx++] = weights_iter.data; - if (!is_null_memory(bias.data.primitive)) inputs[idx++] = bias.data; - - idx = 0; - outputs[idx++] = dst_layer.get(); - if (!is_null_memory(dst_iter.get())) outputs[idx++] = dst_iter.get(); - if (!is_null_memory(workspace.get())) outputs[idx++] = workspace.get(); - - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create an RNN forward primitive"); - reset(result); - } -}; - -struct rnn_backward : public primitive { - struct desc { - mkldnn_rnn_desc_t data; - desc(prop_kind aprop_kind, - rnn_cell::desc cell, - const rnn_direction direction, - const memory::desc &src_layer_desc, - const memory::desc &src_iter_desc, - const memory::desc &weights_layer_desc, - const memory::desc &weights_iter_desc, - const memory::desc &bias_desc, - const memory::desc &dst_layer_desc, - const memory::desc &dst_iter_desc, - const memory::desc &diff_src_layer_desc, - const memory::desc &diff_src_iter_desc, - const memory::desc &diff_weights_layer_desc, - const memory::desc &diff_weights_iter_desc, - const memory::desc &diff_bias_desc, - const memory::desc &diff_dst_layer_desc, - const memory::desc &diff_dst_iter_desc) { - error::wrap_c_api( - mkldnn_rnn_backward_desc_init(&data, - mkldnn::convert_to_c(aprop_kind), - cell, - mkldnn::convert_to_c(direction), - &src_layer_desc.data, - &src_iter_desc.data, - &weights_layer_desc.data, - &weights_iter_desc.data, - &bias_desc.data, - &dst_layer_desc.data, - &dst_iter_desc.data, - &diff_src_layer_desc.data, - &diff_src_iter_desc.data, - &diff_weights_layer_desc.data, - &diff_weights_iter_desc.data, - &diff_bias_desc.data, - &diff_dst_layer_desc.data, - &diff_dst_iter_desc.data), - "could not create an RNN backward descriptor"); - } - }; - struct primitive_desc : public handle { - primitive_desc(const desc &adesc, const engine &aengine) { - mkldnn_primitive_desc_t result; - error::wrap_c_api( - mkldnn_primitive_desc_create( - &result, &adesc.data, aengine.get(), nullptr), - "could not create an RNN backward primitive descriptor"); - reset(result); - } - - memory::primitive_desc src_layer_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone an src layer primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc src_iter_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(src_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a src iter primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc weights_layer_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc weights_iter_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc bias_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(weights_pd), 2); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a bias primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc dst_layer_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 0); - error::wrap_c_api( - mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst last layer primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc dst_iter_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(dst_pd), 1); - error::wrap_c_api( - mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst last iteration primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_src_layer_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_src_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone an src_layer primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_src_iter_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_src_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a src iter primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_weights_layer_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_weights_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_weights_iter_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_weights_pd), 1); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a weights primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_bias_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_weights_pd), 2); - error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a bias primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_dst_layer_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_dst_pd), 0); - error::wrap_c_api( - mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst last layer primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc diff_dst_iter_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t cdesc; - const_mkldnn_primitive_desc_t const_cdesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(diff_dst_pd), 1); - error::wrap_c_api( - mkldnn_primitive_desc_clone(&cdesc, const_cdesc), - "could not clone a dst last iteration primitive descriptor"); - adesc.reset(cdesc); - return adesc; - } - - memory::primitive_desc workspace_primitive_desc() const { - memory::primitive_desc adesc; - mkldnn_primitive_desc_t ldesc; - const_mkldnn_primitive_desc_t const_ldesc = - mkldnn_primitive_desc_query_pd( - get(), mkldnn::convert_to_c(workspace_pd), 0); - error::wrap_c_api(mkldnn_primitive_desc_clone(&ldesc, const_ldesc), - "could not clone a workspace primitive descriptor"); - adesc.reset(ldesc); - return adesc; - } - - engine get_engine() { return engine::query(*this); } - }; - // With last iteration (with and without input src_iter) - rnn_backward(const primitive_desc &aprimitive_desc, - const primitive::at &src_layer, - const primitive::at &src_iter, - const primitive::at &weights_layer, - const primitive::at &weights_iter, - const primitive::at &bias, - const primitive::at &dst_layer, - const primitive::at &dst_iter, - const memory &diff_src_layer, - const memory &diff_src_iter, - const memory &diff_weights_layer, - const memory &diff_weights_iter, - const memory &diff_bias, - const primitive::at &diff_dst_layer, - const primitive::at &diff_dst_iter, - const primitive::at &workspace) { - mkldnn_primitive_t result; - mkldnn_primitive_at_t inputs[10]; - const_mkldnn_primitive_t outputs[5]; - int idx = 0; - inputs[idx] = src_layer.data; - if (!is_null_memory(src_iter.data.primitive)) inputs[idx++] = src_iter.data; - inputs[idx++] = weights_layer.data; - inputs[idx++] = weights_iter.data; - if (!is_null_memory(bias.data.primitive)) inputs[idx++] = bias.data; - inputs[idx] = dst_layer.data; - if (!is_null_memory(dst_iter.data.primitive)) inputs[idx++] = dst_iter.data; - inputs[idx] = diff_dst_layer.data; - if (!is_null_memory(diff_dst_iter.data.primitive)) - inputs[idx++] = diff_dst_iter.data; - inputs[idx] = workspace.data; - - idx = 0; - outputs[idx] = diff_src_layer.get(); - if (!is_null_memory(diff_src_iter.get())) - outputs[idx++] = diff_src_iter.get(); - outputs[idx] = diff_weights_layer.get(); - outputs[idx] = diff_weights_iter.get(); - if (!is_null_memory(diff_bias.get())) outputs[idx] = diff_bias.get(); - error::wrap_c_api(mkldnn_primitive_create( - &result, aprimitive_desc.get(), inputs, outputs), - "could not create an RNN backward primitive"); - reset(result); - } -}; - -/// @} -/// @} Primitives - -/// @addtogroup cpp_api_stream Stream -/// @{ - -#ifndef DOXYGEN_SHOULD_SKIP_THIS -template <> -struct handle_traits { - static constexpr auto destructor = &mkldnn_stream_destroy; -}; -#endif - -struct stream : public handle { - using handle::handle; - - enum kind { - any = mkldnn_stream_kind_t::mkldnn_any_stream, - eager = mkldnn_stream_kind_t::mkldnn_eager, - lazy = mkldnn_stream_kind_t::mkldnn_lazy - }; - - static mkldnn_stream_kind_t convert_to_c(kind akind) { - return static_cast(akind); - } - /// Constructs a stream. - stream(kind akind) { - mkldnn_stream_t astream; - error::wrap_c_api(mkldnn_stream_create(&astream, convert_to_c(akind)), - "could not create a stream"); - reset(astream); - } - - /// Submits a vector of primitives to a stream for computations. - /// - /// @param primitives The vector of primitives to submit. - /// @returns The stream. - stream &submit(std::vector primitives) { - // TODO: find a proper way to convert vector to - // vector - if (primitives.size() == 0) return *this; - std::vector c_api_primitives; - c_api_primitives.reserve(primitives.size()); - auto convert_to_c = [](primitive p) { return p.get(); }; - std::transform(primitives.begin(), - primitives.end(), - std::back_inserter(c_api_primitives), - convert_to_c); - - mkldnn_primitive_t c_api_error_primitive; - error::wrap_c_api(mkldnn_stream_submit(get(), - c_api_primitives.size(), - &c_api_primitives[0], - &c_api_error_primitive), - "could not submit primitives to a stream", - &c_api_error_primitive); - - return *this; - } - - /// Waits for all computations submitted to the stream to complete. - /// - /// @param block Specifies whether the operation should wait indefinitely or - /// return - /// immediately. - /// @returns @c true if all computations completed. - /// @returns @c false if not all computations completed. - bool wait(bool block = true) { - mkldnn_primitive_t c_api_error_primitive; - mkldnn_status_t status = - mkldnn_stream_wait(get(), block, &c_api_error_primitive); - if (status != mkldnn_success && status != mkldnn_try_again) - error::wrap_c_api( - status, "could not wait on a stream", &c_api_error_primitive); - return (status == mkldnn_success); - } - - stream &rerun() { - mkldnn_primitive_t c_api_error_primitive; - error::wrap_c_api(mkldnn_stream_rerun(get(), &c_api_error_primitive), - "could not rerun a stream", - &c_api_error_primitive); - return *this; - } -}; - -/// @} - -/// @} C++ API - -} // namespace mkldnn - -#endif diff --git a/python/paddle/fluid/data_feeder.py b/python/paddle/fluid/data_feeder.py index 0051b698471b40bffc12921f86dcde642714e07d..a44e078d0c13717643a6cfc6dd8bff5901ee9c97 100644 --- a/python/paddle/fluid/data_feeder.py +++ b/python/paddle/fluid/data_feeder.py @@ -54,9 +54,9 @@ class DataToLoDTensorConverter(object): self.data.append(data) else: cur_lod_len = len(data) - lod[-1].append(lod[-1][-1] + cur_lod_len) + lod[0].append(lod[0][-1] + cur_lod_len) for each_data in data: - self._feed_impl_(each_data, lod[:-1], lod_level - 1) + self._feed_impl_(each_data, lod[1:], lod_level - 1) def done(self): arr = numpy.array(self.data, dtype=self.dtype).reshape(self.shape) diff --git a/python/paddle/fluid/evaluator.py b/python/paddle/fluid/evaluator.py index 1ee1d3727174c079d2c217dede27ff1a0316c01c..7c6ad6f27dcfd7040f79c72c01413c8cc84a28ba 100644 --- a/python/paddle/fluid/evaluator.py +++ b/python/paddle/fluid/evaluator.py @@ -273,10 +273,11 @@ class DetectionMAP(Evaluator): [M, 6]. The layout is [label, confidence, xmin, ymin, xmax, ymax]. gt_label (Variable): The ground truth label index, which is a LoDTensor with shape [N, 1]. - gt_difficult (Variable): Whether this ground truth is a difficult - bounding box (bbox), which is a LoDTensor [N, 1]. gt_box (Variable): The ground truth bounding box (bbox), which is a LoDTensor with shape [N, 6]. The layout is [xmin, ymin, xmax, ymax]. + gt_difficult (Variable|None): Whether this ground truth is a difficult + bounding bbox, which can be a LoDTensor [N, 1] or not set. If None, + it means all the ground truth labels are not difficult bbox. class_num (int): The class number. background_label (int): The index of background label, the background label will be ignored. If set to -1, then all categories will be @@ -284,7 +285,8 @@ class DetectionMAP(Evaluator): overlap_threshold (float): The threshold for deciding true/false positive, 0.5 by defalut. evaluate_difficult (bool): Whether to consider difficult ground truth - for evaluation, True by defalut. + for evaluation, True by defalut. This argument does not work when + gt_difficult is None. ap_version (string): The average precision calculation ways, it must be 'integral' or '11point'. Please check https://sanchom.wordpress.com/tag/average-precision/ for details. @@ -295,7 +297,7 @@ class DetectionMAP(Evaluator): exe = fluid.executor(place) map_evaluator = fluid.Evaluator.DetectionMAP(input, - gt_label, gt_difficult, gt_box) + gt_label, gt_box, gt_difficult) cur_map, accum_map = map_evaluator.get_map_var() fetch = [cost, cur_map, accum_map] for epoch in PASS_NUM: @@ -313,8 +315,8 @@ class DetectionMAP(Evaluator): input, gt_label, gt_box, - gt_difficult, - class_num, + gt_difficult=None, + class_num=None, background_label=0, overlap_threshold=0.5, evaluate_difficult=True, @@ -322,8 +324,11 @@ class DetectionMAP(Evaluator): super(DetectionMAP, self).__init__("map_eval") gt_label = layers.cast(x=gt_label, dtype=gt_box.dtype) - gt_difficult = layers.cast(x=gt_difficult, dtype=gt_box.dtype) - label = layers.concat([gt_label, gt_difficult, gt_box], axis=1) + if gt_difficult: + gt_difficult = layers.cast(x=gt_difficult, dtype=gt_box.dtype) + label = layers.concat([gt_label, gt_difficult, gt_box], axis=1) + else: + label = layers.concat([gt_label, gt_box], axis=1) # calculate mean average precision (mAP) of current mini-batch map = layers.detection_map( diff --git a/python/paddle/fluid/framework.py b/python/paddle/fluid/framework.py index 5b222513c1f62a4233a8446ddd246983f336e87b..08b756d95b9b72db5d978afbe437bbfcb52025b0 100644 --- a/python/paddle/fluid/framework.py +++ b/python/paddle/fluid/framework.py @@ -72,6 +72,8 @@ def convert_np_dtype_to_dtype_(np_dtype): return core.VarDesc.VarType.INT64 elif dtype == np.bool: return core.VarDesc.VarType.BOOL + elif dtype == np.uint8: + return core.VarDesc.VarType.UINT8 else: raise ValueError("Not supported numpy dtype " + str(dtype)) diff --git a/python/paddle/fluid/inferencer.py b/python/paddle/fluid/inferencer.py index 56c008d1af70f4b5f6169ebe5174b08fcf8bc722..894f6dbfadcaf532556c439daf2c3b4ca24ffeb4 100644 --- a/python/paddle/fluid/inferencer.py +++ b/python/paddle/fluid/inferencer.py @@ -12,11 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +import contextlib + import core import executor import framework import io +import parallel_executor import unique_name from trainer import check_and_get_place @@ -24,40 +27,53 @@ __all__ = ['Inferencer', ] class Inferencer(object): - def __init__(self, infer_func, param_path, place=None): + def __init__(self, infer_func, param_path, place=None, parallel=False): """ :param infer_func: a function that will return predict Variable :param param_path: the path where the inference model is saved by fluid.io.save_params :param place: place to do the inference + :param parallel: use parallel_executor to run the inference, it will use multi CPU/GPU. """ self.param_path = param_path self.scope = core.Scope() + self.parallel = parallel + self.place = check_and_get_place(place) self.inference_program = framework.Program() with framework.program_guard(self.inference_program): with unique_name.guard(): self.predict_var = infer_func() - self.exe = executor.Executor(check_and_get_place(place)) - with executor.scope_guard(self.scope): + with self._prog_and_scope_guard(): # load params from param_path into scope - io.load_params(self.exe, param_path, self.inference_program) + io.load_params(executor.Executor(self.place), param_path) + + if parallel: + with self._prog_and_scope_guard(): + self.exe = parallel_executor.ParallelExecutor( + use_cuda=isinstance(self.place, core.CUDAPlace), + loss_name=self.predict_var.name) + else: + self.exe = executor.Executor(self.place) - def infer(self, inputs, return_numpy=True): + def infer(self, inputs): """ :param inputs: a map of {"input_name": input_var} that will be feed into the inference program to get the predict value - :param return_numpy: if return numpy value for row tensor :return: the predict value of the inference model """ if not isinstance(inputs, dict): raise ValueError( "inputs should be a map of {'input_name': input_var}") - with executor.scope_guard(self.scope): - results = self.exe.run(self.inference_program, - feed=inputs, - fetch_list=[self.predict_var], - return_numpy=return_numpy) + with self._prog_and_scope_guard(): + results = self.exe.run(feed=inputs, + fetch_list=[self.predict_var.name]) return results + + @contextlib.contextmanager + def _prog_and_scope_guard(self): + with framework.program_guard(main_program=self.inference_program): + with executor.scope_guard(self.scope): + yield diff --git a/python/paddle/fluid/layers/control_flow.py b/python/paddle/fluid/layers/control_flow.py index 4b707973e27391a6bdcba138934f62a255e04bb2..dee41448081cbfcd8224ce2abbf3ba7b7b97eb7c 100644 --- a/python/paddle/fluid/layers/control_flow.py +++ b/python/paddle/fluid/layers/control_flow.py @@ -49,6 +49,7 @@ __all__ = [ 'reorder_lod_tensor_by_rank', 'ParallelDo', 'Print', + 'is_empty', ] @@ -1562,3 +1563,40 @@ def reorder_lod_tensor_by_rank(x, rank_table): 'RankTable': [rank_table]}, outputs={'Out': [out]}) return out + + +def is_empty(x, cond=None, **ignored): + """ + **Is Empty** + + This layer returns the truth value of whether the variable is empty. + + Args: + x(Variable): Operand of *is_empty* + cond(Variable|None): Optional output variable to store the result + of *is_empty* + + Returns: + Variable: The tensor variable storing the output of *is_empty*. + + Raises: + TypeError: If input cond is not a variable, or cond's dtype is + not bool + + Examples: + .. code-block:: python + + less = fluid.layers.is_empty(x=input) + """ + helper = LayerHelper("is_empty", **locals()) + if cond is None: + cond = helper.create_tmp_variable(dtype='bool') + cond.stop_gradient = True + elif not isinstance(cond, Variable): + raise TypeError("cond takes a variable") + elif cond.dtype != 'bool': + raise TypeError("The data type of cond must be bool") + + helper.append_op( + type='is_empty', inputs={'X': [x]}, outputs={'Out': [cond]}) + return cond diff --git a/python/paddle/fluid/layers/detection.py b/python/paddle/fluid/layers/detection.py index a5938fe494265778ef7032c56a8d6d35acd729c5..3a83db12fd13651578deeac6b562bac2f1e4e4b6 100644 --- a/python/paddle/fluid/layers/detection.py +++ b/python/paddle/fluid/layers/detection.py @@ -23,6 +23,7 @@ import nn import math __all__ = [ + 'prior_box', 'multi_box_head', 'bipartite_match', 'target_assign', @@ -564,6 +565,115 @@ def ssd_loss(location, return loss +def prior_box(input, + image, + min_sizes, + max_sizes=None, + aspect_ratios=[1.], + variance=[0.1, 0.1, 0.2, 0.2], + flip=False, + clip=False, + steps=[0.0, 0.0], + offset=0.5, + name=None): + """ + **Prior box operator** + + Generate prior boxes for SSD(Single Shot MultiBox Detector) algorithm. + Each position of the input produce N prior boxes, N is determined by + the count of min_sizes, max_sizes and aspect_ratios, The size of the + box is in range(min_size, max_size) interval, which is generated in + sequence according to the aspect_ratios. + + Args: + input(Variable): The Input Variables, the format is NCHW. + image(Variable): The input image data of PriorBoxOp, + the layout is NCHW. + min_sizes(list|tuple|float value): min sizes of generated prior boxes. + max_sizes(list|tuple|None): max sizes of generated prior boxes. + Default: None. + aspect_ratios(list|tuple|float value): the aspect ratios of generated + prior boxes. Default: [1.]. + variance(list|tuple): the variances to be encoded in prior boxes. + Default:[0.1, 0.1, 0.2, 0.2]. + flip(bool): Whether to flip aspect ratios. Default:False. + clip(bool): Whether to clip out-of-boundary boxes. Default: False. + step(list|turple): Prior boxes step across width and height, If + step[0] == 0.0/step[1] == 0.0, the prior boxes step across + height/weight of the input will be automatically calculated. + Default: [0., 0.] + offset(float): Prior boxes center offset. Default: 0.5 + name(str): Name of the prior box op. Default: None. + + Returns: + boxes(Variable): the output prior boxes of PriorBox. + The layout is [H, W, num_priors, 4]. + H is the height of input, W is the width of input, + num_priors is the total + box count of each position of input. + Variances(Variable): the expanded variances of PriorBox. + The layout is [H, W, num_priors, 4]. + H is the height of input, W is the width of input + num_priors is the total + box count of each position of input + + + Examples: + .. code-block:: python + box, var = prior_box( + input=conv1, + image=images, + min_sizes=[100.], + flip=True, + clip=True) + """ + helper = LayerHelper("prior_box", **locals()) + dtype = helper.input_dtype() + + def _is_list_or_tuple_(data): + return (isinstance(data, list) or isinstance(data, tuple)) + + if not _is_list_or_tuple_(min_sizes): + min_sizes = [min_sizes] + if not _is_list_or_tuple_(aspect_ratios): + aspect_ratios = [aspect_ratios] + if not (_is_list_or_tuple_(steps) and len(steps) == 2): + raise ValueError('steps should be a list or tuple ', + 'with length 2, (step_width, step_height).') + + min_sizes = list(map(float, min_sizes)) + aspect_ratios = list(map(float, aspect_ratios)) + steps = list(map(float, steps)) + + attrs = { + 'min_sizes': min_sizes, + 'aspect_ratios': aspect_ratios, + 'variances': variance, + 'flip': flip, + 'clip': clip, + 'step_w': steps[0], + 'step_h': steps[1], + 'offset': offset + } + if max_sizes is not None and len(max_sizes) > 0 and max_sizes[0] > 0: + if not _is_list_or_tuple_(max_sizes): + max_sizes = [max_sizes] + attrs['max_sizes'] = max_sizes + + box = helper.create_tmp_variable(dtype) + var = helper.create_tmp_variable(dtype) + helper.append_op( + type="prior_box", + inputs={"Input": input, + "Image": image}, + outputs={"Boxes": box, + "Variances": var}, + attrs=attrs, ) + box.stop_gradient = True + var.stop_gradient = True + return box, var + + def multi_box_head(inputs, image, base_size, @@ -660,47 +770,6 @@ def multi_box_head(inputs, clip=True) """ - def _prior_box_(input, - image, - min_sizes, - max_sizes, - aspect_ratios, - variance, - flip=False, - clip=False, - step_w=0.0, - step_h=0.0, - offset=0.5, - name=None): - helper = LayerHelper("prior_box", **locals()) - dtype = helper.input_dtype() - - attrs = { - 'min_sizes': min_sizes, - 'aspect_ratios': aspect_ratios, - 'variances': variance, - 'flip': flip, - 'clip': clip, - 'step_w': step_w, - 'step_h': step_h, - 'offset': offset - } - if len(max_sizes) > 0 and max_sizes[0] > 0: - attrs['max_sizes'] = max_sizes - - box = helper.create_tmp_variable(dtype) - var = helper.create_tmp_variable(dtype) - helper.append_op( - type="prior_box", - inputs={"Input": input, - "Image": image}, - outputs={"Boxes": box, - "Variances": var}, - attrs=attrs, ) - box.stop_gradient = True - var.stop_gradient = True - return box, var - def _reshape_with_axis_(input, axis=1): if not (axis > 0 and axis < len(input.shape)): raise ValueError("The axis should be smaller than " @@ -777,11 +846,10 @@ def multi_box_head(inputs, aspect_ratio = aspect_ratios[i] if not _is_list_or_tuple_(aspect_ratio): aspect_ratio = [aspect_ratio] + step = [step_w[i] if step_w else 0.0, step_h[i] if step_w else 0.0] - box, var = _prior_box_(input, image, min_size, max_size, aspect_ratio, - variance, flip, clip, step_w[i] - if step_w else 0.0, step_h[i] - if step_w else 0.0, offset) + box, var = prior_box(input, image, min_size, max_size, aspect_ratio, + variance, flip, clip, step, offset) box_results.append(box) var_results.append(var) diff --git a/python/paddle/fluid/layers/nn.py b/python/paddle/fluid/layers/nn.py index 1786be22fdcd0d074b45bc94b3b0c4e8c41b4e8a..561c8bd42f90911bf5a0c898fe01412d42d2c9b1 100644 --- a/python/paddle/fluid/layers/nn.py +++ b/python/paddle/fluid/layers/nn.py @@ -1329,6 +1329,8 @@ def sequence_pool(input, pool_type): sqrt : out.data = [2.82, 6.93, 4.24], where 2.82=(1+3)/sqrt(2), 6.93=(2+4+6)/sqrt(3), 4.24=(5+1)/sqrt(2) max : out.data = [3, 6, 5], where 3=max(1,3), 6=max(2,4,6), 5=max(5,1) + last : out.data = [3, 6, 1], where 3=last(1,3), 6=last(2,4,6), 1=last(5,1) + first : out.data = [1, 2, 5], where 1=first(1,3), 2=first(2,4,6), 5=first(5,1) Args: input(variable): The input variable which is a LoDTensor. @@ -1348,6 +1350,8 @@ def sequence_pool(input, pool_type): sum_x = fluid.layers.sequence_pool(input=x, pool_type='sum') sqrt_x = fluid.layers.sequence_pool(input=x, pool_type='sqrt') max_x = fluid.layers.sequence_pool(input=x, pool_type='max') + last_x = fluid.layers.sequence_pool(input=x, pool_type='last') + first_x = fluid.layers.sequence_pool(input=x, pool_type='first') """ helper = LayerHelper('sequence_pool', **locals()) dtype = helper.input_dtype() @@ -3263,35 +3267,35 @@ def smooth_l1(x, y, inside_weight=None, outside_weight=None, sigma=None): """ **Smooth L1 Loss Operator. ** - This operator computes the smooth l1 loss for X and Y. + This operator computes the smooth L1 loss for X and Y. The operator takes the first dimension of X and Y as batch size. - For each instance, it computes the smooth l1 loss element by element first + For each instance, it computes the smooth L1 loss element by element first and then sums all the losses. So the shape of Out is [batch_size, 1]. Args: x (Variable): A tensor with rank at least 2. The input value of smooth - l1 loss op with shape [batch_size, dim1, ..., dimN]. + L1 loss op with shape [batch_size, dim1, ..., dimN]. y (Variable): A tensor with rank at least 2. The target value of smooth - l1 loss op with same shape as x. + L1 loss op with same shape as x. inside_weight (Variable|None): A tensor with rank at least 2. This input is optional and should have same shape with x. If provided, the result of (x - y) will be multiplied by this tensor element by element. outside_weight (Variable|None): A tensor with rank at least 2. This input is optional and should have same shape with x. If provided, - the out smooth l1 loss will be multiplied by this tensor element + the out smooth L1 loss will be multiplied by this tensor element by element. - sigma (float|None): Hyper parameter of smooth l1 loss op. A float scalar + sigma (float|None): Hyper parameter of smooth L1 loss op. A float scalar with default value 1.0. Returns: - Variable: A tensor with rank be 2. The output smooth l1 loss with + Variable: A tensor with rank be 2. The output smooth L1 loss with shape [batch_size, 1]. Examples: .. code-block:: python data = fluid.layers.data(name='data', shape=[128], dtype='float32') - label = fluid.layers.data(name='label', shape=[100], dtype='int64') + label = fluid.layers.data(name='label', shape=[100], dtype='float32') fc = fluid.layers.fc(input=data, size=100) out = fluid.layers.smooth_l1(x=fc, y=label) """ @@ -3769,13 +3773,13 @@ def label_smooth(label, def roi_pool(input, rois, pooled_height=1, pooled_width=1, spatial_scale=1.0): """ - Region of interest pooling (also known as RoI pooling) is to perform + Region of interest pooling (also known as RoI pooling) is to perform is to perform max pooling on inputs of nonuniform sizes to obtain fixed-size feature maps (e.g. 7*7). - The operator has three steps: - 1. Dividing each region proposal into equal-sized sections with - the pooled_width and pooled_height - 2. Finding the largest value in each section + The operator has three steps: + 1. Dividing each region proposal into equal-sized sections with + the pooled_width and pooled_height + 2. Finding the largest value in each section 3. Copying these max values to the output buffer Args: @@ -3783,8 +3787,8 @@ def roi_pool(input, rois, pooled_height=1, pooled_width=1, spatial_scale=1.0): rois (Variable): ROIs (Regions of Interest) to pool over. It should be a 2-D one level LoTensor of shape [num_rois, 4]. The layout is [x1, y1, x2, y2], where (x1, y1) - is the top left coordinates, and (x2, y2) is the - bottom right coordinates. The num_rois is the + is the top left coordinates, and (x2, y2) is the + bottom right coordinates. The num_rois is the total number of ROIs in this batch data. pooled_height (integer): The pooled output height. Default: 1 pooled_width (integer): The pooled output width. Default: 1 @@ -3793,11 +3797,11 @@ def roi_pool(input, rois, pooled_height=1, pooled_width=1, spatial_scale=1.0): to the scale used when pooling. Default: 1.0 Returns: - pool_out (Variable): The output is a 4-D tensor of the shape + pool_out (Variable): The output is a 4-D tensor of the shape (num_rois, channels, pooled_h, pooled_w). Examples: - pool_out = fluid.layers.roi_pool(input=x, rois=rois, 7, 7, 1.0) + pool_out = fluid.layers.roi_pool(input=x, rois=rois, 7, 7, 1.0) """ helper = LayerHelper('roi_pool', **locals()) dtype = helper.input_dtype() diff --git a/python/paddle/fluid/tests/book/high-level-api/CMakeLists.txt b/python/paddle/fluid/tests/book/high-level-api/CMakeLists.txt index c2a15bdb3b17b65fe861dd429f548074c13e2f09..182e30a6a9b4249a895d15cfd65c403bb6813d0d 100644 --- a/python/paddle/fluid/tests/book/high-level-api/CMakeLists.txt +++ b/python/paddle/fluid/tests/book/high-level-api/CMakeLists.txt @@ -8,3 +8,5 @@ endforeach() add_subdirectory(fit_a_line) add_subdirectory(recognize_digits) +add_subdirectory(image_classification) +add_subdirectory(understand_sentiment) diff --git a/python/paddle/fluid/tests/book/high-level-api/fit_a_line/test_fit_a_line.py b/python/paddle/fluid/tests/book/high-level-api/fit_a_line/test_fit_a_line.py index fbcf2a282f6421a546723a1d429c59fb304a0cc2..4c8505acf322a8ee33799c009b523cd70bd01db3 100644 --- a/python/paddle/fluid/tests/book/high-level-api/fit_a_line/test_fit_a_line.py +++ b/python/paddle/fluid/tests/book/high-level-api/fit_a_line/test_fit_a_line.py @@ -57,22 +57,20 @@ def train(use_cuda, train_program, save_dirname): optimizer=fluid.optimizer.SGD(learning_rate=0.001)) def event_handler(event): - if isinstance(event, fluid.EndEpochEvent): - test_metrics = trainer.test( - reader=test_reader, feed_order=['x', 'y']) - print test_metrics - ''' - - ... - ['25.768919467926025'] - ['15.343549569447836'] - ... - - ''' - if float(test_metrics[0]) < 20.0: + if isinstance(event, fluid.EndStepEvent): + if event.step == 10: + test_metrics = trainer.test( + reader=test_reader, feed_order=['x', 'y']) + print test_metrics + ''' + ... + ['25.768919467926025'] + ['15.343549569447836'] + ... + ''' if save_dirname is not None: trainer.save_params(save_dirname) - return + trainer.stop() trainer.train( reader=train_reader, @@ -94,7 +92,7 @@ def infer(use_cuda, inference_program, save_dirname=None): tensor_x = numpy.random.uniform(0, 10, [batch_size, 13]).astype("float32") results = inferencer.infer({'x': tensor_x}) - print("infer results: ", results[0]) + print("infer results: ", numpy.array(results[0])) def main(use_cuda): diff --git a/python/paddle/fluid/tests/book/high-level-api/image_classification/CMakeLists.txt b/python/paddle/fluid/tests/book/high-level-api/image_classification/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..673c965b662a022739f8d489c331f4de9455a926 --- /dev/null +++ b/python/paddle/fluid/tests/book/high-level-api/image_classification/CMakeLists.txt @@ -0,0 +1,7 @@ +file(GLOB TEST_OPS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "test_*.py") +string(REPLACE ".py" "" TEST_OPS "${TEST_OPS}") + +# default test +foreach(src ${TEST_OPS}) + py_test(${src} SRCS ${src}.py) +endforeach() diff --git a/python/paddle/fluid/tests/book/high-level-api/image_classification/cifar10_small_test_set.py b/python/paddle/fluid/tests/book/high-level-api/image_classification/cifar10_small_test_set.py new file mode 100644 index 0000000000000000000000000000000000000000..7fed6d914f75b690e34411aa154359c93b6ca989 --- /dev/null +++ b/python/paddle/fluid/tests/book/high-level-api/image_classification/cifar10_small_test_set.py @@ -0,0 +1,82 @@ +# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +CIFAR dataset. + +This module will download dataset from +https://www.cs.toronto.edu/~kriz/cifar.html and parse train/test set into +paddle reader creators. + +The CIFAR-10 dataset consists of 60000 32x32 colour images in 10 classes, +with 6000 images per class. There are 50000 training images and 10000 test +images. + +The CIFAR-100 dataset is just like the CIFAR-10, except it has 100 classes +containing 600 images each. There are 500 training images and 100 testing +images per class. + +""" + +import cPickle +import itertools +import numpy +import paddle.v2.dataset.common +import tarfile + +__all__ = ['train10'] + +URL_PREFIX = 'https://www.cs.toronto.edu/~kriz/' +CIFAR10_URL = URL_PREFIX + 'cifar-10-python.tar.gz' +CIFAR10_MD5 = 'c58f30108f718f92721af3b95e74349a' + + +def reader_creator(filename, sub_name, batch_size=None): + def read_batch(batch): + data = batch['data'] + labels = batch.get('labels', batch.get('fine_labels', None)) + assert labels is not None + for sample, label in itertools.izip(data, labels): + yield (sample / 255.0).astype(numpy.float32), int(label) + + def reader(): + with tarfile.open(filename, mode='r') as f: + names = (each_item.name for each_item in f + if sub_name in each_item.name) + + batch_count = 0 + for name in names: + batch = cPickle.load(f.extractfile(name)) + for item in read_batch(batch): + if isinstance(batch_size, int) and batch_count > batch_size: + break + batch_count += 1 + yield item + + return reader + + +def train10(batch_size=None): + """ + CIFAR-10 training set creator. + + It returns a reader creator, each sample in the reader is image pixels in + [0, 1] and label in [0, 9]. + + :return: Training reader creator + :rtype: callable + """ + return reader_creator( + paddle.v2.dataset.common.download(CIFAR10_URL, 'cifar', CIFAR10_MD5), + 'data_batch', + batch_size=batch_size) diff --git a/python/paddle/fluid/tests/book/high-level-api/image_classification/notest_image_classification_resnet.py b/python/paddle/fluid/tests/book/high-level-api/image_classification/test_image_classification_resnet.py similarity index 77% rename from python/paddle/fluid/tests/book/high-level-api/image_classification/notest_image_classification_resnet.py rename to python/paddle/fluid/tests/book/high-level-api/image_classification/test_image_classification_resnet.py index 17db38797cf19ae387f69f66daa42fc78cfcb7d5..1160e500dbd6db784eeb81b72968386347fec59a 100644 --- a/python/paddle/fluid/tests/book/high-level-api/image_classification/notest_image_classification_resnet.py +++ b/python/paddle/fluid/tests/book/high-level-api/image_classification/test_image_classification_resnet.py @@ -17,6 +17,7 @@ from __future__ import print_function import paddle import paddle.fluid as fluid import numpy +import cifar10_small_test_set def resnet_cifar10(input, depth=32): @@ -81,46 +82,50 @@ def train_network(): cost = fluid.layers.cross_entropy(input=predict, label=label) avg_cost = fluid.layers.mean(cost) accuracy = fluid.layers.accuracy(input=predict, label=label) - return avg_cost, accuracy + return [avg_cost, accuracy] -def train(use_cuda, save_path): +def train(use_cuda, train_program, save_dirname): BATCH_SIZE = 128 EPOCH_NUM = 1 train_reader = paddle.batch( paddle.reader.shuffle( - paddle.dataset.cifar.train10(), buf_size=128 * 10), + cifar10_small_test_set.train10(batch_size=10), buf_size=128 * 10), batch_size=BATCH_SIZE) test_reader = paddle.batch( paddle.dataset.cifar.test10(), batch_size=BATCH_SIZE) def event_handler(event): - if isinstance(event, fluid.EndIteration): - if (event.batch_id % 10) == 0: - avg_cost, accuracy = trainer.test(reader=test_reader) + if isinstance(event, fluid.EndStepEvent): + avg_cost, accuracy = trainer.test( + reader=test_reader, feed_order=['pixel', 'label']) - print('BatchID {1:04}, Loss {2:2.2}, Acc {3:2.2}'.format( - event.batch_id + 1, avg_cost, accuracy)) + print('Loss {0:2.2}, Acc {1:2.2}'.format(avg_cost, accuracy)) - if accuracy > 0.01: # Low threshold for speeding up CI - trainer.params.save(save_path) - return + if accuracy > 0.01: # Low threshold for speeding up CI + if save_dirname is not None: + trainer.save_params(save_dirname) + return place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() trainer = fluid.Trainer( - train_network, + train_func=train_program, optimizer=fluid.optimizer.Adam(learning_rate=0.001), - place=place, - event_handler=event_handler) - trainer.train(train_reader, EPOCH_NUM, event_handler=event_handler) + place=place) + trainer.train( + reader=train_reader, + num_epochs=EPOCH_NUM, + event_handler=event_handler, + feed_order=['pixel', 'label']) -def infer(use_cuda, save_path): - params = fluid.Params(save_path) + +def infer(use_cuda, inference_program, save_dirname=None): place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() - inferencer = fluid.Inferencer(inference_network, params, place=place) + inferencer = fluid.Inferencer( + infer_func=inference_program, param_path=save_dirname, place=place) # The input's dimension of conv should be 4-D or 5-D. # Use normilized image pixels as input data, which should be in the range @@ -135,8 +140,14 @@ def main(use_cuda): if use_cuda and not fluid.core.is_compiled_with_cuda(): return save_path = "image_classification_resnet.inference.model" - train(use_cuda, save_path) - infer(use_cuda, save_path) + + train( + use_cuda=use_cuda, train_program=train_network, save_dirname=save_path) + + infer( + use_cuda=use_cuda, + inference_program=inference_network, + save_dirname=save_path) if __name__ == '__main__': diff --git a/python/paddle/fluid/tests/book/high-level-api/image_classification/notest_image_classification_vgg.py b/python/paddle/fluid/tests/book/high-level-api/image_classification/test_image_classification_vgg.py similarity index 72% rename from python/paddle/fluid/tests/book/high-level-api/image_classification/notest_image_classification_vgg.py rename to python/paddle/fluid/tests/book/high-level-api/image_classification/test_image_classification_vgg.py index e83afeed2f72635a40aa2ac21dc0c8611c309de4..1e3e955ba0299f2cc0fcc02d79ae6fd8ff4c1171 100644 --- a/python/paddle/fluid/tests/book/high-level-api/image_classification/notest_image_classification_vgg.py +++ b/python/paddle/fluid/tests/book/high-level-api/image_classification/test_image_classification_vgg.py @@ -17,6 +17,7 @@ from __future__ import print_function import paddle import paddle.fluid as fluid import numpy +import cifar10_small_test_set def vgg16_bn_drop(input): @@ -60,46 +61,48 @@ def train_network(): cost = fluid.layers.cross_entropy(input=predict, label=label) avg_cost = fluid.layers.mean(cost) accuracy = fluid.layers.accuracy(input=predict, label=label) - return avg_cost, accuracy + return [avg_cost, accuracy] -def train(use_cuda, save_path): +def train(use_cuda, train_program, save_dirname): BATCH_SIZE = 128 - EPOCH_NUM = 1 - train_reader = paddle.batch( paddle.reader.shuffle( - paddle.dataset.cifar.train10(), buf_size=128 * 10), + cifar10_small_test_set.train10(batch_size=10), buf_size=128 * 10), batch_size=BATCH_SIZE) test_reader = paddle.batch( paddle.dataset.cifar.test10(), batch_size=BATCH_SIZE) def event_handler(event): - if isinstance(event, fluid.EndIteration): - if (event.batch_id % 10) == 0: - avg_cost, accuracy = trainer.test(reader=test_reader) + if isinstance(event, fluid.EndStepEvent): + avg_cost, accuracy = trainer.test( + reader=test_reader, feed_order=['pixel', 'label']) - print('BatchID {1:04}, Loss {2:2.2}, Acc {3:2.2}'.format( - event.batch_id + 1, avg_cost, accuracy)) + print('Loss {0:2.2}, Acc {1:2.2}'.format(avg_cost, accuracy)) - if accuracy > 0.01: # Low threshold for speeding up CI - trainer.params.save(save_path) - return + if accuracy > 0.01: # Low threshold for speeding up CI + if save_dirname is not None: + trainer.save_params(save_dirname) + return place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() trainer = fluid.Trainer( - train_network, - optimizer=fluid.optimizer.Adam(learning_rate=0.001), + train_func=train_program, place=place, - event_handler=event_handler) - trainer.train(train_reader, EPOCH_NUM, event_handler=event_handler) + optimizer=fluid.optimizer.Adam(learning_rate=0.001)) + + trainer.train( + reader=train_reader, + num_epochs=1, + event_handler=event_handler, + feed_order=['pixel', 'label']) -def infer(use_cuda, save_path): - params = fluid.Params(save_path) +def infer(use_cuda, inference_program, save_dirname=None): place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() - inferencer = fluid.Inferencer(inference_network, params, place=place) + inferencer = fluid.Inferencer( + infer_func=inference_program, param_path=save_dirname, place=place) # The input's dimension of conv should be 4-D or 5-D. # Use normilized image pixels as input data, which should be in the range @@ -114,8 +117,14 @@ def main(use_cuda): if use_cuda and not fluid.core.is_compiled_with_cuda(): return save_path = "image_classification_vgg.inference.model" - train(use_cuda, save_path) - infer(use_cuda, save_path) + + train( + use_cuda=use_cuda, train_program=train_network, save_dirname=save_path) + + infer( + use_cuda=use_cuda, + inference_program=inference_network, + save_dirname=save_path) if __name__ == '__main__': diff --git a/python/paddle/fluid/tests/book/high-level-api/recognize_digits/test_recognize_digits_conv.py b/python/paddle/fluid/tests/book/high-level-api/recognize_digits/test_recognize_digits_conv.py index 420e6e6e42adc22508c414f2c2d1ba93aedd4753..2128d4c5b87434ebe30930dc0e338b3b50d921c2 100644 --- a/python/paddle/fluid/tests/book/high-level-api/recognize_digits/test_recognize_digits_conv.py +++ b/python/paddle/fluid/tests/book/high-level-api/recognize_digits/test_recognize_digits_conv.py @@ -62,31 +62,31 @@ def train(use_cuda, train_program, save_dirname): optimizer = fluid.optimizer.Adam(learning_rate=0.001) trainer = fluid.Trainer( - train_func=train_program, place=place, optimizer=optimizer) + train_func=train_program, + place=place, + optimizer=optimizer, + parallel=True) def event_handler(event): if isinstance(event, fluid.EndEpochEvent): test_reader = paddle.batch( paddle.dataset.mnist.test(), batch_size=BATCH_SIZE) - test_metrics = trainer.test( + avg_cost, acc = trainer.test( reader=test_reader, feed_order=['img', 'label']) - avg_cost_set = test_metrics[0] - acc_set = test_metrics[1] - - # get test acc and loss - acc = numpy.array(acc_set).mean() - avg_cost = numpy.array(avg_cost_set).mean() print("avg_cost: %s" % avg_cost) print("acc : %s" % acc) - if float(acc) > 0.2: # Smaller value to increase CI speed + if acc > 0.2: # Smaller value to increase CI speed trainer.save_params(save_dirname) else: print('BatchID {0}, Test Loss {1:0.2}, Acc {2:0.2}'.format( - event.epoch + 1, float(avg_cost), float(acc))) - if math.isnan(float(avg_cost)): + event.epoch + 1, avg_cost, acc)) + if math.isnan(avg_cost): sys.exit("got NaN loss, training failed.") + elif isinstance(event, fluid.EndStepEvent): + print("Step {0}, Epoch {1} Metrics {2}".format( + event.step, event.epoch, map(numpy.array, event.metrics))) train_reader = paddle.batch( paddle.reader.shuffle( @@ -112,7 +112,7 @@ def infer(use_cuda, inference_program, save_dirname=None): results = inferencer.infer({'img': tensor_img}) - print("infer results: ", results[0]) + print("infer results: ", numpy.array(results[0])) def main(use_cuda): @@ -131,4 +131,4 @@ def main(use_cuda): if __name__ == '__main__': # for use_cuda in (False, True): - main(use_cuda=False) + main(use_cuda=True) diff --git a/python/paddle/fluid/tests/book/high-level-api/recognize_digits/test_recognize_digits_mlp.py b/python/paddle/fluid/tests/book/high-level-api/recognize_digits/test_recognize_digits_mlp.py index 9427a772f54fb58ca1f50ed792cccf5d8f9b3d84..041c8d778e5c03aa68dad6ef450934f09c8d2a52 100644 --- a/python/paddle/fluid/tests/book/high-level-api/recognize_digits/test_recognize_digits_mlp.py +++ b/python/paddle/fluid/tests/book/high-level-api/recognize_digits/test_recognize_digits_mlp.py @@ -55,24 +55,18 @@ def train(use_cuda, train_program, save_dirname): if isinstance(event, fluid.EndEpochEvent): test_reader = paddle.batch( paddle.dataset.mnist.test(), batch_size=BATCH_SIZE) - test_metrics = trainer.test( + avg_cost, acc = trainer.test( reader=test_reader, feed_order=['img', 'label']) - avg_cost_set = test_metrics[0] - acc_set = test_metrics[1] - - # get test acc and loss - acc = numpy.array(acc_set).mean() - avg_cost = numpy.array(avg_cost_set).mean() print("avg_cost: %s" % avg_cost) print("acc : %s" % acc) - if float(acc) > 0.2: # Smaller value to increase CI speed + if acc > 0.2: # Smaller value to increase CI speed trainer.save_params(save_dirname) else: print('BatchID {0}, Test Loss {1:0.2}, Acc {2:0.2}'.format( - event.epoch + 1, float(avg_cost), float(acc))) - if math.isnan(float(avg_cost)): + event.epoch + 1, avg_cost, acc)) + if math.isnan(avg_cost): sys.exit("got NaN loss, training failed.") train_reader = paddle.batch( @@ -99,7 +93,7 @@ def infer(use_cuda, inference_program, save_dirname=None): results = inferencer.infer({'img': tensor_img}) - print("infer results: ", results[0]) + print("infer results: ", numpy.array(results[0])) def main(use_cuda): diff --git a/python/paddle/fluid/tests/book/high-level-api/understand_sentiment/CMakeLists.txt b/python/paddle/fluid/tests/book/high-level-api/understand_sentiment/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..673c965b662a022739f8d489c331f4de9455a926 --- /dev/null +++ b/python/paddle/fluid/tests/book/high-level-api/understand_sentiment/CMakeLists.txt @@ -0,0 +1,7 @@ +file(GLOB TEST_OPS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "test_*.py") +string(REPLACE ".py" "" TEST_OPS "${TEST_OPS}") + +# default test +foreach(src ${TEST_OPS}) + py_test(${src} SRCS ${src}.py) +endforeach() diff --git a/python/paddle/fluid/tests/book/high-level-api/understand_sentiment/notest_understand_sentiment_stacked_lstm.py b/python/paddle/fluid/tests/book/high-level-api/understand_sentiment/test_understand_sentiment_stacked_lstm.py similarity index 63% rename from python/paddle/fluid/tests/book/high-level-api/understand_sentiment/notest_understand_sentiment_stacked_lstm.py rename to python/paddle/fluid/tests/book/high-level-api/understand_sentiment/test_understand_sentiment_stacked_lstm.py index 9948e5c0234ed78237c94f9a25d6401619267d0d..0d7cbe3874cbc0c2def9d0032737f81e662296d6 100644 --- a/python/paddle/fluid/tests/book/high-level-api/understand_sentiment/notest_understand_sentiment_stacked_lstm.py +++ b/python/paddle/fluid/tests/book/high-level-api/understand_sentiment/test_understand_sentiment_stacked_lstm.py @@ -17,11 +17,13 @@ from __future__ import print_function import paddle import paddle.fluid as fluid from functools import partial +import numpy as np CLASS_DIM = 2 EMB_DIM = 128 HID_DIM = 512 STACKED_NUM = 3 +BATCH_SIZE = 128 def stacked_lstm_net(data, input_dim, class_dim, emb_dim, hid_dim, stacked_num): @@ -50,7 +52,7 @@ def stacked_lstm_net(data, input_dim, class_dim, emb_dim, hid_dim, stacked_num): return prediction -def inference_network(word_dict): +def inference_program(word_dict): data = fluid.layers.data( name="words", shape=[1], dtype="int64", lod_level=1) @@ -60,57 +62,71 @@ def inference_network(word_dict): return net -def train_network(word_dict): - prediction = inference_network(word_dict) +def train_program(word_dict): + prediction = inference_program(word_dict) label = fluid.layers.data(name="label", shape=[1], dtype="int64") cost = fluid.layers.cross_entropy(input=prediction, label=label) avg_cost = fluid.layers.mean(cost) accuracy = fluid.layers.accuracy(input=prediction, label=label) - return avg_cost, accuracy + return [avg_cost, accuracy] -def train(use_cuda, save_path): - BATCH_SIZE = 128 - EPOCH_NUM = 5 +def train(use_cuda, train_program, save_dirname): + place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() + optimizer = fluid.optimizer.Adagrad(learning_rate=0.002) word_dict = paddle.dataset.imdb.word_dict() + trainer = fluid.Trainer( + train_func=partial(train_program, word_dict), + place=place, + optimizer=optimizer) - train_data = paddle.batch( + def event_handler(event): + if isinstance(event, fluid.EndEpochEvent): + test_reader = paddle.batch( + paddle.dataset.imdb.test(word_dict), batch_size=BATCH_SIZE) + avg_cost, acc = trainer.test( + reader=test_reader, feed_order=['words', 'label']) + + print("avg_cost: %s" % avg_cost) + print("acc : %s" % acc) + + if acc > 0.2: # Smaller value to increase CI speed + trainer.save_params(save_dirname) + trainer.stop() + + else: + print('BatchID {0}, Test Loss {1:0.2}, Acc {2:0.2}'.format( + event.epoch + 1, avg_cost, acc)) + if math.isnan(avg_cost): + sys.exit("got NaN loss, training failed.") + elif isinstance(event, fluid.EndStepEvent): + print("Step {0}, Epoch {1} Metrics {2}".format( + event.step, event.epoch, map(np.array, event.metrics))) + if event.step == 1: # Run 2 iterations to speed CI + trainer.save_params(save_dirname) + trainer.stop() + + train_reader = paddle.batch( paddle.reader.shuffle( - paddle.dataset.imdb.train(word_dict), buf_size=1000), + paddle.dataset.imdb.train(word_dict), buf_size=25000), batch_size=BATCH_SIZE) - test_data = paddle.batch( - paddle.dataset.imdb.test(word_dict), batch_size=BATCH_SIZE) - - def event_handler(event): - if isinstance(event, fluid.EndIteration): - if (event.batch_id % 10) == 0: - avg_cost, accuracy = trainer.test(reader=test_data) - - print('BatchID {1:04}, Loss {2:2.2}, Acc {3:2.2}'.format( - event.batch_id + 1, avg_cost, accuracy)) + trainer.train( + num_epochs=1, + event_handler=event_handler, + reader=train_reader, + feed_order=['words', 'label']) - if accuracy > 0.01: # Low threshold for speeding up CI - trainer.params.save(save_path) - return - place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() - trainer = fluid.Trainer( - partial(train_network, word_dict), - optimizer=fluid.optimizer.Adagrad(learning_rate=0.002), - place=place, - event_handler=event_handler) - - trainer.train(train_data, EPOCH_NUM, event_handler=event_handler) - - -def infer(use_cuda, save_path): - params = fluid.Params(save_path) +def infer(use_cuda, inference_program, save_dirname=None): place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() word_dict = paddle.dataset.imdb.word_dict() + inferencer = fluid.Inferencer( - partial(inference_network, word_dict), params, place=place) + infer_func=partial(inference_program, word_dict), + param_path=save_dirname, + place=place) def create_random_lodtensor(lod, place, low, high): data = np.random.random_integers(low, high, @@ -131,8 +147,8 @@ def main(use_cuda): if use_cuda and not fluid.core.is_compiled_with_cuda(): return save_path = "understand_sentiment_stacked_lstm.inference.model" - train(use_cuda, save_path) - infer(use_cuda, save_path) + train(use_cuda, train_program, save_path) + infer(use_cuda, inference_program, save_path) if __name__ == '__main__': diff --git a/python/paddle/fluid/tests/book/high-level-api/word2vec/no_test_word2vec_new_api.py b/python/paddle/fluid/tests/book/high-level-api/word2vec/test_word2vec_new_api.py similarity index 80% rename from python/paddle/fluid/tests/book/high-level-api/word2vec/no_test_word2vec_new_api.py rename to python/paddle/fluid/tests/book/high-level-api/word2vec/test_word2vec_new_api.py index 4f861e5aaeca7ce0f73450c09f9ddc1ed7417469..bf86cd9acf8da940fcc2fb5b594e33f9b6965acb 100644 --- a/python/paddle/fluid/tests/book/high-level-api/word2vec/no_test_word2vec_new_api.py +++ b/python/paddle/fluid/tests/book/high-level-api/word2vec/test_word2vec_new_api.py @@ -90,7 +90,7 @@ def train_program(is_sparse): return avg_cost -def train(use_cuda, train_program, save_path): +def train(use_cuda, train_program, save_dirname): train_reader = paddle.batch( paddle.dataset.imikolov.train(word_dict, N), BATCH_SIZE) test_reader = paddle.batch( @@ -99,27 +99,36 @@ def train(use_cuda, train_program, save_path): place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() def event_handler(event): - if isinstance(event, fluid.EndEpochEvent): - outs = trainer.test(reader=test_reader) + if isinstance(event, fluid.EndStepEvent): + outs = trainer.test( + reader=test_reader, + feed_order=['firstw', 'secondw', 'thirdw', 'forthw', 'nextw']) avg_cost = outs[0] print("loss= ", avg_cost) - if avg_cost < 5.0: - trainer.save_params(save_path) - return + if avg_cost < 10.0: + trainer.save_params(save_dirname) + trainer.stop() + if math.isnan(avg_cost): sys.exit("got NaN loss, training failed.") trainer = fluid.Trainer( - train_program, fluid.optimizer.SGD(learning_rate=0.001), place=place) + train_func=train_program, + optimizer=fluid.optimizer.SGD(learning_rate=0.001), + place=place) + trainer.train( - reader=train_reader, num_epochs=1, event_handler=event_handler) + reader=train_reader, + num_epochs=1, + event_handler=event_handler, + feed_order=['firstw', 'secondw', 'thirdw', 'forthw', 'nextw']) -def infer(use_cuda, inference_program, save_path): +def infer(use_cuda, inference_program, save_dirname=None): place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() inferencer = fluid.Inferencer( - infer_func=inference_program, param_path=save_path, place=place) + infer_func=inference_program, param_path=save_dirname, place=place) lod = [0, 1] first_word = create_random_lodtensor(lod, place, low=0, high=dict_size - 1) @@ -142,9 +151,17 @@ def main(use_cuda, is_sparse): if use_cuda and not fluid.core.is_compiled_with_cuda(): return - save_path = "word2vec.params" - train(use_cuda, partial(train_program, is_sparse), save_path) - infer(use_cuda, partial(inference_program, is_sparse), save_path) + save_path = "word2vec.inference.model" + + train( + use_cuda=use_cuda, + train_program=partial(train_program, is_sparse), + save_dirname=save_path) + + infer( + use_cuda=use_cuda, + inference_program=partial(inference_program, is_sparse), + save_dirname=save_path) if __name__ == '__main__': diff --git a/python/paddle/fluid/tests/book/test_label_semantic_roles.py b/python/paddle/fluid/tests/book/test_label_semantic_roles.py index 09793760e5504c04ad4b0bfac5c5d7b7047cf85d..f1ee5dfd99e1c8b26280c010c1aaca05a004a5b6 100644 --- a/python/paddle/fluid/tests/book/test_label_semantic_roles.py +++ b/python/paddle/fluid/tests/book/test_label_semantic_roles.py @@ -182,12 +182,6 @@ def train(use_cuda, save_dirname=None, is_local=True): crf_decode = fluid.layers.crf_decoding( input=feature_out, param_attr=fluid.ParamAttr(name='crfw')) - chunk_evaluator = fluid.evaluator.ChunkEvaluator( - input=crf_decode, - label=target, - chunk_scheme="IOB", - num_chunk_types=int(math.ceil((label_dict_len - 1) / 2.0))) - train_data = paddle.batch( paddle.reader.shuffle( paddle.dataset.conll05.test(), buf_size=8192), @@ -203,7 +197,6 @@ def train(use_cuda, save_dirname=None, is_local=True): def train_loop(main_program): exe.run(fluid.default_startup_program()) - embedding_param = fluid.global_scope().find_var( embedding_name).get_tensor() embedding_param.set( @@ -213,27 +206,19 @@ def train(use_cuda, save_dirname=None, is_local=True): start_time = time.time() batch_id = 0 for pass_id in xrange(PASS_NUM): - chunk_evaluator.reset(exe) for data in train_data(): - cost, precision, recall, f1_score = exe.run( - main_program, - feed=feeder.feed(data), - fetch_list=[avg_cost] + chunk_evaluator.metrics) - pass_precision, pass_recall, pass_f1_score = chunk_evaluator.eval( - exe) + cost = exe.run(main_program, + feed=feeder.feed(data), + fetch_list=[avg_cost]) + cost = cost[0] if batch_id % 10 == 0: - print("avg_cost:" + str(cost) + " precision:" + str( - precision) + " recall:" + str(recall) + " f1_score:" + - str(f1_score) + " pass_precision:" + str( - pass_precision) + " pass_recall:" + str( - pass_recall) + " pass_f1_score:" + str( - pass_f1_score)) + print("avg_cost:" + str(cost)) if batch_id != 0: print("second per batch: " + str((time.time( ) - start_time) / batch_id)) # Set the threshold low to speed up the CI test - if float(pass_precision) > 0.01: + if float(cost) < 60.0: if save_dirname is not None: # TODO(liuyiqun): Change the target to crf_decode fluid.io.save_inference_model(save_dirname, [ diff --git a/python/paddle/fluid/tests/test_data_feeder.py b/python/paddle/fluid/tests/test_data_feeder.py index 861dd3174a21d59fe12e0b794ecb2a934946ac71..ce3ba3ebc50d7b015f379b5e80b179463a7b231a 100644 --- a/python/paddle/fluid/tests/test_data_feeder.py +++ b/python/paddle/fluid/tests/test_data_feeder.py @@ -13,15 +13,62 @@ # limitations under the License. import paddle.fluid as fluid +import unittest -def test_converter(): - img = fluid.layers.data(name='image', shape=[1, 28, 28]) - label = fluid.layers.data(name='label', shape=[1], dtype='int64') - feeder = fluid.DataFeeder([img, label], fluid.CPUPlace()) - result = feeder.feed([[[0] * 784, [9]], [[1] * 784, [1]]]) - print(result) +class TestDataFeeder(unittest.TestCase): + def test_lod_level_0_converter(self): + img = fluid.layers.data(name='image', shape=[1, 28, 28]) + label = fluid.layers.data(name='label', shape=[1], dtype='int64') + feeder = fluid.DataFeeder([img, label], fluid.CPUPlace()) + result = feeder.feed([([0] * 784, [9]), ([1] * 784, [1])]) + print(result) + + self.assertEqual(result['image'].shape(), [2, 1, 28, 28]) + self.assertEqual(result['label'].shape(), [2, 1]) + self.assertEqual(result['image'].lod(), []) + self.assertEqual(result['label'].lod(), []) + + def test_lod_level_1_converter(self): + # lod_level = 1 + # each sentence has a different number of words + sentences = fluid.layers.data( + name='sentences', shape=[1], dtype='int64', lod_level=1) + label = fluid.layers.data(name='label', shape=[1], dtype='int64') + feeder = fluid.DataFeeder([sentences, label], fluid.CPUPlace()) + + # lod = [[0, 3, 5, 9]] + # data = [[1, 2, 3], [4, 5], [6, 7, 8, 9]] + # label = [1] * len(data) + result = feeder.feed( + [([1, 2, 3], [1]), ([4, 5], [1]), ([6, 7, 8, 9], [1])]) + print(result) + + self.assertEqual(result['sentences'].shape(), [9, 1]) + self.assertEqual(result['label'].shape(), [3, 1]) + self.assertEqual(result['sentences'].lod(), [[0, 3, 5, 9]]) + self.assertEqual(result['label'].lod(), []) + + def test_lod_level_2_converter(self): + # lod_level = 2 + # paragraphs -> sentences -> words + paragraphs = fluid.layers.data( + name='paragraphs', shape=[1], dtype='int64', lod_level=2) + label = fluid.layers.data(name='label', shape=[1], dtype='int64') + feeder = fluid.DataFeeder([paragraphs, label], fluid.CPUPlace()) + + # lod = [[0, 2, 3], [0, 3, 5, 9]] + # data = [[[1, 2, 3], [4, 5]], [[6, 7, 8, 9]]] + # label = [1] * len(data) + result = feeder.feed( + [([[1, 2, 3], [4, 5]], [1]), ([[6, 7, 8, 9]], [1])]) + print(result) + + self.assertEqual(result['paragraphs'].shape(), [9, 1]) + self.assertEqual(result['label'].shape(), [2, 1]) + self.assertEqual(result['paragraphs'].lod(), [[0, 2, 3], [0, 3, 5, 9]]) + self.assertEqual(result['label'].lod(), []) if __name__ == '__main__': - test_converter() + unittest.main() diff --git a/python/paddle/fluid/tests/test_detection.py b/python/paddle/fluid/tests/test_detection.py index 921260ef3f4b1f9e4c65b3ffb440dc34cb0a9376..8569d838bdd414eb84c6c87674990a25a2fdcdf9 100644 --- a/python/paddle/fluid/tests/test_detection.py +++ b/python/paddle/fluid/tests/test_detection.py @@ -109,6 +109,24 @@ class TestDetection(unittest.TestCase): print(str(program)) +class TestPriorBox(unittest.TestCase): + def test_prior_box(self): + data_shape = [3, 224, 224] + images = fluid.layers.data( + name='pixel', shape=data_shape, dtype='float32') + conv1 = fluid.layers.conv2d(images, 3, 3, 2) + box, var = layers.prior_box( + input=conv1, + image=images, + min_sizes=[100.0], + aspect_ratios=[1.], + flip=True, + clip=True) + assert len(box.shape) == 4 + assert box.shape == var.shape + assert box.shape[3] == 4 + + class TestMultiBoxHead(unittest.TestCase): def test_multi_box_head(self): data_shape = [3, 224, 224] diff --git a/python/paddle/fluid/tests/unittests/CMakeLists.txt b/python/paddle/fluid/tests/unittests/CMakeLists.txt index d9190408e151283ece8460286dd67818dd39da3e..2ae9653953c2f5f6a399243bef2c7fb756f9692f 100644 --- a/python/paddle/fluid/tests/unittests/CMakeLists.txt +++ b/python/paddle/fluid/tests/unittests/CMakeLists.txt @@ -28,11 +28,11 @@ function(py_test_modules TARGET_NAME) if(WITH_TESTING) set(options "") set(oneValueArgs "") - set(multiValueArgs MODULES DEPS ARGS ENVS) + set(multiValueArgs MODULES DEPS ENVS) cmake_parse_arguments(py_test_modules "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) add_test(NAME ${TARGET_NAME} COMMAND env PYTHONPATH=${PADDLE_BINARY_DIR}/python ${py_test_modules_ENVS} - ${PYTHON_EXECUTABLE} -u -m unittest --verbose ${py_test_modules_MODULES} ${py_test_modules_ARGS} + ${PYTHON_EXECUTABLE} ${PADDLE_SOURCE_DIR}/tools/test_runner.py ${py_test_modules_MODULES} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endif() endfunction() @@ -66,6 +66,7 @@ list(REMOVE_ITEM TEST_OPS test_fetch_var) list(REMOVE_ITEM TEST_OPS test_parallel_op) list(REMOVE_ITEM TEST_OPS test_dynrnn_static_input) list(REMOVE_ITEM TEST_OPS test_dist_train) +list(REMOVE_ITEM TEST_OPS test_network_with_dtype) # tests that can be bundled together in one python process for speed. if(WITH_FAST_BUNDLE_TEST) @@ -83,6 +84,7 @@ py_test_modules(test_parallel_executor MODULES test_parallel_executor) py_test_modules(test_warpctc_op MODULES test_warpctc_op ENVS FLAGS_warpctc_dir=${WARPCTC_LIB_DIR}) py_test_modules(test_train_dyn_rnn MODULES test_dyn_rnn) py_test_modules(test_mul_op MODULES test_mul_op) +py_test_modules(test_network_with_dtype MODULES test_network_with_dtype) # tests that need to be run in separate process. py_test_modules(test_multihead_attention MODULES test_multihead_attention) diff --git a/python/paddle/fluid/tests/unittests/test_detection_map_op.py b/python/paddle/fluid/tests/unittests/test_detection_map_op.py index a905a854ad157ffa3d7816dfbd445f3e344a1249..f545ad155ccd28c2d34e424d307eed49b37f20fb 100644 --- a/python/paddle/fluid/tests/unittests/test_detection_map_op.py +++ b/python/paddle/fluid/tests/unittests/test_detection_map_op.py @@ -160,7 +160,9 @@ class TestDetectionMAPOp(OpTest): label_count, true_pos, false_pos = get_input_pos( self.class_pos_count, self.true_pos, self.true_pos_lod, self.false_pos, self.false_pos_lod) - for (label, difficult, xmin, ymin, xmax, ymax) in self.label: + for v in self.label: + label = v[0] + difficult = False if len(v) == 5 else v[1] if self.evaluate_difficult: label_count[label] += 1 elif not difficult: @@ -245,6 +247,15 @@ class TestDetectionMAPOpSkipDiff(TestDetectionMAPOp): [2, 0.8, 0, 1], [2, 0.1, 1, 0], [3, 0.2, 0, 1]] +class TestDetectionMAPOpWithoutDiff(TestDetectionMAPOp): + def init_test_case(self): + super(TestDetectionMAPOpWithoutDiff, self).init_test_case() + + # label xmin ymin xmax ymax + self.label = [[1, 0.1, 0.1, 0.3, 0.3], [1, 0.6, 0.6, 0.8, 0.8], + [2, 0.3, 0.3, 0.6, 0.5], [1, 0.7, 0.1, 0.9, 0.3]] + + class TestDetectionMAPOp11Point(TestDetectionMAPOp): def init_test_case(self): super(TestDetectionMAPOp11Point, self).init_test_case() diff --git a/python/paddle/fluid/tests/unittests/test_dist_train.py b/python/paddle/fluid/tests/unittests/test_dist_train.py index 77e9a8f7e72a9e0790ce1d1f48356abcca8eaccf..c2393a288c6ebb5dd4a12f7b591d12cc94f4ea55 100644 --- a/python/paddle/fluid/tests/unittests/test_dist_train.py +++ b/python/paddle/fluid/tests/unittests/test_dist_train.py @@ -52,15 +52,18 @@ class TestSendOp(unittest.TestCase): serv = layers.ListenAndServ( "127.0.0.1:0", ["X"], optimizer_mode=False) with serv.do(): + out_var = main.global_block().create_var( + name="scale_0.tmp_0", + psersistable=True, + dtype="float32", + shape=[32, 32]) x = layers.data( shape=[32, 32], dtype='float32', name="X", append_batch_size=False) fluid.initializer.Constant(value=1.0)(x, main.global_block()) - o = layers.scale(x=x, scale=10.0) - main.global_block().create_var( - name=o.name, psersistable=False, dtype=o.dtype, shape=o.shape) + layers.scale(x=x, scale=10.0, out=out_var) self.server_exe = fluid.Executor(place) self.server_exe.run(main) diff --git a/python/paddle/fluid/tests/unittests/test_is_empty_op.py b/python/paddle/fluid/tests/unittests/test_is_empty_op.py index 4d11cf226be2ba4ffbe015198fed3191f1e02f72..11121d9b65351eab639b7618fac0e54714cf4680 100644 --- a/python/paddle/fluid/tests/unittests/test_is_empty_op.py +++ b/python/paddle/fluid/tests/unittests/test_is_empty_op.py @@ -14,42 +14,24 @@ import unittest import numpy as np -from paddle.fluid.op import Operator -import paddle.fluid.core as core +from op_test import OpTest -def create_tensor(scope, name, np_data): - tensor = scope.var(name).get_tensor() - tensor.set_dims(np_data.shape) - tensor.set(np_data, core.CPUPlace()) - return tensor - - -class TestIsEmptyOp(unittest.TestCase): +class TestEmpty(OpTest): def setUp(self): - self.scope = core.Scope() - # create input variables - np_data0 = np.array([0, 1, 2]) - create_tensor(self.scope, "X0", np_data0) - - np_data1 = np.array([1]) - t = create_tensor(self.scope, "X1", np_data1) - t.set_dims([0]) + self.op_type = "is_empty" + self.inputs = {'X': np.array([1, 2, 3])} + self.outputs = {'Out': np.array([False])} - # create output variables - self.scope.var("out") + def test_check_output(self): + self.check_output() - def test_no_empty(self): - self.one_case("X0", False) - def test_empty(self): - self.one_case("X1", True) - - def one_case(self, input, target): - op = Operator(type="is_empty", X=input, Out="out") - op.run(self.scope, core.CPUPlace()) - out = self.scope.var("out").get_tensor() - self.assertEqual(np.array(out)[0], target) +class TestNotEmpty(TestEmpty): + def setUp(self): + self.op_type = "is_empty" + self.inputs = {'X': np.array([])} + self.outputs = {'Out': np.array([True])} if __name__ == "__main__": diff --git a/python/paddle/fluid/tests/unittests/test_network_with_dtype.py b/python/paddle/fluid/tests/unittests/test_network_with_dtype.py index fe8aceb3ae42f73590bffe2a372c771654a372a9..d4835dd18405fc7a0d508a780a734922e0abd12c 100644 --- a/python/paddle/fluid/tests/unittests/test_network_with_dtype.py +++ b/python/paddle/fluid/tests/unittests/test_network_with_dtype.py @@ -24,33 +24,30 @@ BATCH_SIZE = 20 class TestNetWithDtype(unittest.TestCase): - def set_network(self): + def setUp(self): self.dtype = "float64" self.init_dtype() - main = fluid.Program() - with fluid.program_guard(main): - self.x = fluid.layers.data(name='x', shape=[13], dtype=self.dtype) - self.y = fluid.layers.data(name='y', shape=[1], dtype=self.dtype) - y_predict = fluid.layers.fc(input=self.x, size=1, act=None) - cost = fluid.layers.square_error_cost(input=y_predict, label=self.y) + def run_net_on_place(self, place): + main = fluid.Program() + startup = fluid.Program() + with fluid.program_guard(main, startup): + x = fluid.layers.data(name='x', shape=[13], dtype=self.dtype) + y = fluid.layers.data(name='y', shape=[1], dtype=self.dtype) + y_predict = fluid.layers.fc(input=x, size=1, act=None) + cost = fluid.layers.square_error_cost(input=y_predict, label=y) avg_cost = fluid.layers.mean(cost) - self.program = main - self.fetch_list = [avg_cost] + sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.001) + sgd_optimizer.minimize(avg_cost) - sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.001) - sgd_optimizer.minimize(avg_cost) - - def run_net_on_place(self, place): + fetch_list = [avg_cost] train_reader = paddle.batch( paddle.dataset.uci_housing.train(), batch_size=BATCH_SIZE) - feeder = fluid.DataFeeder(place=place, feed_list=[self.x, self.y]) + feeder = fluid.DataFeeder(place=place, feed_list=[x, y]) exe = fluid.Executor(place) - exe.run(fluid.default_startup_program()) + exe.run(startup) for data in train_reader(): - exe.run(self.program, - feed=feeder.feed(data), - fetch_list=self.fetch_list) + exe.run(main, feed=feeder.feed(data), fetch_list=fetch_list) # the main program is runable, the datatype is fully supported break @@ -58,14 +55,12 @@ class TestNetWithDtype(unittest.TestCase): pass def test_cpu(self): - self.set_network() place = fluid.CPUPlace() self.run_net_on_place(place) def test_gpu(self): if not core.is_compiled_with_cuda(): return - self.set_network() place = fluid.CUDAPlace(0) self.run_net_on_place(place) diff --git a/python/paddle/fluid/tests/unittests/test_parallel_executor.py b/python/paddle/fluid/tests/unittests/test_parallel_executor.py index 6dc016487fd81a9292f94042a20b7356bc50abe1..056f9e1781997aa1586d972874b652d5b725fe3f 100644 --- a/python/paddle/fluid/tests/unittests/test_parallel_executor.py +++ b/python/paddle/fluid/tests/unittests/test_parallel_executor.py @@ -775,7 +775,7 @@ class TestCRFModel(unittest.TestCase): build_strategy = fluid.BuildStrategy() build_strategy.reduce_strategy = fluid.BuildStrategy.ReduceStrategy.Reduce self.check_network_convergence( - is_sparse=False, build_strategy=build_strategy) + is_sparse=True, build_strategy=build_strategy) def test_update_dense_parameter_reduce(self): build_strategy = fluid.BuildStrategy() @@ -849,8 +849,7 @@ class TestFetchOp(unittest.TestCase): assert not math.isnan(np.sum(ret[i])) and \ not math.isinf(np.sum(ret[i])) - @unittest.skip("this test is buggy") - def test_feed(self): + def test_fetch_op(self): tst_reader = paddle.batch(flowers.test(use_xmap=False), batch_size=16) tst_reader_iter = tst_reader() diff --git a/python/paddle/fluid/trainer.py b/python/paddle/fluid/trainer.py index c24662ac2114c286b1c50286fea1b65cf7c1b3a8..7da123dd92ed9d111d68cd70efb8ce1493452609 100644 --- a/python/paddle/fluid/trainer.py +++ b/python/paddle/fluid/trainer.py @@ -12,17 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +import contextlib import os + import core -import framework -import executor + import data_feeder -import contextlib +import executor +import framework import io -import unique_name - # optimizer is same as the parameter of Trainer.__init__. Rename it to opt_module import optimizer as opt_module +import parallel_executor from transpiler import distribute_transpiler __all__ = [ @@ -48,12 +49,14 @@ class BeginStepEvent(object): def __init__(self, epoch_id, step_id): self.epoch = epoch_id self.step = step_id + self.fetch_metrics = True class EndStepEvent(object): - def __init__(self, epoch_id, step_id): + def __init__(self, epoch_id, step_id, metrics): self.epoch = epoch_id self.step = step_id + self.metrics = metrics def check_and_get_place(place): @@ -87,12 +90,18 @@ class Trainer(object): Args: train_func(callable): A function which will return loss. The loss must be a scalar. - infer_func(callable): A function which will return predict, used to save inference model optimizer(optimizer.Optimizer): The optimizer should be an instance of Optimizer place: The device place of this trainer. """ - def __init__(self, train_func, optimizer, param_path=None, place=None): + def __init__(self, + train_func, + optimizer, + param_path=None, + place=None, + parallel=False): + self.__stop = False + self.parallel = parallel # 1. we need to generate a framework.Program by calling # program_func. Reference: fluid.program_guard in # test_word2vec.py @@ -106,14 +115,14 @@ class Trainer(object): with framework.program_guard(self.train_program, self.startup_program): program_func_outs = train_func() - self.test_outputs = program_func_outs if isinstance( + self.train_func_outputs = program_func_outs if isinstance( program_func_outs, list) else [program_func_outs] self.test_program = self.train_program.clone() if not isinstance(optimizer, opt_module.Optimizer): raise TypeError( "The optimizer should be an instance of Optimizer") # The fisrt element of program_func_outs is loss. - loss = self.test_outputs[0] + loss = self.train_func_outputs[0] optimize_ops, params_grads = optimizer.minimize(loss) self.place = check_and_get_place(place) @@ -131,7 +140,40 @@ class Trainer(object): # load params from param_path into scope io.load_persistables(exe, dirname=param_path) + def _transpile_nccl2_dist(self): + # PADDLE_TRAINER_IPS + if "PADDLE_TRAINER_IPS" not in os.environ: + self.nccl_id_var = None + else: + self.trainer_id = int(os.getenv("PADDLE_TRAINER_ID")) + port = os.getenv("PADDLE_PSERVER_PORT") + worker_ips = os.getenv("PADDLE_TRAINER_IPS") + worker_endpoints = [] + for ip in worker_ips.split(","): + worker_endpoints.append(':'.join([ip, port])) + self.num_trainers = len(worker_endpoints) + current_endpoint = os.getenv("POD_IP") + ":" + port + worker_endpoints.remove(current_endpoint) + # TODO(wuyi): use self.nccl_id_var, self.num_trainers and self.trainer_id + # in ParallelExecutor to start + # distributed training using NCCL2 + self.nccl_id_var = self.startup_program.global_block().create_var( + name="NCCLID", persistable=True, type=core.VarDesc.VarType.RAW) + self.startup_program.global_block().append_op( + type="gen_nccl_id", + inputs={}, + outputs={"NCCLID": self.nccl_id_var}, + attrs={ + "endpoint": current_endpoint, + "endpoint_list": worker_endpoints, + "trainer_id": self.trainer_id + }) + def _dist_transpile_if_necessary(self, optimize_ops, params_grads): + self._transpile_nccl2_dist() + if self.nccl_id_var != None: + return + if "PADDLE_TRAINING_ROLE" not in os.environ: return @@ -169,12 +211,13 @@ class Trainer(object): 'TRAINING_ROLE environment variable must be either TRAINER or PSERVER' ) - def train(self, - num_epochs, - event_handler, - reader, - feed_order, - parallel=False): + def stop(self): + """ + stop training + """ + self.__stop = True + + def train(self, num_epochs, event_handler, reader=None, feed_order=None): """ Train the model. @@ -182,25 +225,24 @@ class Trainer(object): num_epochs: The number of epoch. An epoch will process all data in reader event_handler: The event handler. A function with type (ev:Event)->void reader: - parallel: True if use multi-CPUs or multi-GPUs feed_order: Feeding order of reader. None will following the defining order in program Returns: """ - if parallel: - raise NotImplementedError( - "Parallel Executor version of trainer is not implemented") - training_role = os.getenv("PADDLE_TRAINING_ROLE", "") if training_role == "PSERVER": with self._prog_and_scope_guard(): exe = executor.Executor(self.place) exe.run() return - - self._train_by_executor(num_epochs, event_handler, reader, feed_order) + if self.parallel: + self._train_by_parallel_executor(num_epochs, event_handler, reader, + feed_order) + else: + self._train_by_executor(num_epochs, event_handler, reader, + feed_order) def test(self, reader, feed_order): """ @@ -212,7 +254,8 @@ class Trainer(object): order in program """ - return self._test_by_executor(reader, feed_order, self.test_outputs) + return self._test_by_executor(reader, feed_order, + self.train_func_outputs) def save_params(self, param_path): # reference: save_persistables in io.py @@ -246,13 +289,27 @@ class Trainer(object): feeder = data_feeder.DataFeeder( feed_list=feed_var_list, place=self.place) exe = executor.Executor(self.place) - for epoch_id in range(num_epochs): - event_handler(BeginEpochEvent(epoch_id)) - for step_id, data in enumerate(reader()): - event_handler(BeginStepEvent(epoch_id, step_id)) - exe.run(feed=feeder.feed(data), fetch_list=[]) - event_handler(EndStepEvent(epoch_id, step_id)) - event_handler(EndEpochEvent(epoch_id)) + reader = feeder.decorate_reader(reader, multi_devices=False) + self._train_by_any_executor(event_handler, exe, num_epochs, reader) + + def _train_by_any_executor(self, event_handler, exe, num_epochs, reader): + for epoch_id in range(num_epochs): + event_handler(BeginEpochEvent(epoch_id)) + for step_id, data in enumerate(reader()): + if self.__stop: + return + begin_event = BeginStepEvent(epoch_id, step_id) + event_handler(begin_event) + if begin_event.fetch_metrics: + metrics = exe.run(feed=data, + fetch_list=[ + var.name + for var in self.train_func_outputs + ]) + else: + metrics = exe.run(feed=data, fetch_list=[]) + event_handler(EndStepEvent(epoch_id, step_id, metrics)) + event_handler(EndEpochEvent(epoch_id)) def _test_by_executor(self, reader, feed_order, fetch_list): with executor.scope_guard(self.scope): @@ -271,6 +328,26 @@ class Trainer(object): return [x / count for x in accumulated] + def _train_by_parallel_executor(self, num_epochs, event_handler, reader, + feed_order): + with self._prog_and_scope_guard(): + pe = self._get_or_create_parallel_executor() + feed_var_list = build_feed_var_list(self.train_program, feed_order) + feeder = data_feeder.DataFeeder( + feed_list=feed_var_list, place=self.place) + reader = feeder.decorate_reader(reader, multi_devices=True) + self._train_by_any_executor(event_handler, pe, num_epochs, reader) + + def _get_parallel_executor(self): + return getattr(self, 'parallel_executor', None) + + def _get_or_create_parallel_executor(self): + if self._get_parallel_executor() is None: + self.parallel_executor = parallel_executor.ParallelExecutor( + use_cuda=isinstance(self.place, core.CUDAPlace), + loss_name=self.train_func_outputs[0].name) + return self._get_parallel_executor() + def build_feed_var_list(program, feed_order): if not isinstance(program, framework.Program): diff --git a/python/paddle/fluid/transpiler/memory_optimization_transpiler.py b/python/paddle/fluid/transpiler/memory_optimization_transpiler.py index 49034b47b2d184e4027bcebc29413a163340fdaa..80a8f7c09cfe521f8f94a27e85fc8d86c02b3e97 100644 --- a/python/paddle/fluid/transpiler/memory_optimization_transpiler.py +++ b/python/paddle/fluid/transpiler/memory_optimization_transpiler.py @@ -24,7 +24,8 @@ dtype_to_size = { core.VarDesc.VarType.INT16: 2, core.VarDesc.VarType.INT32: 4, core.VarDesc.VarType.INT64: 8, - core.VarDesc.VarType.BOOL: 1 + core.VarDesc.VarType.BOOL: 1, + core.VarDesc.VarType.UINT8: 1, } SUB_BLOCK_OPS = [ diff --git a/tools/test_runner.py b/tools/test_runner.py new file mode 100644 index 0000000000000000000000000000000000000000..9dc750b89058cd73355a2f7984d577252c03526d --- /dev/null +++ b/tools/test_runner.py @@ -0,0 +1,48 @@ +# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest +import os +import sys +import paddle.fluid as fluid +import importlib +import cStringIO + + +def main(): + sys.path.append(os.getcwd()) + some_test_failed = False + for module_name in sys.argv[1:]: + buffer = cStringIO.StringIO() + main = fluid.Program() + startup = fluid.Program() + scope = fluid.core.Scope() + with fluid.program_guard(main, startup): + with fluid.scope_guard(scope): + with fluid.unique_name.guard(): + test_loader = unittest.TestLoader() + module = importlib.import_module(module_name) + tests = test_loader.loadTestsFromModule(module) + res = unittest.TextTestRunner(stream=buffer).run(tests) + if not res.wasSuccessful(): + some_test_failed = True + print >> sys.stderr, module_name, 'failed\n', buffer.getvalue( + ) + + if some_test_failed: + exit(1) + + +if __name__ == '__main__': + main() diff --git a/tools/timeline.py b/tools/timeline.py index 8cd6353d46f496831cb61c1cdbbd156ca0579fb4..b413bb6fe0505df8fb09fa0759fefb6509b95bc9 100644 --- a/tools/timeline.py +++ b/tools/timeline.py @@ -171,7 +171,7 @@ if args.timeline_path: profile_paths = profile_path.split(',') profile_dict = dict() -if len(profile_path) == 1: +if len(profile_paths) == 1: with open(profile_path, 'r') as f: profile_s = f.read() profile_pb = profiler_pb2.Profile()