提交 01bee86d 编写于 作者: L Liu Yiqun

Merge branch 'develop' into cmake_protobuf

| Github account | name |
|---|---|
| reyoung | Yang Yu |
| gangliao | Gang Liao |
| luotao01 | Tao Luo |
| jacquesqiao | Long-Fei Qiao |
| qingqing01 | Qing-Qing Dang |
| hedaoyuan | Dao-Yuan He |
| wangyang59 | Yang Wang |
| QiJune | Jun Qi |
| tianbingsz | Tian-Bing Xu |
| cxwangyi, yiwangbaidu, wangkuiyi | Yi Wang |
| typhoonzero | Yi Wu |
| backyes | Yan-Fei Wang |
| pengli09 | Peng Li |
| livc | Zhao Li |
| Xreki | Yi-Qun Liu |
| Yancey1989 | Xu Yan |
| emailweixu | Wei Xu |
| wen-bo-yang | Wen-Bo Yang |
| helinwang | He-Lin Wang |
| lcy-seso | Ying Cao |
| Zrachel | Rui-Qing Zhang |
| Haichao-Zhang | Hai-Chao Zhang |
| gongweibao | Wei-Bao Gong |
| lzhao4ever | Liang Zhao |
| zhouxiao-coder | Xiao Zhou |
| lipeng-unisound | Peng Li |
# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. # Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
# You may obtain a copy of the License at # You may obtain a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, # distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
set(PROJ_ROOT ${CMAKE_SOURCE_DIR}) set(PROJ_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
include(system) include(system)
......
Cao, Ying
Cheng, Yujuan
Dang, Qingqing
Dong, Tengfei
Du, Dalong
Feng, Shouqiang
Gao, Haoyuan
Han, Baochang
Han, Jinchen
Hao, Nanyu
He, Daoyuan
He, Zhengyan
Hou, Jue
Huang, Chang
Huang, Zhiheng
Hu, Na
Kong, Qi
Liao, Gang
Li, Bo
Li, Jiajie
Li, Jing
Li, Lei
Li, Peng
Liu, Sheng
Liu, Yuan
Li, Yuze
Luo, Heng
Luo, Tao
Lyu, Qin
Mao, Hongyue
Qian, Xiaojun
Qiao, Longfei
Qi, Jun
Qin, Duohao
Shen, Guolong
Shi, Guangchuan
Song, Xiang
Wang, Helin
Wang, Jiang
Wang, Yanfei
Wang, Yi
Wang, Yong
Weng, Renliang
Xu, Tianbing
Xu, Wei
Xu, Xingyu
Yan, Chong
Yan, Chunwei
Yang, Yi
Yu, Yang
Yu, Yinan
Zhang, Jian
Zhang, Ruiqing
Zhang, Weide
Zhao, Liang
Zhou, Jie
...@@ -34,7 +34,7 @@ set(IGNORE_PATTERN ...@@ -34,7 +34,7 @@ set(IGNORE_PATTERN
# #
# first argument: target name to attach # first argument: target name to attach
# rest arguments: source list to check code style. # rest arguments: source list to check code style.
# #
# NOTE: If WITH_STYLE_CHECK is OFF, then this macro just do nothing. # NOTE: If WITH_STYLE_CHECK is OFF, then this macro just do nothing.
macro(add_style_check_target TARGET_NAME) macro(add_style_check_target TARGET_NAME)
if(WITH_STYLE_CHECK) if(WITH_STYLE_CHECK)
...@@ -48,13 +48,17 @@ macro(add_style_check_target TARGET_NAME) ...@@ -48,13 +48,17 @@ macro(add_style_check_target TARGET_NAME)
if(filename MATCHES ${pattern}) if(filename MATCHES ${pattern})
message(STATUS "DROP LINT ${filename}") message(STATUS "DROP LINT ${filename}")
set(LINT OFF) set(LINT OFF)
endif() endif()
endforeach() endforeach()
if(LINT MATCHES ON) if(LINT MATCHES ON)
add_custom_command(TARGET ${TARGET_NAME} get_filename_component(base_filename ${filename} NAME)
set(CUR_GEN ${CMAKE_CURRENT_BINARY_DIR}/${base_filename}.cpplint)
add_custom_command(OUTPUT ${CUR_GEN}
PRE_BUILD PRE_BUILD
COMMAND env ${py_env} "${PYTHON_EXECUTABLE}" "${PROJ_ROOT}/paddle/scripts/cpplint.py" COMMAND env ${py_env} "${PYTHON_EXECUTABLE}" "${PROJ_ROOT}/paddle/scripts/cpplint.py"
"--filter=${STYLE_FILTER}" ${filename} "--filter=${STYLE_FILTER}"
"--write-success=${CUR_GEN}" ${filename}
DEPENDS ${filename}
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
endif() endif()
endforeach() endforeach()
......
# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. # Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
# You may obtain a copy of the License at # You may obtain a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, # distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
...@@ -18,7 +18,8 @@ FUNCTION(build_protobuf TARGET_NAME BUILD_FOR_HOST) ...@@ -18,7 +18,8 @@ FUNCTION(build_protobuf TARGET_NAME BUILD_FOR_HOST)
SET(PROTOBUF_SOURCES_DIR ${THIRD_PARTY_PATH}/${TARGET_NAME}) SET(PROTOBUF_SOURCES_DIR ${THIRD_PARTY_PATH}/${TARGET_NAME})
SET(PROTOBUF_INSTALL_DIR ${THIRD_PARTY_PATH}/install/${TARGET_NAME}) SET(PROTOBUF_INSTALL_DIR ${THIRD_PARTY_PATH}/install/${TARGET_NAME})
SET(${TARGET_NAME}_INCLUDE_DIR "${PROTOBUF_INSTALL_DIR}/include" PARENT_SCOPE) SET(${TARGET_NAME}_INCLUDE_DIR "${PROTOBUF_INSTALL_DIR}/include"
SET(PROTOBUF_INCLUDE_DIR "${PROTOBUF_INSTALL_DIR}/include" PARENT_SCOPE)
SET(${TARGET_NAME}_LITE_LIBRARY SET(${TARGET_NAME}_LITE_LIBRARY
"${PROTOBUF_INSTALL_DIR}/lib/libprotobuf-lite${STATIC_LIBRARY_SUFFIX}" "${PROTOBUF_INSTALL_DIR}/lib/libprotobuf-lite${STATIC_LIBRARY_SUFFIX}"
PARENT_SCOPE) PARENT_SCOPE)
...@@ -81,7 +82,7 @@ IF(NOT CMAKE_CROSSCOMPILING) ...@@ -81,7 +82,7 @@ IF(NOT CMAKE_CROSSCOMPILING)
IF(PROTOBUF_FOUND) IF(PROTOBUF_FOUND)
EXEC_PROGRAM(${PROTOBUF_PROTOC_EXECUTABLE} ARGS --version OUTPUT_VARIABLE PROTOBUF_VERSION) EXEC_PROGRAM(${PROTOBUF_PROTOC_EXECUTABLE} ARGS --version OUTPUT_VARIABLE PROTOBUF_VERSION)
STRING(REGEX MATCH "[0-9]+.[0-9]+" PROTOBUF_VERSION "${PROTOBUF_VERSION}") STRING(REGEX MATCH "[0-9]+.[0-9]+" PROTOBUF_VERSION "${PROTOBUF_VERSION}")
IF (${PROTOBUF_VERSION} VERSION_LESS "3.1.0") IF("${PROTOBUF_VERSION}" VERSION_LESS "3.1.0")
SET(PROTOBUF_FOUND OFF) SET(PROTOBUF_FOUND OFF)
ENDIF() ENDIF()
ENDIF(PROTOBUF_FOUND) ENDIF(PROTOBUF_FOUND)
......
...@@ -13,79 +13,108 @@ ...@@ -13,79 +13,108 @@
### 训练数据的存储 ### 训练数据的存储
选择GlusterFS作为训练数据的存储服务(后续的实现考虑HDFS) 选择CephFS作为训练数据的存储服务
在Kubernetes上运行的不同的计算框架,可以通过Volume或PersistentVolume挂载存储空间到每个容器中。 在Kubernetes上运行的不同的计算框架,可以通过Volume或PersistentVolume挂载存储空间到每个容器中。
GlusterFS存储系统中的公开目录,需要保存一些预置的公开数据集(比如MNIST, BOW, imagenet数据集等),并且可以被提交的job直接使用。 CephFS存储系统中的公开目录,需要保存一些预置的公开数据集(比如MNIST, BOW, ImageNet数据集等),并且可以被提交的job直接使用。
### 上传训练文件 ### 文件预处理
使用下面命令,可以把本地的训练数据上传到存储集群中,并指定上传数据的`dataset-name` 在数据集可以被训练之前,文件需要预先被转换成PaddlePaddle集群内部的存储格式(SSTable)。我们提供两个转换方式
``` - 提供给用户本地转换的库,用户可以编写程序完成转换。
paddle upload train_data.list "dataset-name" - 用户可以上传自己的数据集,在集群运行MapReduce job完成转换。
```
其中`.list`文件描述了训练数据的文件和对应的label,对于图像类数据,`.list文件`样例如下,每一行包含了图片文件的路径和其label(用tab分隔开) 转换生成的文件名会是以下格式
``` ```text
./data/image1.jpg 1 name_prefix-aaaaa-of-bbbbb
./data/image2.jpg 5
./data/image3.jpg 2
./data/image4.jpg 5
./data/image5.jpg 1
./data/image6.jpg 8
...
``` ```
对于文本类训练数据样例如下(机器翻译),一行中包含源语言,目标语言的文本(label): "aaaaa"和"bbbbb"都是五位的数字,每一个文件是数据集的一个shard,"aaaaa"代表shard的index,"bbbbb"代表这个shard的最大index。
比如ImageNet这个数据集可能被分成1000个shard,它们的文件名是:
```text
imagenet-00000-of-00999
imagenet-00001-of-00999
...
imagenet-00999-of-00999
``` ```
L' inflation , en Europe , a dérapé sur l' alimentation Food : Where European inflation slipped up
L' inflation accélérée , mesurée dans la zone euro , est due principalement à l' augmentation rapide des prix de l' alimentation . The skyward zoom in food prices is the dominant force behind the speed up in eurozone inflation . #### 转换库
...
无论是在本地或是云端转换,我们都提供Python的转换库,接口是:
```python
def convert(output_path, reader, num_shards, name_prefix)
``` ```
### 使用reader - `output_path`: directory in which output files will be saved.
- `reader`: a [data reader](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/reader/README.md#data-reader-interface), from which the convert program will read data instances.
- `num_shards`: the number of shards that the dataset will be partitioned into.
- `name_prefix`: the name prefix of generated files.
用户在使用v2 API编写训练任务时,可以使用paddle内置的reader完成对GlusterFS存储中的训练数据的读取,返回文件中的各列,然后在调用`trainer.train()`时传入,完成训练数据的读取 `reader`每次输出一个data instance,这个instance可以是单个值,或者用tuple表示的多个值
```python ```python
reader = paddle.dist.reader("dataset-name") yield 1 # 单个值
trainer.train(reader, ...) yield numpy.random.uniform(-1, 1, size=28*28) # 单个值
batch_reader = paddle.batch(paddle.dataset.mnist.train(), 128) yield numpy.random.uniform(-1, 1, size=28*28), 0 # 多个值
trainer.train(batch_reader, ...)
``` ```
trainer.train内部会获取reader的内容: 每个值的类型可以是整形、浮点型数据、字符串,或者由它们组成的list,以及numpy.ndarray。如果是其它类型,会被Pickle序列化成字符串。
``` ### 示例程序
def paddle.train(batch_reader):
r = batch_reader() # create a iterator for one pass of data #### 使用转换库
for batch in r:
# train 以下`reader_creator`生成的`reader`每次输出一个data instance,每个data instance包涵两个值:numpy.ndarray类型的值和整型的值:
```python
def reader_creator():
def reader():
for i in range(1000):
yield numpy.random.uniform(-1, 1, size=28*28), 0 # 多个值
return reader
``` ```
这里面batch是含有128个data instance的mini-batch。每一个data instance会是一个tuple,tuple元素的顺序与`.list`文件文件中每一列的顺序是一致的。每一个data instance会是(raw_image_file_binary_data, label)。其中raw_image_file_binary_data是对应图像文件的没有解码的原始二进制数据,用户需要自己解码。label是文本类型(比如:“1“,”2“),这里用户需要的其实是整形,用户需要自己转换成整形。 `reader_creator`生成的`reader`传入`convert`函数即可完成转换:
```python
convert("./", reader_creator(), 100, random_images)
```
### 实现reader 以上命令会在当前目录下生成100个文件:
```text
random_images-00000-of-00099
random_images-00001-of-00099
...
random_images-00099-of-00099
```
reader的实现需要考虑本地训练程序实现之后,可以不修改程序直接提交集群进行分布式训练。要达到这样的目标,需要实现下面的功能: #### 进行训练
paddle会封装一个在集群中使用的reader: `paddle.dist.reader()`。在集群训练时需要使用这个reader指定要使用的数据集开始训练。用户的训练程序需要按照如下方式初始化reader PaddlePaddle提供专用的[data reader creator](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/reader/README.md#python-data-reader-design-doc),生成给定SSTable文件对应的data reader。**无论在本地还是在云端,reader的使用方式都是一致的**
```python ```python
if os.getenv("PADDLE_TRAIN_LOCAL"): # ...
reader = my_local_reader("dataset-name") reader = paddle.reader.creator.SSTable("/home/random_images-*-of-*")
else: batch_reader = paddle.batch(paddle.dataset.mnist.train(), 128)
reader = paddle.dist.reader("dataset-name") trainer.train(batch_reader, ...)
``` ```
用户训练程序提交到集群之后,集群会自动设置`PADDLE_TRAIN_LOCAL`环境变量,reader会被配置成集群训练的版本。其中`paddle.dist.reader()`需要从master的队列中获得需要开始执行的训练task,并找到对应的训练数据文件,开始训练任务。如果用户的训练数据源来自于其他服务,比如从集群中的Kafka,zeromq队列读取,也可以根据实际情况实现集群中运行的reader程序 以上代码的reader输出的data instance与生成数据集时,reader输出的data instance是一模一样的
### 上传训练文件
使用下面命令,可以把本地的数据上传到存储集群中。
```bash
paddle cp filenames pfs://home/folder/
```
比如,把之前示例中转换完毕的random_images数据集上传到云端的`/home/`可以用以下指令:
```bash
paddle cp random_images-*-of-* pfs://home/
```
## TODO ## TODO
### 支持将数据合并成内部的文件格式(key-value),方便sharding与顺序读取
### 支持用户自定义的数据预处理job ### 支持用户自定义的数据预处理job
...@@ -4,93 +4,112 @@ PaddlePaddle的Docker容器使用方式 ...@@ -4,93 +4,112 @@ PaddlePaddle的Docker容器使用方式
PaddlePaddle目前唯一官方支持的运行的方式是Docker容器。因为Docker能在所有主要操作系统(包括Linux,Mac OS X和Windows)上运行。 请注意,您需要更改 `Dockers设置 <https://github.com/PaddlePaddle/Paddle/issues/627>`_ 才能充分利用Mac OS X和Windows上的硬件资源。 PaddlePaddle目前唯一官方支持的运行的方式是Docker容器。因为Docker能在所有主要操作系统(包括Linux,Mac OS X和Windows)上运行。 请注意,您需要更改 `Dockers设置 <https://github.com/PaddlePaddle/Paddle/issues/627>`_ 才能充分利用Mac OS X和Windows上的硬件资源。
PaddlePaddle发布的docker镜像使用说明 PaddlePaddle发布的Docker镜像使用说明
------------------------------ ------------------------------
对于每一个PaddlePaddle版本,我们都会发布两种Docker镜像:开发镜像、运行镜像。运行镜像包括纯CPU版本和GPU版本以及其对应的非AVX版本。 我们把PaddlePaddle的编译环境打包成一个镜像,称为开发镜像,里面涵盖了
我们会在 `dockerhub.com <https://hub.docker.com/r/paddledev/paddle/>`_ 提供最新的docker镜像,可以在"tags"标签下找到最新的Paddle镜像版本。 PaddlePaddle需要的所有编译工具。把编译出来的PaddlePaddle也打包成一个镜
像,称为生产镜像,里面涵盖了PaddlePaddle运行所需的所有环境。每次
PaddlePaddle发布新版本的时候都会发布对应版本的生产镜像以及开发镜像。运
行镜像包括纯CPU版本和GPU版本以及其对应的非AVX版本。我们会在
`dockerhub.com <https://hub.docker.com/r/paddledev/paddle/>`_ 提供最新
的Docker镜像,可以在"tags"标签下找到最新的Paddle镜像版本。为了方便在国
内的开发者下载Docker镜像,我们提供了国内的镜像服务器供大家使用。如果您
在国内,请把文档里命令中的paddlepaddle/paddle替换成
docker.paddlepaddle.org/paddle。
1. 开发镜像::code:`paddlepaddle/paddle:<version>-dev` 1. 开发镜像::code:`paddlepaddle/paddle:<version>-dev`
这个镜像包含了Paddle相关的开发工具以及编译和运行环境。用户可以使用开发镜像代替配置本地环境,完成开发,编译,发布, 这个镜像包含了Paddle相关的开发工具以及编译和运行环境。用户可以使用开发镜像代替配置本地环境,完成开发,编译,发布,
文档编写等工作。由于不同的Paddle的版本可能需要不同的依赖和工具,所以如果需要自行配置开发环境需要考虑版本的因素。 文档编写等工作。由于不同的Paddle的版本可能需要不同的依赖和工具,所以如果需要自行配置开发环境需要考虑版本的因素。
开发镜像包含了以下工具: 开发镜像包含了以下工具:
- gcc/clang
- nvcc - gcc/clang
- Python - nvcc
- sphinx - Python
- woboq - sphinx
- sshd - woboq
很多开发者会使用远程的安装有GPU的服务器工作,用户可以使用ssh登录到这台服务器上并执行 :code:`docker exec`进入开发镜像并开始工作, - sshd
也可以在开发镜像中启动一个SSHD服务,方便开发者直接登录到镜像中进行开发: 很多开发者会使用远程的安装有GPU的服务器工作,用户可以使用ssh登录到这台服务器上并执行 :code:`docker exec`进入开发镜像并开始工作,
也可以在开发镜像中启动一个SSHD服务,方便开发者直接登录到镜像中进行开发:
以交互容器方式运行开发镜像:
.. code-block:: bash
docker run -it --rm paddlepaddle/paddle:<version>-dev /bin/bash
或者,可以以后台进程方式运行容器:
.. code-block:: bash
docker run -d -p 2202:22 -p 8888:8888 paddledev/paddle:<version>-dev
以交互容器方式运行开发镜像 然后用密码 :code:`root` SSH进入容器
.. code-block:: bash .. code-block:: bash
docker run -it --rm paddledev/paddle:<version>-dev /bin/bash ssh -p 2202 root@localhost
或者,可以以后台进程方式运行容器: SSH方式的一个优点是我们可以从多个终端进入容器。比如,一个终端运行vi,另一个终端运行Python。另一个好处是我们可以把PaddlePaddle容器运行在远程服务器上,并在笔记本上通过SSH与其连接。
.. code-block:: bash 2. 生产镜像:根据CPU、GPU和非AVX区分了如下4个镜像:
docker run -d -p 2202:22 -p 8888:8888 paddledev/paddle:<version>-dev - GPU/AVX::code:`paddlepaddle/paddle:<version>-gpu`
- GPU/no-AVX::code:`paddlepaddle/paddle:<version>-gpu-noavx`
- CPU/AVX::code:`paddlepaddle/paddle:<version>`
- CPU/no-AVX::code:`paddlepaddle/paddle:<version>-noavx`
然后用密码 :code:`root` SSH进入容器 纯CPU镜像以及GPU镜像都会用到AVX指令集,但是2008年之前生产的旧电脑不支持AVX。以下指令能检查Linux电脑是否支持AVX
.. code-block:: bash .. code-block:: bash
ssh -p 2202 root@localhost if cat /proc/cpuinfo | grep -i avx; then echo Yes; else echo No; fi
SSH方式的一个优点是我们可以从多个终端进入容器。比如,一个终端运行vi,另一个终端运行Python。另一个好处是我们可以把PaddlePaddle容器运行在远程服务器上,并在笔记本上通过SSH与其连接。 如果输出是No,就需要选择使用no-AVX的镜像
2. 运行镜像:根据CPU、GPU和非AVX区分了如下4个镜像: 以上方法在GPU镜像里也能用,只是请不要忘记提前在物理机上安装GPU最新驱动。
- GPU/AVX::code:`paddlepaddle/paddle:<version>-gpu` 为了保证GPU驱动能够在镜像里面正常运行,我们推荐使用[nvidia-docker](https://github.com/NVIDIA/nvidia-docker)来运行镜像。
- GPU/no-AVX::code:`paddlepaddle/paddle:<version>-gpu-noavx`
- CPU/AVX::code:`paddlepaddle/paddle:<version>`
- CPU/no-AVX::code:`paddlepaddle/paddle:<version>-noavx`
纯CPU镜像以及GPU镜像都会用到AVX指令集,但是2008年之前生产的旧电脑不支持AVX。以下指令能检查Linux电脑是否支持AVX: .. code-block:: bash
.. code-block:: bash nvidia-docker run -it --rm paddledev/paddle:0.10.0rc1-gpu /bin/bash
if cat /proc/cpuinfo | grep -i avx; then echo Yes; else echo No; fi 注意: 如果使用nvidia-docker存在问题,你也许可以尝试更老的方法,具体如下,但是我们并不推荐这种方法。:
如果输出是No,就需要选择使用no-AVX的镜像 .. code-block:: bash
以上方法在GPU镜像里也能用,只是请不要忘记提前在物理机上安装GPU最新驱动。 export CUDA_SO="$(\ls /usr/lib64/libcuda* | xargs -I{} echo '-v {}:{}') $(\ls /usr/lib64/libnvidia* | xargs -I{} echo '-v {}:{}')"
为了保证GPU驱动能够在镜像里面正常运行,我们推荐使用[nvidia-docker](https://github.com/NVIDIA/nvidia-docker)来运行镜像。 export DEVICES=$(\ls /dev/nvidia* | xargs -I{} echo '--device {}:{}')
docker run ${CUDA_SO} ${DEVICES} -it paddledev/paddle:<version>-gpu
.. code-block:: bash 3. 运行以及发布您的AI程序
nvidia-docker run -it --rm paddledev/paddle:0.10.0rc1-gpu /bin/bash 假设您已经完成了一个AI训练的python程序 :code:`a.py`,这个程序是您在开发机上使用开发镜像完成开发。此时您可以运行这个命令在开发机上进行测试运行:
注意: 如果使用nvidia-docker存在问题,你也许可以尝试更老的方法,具体如下,但是我们并不推荐这种方法。: .. code-block:: bash
.. code-block:: bash docker run -it -v $PWD:/work paddle /work/a.py
export CUDA_SO="$(\ls /usr/lib64/libcuda* | xargs -I{} echo '-v {}:{}') $(\ls /usr/lib64/libnvidia* | xargs -I{} echo '-v {}:{}')" 如果要使用GPU,请运行:
export DEVICES=$(\ls /dev/nvidia* | xargs -I{} echo '--device {}:{}')
docker run ${CUDA_SO} ${DEVICES} -it paddledev/paddle:<version>-gpu
3. 使用运行镜像发布你的AI程序 .. code-block:: bash
假设您已经完成了一个AI训练的python程序 :code:`a.py`,这个程序是您在开发机上使用开发镜像完成开发。此时您可以运行这个命令在开发机上进行测试运行:
.. code-block:: bash nvidia-docker run -it -v $PWD:/work paddle /work/a.py
docker run -it -v $PWD:/work paddle /work/a.py
这里`a.py`包含的所有依赖假设都可以在Paddle的运行容器中。如果需要包含更多的依赖、或者需要发布您的应用的镜像,可以编写`Dockerfile`使用`FROM paddledev/paddle:<version>` 这里`a.py`包含的所有依赖假设都可以在Paddle的运行容器中。如果需要包含更多的依赖、或者需要发布您的应用的镜像,可以编写`Dockerfile`使用`FROM paddledev/paddle:<version>`
创建和发布自己的AI程序镜像。 创建和发布自己的AI程序镜像。
运行PaddlePaddle书籍 运行PaddlePaddle Book
--------------------- ---------------------
Jupyter Notebook是一个开源的web程序,大家可以通过它制作和分享带有代码、公式、图表、文字的交互式文档。用户可以通过网页浏览文档。 Jupyter Notebook是一个开源的web程序,大家可以通过它制作和分享带有代码、公式、图表、文字的交互式文档。用户可以通过网页浏览文档。
PaddlePaddle书籍是为用户和开发者制作的一个交互式的Jupyter Nodebook。 PaddlePaddle Book是为用户和开发者制作的一个交互式的Jupyter Nodebook。
如果您想要更深入了解deep learning,PaddlePaddle书籍一定是您最好的选择。 如果您想要更深入了解deep learning,PaddlePaddle Book一定是您最好的选择。
我们提供可以直接运行PaddlePaddle书籍的docker镜像,直接运行: 我们提供可以直接运行PaddlePaddle Book的Docker镜像,直接运行:
.. code-block:: bash .. code-block:: bash
...@@ -109,53 +128,44 @@ PaddlePaddle书籍是为用户和开发者制作的一个交互式的Jupyter Nod ...@@ -109,53 +128,44 @@ PaddlePaddle书籍是为用户和开发者制作的一个交互式的Jupyter Nod
开发人员可以在Docker开发镜像中开发PaddlePaddle。这样开发人员可以以一致的方式在不同的平台上工作 - Linux,Mac OS X和Windows。 开发人员可以在Docker开发镜像中开发PaddlePaddle。这样开发人员可以以一致的方式在不同的平台上工作 - Linux,Mac OS X和Windows。
1. 构建开发镜像 1. 制作PaddlePaddle开发镜像
.. code-block:: bash PaddlePaddle每次发布新版本都会发布对应的开发镜像供开发者直接使用。这里介绍如生成造这个开发镜像。
生成Docker镜像的方式有两个,一个是直接把一个容器转换成镜像,另一个是创建Dockerfile并运行docker build指令按照Dockerfile生成镜像。第一个方法的好处是简单快捷,适合自己实验,可以快速迭代。第二个方法的好处是Dockerfile可以把整个生成流程描述很清楚,其他人很容易看懂镜像生成过程,持续集成系统也可以简单地复现这个过程。我们采用第二个方法。Dockerfile位于PaddlePaddle repo的根目录。生成生产镜像只需要运行:
git clone --recursive https://github.com/PaddlePaddle/Paddle .. code-block:: bash
git clone https://github.com/PaddlePaddle/Paddle.git
cd Paddle cd Paddle
docker build -t paddle:dev . docker build -t paddle:dev .
docker build这个命令的-t指定了生成的镜像的名字,这里我们用paddle:dev。到此,PaddlePaddle开发镜像就被构建完毕了。
请注意,默认情况下,:code:`docker build` 不会将源码导入到镜像中并编译它。如果我们想这样做,需要构建完开发镜像,然后执行: 2. 制作PaddlePaddle生产镜像
.. code-block:: bash
docker run -v $PWD:/paddle -e "WITH_GPU=OFF" -e "WITH_AVX=ON" -e "TEST=OFF" paddle:dev
2. 运行开发环境
当我们编译好了 :code:`paddle:dev`, 我们可以在docker容器里做开发,源代码可以通过挂载本地文件来被载入Docker的开发环境里面 生产镜像的生成分为两步,第一步是运行
.. code-block:: bash .. code-block:: bash
docker run -v $(pwd):/paddle -e "WITH_GPU=OFF" -e "WITH_AVX=OFF" -e "WITH_TEST=ON" paddle:dev
docker run -d -p 2202:22 -v $PWD:/paddle paddle:dev sshd 以上命令会编译PaddlePaddle,生成运行程序,以及生成创建生产镜像的Dockerfile。所有生成的的文件都在build目录下。“WITH_GPU”控制生成的生产镜像是否支持GPU,“WITH_AVX”控制生成的生产镜像是否支持AVX,”WITH_TEST“控制是否生成单元测试。
以上代码会启动一个带有PaddlePaddle开发环境的docker容器,源代码会被挂载到 :code:`/paddle` 。 第二步是运行:
以上的 :code:`docker run` 命令其实会启动一个在2202端口监听的SSHD服务器。这样,我们就能SSH进入我们的开发容器了:
.. code-block:: bash .. code-block:: bash
docker build -t paddle:prod -f build/Dockerfile ./build
ssh root@localhost -p 2202 以上命令会按照生成的Dockerfile把生成的程序拷贝到生产镜像中并做相应的配置,最终生成名为paddle:prod的生产镜像。
3. 在Docker开发环境中编译与安装PaddlPaddle代码 3. 运行单元测试
当在容器里面的时候,可以用脚本 :code:`paddle/scripts/docker/build.sh` 来编译、安装与测试PaddlePaddle 运行以下指令
.. code-block:: bash .. code-block:: bash
/paddle/paddle/scripts/docker/build.sh docker run -it -v $(pwd):/paddle paddle:dev bash -c "cd /paddle/build && ctest"
以上指令会在 :code:`/paddle/build` 中编译PaddlePaddle。通过以下指令可以运行单元测试:
.. code-block:: bash
cd /paddle/build
ctest
文档 文档
---- ----
......
...@@ -53,12 +53,20 @@ Docker is simple as long as we understand a few basic concepts: ...@@ -53,12 +53,20 @@ Docker is simple as long as we understand a few basic concepts:
Usage of CPU-only and GPU Images Usage of CPU-only and GPU Images
---------------------------------- ----------------------------------
For each version of PaddlePaddle, we release two types of Docker images: We package PaddlePaddle's compile environment into a Docker image,
development image and production image. Production image includes called the develop image, it contains all compiling tools that
CPU-only version and a CUDA GPU version and their no-AVX versions. We PaddlePaddle needs. We package compiled PaddlePaddle program into a
put the docker images on `dockerhub.com Docker image as well, called the production image, it contains all
runtime environment that running PaddlePaddle needs. For each version
of PaddlePaddle, we release both of them. Production image includes
CPU-only version and a CUDA GPU version and their no-AVX versions.
We put the docker images on `dockerhub.com
<https://hub.docker.com/r/paddledev/paddle/>`_. You can find the <https://hub.docker.com/r/paddledev/paddle/>`_. You can find the
latest versions under "tags" tab at dockerhub.com latest versions under "tags" tab at dockerhub.com. If you are in
China, you can use our Docker image registry mirror to speed up the
download process. To use it, please replace all paddlepaddle/paddle in
the commands to docker.paddlepaddle.org/paddle.
1. Production images, this image might have multiple variants: 1. Production images, this image might have multiple variants:
...@@ -179,59 +187,40 @@ Develop PaddlePaddle or Train Model Using C++ API ...@@ -179,59 +187,40 @@ Develop PaddlePaddle or Train Model Using C++ API
We will be using PaddlePaddle development image since it contains all We will be using PaddlePaddle development image since it contains all
compiling tools and dependencies. compiling tools and dependencies.
Let's clone PaddlePaddle repo first: 1. Build PaddlePaddle develop image
.. code-block:: bash Use following command to build PaddlePaddle develop image:
git clone https://github.com/PaddlePaddle/Paddle.git && cd Paddle
Mount both workspace folder and paddle code folder into docker
container, so we can access them inside docker container. There are
two ways of using PaddlePaddle development docker image:
- run interactive bash directly
.. code-block:: bash .. code-block:: bash
# use nvidia-docker instead of docker if you need to use GPU
docker run -it -v ~/workspace:/workspace -v $(pwd):/paddle paddlepaddle/paddle:0.10.0rc2-dev /bin/bash
# now we are inside docker container
- or, we can run it as a daemon container git clone https://github.com/PaddlePaddle/Paddle.git && cd Paddle
docker build -t paddle:dev .
.. code-block:: bash 2. Build PaddlePaddle production image
# use nvidia-docker instead of docker if you need to use GPU There are two steps for building production image, the first step is to run:
docker run -d -p 2202:22 -p 8888:8888 -v ~/workspace:/workspace -v $(pwd):/paddle paddlepaddle/paddle:0.10.0rc2-dev /usr/sbin/sshd -D
and SSH to this container using password :code:`root`: .. code-block:: bash
.. code-block:: bash
ssh -p 2202 root@localhost docker run -v $(pwd):/paddle -e "WITH_GPU=OFF" -e "WITH_AVX=OFF" -e "WITH_TEST=ON" paddle:dev
An advantage is that we can run the PaddlePaddle container on a The above command will compile PaddlePaddle and create a Dockerfile for building production image. All the generated files are in the build directory. "WITH_GPU" controls if the generated production image supports GPU. "WITH_AVX" controls if the generated production image supports AVX. "WITH_TEST" controls if the unit test will be generated.
remote server and SSH to it from a laptop.
When developing PaddlePaddle, you can edit PaddlePaddle source code The second step is to run:
from outside of docker container using your favoriate editor. To
compile PaddlePaddle, run inside container:
.. code-block:: bash .. code-block:: bash
WITH_GPU=OFF WITH_AVX=ON WITH_TEST=ON bash /paddle/paddle/scripts/docker/build.sh docker build -t paddle:prod -f build/Dockerfile ./build
This builds everything about Paddle in :code:`/paddle/build`. And we The above command will generate the production image by copying the compiled PaddlePaddle program into the image.
can run unit tests there:
.. code-block:: bash 3. Run unit test
cd /paddle/build Following command will run unit test:
ctest
When training model using C++ API, we can edit paddle program in .. code-block:: bash
~/workspace outside of docker. And build from /workspace inside of
docker. docker run -it -v $(pwd):/paddle paddle:dev bash -c "cd /paddle/build && ctest"
PaddlePaddle Book PaddlePaddle Book
------------------ ------------------
......
# 如何贡献代码 # 如何贡献代码
我们真诚地感谢您的贡献,欢迎通过 GitHub 的 fork 和 pull request 流程来提交代码。 我们真诚地感谢您的贡献,欢迎通过 GitHub 的 fork 和 pull request 流程来提交代码。
## 代码要求 ## 代码要求
- 你的代码必须完全遵守 [doxygen](http://www.stack.nl/~dimitri/doxygen/) 的样式。 - 代码注释请遵守 [Doxygen](http://www.stack.nl/~dimitri/doxygen/) 的样式。
- 确保编译器选项 WITH\_STYLE\_CHECK 已打开,并且编译能通过代码样式检查。 - 确保编译器选项 `WITH_STYLE_CHECK` 已打开,并且编译能通过代码样式检查。
- 所有代码必须具有单元测试。 - 所有代码必须具有单元测试。
- 通过所有单元测试。 - 通过所有单元测试。
以下教程将指导您提交代码。 以下教程将指导您提交代码。
## [Fork](https://help.github.com/articles/fork-a-repo/) ## [Fork](https://help.github.com/articles/fork-a-repo/)
跳转到[PaddlePaddle](https://github.com/PaddlePaddle/Paddle) GitHub首页,然后单击 `Fork` 按钮。 跳转到[PaddlePaddle](https://github.com/PaddlePaddle/Paddle) GitHub首页,然后单击 `Fork` 按钮,生成自己目录下的仓库,比如 <https://github.com/USERNAME/Paddle>
## 克隆(Clone) ## 克隆(Clone)
Paddle 目前使用[git流分支模型](http://nvie.com/posts/a-successful-git-branching-model/)进行开发,测试,发行和维护。 将远程仓库 clone 到本地:
**develop** 是主分支,其他用户分支是特征分支(feature branches)。
```bash
➜ git clone https://github.com/USERNAME/Paddle
cd Paddle
```
## 创建本地分支
Paddle 目前使用[Git流分支模型](http://nvie.com/posts/a-successful-git-branching-model/)进行开发,测试,发行和维护,具体请参考 [Paddle 分支规范](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/releasing_process.md#paddle-分支规范)
一旦你创建了一个fork,你可以使用你最喜欢的 git 客户端克隆你的仓库(repo)或只是直接在命令行输入: 所有的 feature 和 bug fix 的开发工作都应该在一个新的分支上完成,一般从 `develop` 分支上创建新分支。
```shell 使用 `git checkout -b` 创建并切换到新分支。
# 克隆 fork 到本地
git clone --branch develop https://github.com/USERNAME/Paddle.git ```bash
➜ git checkout -b my-cool-stuff
``` ```
如果你的仓库不包含 **develop** 分支,你只需自己创建它。
```shell 值得注意的是,在 checkout 之前,需要保持当前分支目录 clean,否则会把 untracked 的文件也带到新分支上,这可以通过 `git status` 查看。
git clone https://github.com/USERNAME/Paddle.git Paddle
cd Paddle ## 使用 `pre-commit` 钩子
git checkout -b develop # 创建 develop 分支
git remote add upstream https://github.com/PaddlePaddle/Paddle.git # 添加 upstream 到 baidu/Paddle Paddle 开发人员使用 [pre-commit](http://pre-commit.com/) 工具来管理 Git 预提交钩子。 它可以帮助我们格式化源代码(C++,Python),在提交(commit)前自动检查一些基本事宜(如每个文件只有一个 EOL,Git 中不要添加大文件等)。
git pull upstream develop # 更新 upstream
`pre-commit`测试是 Travis-CI 中单元测试的一部分,不满足钩子的 PR 不能被提交到 Paddle,首先安装并在当前目录运行它:
```bash
➜ pip install pre-commit
➜ pre-commit install
``` ```
然后你可以通过做一个本地开发分支开始开发 Paddle 使用 `clang-format` 来调整 C/C++ 源代码格式,请确保 `clang-format` 版本在 3.8 以上。
```shell ## 开始开发
git checkout -b MY_COOL_STUFF_BRANCH
在本例中,我删除了 README.md 中的一行,并创建了一个新文件。
通过 `git status` 查看当前状态,这会提示当前目录的一些变化,同时也可以通过 `git diff` 查看文件具体被修改的内容。
```bash
➜ git status
On branch test
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: README.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
test
no changes added to commit (use "git add" and/or "git commit -a")
``` ```
## 使用 `pre-commit` 钩子 ## 构建和测试
编译 PaddlePaddle 的源码以及生成文档需要多种开发工具。为了方便大家,我们的标准开发流程是把这些工具都装进一个Docker image,称为*开发镜像*,通常名字是 `paddle:dev`。然后所有用 `cmake && make` 的地方(比如IDE配置里)都用 `docker run paddle:dev`来代替。
Paddle 开发人员使用 [pre-commit](http://pre-commit.com/) 工具来管理git预提交钩子。 它可以帮助我们格式化源代码(cpp,python),在提交前检查一些基本事宜(每个文件只有一个 EOL 如要build这个开发镜像,在源码目录树的根目录中运行:
,git 中不要添加大文件)。 `pre-commit`测试是 Travis-CI 中单元测试的一部分,不满足钩子
的 PR 不能提交代码到 Paddle。
你可以通过 `pip install pre-commit` 安装 [pre-commit](http://pre-commit.com/) ```bash
目前 Paddle 使用 `clang-format` 来调整C/C++源代码格式。请确保 clang-format 版本在3.8以上。 ➜ docker build -t paddle:dev .
```
然后只需在 Paddle clone 目录中运行 `pre-commit install` 。当你 随后可以用这个开发镜像开build PaddlePaddle的源码。比如如果要build一个不依赖GPU,但是支持AVX指令集,并且包括unit tests的PaddlePaddle,可以:
提交你的代码时,pre-commit 钩子会检查本地代码是否存在
不适合提交的东西,等等。
## 提交(Commit) ```bash
➜ docker run -v $(pwd):/paddle -e "WITH_GPU=OFF" -e "WITH_AVX=ON" -e "WITH_TEST=ON" paddle:dev
```
提交你的代码 这个过程除了编译PaddlePaddle为 `./build/libpaddle.so`,并且输出一个 `./build/paddle.deb`文件之外,还会输出一个 `build/Dockerfile`。我们只需要运行下面命令把编译好的PaddlePaddle打包成一个*生产镜像*`paddle:prod`
```shell ```bash
# 显示工作树状态 ➜ docker build -t paddle:prod -f build/Dockerfile .
git status
# 添加修改过的文件
git add xx
env EDITOR=vim git commit # 你可以用 vim/nano/emacs 写下你的注释
``` ```
提交信息的第一行是标题,其他行可以添加一些细节(如果有必要的话)。
## 保持 Fork 状态最新 如果要运行所有的单元测试,可以用如下命令:
在拉(pull)你的请求(request)之前,你应该从最新的 PaddlePaddle 同步代码。 ```bash
为此,你需要首先添加远程(remote): ➜ docker run -it -v $(pwd):/paddle paddle:dev bash -c "cd /paddle/build && ctest"
```
```shell 关于构建和测试的更多信息,请参见[这篇文档](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/getstarted/build_and_install/docker_install_cn.rst)
# 观察当前远程仓库配置
git remote -v ## 提交(commit)
# 添加上游(upstream)仓库
git remote add upstream https://github.com/PaddlePaddle/Paddle.git 接下来我们取消对 README.md 文件的改变,然后提交新添加的 test 文件。
# 验证新的 upstream
git remote -v ```bash
➜ git checkout -- README.md
➜ git status
On branch test
Untracked files:
(use "git add <file>..." to include in what will be committed)
test
nothing added to commit but untracked files present (use "git add" to track)
➜ git add test
```
Git 每次提交代码,都需要写提交说明,这可以让其他人知道这次提交做了哪些改变,这可以通过`git commit` 完成。
```bash
➜ git commit
CRLF end-lines remover...............................(no files to check)Skipped
yapf.................................................(no files to check)Skipped
Check for added large files..............................................Passed
Check for merge conflicts................................................Passed
Check for broken symlinks................................................Passed
Detect Private Key...................................(no files to check)Skipped
Fix End of Files.....................................(no files to check)Skipped
clang-formater.......................................(no files to check)Skipped
[my-cool-stuff c703c041] add test file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 233
```
## 保持本地仓库最新
在准备发起 Pull Request 之前,需要同步原仓库(<https://github.com/PaddlePaddle/Paddle>)最新的代码。
首先通过 `git remote` 查看当前远程仓库的名字。
```bash
➜ git remote
origin
➜ git remote -v
origin https://github.com/USERNAME/Paddle (fetch)
origin https://github.com/USERNAME/Paddle (push)
``` ```
用最新的 upstream 更新你的 fork: 这里 origin 是我们 clone 的远程仓库的名字,也就是自己用户名下的 Paddle,接下来我们创建一个原始 Paddle 仓库的远程主机,命名为 upstream。
```shell ```bash
git pull --rebase upstream develop ➜ git remote add upstream https://github.com/PaddlePaddle/Paddle
➜ git remote
origin
upstream
``` ```
如果本地没有提交,git 将简单地执行快进。但是,如果你一直在做一些改变(绝大多数情况下不应该),你可能要处理冲突。
现在,你的本地主分支与上游修改的一致并是最新的 获取 upstream 的最新代码并更新当前分支
## 推送(Push)到 GitHub ```bash
➜ git fetch upstream
➜ git pull upstream develop
```
## Push 到远程仓库
将本地的修改推送到 GitHub 上,也就是 https://github.com/USERNAME/Paddle。
```shell ```bash
# 在 GitHub 上 push 你的仓库 # 推送到远程仓库 origin 的 my-cool-stuff 分支上
git push -u origin MY_COOL_STUFF_BRANCH # 创建远程分支 MY_COOL_STUFF_BRANCH 到 origin. ➜ git push origin my-cool-stuff
``` ```
## 拉取请求(Pull Request) ## 建立 Issue 并完成 Pull Request
建立一个 Issue 描述问题,并记录它的编号。
切换到所建分支,然后点击 `New pull request`
<img width="295" alt="screen shot 2017-04-26 at 9 09 28 pm" src="https://cloud.githubusercontent.com/assets/11692045/25436054/a6d98c66-2ac4-11e7-9cb1-18dd13150230.png">
转到 GitHub上 你 fork 的页面,选择你的开发分支并单击 **pull request 按钮** 选择目标分支:
## 使用最新版本更新你的 pull 请求 <img width="750" alt="screen shot 2017-04-26 at 9 11 52 pm" src="https://cloud.githubusercontent.com/assets/11692045/25436139/f83b1e6c-2ac4-11e7-8c0e-add499023c46.png">
代码审查(code review)期间,由于 baidu/Paddle 中新的提交导致你的 pull 请求可能会失效。如果没有冲突,GitHub允许自动更新。 你可以点击 pull request 页面中的“更新分支(Update Branch)”按钮。 但是如果存在代码冲突,你需要手动进行更新。你需要在本地仓库执行如下命令: PR 的描述说明中,填写 `resolve #Issue编号` 可以在这个 PR 被 merge 后,自动关闭对应的 Issue,具体请见 <https://help.github.com/articles/closing-issues-via-commit-messages/>
```shell 接下来等待 review,如果有需要修改的地方,参照上述步骤更新 origin 中的对应分支即可。
git checkout MY_COOL_STUFF_BRANCH
git pull upstream develop ## 删除远程分支
# 你可能需要根据git提示解决冲突
# 创建并测试你的代码 在 PR 被 merge 进主仓库后,我们可以在 PR 的页面删除远程仓库的分支。
git push origin MY_COOL_STUFF_BRANCH
<img width="775" alt="screen shot 2017-04-26 at 9 18 24 pm" src="https://cloud.githubusercontent.com/assets/11692045/25436457/e4cdd472-2ac5-11e7-9272-badc76c4a23e.png">
也可以使用 `git push origin :分支名` 删除远程分支,如:
```bash
➜ git push origin :my-cool-stuff
``` ```
现在你的 Pull Request 是最新的了。
## 修改你的 pull request ## 删除本地分支
当根据审阅者的意见修改 pull 请求时,请使用“git commit”而不是“git commit --amend”来提交更改,以便审阅者可以看到新的请求和旧的请求之间的区别 最后,删除本地分支
可能的命令是 ```bash
# 切换到 develop 分支
➜ git checkout develop
```shell # 删除 my-cool-stuff 分支
git checkout MY_COOL_STUFF_BRANCH ➜ git branch -D my-cool-stuff
git pull upstream develop # 将本地更新到最新的代码库
# 可能会发生一些冲突
# 开始开发吧!
env EDITOR=vim git commit # 添加修改日志
git push origin MY_COOL_STUFF_BRANCH
``` ```
至此,我们就完成了一次代码贡献的过程。
...@@ -8,7 +8,8 @@ PaddlePaddle的文档包括英文文档 ``doc`` 和中文文档 ``doc_cn`` 两 ...@@ -8,7 +8,8 @@ PaddlePaddle的文档包括英文文档 ``doc`` 和中文文档 ``doc_cn`` 两
如何构建PaddlePaddle的文档 如何构建PaddlePaddle的文档
========================== ==========================
PaddlePaddle的文档构建有直接构建和基于Docker构建两种方式。构建PaddlePaddle文档需要准备的环境相对较复杂,所以我们推荐使用基于Docker来构建PaddlePaddle的文档。 PaddlePaddle的文档构建有直接构建和基于Docker构建两种方式,我们提供了一个构建脚本build_docs.sh来进行构建。
PaddlePaddle文档需要准备的环境相对较复杂,所以我们推荐使用基于Docker来构建PaddlePaddle的文档。
使用Docker构建PaddlePaddle的文档 使用Docker构建PaddlePaddle的文档
...@@ -16,39 +17,62 @@ PaddlePaddle的文档构建有直接构建和基于Docker构建两种方式。 ...@@ -16,39 +17,62 @@ PaddlePaddle的文档构建有直接构建和基于Docker构建两种方式。
使用Docker构建PaddlePaddle的文档,需要在系统里先安装好Docker工具包。Docker安装请参考 `Docker的官网 <https://docs.docker.com/>`_ 。安装好Docker之后可以使用源码目录下的脚本构建文档,即 使用Docker构建PaddlePaddle的文档,需要在系统里先安装好Docker工具包。Docker安装请参考 `Docker的官网 <https://docs.docker.com/>`_ 。安装好Docker之后可以使用源码目录下的脚本构建文档,即
.. code-block:: bash .. code-block:: bash
cd TO_YOUR_PADDLE_CLONE_PATH cd TO_YOUR_PADDLE_CLONE_PATH
cd paddle/scripts/tools/build_docs cd paddle/scripts/tools/build_docs
bash build_docs.sh bash build_docs.sh with_docker
编译完成后,该目录下会生成如下两个子目录\: 编译完成后,会在当前目录生成两个子目录\:
* doc 英文文档目录 * doc 英文文档目录
* doc_cn 中文文档目录 * doc_cn 中文文档目录
打开浏览器访问对应目录下的index.html即可访问本地文档。 打开浏览器访问对应目录下的index.html即可访问本地文档。
.. code-block:: bash
open doc_cn/index.html
直接构建PaddlePaddle的文档 直接构建PaddlePaddle的文档
-------------------------- --------------------------
TBD 因为PaddlePaddle的v2 api文档生成过程依赖于py_paddle Python包,用户需要首先确认py_paddle包已经安装。
.. code-block:: bash
python -c "import py_paddle"
如果提示错误,那么用户需要在本地编译安装PaddlePaddle,请参考 `源码编译文档 <http://www.paddlepaddle.org/develop/doc/getstarted/build_and_install/build_from_source_en.html>`_ 。
注意,用户在首次编译安装PaddlePaddle时,请将WITH_DOC选项关闭。在编译安装正确之后,请再次确认py_paddle包已经安装,即可进行下一步操作。
如果提示正确,可以执行以下命令编译生成文档,即
.. code-block:: bash
cd TO_YOUR_PADDLE_CLONE_PATH
cd paddle/scripts/tools/build_docs
bash build_docs.sh local
编译完成之后,会在当前目录生成两个子目录\:
* doc 英文文档目录
* doc_cn 中文文档目录
打开浏览器访问对应目录下的index.html即可访问本地文档。
如何书写PaddlePaddle的文档 如何书写PaddlePaddle的文档
========================== ==========================
TBD PaddlePaddle文档使用 `sphinx`_ 自动生成,用户可以参考sphinx教程进行书写。
如何更新www.paddlepaddle.org文档 如何更新www.paddlepaddle.org文档
================================ ================================
TBD 开发者给PaddlePaddle代码增加的注释以PR的形式提交到github中,提交方式可参见 `贡献文档 <http://paddlepaddle.org/develop/doc_cn/howto/dev/contribute_to_paddle_cn.html>`_ 。
目前PaddlePaddle的develop分支的文档是自动触发更新的,用户可以分别查看最新的 `中文文档 <http://www.paddlepaddle.org/develop/doc_cn/>`_ 和
`英文文档 <http://www.paddlepaddle.org/develop/doc/>`_ 。
.. _cmake: https://cmake.org/ .. _cmake: https://cmake.org/
.. _sphinx: http://www.sphinx-doc.org/en/1.4.8/ .. _sphinx: http://www.sphinx-doc.org/en/1.4.8/
...@@ -14,20 +14,18 @@ limitations under the License. */ ...@@ -14,20 +14,18 @@ limitations under the License. */
#pragma once #pragma once
#include <paddle/parameter/Argument.h>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include "ModelConfig.pb.h" #include "ModelConfig.pb.h"
#include "paddle/function/Function.h" #include "paddle/function/Function.h"
#include "paddle/gserver/activations/ActivationFunction.h"
#include "paddle/math/CpuSparseMatrix.h" #include "paddle/math/CpuSparseMatrix.h"
#include "paddle/parameter/Argument.h"
#include "paddle/parameter/Parameter.h" #include "paddle/parameter/Parameter.h"
#include "paddle/parameter/Weight.h"
#include "paddle/utils/ClassRegistrar.h" #include "paddle/utils/ClassRegistrar.h"
#include "paddle/utils/Util.h" #include "paddle/utils/Util.h"
#include <paddle/parameter/ParallelParameter.h>
#include <paddle/parameter/Weight.h>
#include "paddle/gserver/activations/ActivationFunction.h"
/// Macro for registering a layer type. /// Macro for registering a layer type.
/// Example: REGISTER_LAYER(crf_error, CRFDecodingErrorLayer); /// Example: REGISTER_LAYER(crf_error, CRFDecodingErrorLayer);
#define REGISTER_LAYER(__type_name, __class_name) \ #define REGISTER_LAYER(__type_name, __class_name) \
......
...@@ -14,6 +14,7 @@ limitations under the License. */ ...@@ -14,6 +14,7 @@ limitations under the License. */
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <paddle/gserver/gradientmachines/GradientMachine.h> #include <paddle/gserver/gradientmachines/GradientMachine.h>
#include <paddle/parameter/ParameterUpdateFunctions.h>
#include <paddle/trainer/Trainer.h> #include <paddle/trainer/Trainer.h>
#include <paddle/trainer/TrainerInternal.h> #include <paddle/trainer/TrainerInternal.h>
#include <paddle/utils/PythonUtil.h> #include <paddle/utils/PythonUtil.h>
......
...@@ -570,7 +570,7 @@ void Argument::poolSequenceWithStride(const Argument& input, ...@@ -570,7 +570,7 @@ void Argument::poolSequenceWithStride(const Argument& input,
CHECK(input.sequenceStartPositions); CHECK(input.sequenceStartPositions);
CHECK_EQ(input.hasSubseq(), 0UL); CHECK_EQ(input.hasSubseq(), 0UL);
CHECK_GT(stride, 0) << "stride must larger than 0"; CHECK_GT(stride, 0UL) << "stride must larger than 0";
size_t numSequences = input.getNumSequences(); size_t numSequences = input.getNumSequences();
ICpuGpuVector::resizeOrCreate( ICpuGpuVector::resizeOrCreate(
sequenceStartPositions, numSequences + 1, false); sequenceStartPositions, numSequences + 1, false);
......
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#include <fstream>
#include "paddle/utils/Logging.h"
#include "ParallelParameter.h"
namespace paddle {
UpdateFunction paramUpdateFunctions[UPDATE_TYPE_NUM] = {
nullptr, // &ParallelParameter::singleUpdate, /* single thread */
nullptr, // &ParallelParameter::controlUpdate, /* controller thread */
&ParallelParameter::majorUpdate, /* major thread */
&ParallelParameter::minorUpdate, /* minor thread */
nullptr, /* master */
&ParallelParameter::slaveUpdate, /* slave */
};
ParallelParameterPtr ParallelParameter::create(TrainerRole role,
ParameterPtr localParam,
int asyncCount) {
ParallelParameterPtr ptr = nullptr;
switch (role) {
case TRAINER_ROLE_CONTROL:
case TRAINER_ROLE_MAJOR:
case TRAINER_ROLE_MINOR:
ptr = std::make_shared<SyncParameter>(role, localParam);
break;
case TRAINER_ROLE_MASTER:
case TRAINER_ROLE_SLAVE:
ptr = std::make_shared<AsyncParameter>(role, asyncCount, localParam);
break;
default:
LOG(FATAL) << "unknown role " << role << "\n";
}
return ptr;
}
void ParallelParameter::syncUpdate(TrainerRole role, real learnRate) {
if (paramUpdateFunctions[role]) {
(this->*paramUpdateFunctions[role])(learnRate);
}
}
void SyncParameter::attachControlParam(ParallelParameterPtr controler) {
controlParam_ = controler;
}
void SyncParameter::attachMajorParam(ParallelParameterPtr partner) {
majorPartners_.push_back(partner);
if (role_ == TRAINER_ROLE_CONTROL) {
localParam_->setSharedCount(majorPartners_.size());
}
// partnerParam_ = partner;
}
void SyncParameter::attachMinorParam(ParallelParameterPtr partner,
int deviceId) {
minorPartners_.push_back(partner);
minorDeviceIds_.push_back(deviceId);
// partnerParam_ = partner;
}
void SyncParameter::waitAllMajorGradReady() {
for (size_t i = 0; i < majorPartners_.size(); i++) {
majorPartners_[i]->waitGradReady();
partnerParam_ = majorPartners_[i]->getLocalParameter();
VectorPtr localGrad = localParam_->getBuf(PARAMETER_GRADIENT);
VectorPtr patnrGrad = partnerParam_->getBuf(PARAMETER_GRADIENT);
if (FLAGS_use_gpu) hl_set_device(minorDeviceIds_[i]);
localGrad->add(*patnrGrad);
}
}
void SyncParameter::synchronizeParamter() {
valueSem_->wait();
if (role_ == TRAINER_ROLE_MINOR) {
/* copy the value from controller */
VectorPtr cntrlVec =
(controlParam_->getLocalParameter())->getBuf(PARAMETER_VALUE);
VectorPtr localVec = localParam_->getBuf(PARAMETER_VALUE);
localVec->copyFrom(*cntrlVec);
/* dispatch the value to major */
for (size_t i = 0; i < majorPartners_.size(); i++) {
VectorPtr majorVec =
(majorPartners_[i]->getLocalParameter())->getBuf(PARAMETER_VALUE);
majorVec->copyFrom(*localVec);
majorPartners_[i]->postValueReady();
}
}
}
void SyncParameter::singleUpdate(real learnRate) {
CHECK(role_ == TRAINER_ROLE_SINGLE);
localParam_->updateWithGradient(learnRate);
}
void SyncParameter::controlUpdate(const UpdateCallback &callBack) {
CHECK(role_ == TRAINER_ROLE_CONTROL);
CHECK(gradSem_ != NULL && valueSem_ != NULL);
CHECK(majorPartners_.size());
/* update */
if (callBack) {
callBack(localParam_.get());
localParam_->clearGradient();
}
for (size_t i = 0; i < minorPartners_.size(); i++) {
minorPartners_[i]->postValueReady();
}
}
void SyncParameter::majorUpdate(real learnRate) {
(void)learnRate;
CHECK(role_ == TRAINER_ROLE_MAJOR);
CHECK(gradSem_ != NULL && valueSem_ != NULL);
CHECK(minorPartners_.size() && controlParam_);
/* wait the minor-Gradient is ready */
for (size_t i = 0; i < minorPartners_.size(); i++) {
minorPartners_[i]->waitGradReady();
partnerParam_ = minorPartners_[i]->getLocalParameter();
VectorPtr localGrad = localParam_->getBuf(PARAMETER_GRADIENT);
VectorPtr minorGrad = partnerParam_->getBuf(PARAMETER_GRADIENT);
localGrad->add(*minorGrad);
}
/* notice the controller that the gradient is ready */
gradSem_->post();
}
void SyncParameter::minorUpdate(real learnRate) {
(void)learnRate;
CHECK(role_ == TRAINER_ROLE_MINOR);
CHECK(gradSem_ != NULL && valueSem_ != NULL);
// notice the major that the gradient is ready
gradSem_->post();
}
AsyncParameter::AsyncParameter(TrainerRole role,
int asyncCount,
ParameterPtr localParam)
: ParallelParameter(role, localParam) {
asyncCount_ = asyncCount;
accumCounter_ = 0;
gradientAccum_ = Vector::create(localParam->getSize(), localParam->useGpu());
gradientAccum_->zeroMem();
}
void AsyncParameter::slaveUpdate(real learnRate) {
/* increase the accumCounter_ */
accumCounter_++;
/* accumulate the gradient to the buffer */
VectorPtr grad = localParam_->getBuf(PARAMETER_GRADIENT);
gradientAccum_->add(*grad);
/* if need to be synchronized with the master */
if (accumCounter_ == asyncCount_) {
gradSem_->post();
// accumCounter_ = 0; NOTICE: the upper-function need to reset the counter
} else { // self update
localParam_->updateWithGradient(learnRate);
}
localParam_->clearGradient();
}
bool AsyncParameter::masterUpdate(ParallelParameterPtr slaveParam,
const UpdateCallback &callback) {
CHECK(slaveParam && callback);
/* wait the slave is ready */
if (!slaveParam->timeWaitGradReady(5)) {
return false;
}
AsyncParameter *asyncParam = dynamic_cast<AsyncParameter *>(slaveParam.get());
/* get the accum-gradient to update local parameter */
VectorPtr slaveVec = asyncParam->getAccum();
localParam_->getBuf(PARAMETER_GRADIENT)->copyFrom(*slaveVec);
callback(localParam_.get());
// slaveVec->zeroMem();
/* copy the newest parameter-value to the slave */
slaveVec = (slaveParam->getLocalParameter())->getBuf(PARAMETER_VALUE);
slaveVec->copyFrom(*(localParam_->getBuf(PARAMETER_VALUE)));
/* release the semphore */
slaveParam->postValueReady();
return true;
}
} // namespace paddle
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#pragma once
#include <stdint.h>
#include <sys/time.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <vector>
#include "hl_gpu.h"
#include "paddle/math/Vector.h"
#include "paddle/parameter/Parameter.h"
#include "paddle/parameter/ParameterUpdateFunctions.h"
#include "paddle/utils/Common.h"
#include "paddle/utils/Flags.h"
#include "paddle/utils/Locks.h"
#include "ParameterConfig.pb.h"
namespace paddle {
class ParallelParameter;
class SyncParameter;
class AsyncParameter;
typedef std::shared_ptr<ParallelParameter> ParallelParameterPtr;
const int UPDATE_TYPE_NUM = 32;
/**
* TrainRole denotes the role of current training, different roles have
* different jobs.
*
* control, major, minor are three kinds of role to support mutiple GPUs
* parallel SGD training. SM on GPU card has two groups, each group
* consist of a major and a minor.
*
* @param single single GPU card single thread training.
*
*
* @param control current parameter updates via control role,
* not participate in real training. control role is
* responsible for merging all major's gradient and
* update parameter value.
*
* @param major major role paticipates in real training, when local
* gradient is ready, merge its corresponding minor's
* gradient and notify controller: this group's gradient
* is already ready.
*
* @param minor minor role participates in real training, when local
* gradient is ready, only notify its corresponding major.
* In order to maximum apportion jobs, after controller
* updates the paramemter value, each group's minior
* reponses to dispatch the latest model into local and
* major.
*/
enum TrainerRole {
TRAINER_ROLE_SINGLE,
TRAINER_ROLE_CONTROL,
TRAINER_ROLE_MAJOR,
TRAINER_ROLE_MINOR,
TRAINER_ROLE_MASTER,
TRAINER_ROLE_SLAVE
};
typedef void (ParallelParameter::*UpdateFunction)(real learnRate);
class ParallelParameter {
public:
static ParallelParameterPtr create(TrainerRole role,
ParameterPtr localParam,
int asyncCount = 1);
ParallelParameter(TrainerRole role, ParameterPtr localParam) {
role_ = role;
gradSem_.reset(new Semaphore(0));
valueSem_.reset(new Semaphore(0));
localParam_ = localParam;
}
virtual ~ParallelParameter() {}
ParameterPtr getLocalParameter() { return localParam_; }
bool timeWaitGradReady(int sec) {
struct timespec ts;
ts.tv_nsec = 0;
ts.tv_sec = time(NULL) + sec;
return gradSem_->timeWait(&ts);
}
void waitGradReady() { gradSem_->wait(); }
void postValueReady() { valueSem_->post(); }
void syncUpdate(TrainerRole role, real learnRate);
virtual void synchronizeParamter() = 0;
/**
* for synchronous
*/
virtual void singleUpdate(real learnRate) { (void)learnRate; }
virtual void controlUpdate(const UpdateCallback& callback) { (void)callback; }
virtual void majorUpdate(real learnRate) { (void)learnRate; }
virtual void minorUpdate(real learnRate) { (void)learnRate; }
/**
* for asynchronous
*/
virtual void slaveUpdate(real learnRate) { (void)learnRate; }
protected:
TrainerRole role_;
ParameterPtr localParam_;
std::unique_ptr<Semaphore>
gradSem_; /// wether the local parameter-gradient is ready
std::unique_ptr<Semaphore>
valueSem_; /// wether the local parameter-value is updated
};
/**
* this class is designed for multi-threading training.
*
* "Synchronous" means multiple GPUs calculate 1/4 mini-Batch,
* but will get only one gradient
*/
class SyncParameter : public ParallelParameter {
public:
SyncParameter(TrainerRole role, ParameterPtr localParam)
: ParallelParameter(role, localParam) {
controlParam_ = nullptr;
majorPartners_.clear();
minorPartners_.clear();
}
~SyncParameter() {
majorPartners_.clear();
minorPartners_.clear();
}
void attachControlParam(ParallelParameterPtr controler);
void attachMajorParam(ParallelParameterPtr partner);
void attachMinorParam(ParallelParameterPtr partner, int deviceId);
void waitAllMajorGradReady();
void synchronizeParamter();
void singleUpdate(real learnRate);
void controlUpdate(const UpdateCallback& callback);
void majorUpdate(real learnRate);
void minorUpdate(real learnRate);
std::vector<ParallelParameterPtr>& getMajorPartners() {
return majorPartners_;
}
std::vector<ParallelParameterPtr>& getMinorPartners() {
return minorPartners_;
}
private:
// The following variables are used in a multithreaded training situation
// partnerParam_ is local-parameter's partner
// controlParam_ is the controller-thread 's parameter
ParameterPtr partnerParam_;
std::vector<ParallelParameterPtr> majorPartners_;
std::vector<ParallelParameterPtr> minorPartners_;
std::vector<int> minorDeviceIds_;
ParallelParameterPtr controlParam_;
};
class AsyncParameter : public ParallelParameter {
public:
AsyncParameter(TrainerRole role, int asyncCount, ParameterPtr localParam);
void clearCounter() { accumCounter_ = 0; }
VectorPtr getAccum() { return gradientAccum_; }
void synchronizeParamter() {
if (accumCounter_ == asyncCount_) {
valueSem_->wait();
clearCounter();
gradientAccum_->zeroMem();
}
}
/**
* When asynchronous training, update strategy including slave and master.
*
* slave: If in range asyncCount, adopting self-update method.
* If beyond asyncCount, waiting for master to update.
*/
void slaveUpdate(real learnRate);
/**
* When asynchronous training, update strategy including slave and master.
*
* master: it only polls slaves, do not training data.
* If slave's gradient is ready, fetch it.
* Update master's parameter, then copy it into
* corresponding slave.
*/
bool masterUpdate(ParallelParameterPtr slaveParam,
const UpdateCallback& callback);
private:
/**
* When asynchronous training, every aysnc trainer needs to
* accumulate a number of batch gradient.
*
* gradientAccum_ is used to save the sum of gradients.
*/
VectorPtr gradientAccum_;
/// Asynchronous count.
int asyncCount_;
/// Accumulate counter of current gradients.
int accumCounter_;
};
typedef std::map<std::string, ParallelParameterPtr> ParallelParameterMap;
} // namespace paddle
...@@ -271,55 +271,6 @@ SparsePrefetchRowCpuMatrix* Parameter::getPrefetchMatrix() { ...@@ -271,55 +271,6 @@ SparsePrefetchRowCpuMatrix* Parameter::getPrefetchMatrix() {
return nullptr; return nullptr;
} }
void Parameter::updateWithGradient(real learningRate) {
sgdUpdate(learningRate * config_.learning_rate(),
config_.momentum(),
config_.decay_rate(),
bufs_[PARAMETER_VALUE].get(),
bufs_[PARAMETER_GRADIENT].get(),
bufs_[PARAMETER_MOMENTUM].get());
}
void Parameter::updateWithGradient(real learningRate,
MatrixPtr gradMat,
IVectorPtr t0,
int currentTime,
bool fini) {
SparseRowCpuMatrix* sparseMat =
dynamic_cast<SparseRowCpuMatrix*>(gradMat.get());
CHECK(sparseMat);
CHECK_EQ(config_.momentum(), 0.0f)
<< "not support momentum in sparse input sgd";
bool useL1 = (config_.decay_rate_l1() != 0.0f);
sparseMat->sgdUpdate(*bufs_[PARAMETER_VALUE],
*t0,
learningRate * config_.learning_rate(),
currentTime,
useL1 ? config_.decay_rate_l1() : config_.decay_rate(),
useL1,
fini);
}
void Parameter::updateWithGradient(real learningRate,
VectorPtr gradVec,
bool normalUpdate) {
if (normalUpdate) {
sgdUpdate(learningRate * config_.learning_rate(),
config_.momentum(),
config_.decay_rate(),
bufs_[PARAMETER_VALUE].get(),
gradVec.get(),
bufs_[PARAMETER_MOMENTUM].get());
} else {
size_t size = gradVec->getSize();
real* mom = bufs_[PARAMETER_MOMENTUM]->getData();
real* grad = gradVec->getData();
real* value = bufs_[PARAMETER_VALUE]->getData();
hl_matrix_add(mom, grad, mom, 1, size, 1.0f, learningRate);
hl_matrix_add(value, grad, value, 1, size, 1.0f, learningRate);
}
}
void Parameter::incUpdate(const UpdateCallback& callback) { void Parameter::incUpdate(const UpdateCallback& callback) {
// Static parameter is fixed, and does not need to be updated // Static parameter is fixed, and does not need to be updated
if (isStatic()) { if (isStatic()) {
......
...@@ -223,29 +223,6 @@ public: ...@@ -223,29 +223,6 @@ public:
bool isValueUpdated() const { return updated_; } bool isValueUpdated() const { return updated_; }
/**
* Update bufs_[PARAMETER_VALUE] using bufs_[PARAMETER_GRADIENT]
*/
void updateWithGradient(real learningRate);
/**
* Update bufs_[PARAMETER_VALUE] using sparse row grad matrix.
*
* @see SparseRowCpuMatrix::sgdUpdate for more information.
*/
void updateWithGradient(real learningRate,
MatrixPtr gradMat,
IVectorPtr t0,
int currentTime,
bool fini = false);
/**
* This function is used to calculate multiple gpus, but only as a candidate
*/
void updateWithGradient(real learningRate,
VectorPtr grad,
bool normalUpdate = true);
/** /**
* Save parameter value to a file * Save parameter value to a file
*/ */
......
...@@ -58,6 +58,7 @@ _USAGE = """ ...@@ -58,6 +58,7 @@ _USAGE = """
Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
[--counting=total|toplevel|detailed] [--root=subdir] [--counting=total|toplevel|detailed] [--root=subdir]
[--linelength=digits] [--linelength=digits]
[--write-success=success_status_file]
<file> [file] ... <file> [file] ...
The style guidelines this tries to follow are those in The style guidelines this tries to follow are those in
...@@ -499,6 +500,8 @@ _line_length = 80 ...@@ -499,6 +500,8 @@ _line_length = 80
# This is set by --extensions flag. # This is set by --extensions flag.
_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh']) _valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh'])
_write_success = None
def ParseNolintSuppressions(filename, raw_line, linenum, error): def ParseNolintSuppressions(filename, raw_line, linenum, error):
"""Updates the global list of error-suppressions. """Updates the global list of error-suppressions.
...@@ -6337,7 +6340,7 @@ def ParseArguments(args): ...@@ -6337,7 +6340,7 @@ def ParseArguments(args):
try: try:
(opts, filenames) = getopt.getopt(args, '', [ (opts, filenames) = getopt.getopt(args, '', [
'help', 'output=', 'verbose=', 'counting=', 'filter=', 'root=', 'help', 'output=', 'verbose=', 'counting=', 'filter=', 'root=',
'linelength=', 'extensions=' 'linelength=', 'extensions=', 'write-success='
]) ])
except getopt.GetoptError: except getopt.GetoptError:
PrintUsage('Invalid arguments.') PrintUsage('Invalid arguments.')
...@@ -6382,6 +6385,9 @@ def ParseArguments(args): ...@@ -6382,6 +6385,9 @@ def ParseArguments(args):
_valid_extensions = set(val.split(',')) _valid_extensions = set(val.split(','))
except ValueError: except ValueError:
PrintUsage('Extensions must be comma seperated list.') PrintUsage('Extensions must be comma seperated list.')
elif opt == '--write-success':
global _write_success
_write_success = val
if not filenames: if not filenames:
PrintUsage('No files were specified.') PrintUsage('No files were specified.')
...@@ -6408,6 +6414,10 @@ def main(): ...@@ -6408,6 +6414,10 @@ def main():
ProcessFile(filename, _cpplint_state.verbose_level) ProcessFile(filename, _cpplint_state.verbose_level)
_cpplint_state.PrintErrorCounts() _cpplint_state.PrintErrorCounts()
if _cpplint_state.error_count == 0 and _write_success is not None:
with open(_write_success, 'a'):
os.utime(_write_success, None)
sys.exit(_cpplint_state.error_count > 0) sys.exit(_cpplint_state.error_count > 0)
......
...@@ -119,7 +119,7 @@ Users can specify the following Docker build arguments with either "ON" or "OFF" ...@@ -119,7 +119,7 @@ Users can specify the following Docker build arguments with either "ON" or "OFF"
The following command builds the production image: The following command builds the production image:
```bash ```bash
docker build -t paddle -f build/Dockerfile . docker build -t paddle -f build/Dockerfile ./build
``` ```
This production image is minimal -- it includes binary `paddle`, the shared library `libpaddle.so`, and Python runtime. This production image is minimal -- it includes binary `paddle`, the shared library `libpaddle.so`, and Python runtime.
......
...@@ -57,7 +57,13 @@ if [ ${WITH_DOC} == "ON" ]; then ...@@ -57,7 +57,13 @@ if [ ${WITH_DOC} == "ON" ]; then
-DWITH_SWIG_PY=ON \ -DWITH_SWIG_PY=ON \
-DWITH_STYLE_CHECK=OFF -DWITH_STYLE_CHECK=OFF
make paddle_docs paddle_docs_cn make paddle_docs paddle_docs_cn
DOC_DIR="/paddle/paddle/scripts/tools/build_docs/"
mkdir -p $DOC_DIR/doc
mkdir -p $DOC_DIR/doc_cn
cp -r /paddle/build_doc/doc/en/html/* $DOC_DIR/doc
cp -r /paddle/build_doc/doc/cn/html/* $DOC_DIR/doc_cn
popd popd
rm -rf /paddle/build_doc
fi fi
# generate deb package for current build # generate deb package for current build
# FIXME(typhoonzero): should we remove paddle/scripts/deb ? # FIXME(typhoonzero): should we remove paddle/scripts/deb ?
...@@ -110,7 +116,7 @@ RUN ${MIRROR_UPDATE} ...@@ -110,7 +116,7 @@ RUN ${MIRROR_UPDATE}
pip install --upgrade pip && \ pip install --upgrade pip && \
pip install -U 'protobuf==3.1.0' requests numpy pip install -U 'protobuf==3.1.0' requests numpy
# Use different deb file when building different type of images # Use different deb file when building different type of images
ADD build/*.deb /usr/local/opt/paddle/deb/ ADD *.deb /usr/local/opt/paddle/deb/
# run paddle version to install python packages first # run paddle version to install python packages first
RUN dpkg -i /usr/local/opt/paddle/deb/*.deb && \ RUN dpkg -i /usr/local/opt/paddle/deb/*.deb && \
rm -f /usr/local/opt/paddle/deb/*.deb && \ rm -f /usr/local/opt/paddle/deb/*.deb && \
......
FROM paddledev/paddle:cpu-devel-latest
COPY build.sh /
RUN pip install sphinx &&\
pip install sphinx_rtd_theme &&\
apt install -y doxygen graphviz &&\
pip install recommonmark numpy protobuf==2.6.1
CMD /build.sh
#!/bin/bash
set -ex
mkdir -p /build
cd /build
cmake /paddle -DWITH_DOC=ON
make paddle_docs paddle_docs_cn -j `nproc`
mkdir -p /output/doc
mkdir -p /output/doc_cn
cp -r doc/html/* /output/doc/
cp -r doc_cn/html/* /output/doc_cn/
cd /
rm -rf /paddle/build
#!/bin/bash #!/bin/bash
set -e set -e
docker build . -t paddle_build_doc function usage(){
docker run --rm -v $PWD/../../../../:/paddle -v $PWD:/output paddle_build_doc echo "usage: build_doc [--help] [<args>]"
echo "This script generates doc and doc_cn in the script's directory."
echo "These are common commands used in various situations:"
echo " with_docker build doc and doc_cn with docker"
echo " local build doc and doc_cn locally"
}
case "$1" in
"with_docker")
docker run --rm -v $PWD/../../../../:/paddle \
-e "WITH_GPU=OFF" -e "WITH_AVX=ON" -e "WITH_DOC=ON" paddledev/paddle:dev
;;
"local")
mkdir -p doc
mkdir -p doc_cn
PADDLE_SOURCE_DIR=$PWD/../../../../
mkdir -p $PADDLE_SOURCE_DIR/build_doc
pushd $PADDLE_SOURCE_DIR/build_doc
cmake .. -DWITH_DOC=ON
make paddle_docs paddle_docs_cn
popd
cp -r $PADDLE_SOURCE_DIR/build_doc/doc/en/html/* doc
cp -r $PADDLE_SOURCE_DIR/build_doc/doc/cn/html/* doc_cn
rm -rf $PADDLE_SOURCE_DIR/build_doc
;;
"--help")
usage
;;
*)
usage
;;
esac
...@@ -17,14 +17,17 @@ add_test(NAME test_Trainer ...@@ -17,14 +17,17 @@ add_test(NAME test_Trainer
WORKING_DIRECTORY ${PROJ_ROOT}/paddle/) WORKING_DIRECTORY ${PROJ_ROOT}/paddle/)
############### test_TrainerOnePass ########################## ############### test_TrainerOnePass ##########################
add_unittest_without_exec(test_TrainerOnePass if(WITH_PYTHON)
test_TrainerOnePass.cpp) # only run test_TrainerOnePass when PYTHON is enabled, because train one pass
add_test(NAME test_TrainerOnePass # is using PyDataProvider2.
COMMAND ${PROJ_ROOT}/paddle/.set_python_path.sh -d add_unittest_without_exec(test_TrainerOnePass
${PROJ_ROOT}/python/:${PROJ_ROOT}/paddle/trainer/tests test_TrainerOnePass.cpp)
${PROJ_ROOT}/paddle/.set_port.sh -p port ${CMAKE_CURRENT_BINARY_DIR}/test_TrainerOnePass add_test(NAME test_TrainerOnePass
WORKING_DIRECTORY ${PROJ_ROOT}/paddle/) COMMAND ${PROJ_ROOT}/paddle/.set_python_path.sh -d
${PROJ_ROOT}/python/:${PROJ_ROOT}/paddle/trainer/tests
${PROJ_ROOT}/paddle/.set_port.sh -p port ${CMAKE_CURRENT_BINARY_DIR}/test_TrainerOnePass
WORKING_DIRECTORY ${PROJ_ROOT}/paddle/)
endif()
################ test_CompareTwoNets ###################### ################ test_CompareTwoNets ######################
add_unittest_without_exec(test_CompareTwoNets add_unittest_without_exec(test_CompareTwoNets
test_CompareTwoNets.cpp) test_CompareTwoNets.cpp)
......
...@@ -24,9 +24,12 @@ add_custom_target(paddle_python ALL DEPENDS ...@@ -24,9 +24,12 @@ add_custom_target(paddle_python ALL DEPENDS
${OUTPUT_DIR}/.timestamp) ${OUTPUT_DIR}/.timestamp)
add_subdirectory(paddle/trainer_config_helpers/tests) add_subdirectory(paddle/trainer_config_helpers/tests)
add_subdirectory(paddle/v2/tests) if (WITH_SWIG_PY)
add_subdirectory(paddle/v2/reader/tests) # enable v2 API unittest only when paddle swig api is compiled
add_subdirectory(paddle/v2/plot/tests) add_subdirectory(paddle/v2/tests)
add_subdirectory(paddle/v2/reader/tests)
add_subdirectory(paddle/v2/plot/tests)
endif()
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dist/ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dist/
DESTINATION opt/paddle/share/wheels DESTINATION opt/paddle/share/wheels
......
...@@ -1349,9 +1349,9 @@ def last_seq(input, ...@@ -1349,9 +1349,9 @@ def last_seq(input,
""" """
Get Last Timestamp Activation of a sequence. Get Last Timestamp Activation of a sequence.
If stride > 0, this layer slides a window whose size is determined by stride, If stride > 0, this layer slides a window whose size is determined by stride,
and return the last value of the window as the output. Thus, a long sequence and return the last value of the window as the output. Thus, a long sequence
will be shorten. Note that for sequence with sub-sequence, the default value will be shorten. Note that for sequence with sub-sequence, the default value
of stride is -1. of stride is -1.
The simple usage is: The simple usage is:
...@@ -1365,7 +1365,7 @@ def last_seq(input, ...@@ -1365,7 +1365,7 @@ def last_seq(input,
:type name: basestring :type name: basestring
:param input: Input layer name. :param input: Input layer name.
:type input: LayerOutput :type input: LayerOutput
:param stride: window size. :param stride: window size.
:type stride: Int :type stride: Int
:param layer_attr: extra layer attributes. :param layer_attr: extra layer attributes.
:type layer_attr: ExtraLayerAttribute. :type layer_attr: ExtraLayerAttribute.
...@@ -1405,9 +1405,9 @@ def first_seq(input, ...@@ -1405,9 +1405,9 @@ def first_seq(input,
""" """
Get First Timestamp Activation of a sequence. Get First Timestamp Activation of a sequence.
If stride > 0, this layer slides a window whose size is determined by stride, If stride > 0, this layer slides a window whose size is determined by stride,
and return the first value of the window as the output. Thus, a long sequence and return the first value of the window as the output. Thus, a long sequence
will be shorten. Note that for sequence with sub-sequence, the default value will be shorten. Note that for sequence with sub-sequence, the default value
of stride is -1. of stride is -1.
The simple usage is: The simple usage is:
...@@ -1421,7 +1421,7 @@ def first_seq(input, ...@@ -1421,7 +1421,7 @@ def first_seq(input,
:type name: basestring :type name: basestring
:param input: Input layer name. :param input: Input layer name.
:type input: LayerOutput :type input: LayerOutput
:param stride: window size. :param stride: window size.
:type stride: Int :type stride: Int
:param layer_attr: extra layer attributes. :param layer_attr: extra layer attributes.
:type layer_attr: ExtraLayerAttribute. :type layer_attr: ExtraLayerAttribute.
...@@ -1561,7 +1561,7 @@ def seq_reshape_layer(input, ...@@ -1561,7 +1561,7 @@ def seq_reshape_layer(input,
bias_attr=None): bias_attr=None):
""" """
A layer for reshaping the sequence. Assume the input sequence has T instances, A layer for reshaping the sequence. Assume the input sequence has T instances,
the dimension of each instance is M, and the input reshape_size is N, then the the dimension of each instance is M, and the input reshape_size is N, then the
output sequence has T*M/N instances, the dimension of each instance is N. output sequence has T*M/N instances, the dimension of each instance is N.
Note that T*M/N must be an integer. Note that T*M/N must be an integer.
...@@ -2118,8 +2118,8 @@ def img_conv_layer(input, ...@@ -2118,8 +2118,8 @@ def img_conv_layer(input,
:param trans: true if it is a convTransLayer, false if it is a convLayer :param trans: true if it is a convTransLayer, false if it is a convLayer
:type trans: bool :type trans: bool
:param layer_type: specify the layer_type, default is None. If trans=True, :param layer_type: specify the layer_type, default is None. If trans=True,
layer_type has to be "exconvt" or "cudnn_convt", layer_type has to be "exconvt" or "cudnn_convt",
otherwise layer_type has to be either "exconv" or otherwise layer_type has to be either "exconv" or
"cudnn_conv" "cudnn_conv"
:type layer_type: String :type layer_type: String
:return: LayerOutput object. :return: LayerOutput object.
...@@ -2337,9 +2337,9 @@ def spp_layer(input, ...@@ -2337,9 +2337,9 @@ def spp_layer(input,
.. code-block:: python .. code-block:: python
spp = spp_layer(input=data, spp = spp_layer(input=data,
pyramid_height=2, pyramid_height=2,
num_channels=16, num_channels=16,
pool_type=MaxPooling()) pool_type=MaxPooling())
:param name: layer name. :param name: layer name.
...@@ -2433,7 +2433,7 @@ def img_cmrnorm_layer(input, ...@@ -2433,7 +2433,7 @@ def img_cmrnorm_layer(input,
The example usage is: The example usage is:
.. code-block:: python .. code-block:: python
norm = img_cmrnorm_layer(input=net, size=5) norm = img_cmrnorm_layer(input=net, size=5)
:param name: layer name. :param name: layer name.
...@@ -2494,7 +2494,7 @@ def batch_norm_layer(input, ...@@ -2494,7 +2494,7 @@ def batch_norm_layer(input,
The example usage is: The example usage is:
.. code-block:: python .. code-block:: python
norm = batch_norm_layer(input=net, act=ReluActivation()) norm = batch_norm_layer(input=net, act=ReluActivation())
:param name: layer name. :param name: layer name.
...@@ -2795,11 +2795,11 @@ def seq_concat_layer(a, b, act=None, name=None, layer_attr=None, ...@@ -2795,11 +2795,11 @@ def seq_concat_layer(a, b, act=None, name=None, layer_attr=None,
""" """
Concat sequence a with sequence b. Concat sequence a with sequence b.
Inputs: Inputs:
- a = [a1, a2, ..., an] - a = [a1, a2, ..., an]
- b = [b1, b2, ..., bn] - b = [b1, b2, ..., bn]
- Note that the length of a and b should be the same. - Note that the length of a and b should be the same.
Output: [a1, b1, a2, b2, ..., an, bn] Output: [a1, b1, a2, b2, ..., an, bn]
The example usage is: The example usage is:
...@@ -3563,9 +3563,15 @@ def beam_search(step, ...@@ -3563,9 +3563,15 @@ def beam_search(step,
simple_rnn += last_time_step_output simple_rnn += last_time_step_output
return simple_rnn return simple_rnn
generated_word_embedding = GeneratedInput(
size=target_dictionary_dim,
embedding_name="target_language_embedding",
embedding_size=word_vector_dim)
beam_gen = beam_search(name="decoder", beam_gen = beam_search(name="decoder",
step=rnn_step, step=rnn_step,
input=[StaticInput(encoder_last)], input=[StaticInput(encoder_last),
generated_word_embedding],
bos_id=0, bos_id=0,
eos_id=1, eos_id=1,
beam_size=5) beam_size=5)
...@@ -3584,7 +3590,8 @@ def beam_search(step, ...@@ -3584,7 +3590,8 @@ def beam_search(step,
You can refer to the first parameter of recurrent_group, or You can refer to the first parameter of recurrent_group, or
demo/seqToseq/seqToseq_net.py for more details. demo/seqToseq/seqToseq_net.py for more details.
:type step: callable :type step: callable
:param input: Input data for the recurrent unit :param input: Input data for the recurrent unit, which should include the
previously generated words as a GeneratedInput object.
:type input: list :type input: list
:param bos_id: Index of the start symbol in the dictionary. The start symbol :param bos_id: Index of the start symbol in the dictionary. The start symbol
is a special token for NLP task, which indicates the is a special token for NLP task, which indicates the
......
...@@ -13,6 +13,9 @@ packages=['paddle', ...@@ -13,6 +13,9 @@ packages=['paddle',
setup(name='paddle', setup(name='paddle',
version='${PADDLE_VERSION}', version='${PADDLE_VERSION}',
description='Parallel Distributed Deep Learning', description='Parallel Distributed Deep Learning',
install_requires=[
"requests",
],
packages=packages, packages=packages,
package_dir={ package_dir={
'': '${CMAKE_CURRENT_SOURCE_DIR}' '': '${CMAKE_CURRENT_SOURCE_DIR}'
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册