提交 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 |
......@@ -14,8 +14,8 @@
cmake_minimum_required(VERSION 3.0)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
set(PROJ_ROOT ${CMAKE_SOURCE_DIR})
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
set(PROJ_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
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
......@@ -51,10 +51,14 @@ macro(add_style_check_target TARGET_NAME)
endif()
endforeach()
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
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})
endif()
endforeach()
......
......@@ -18,7 +18,8 @@ FUNCTION(build_protobuf TARGET_NAME BUILD_FOR_HOST)
SET(PROTOBUF_SOURCES_DIR ${THIRD_PARTY_PATH}/${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
"${PROTOBUF_INSTALL_DIR}/lib/libprotobuf-lite${STATIC_LIBRARY_SUFFIX}"
PARENT_SCOPE)
......@@ -81,7 +82,7 @@ IF(NOT CMAKE_CROSSCOMPILING)
IF(PROTOBUF_FOUND)
EXEC_PROGRAM(${PROTOBUF_PROTOC_EXECUTABLE} ARGS --version OUTPUT_VARIABLE 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)
ENDIF()
ENDIF(PROTOBUF_FOUND)
......
......@@ -13,79 +13,108 @@
### 训练数据的存储
选择GlusterFS作为训练数据的存储服务(后续的实现考虑HDFS)
选择CephFS作为训练数据的存储服务
在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分隔开)
转换生成的文件名会是以下格式
```
./data/image1.jpg 1
./data/image2.jpg 5
./data/image3.jpg 2
./data/image4.jpg 5
./data/image5.jpg 1
./data/image6.jpg 8
...
```text
name_prefix-aaaaa-of-bbbbb
```
对于文本类训练数据样例如下(机器翻译),一行中包含源语言,目标语言的文本(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
reader = paddle.dist.reader("dataset-name")
trainer.train(reader, ...)
batch_reader = paddle.batch(paddle.dataset.mnist.train(), 128)
trainer.train(batch_reader, ...)
yield 1 # 单个值
yield numpy.random.uniform(-1, 1, size=28*28) # 单个值
yield numpy.random.uniform(-1, 1, size=28*28), 0 # 多个值
```
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
if os.getenv("PADDLE_TRAIN_LOCAL"):
reader = my_local_reader("dataset-name")
else:
reader = paddle.dist.reader("dataset-name")
# ...
reader = paddle.reader.creator.SSTable("/home/random_images-*-of-*")
batch_reader = paddle.batch(paddle.dataset.mnist.train(), 128)
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
### 支持将数据合并成内部的文件格式(key-value),方便sharding与顺序读取
### 支持用户自定义的数据预处理job
......@@ -4,16 +4,26 @@ PaddlePaddle的Docker容器使用方式
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版本。
我们会在 `dockerhub.com <https://hub.docker.com/r/paddledev/paddle/>`_ 提供最新的docker镜像,可以在"tags"标签下找到最新的Paddle镜像版本。
我们把PaddlePaddle的编译环境打包成一个镜像,称为开发镜像,里面涵盖了
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`
这个镜像包含了Paddle相关的开发工具以及编译和运行环境。用户可以使用开发镜像代替配置本地环境,完成开发,编译,发布,
文档编写等工作。由于不同的Paddle的版本可能需要不同的依赖和工具,所以如果需要自行配置开发环境需要考虑版本的因素。
开发镜像包含了以下工具:
- gcc/clang
- nvcc
- Python
......@@ -27,7 +37,7 @@ PaddlePaddle发布的docker镜像使用说明
.. code-block:: bash
docker run -it --rm paddledev/paddle:<version>-dev /bin/bash
docker run -it --rm paddlepaddle/paddle:<version>-dev /bin/bash
或者,可以以后台进程方式运行容器:
......@@ -43,7 +53,8 @@ PaddlePaddle发布的docker镜像使用说明
SSH方式的一个优点是我们可以从多个终端进入容器。比如,一个终端运行vi,另一个终端运行Python。另一个好处是我们可以把PaddlePaddle容器运行在远程服务器上,并在笔记本上通过SSH与其连接。
2. 运行镜像:根据CPU、GPU和非AVX区分了如下4个镜像:
2. 生产镜像:根据CPU、GPU和非AVX区分了如下4个镜像:
- GPU/AVX::code:`paddlepaddle/paddle:<version>-gpu`
- GPU/no-AVX::code:`paddlepaddle/paddle:<version>-gpu-noavx`
- CPU/AVX::code:`paddlepaddle/paddle:<version>`
......@@ -72,25 +83,33 @@ PaddlePaddle发布的docker镜像使用说明
export DEVICES=$(\ls /dev/nvidia* | xargs -I{} echo '--device {}:{}')
docker run ${CUDA_SO} ${DEVICES} -it paddledev/paddle:<version>-gpu
3. 使用运行镜像发布你的AI程序
3. 运行以及发布您的AI程序
假设您已经完成了一个AI训练的python程序 :code:`a.py`,这个程序是您在开发机上使用开发镜像完成开发。此时您可以运行这个命令在开发机上进行测试运行:
.. code-block:: bash
docker run -it -v $PWD:/work paddle /work/a.py
如果要使用GPU,请运行:
.. code-block:: bash
nvidia-docker run -it -v $PWD:/work paddle /work/a.py
这里`a.py`包含的所有依赖假设都可以在Paddle的运行容器中。如果需要包含更多的依赖、或者需要发布您的应用的镜像,可以编写`Dockerfile`使用`FROM paddledev/paddle:<version>`
创建和发布自己的AI程序镜像。
运行PaddlePaddle书籍
运行PaddlePaddle Book
---------------------
Jupyter Notebook是一个开源的web程序,大家可以通过它制作和分享带有代码、公式、图表、文字的交互式文档。用户可以通过网页浏览文档。
PaddlePaddle书籍是为用户和开发者制作的一个交互式的Jupyter Nodebook。
如果您想要更深入了解deep learning,PaddlePaddle书籍一定是您最好的选择。
PaddlePaddle Book是为用户和开发者制作的一个交互式的Jupyter Nodebook。
如果您想要更深入了解deep learning,PaddlePaddle Book一定是您最好的选择。
我们提供可以直接运行PaddlePaddle书籍的docker镜像,直接运行:
我们提供可以直接运行PaddlePaddle Book的Docker镜像,直接运行:
.. code-block:: bash
......@@ -109,53 +128,44 @@ PaddlePaddle书籍是为用户和开发者制作的一个交互式的Jupyter Nod
开发人员可以在Docker开发镜像中开发PaddlePaddle。这样开发人员可以以一致的方式在不同的平台上工作 - Linux,Mac OS X和Windows。
1. 构建开发镜像
1. 制作PaddlePaddle开发镜像
PaddlePaddle每次发布新版本都会发布对应的开发镜像供开发者直接使用。这里介绍如生成造这个开发镜像。
生成Docker镜像的方式有两个,一个是直接把一个容器转换成镜像,另一个是创建Dockerfile并运行docker build指令按照Dockerfile生成镜像。第一个方法的好处是简单快捷,适合自己实验,可以快速迭代。第二个方法的好处是Dockerfile可以把整个生成流程描述很清楚,其他人很容易看懂镜像生成过程,持续集成系统也可以简单地复现这个过程。我们采用第二个方法。Dockerfile位于PaddlePaddle repo的根目录。生成生产镜像只需要运行:
.. code-block:: bash
git clone --recursive https://github.com/PaddlePaddle/Paddle
git clone https://github.com/PaddlePaddle/Paddle.git
cd Paddle
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
docker run -d -p 2202:22 -v $PWD:/paddle paddle:dev sshd
docker run -v $(pwd):/paddle -e "WITH_GPU=OFF" -e "WITH_AVX=OFF" -e "WITH_TEST=ON" paddle:dev
以上代码会启动一个带有PaddlePaddle开发环境的docker容器,源代码会被挂载到 :code:`/paddle`
以上命令会编译PaddlePaddle,生成运行程序,以及生成创建生产镜像的Dockerfile。所有生成的的文件都在build目录下。“WITH_GPU”控制生成的生产镜像是否支持GPU,“WITH_AVX”控制生成的生产镜像是否支持AVX,”WITH_TEST“控制是否生成单元测试
以上的 :code:`docker run` 命令其实会启动一个在2202端口监听的SSHD服务器。这样,我们就能SSH进入我们的开发容器了
第二步是运行
.. code-block:: bash
ssh root@localhost -p 2202
docker build -t paddle:prod -f build/Dockerfile ./build
3. 在Docker开发环境中编译与安装PaddlPaddle代码
以上命令会按照生成的Dockerfile把生成的程序拷贝到生产镜像中并做相应的配置,最终生成名为paddle:prod的生产镜像。
当在容器里面的时候,可以用脚本 :code:`paddle/scripts/docker/build.sh` 来编译、安装与测试PaddlePaddle:
3. 运行单元测试
.. code-block:: bash
/paddle/paddle/scripts/docker/build.sh
以上指令会在 :code:`/paddle/build` 中编译PaddlePaddle。通过以下指令可以运行单元测试:
运行以下指令:
.. code-block:: bash
cd /paddle/build
ctest
docker run -it -v $(pwd):/paddle paddle:dev bash -c "cd /paddle/build && ctest"
文档
----
......
......@@ -53,12 +53,20 @@ Docker is simple as long as we understand a few basic concepts:
Usage of CPU-only and GPU Images
----------------------------------
For each version of PaddlePaddle, we release two types of Docker images:
development image and production image. Production image includes
CPU-only version and a CUDA GPU version and their no-AVX versions. We
put the docker images on `dockerhub.com
We package PaddlePaddle's compile environment into a Docker image,
called the develop image, it contains all compiling tools that
PaddlePaddle needs. We package compiled PaddlePaddle program into a
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
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:
......@@ -179,59 +187,40 @@ Develop PaddlePaddle or Train Model Using C++ API
We will be using PaddlePaddle development image since it contains all
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:
.. code-block:: bash
git clone https://github.com/PaddlePaddle/Paddle.git && cd Paddle
docker build -t paddle:dev .
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:
2. Build PaddlePaddle production image
- run interactive bash directly
There are two steps for building production image, the first step is to run:
.. 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
.. code-block:: bash
docker run -v $(pwd):/paddle -e "WITH_GPU=OFF" -e "WITH_AVX=OFF" -e "WITH_TEST=ON" paddle:dev
# use nvidia-docker instead of docker if you need to use GPU
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
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.
and SSH to this container using password :code:`root`:
The second step is to run:
.. code-block:: bash
ssh -p 2202 root@localhost
docker build -t paddle:prod -f build/Dockerfile ./build
An advantage is that we can run the PaddlePaddle container on a
remote server and SSH to it from a laptop.
The above command will generate the production image by copying the compiled PaddlePaddle program into the image.
When developing PaddlePaddle, you can edit PaddlePaddle source code
from outside of docker container using your favoriate editor. To
compile PaddlePaddle, run inside container:
3. Run unit test
.. code-block:: bash
WITH_GPU=OFF WITH_AVX=ON WITH_TEST=ON bash /paddle/paddle/scripts/docker/build.sh
This builds everything about Paddle in :code:`/paddle/build`. And we
can run unit tests there:
Following command will run unit test:
.. code-block:: bash
cd /paddle/build
ctest
.. code-block:: bash
When training model using C++ API, we can edit paddle program in
~/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
------------------
......
......@@ -3,128 +3,217 @@
我们真诚地感谢您的贡献,欢迎通过 GitHub 的 fork 和 pull request 流程来提交代码。
## 代码要求
- 你的代码必须完全遵守 [doxygen](http://www.stack.nl/~dimitri/doxygen/) 的样式。
- 确保编译器选项 WITH\_STYLE\_CHECK 已打开,并且编译能通过代码样式检查。
- 代码注释请遵守 [Doxygen](http://www.stack.nl/~dimitri/doxygen/) 的样式。
- 确保编译器选项 `WITH_STYLE_CHECK` 已打开,并且编译能通过代码样式检查。
- 所有代码必须具有单元测试。
- 通过所有单元测试。
以下教程将指导您提交代码。
## [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)
Paddle 目前使用[git流分支模型](http://nvie.com/posts/a-successful-git-branching-model/)进行开发,测试,发行和维护。
**develop** 是主分支,其他用户分支是特征分支(feature branches)。
将远程仓库 clone 到本地:
```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
# 克隆 fork 到本地
git clone --branch develop https://github.com/USERNAME/Paddle.git
使用 `git checkout -b` 创建并切换到新分支。
```bash
➜ git checkout -b my-cool-stuff
```
如果你的仓库不包含 **develop** 分支,你只需自己创建它。
```shell
git clone https://github.com/USERNAME/Paddle.git Paddle
cd Paddle
git checkout -b develop # 创建 develop 分支
git remote add upstream https://github.com/PaddlePaddle/Paddle.git # 添加 upstream 到 baidu/Paddle
git pull upstream develop # 更新 upstream
值得注意的是,在 checkout 之前,需要保持当前分支目录 clean,否则会把 untracked 的文件也带到新分支上,这可以通过 `git status` 查看。
## 使用 `pre-commit` 钩子
Paddle 开发人员使用 [pre-commit](http://pre-commit.com/) 工具来管理 Git 预提交钩子。 它可以帮助我们格式化源代码(C++,Python),在提交(commit)前自动检查一些基本事宜(如每个文件只有一个 EOL,Git 中不要添加大文件等)。
`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`来代替。
如要build这个开发镜像,在源码目录树的根目录中运行:
```bash
➜ docker build -t paddle:dev .
```
Paddle 开发人员使用 [pre-commit](http://pre-commit.com/) 工具来管理git预提交钩子。 它可以帮助我们格式化源代码(cpp,python),在提交前检查一些基本事宜(每个文件只有一个 EOL
,git 中不要添加大文件)。 `pre-commit`测试是 Travis-CI 中单元测试的一部分,不满足钩子
的 PR 不能提交代码到 Paddle。
随后可以用这个开发镜像开build PaddlePaddle的源码。比如如果要build一个不依赖GPU,但是支持AVX指令集,并且包括unit tests的PaddlePaddle,可以:
你可以通过 `pip install pre-commit` 安装 [pre-commit](http://pre-commit.com/)
目前 Paddle 使用 `clang-format` 来调整C/C++源代码格式。请确保 clang-format 版本在3.8以上。
```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`):
```bash
➜ docker build -t paddle:prod -f build/Dockerfile .
```
如果要运行所有的单元测试,可以用如下命令:
```bash
➜ docker run -it -v $(pwd):/paddle paddle:dev bash -c "cd /paddle/build && ctest"
```
关于构建和测试的更多信息,请参见[这篇文档](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/getstarted/build_and_install/docker_install_cn.rst)
## 提交(commit)
然后只需在 Paddle clone 目录中运行 `pre-commit install` 。当你
提交你的代码时,pre-commit 钩子会检查本地代码是否存在
不适合提交的东西,等等。
接下来我们取消对 README.md 文件的改变,然后提交新添加的 test 文件。
## 提交(Commit)
```bash
➜ git checkout -- README.md
➜ git status
On branch test
Untracked files:
(use "git add <file>..." to include in what will be committed)
提交你的代码:
test
```shell
# 显示工作树状态
git status
# 添加修改过的文件
git add xx
env EDITOR=vim git commit # 你可以用 vim/nano/emacs 写下你的注释
nothing added to commit but untracked files present (use "git add" to track)
➜ git add test
```
提交信息的第一行是标题,其他行可以添加一些细节(如果有必要的话)。
## 保持 Fork 状态最新
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>)最新的代码。
在拉(pull)你的请求(request)之前,你应该从最新的 PaddlePaddle 同步代码。
为此,你需要首先添加远程(remote):
首先通过 `git remote` 查看当前远程仓库的名字。
```shell
# 观察当前远程仓库配置
git remote -v
# 添加上游(upstream)仓库
git remote add upstream https://github.com/PaddlePaddle/Paddle.git
# 验证新的 upstream
git remote -v
```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
git pull --rebase upstream develop
```bash
➜ 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
# 在 GitHub 上 push 你的仓库
git push -u origin MY_COOL_STUFF_BRANCH # 创建远程分支 MY_COOL_STUFF_BRANCH 到 origin.
```bash
# 推送到远程仓库 origin 的 my-cool-stuff 分支上
➜ 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
git checkout MY_COOL_STUFF_BRANCH
git pull upstream develop
# 你可能需要根据git提示解决冲突
# 创建并测试你的代码
git push origin MY_COOL_STUFF_BRANCH
接下来等待 review,如果有需要修改的地方,参照上述步骤更新 origin 中的对应分支即可。
## 删除远程分支
在 PR 被 merge 进主仓库后,我们可以在 PR 的页面删除远程仓库的分支。
<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
git checkout MY_COOL_STUFF_BRANCH
git pull upstream develop # 将本地更新到最新的代码库
# 可能会发生一些冲突
# 开始开发吧!
env EDITOR=vim git commit # 添加修改日志
git push origin MY_COOL_STUFF_BRANCH
# 删除 my-cool-stuff 分支
➜ git branch -D my-cool-stuff
```
至此,我们就完成了一次代码贡献的过程。
......@@ -8,7 +8,8 @@ PaddlePaddle的文档包括英文文档 ``doc`` 和中文文档 ``doc_cn`` 两
如何构建PaddlePaddle的文档
==========================
PaddlePaddle的文档构建有直接构建和基于Docker构建两种方式。构建PaddlePaddle文档需要准备的环境相对较复杂,所以我们推荐使用基于Docker来构建PaddlePaddle的文档。
PaddlePaddle的文档构建有直接构建和基于Docker构建两种方式,我们提供了一个构建脚本build_docs.sh来进行构建。
PaddlePaddle文档需要准备的环境相对较复杂,所以我们推荐使用基于Docker来构建PaddlePaddle的文档。
使用Docker构建PaddlePaddle的文档
......@@ -20,34 +21,57 @@ PaddlePaddle的文档构建有直接构建和基于Docker构建两种方式。
cd TO_YOUR_PADDLE_CLONE_PATH
cd paddle/scripts/tools/build_docs
bash build_docs.sh
bash build_docs.sh with_docker
编译完成后,该目录下会生成如下两个子目录\:
编译完成后,会在当前目录生成两个子目录\:
* doc 英文文档目录
* doc_cn 中文文档目录
打开浏览器访问对应目录下的index.html即可访问本地文档。
.. code-block:: bash
open doc_cn/index.html
直接构建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的文档
==========================
TBD
PaddlePaddle文档使用 `sphinx`_ 自动生成,用户可以参考sphinx教程进行书写。
如何更新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/
......
......@@ -14,20 +14,18 @@ limitations under the License. */
#pragma once
#include <paddle/parameter/Argument.h>
#include <functional>
#include <memory>
#include "ModelConfig.pb.h"
#include "paddle/function/Function.h"
#include "paddle/gserver/activations/ActivationFunction.h"
#include "paddle/math/CpuSparseMatrix.h"
#include "paddle/parameter/Argument.h"
#include "paddle/parameter/Parameter.h"
#include "paddle/parameter/Weight.h"
#include "paddle/utils/ClassRegistrar.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.
/// Example: REGISTER_LAYER(crf_error, CRFDecodingErrorLayer);
#define REGISTER_LAYER(__type_name, __class_name) \
......
......@@ -14,6 +14,7 @@ limitations under the License. */
#include <gtest/gtest.h>
#include <paddle/gserver/gradientmachines/GradientMachine.h>
#include <paddle/parameter/ParameterUpdateFunctions.h>
#include <paddle/trainer/Trainer.h>
#include <paddle/trainer/TrainerInternal.h>
#include <paddle/utils/PythonUtil.h>
......
......@@ -570,7 +570,7 @@ void Argument::poolSequenceWithStride(const Argument& input,
CHECK(input.sequenceStartPositions);
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();
ICpuGpuVector::resizeOrCreate(
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() {
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) {
// Static parameter is fixed, and does not need to be updated
if (isStatic()) {
......
......@@ -223,29 +223,6 @@ public:
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
*/
......
......@@ -58,6 +58,7 @@ _USAGE = """
Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
[--counting=total|toplevel|detailed] [--root=subdir]
[--linelength=digits]
[--write-success=success_status_file]
<file> [file] ...
The style guidelines this tries to follow are those in
......@@ -499,6 +500,8 @@ _line_length = 80
# This is set by --extensions flag.
_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh'])
_write_success = None
def ParseNolintSuppressions(filename, raw_line, linenum, error):
"""Updates the global list of error-suppressions.
......@@ -6337,7 +6340,7 @@ def ParseArguments(args):
try:
(opts, filenames) = getopt.getopt(args, '', [
'help', 'output=', 'verbose=', 'counting=', 'filter=', 'root=',
'linelength=', 'extensions='
'linelength=', 'extensions=', 'write-success='
])
except getopt.GetoptError:
PrintUsage('Invalid arguments.')
......@@ -6382,6 +6385,9 @@ def ParseArguments(args):
_valid_extensions = set(val.split(','))
except ValueError:
PrintUsage('Extensions must be comma seperated list.')
elif opt == '--write-success':
global _write_success
_write_success = val
if not filenames:
PrintUsage('No files were specified.')
......@@ -6408,6 +6414,10 @@ def main():
ProcessFile(filename, _cpplint_state.verbose_level)
_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)
......
......@@ -119,7 +119,7 @@ Users can specify the following Docker build arguments with either "ON" or "OFF"
The following command builds the production image:
```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.
......
......@@ -57,7 +57,13 @@ if [ ${WITH_DOC} == "ON" ]; then
-DWITH_SWIG_PY=ON \
-DWITH_STYLE_CHECK=OFF
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
rm -rf /paddle/build_doc
fi
# generate deb package for current build
# FIXME(typhoonzero): should we remove paddle/scripts/deb ?
......@@ -110,7 +116,7 @@ RUN ${MIRROR_UPDATE}
pip install --upgrade pip && \
pip install -U 'protobuf==3.1.0' requests numpy
# 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 dpkg -i /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
set -e
docker build . -t paddle_build_doc
docker run --rm -v $PWD/../../../../:/paddle -v $PWD:/output paddle_build_doc
function usage(){
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
WORKING_DIRECTORY ${PROJ_ROOT}/paddle/)
############### test_TrainerOnePass ##########################
add_unittest_without_exec(test_TrainerOnePass
if(WITH_PYTHON)
# only run test_TrainerOnePass when PYTHON is enabled, because train one pass
# is using PyDataProvider2.
add_unittest_without_exec(test_TrainerOnePass
test_TrainerOnePass.cpp)
add_test(NAME test_TrainerOnePass
add_test(NAME test_TrainerOnePass
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 ######################
add_unittest_without_exec(test_CompareTwoNets
test_CompareTwoNets.cpp)
......
......@@ -24,9 +24,12 @@ add_custom_target(paddle_python ALL DEPENDS
${OUTPUT_DIR}/.timestamp)
add_subdirectory(paddle/trainer_config_helpers/tests)
add_subdirectory(paddle/v2/tests)
add_subdirectory(paddle/v2/reader/tests)
add_subdirectory(paddle/v2/plot/tests)
if (WITH_SWIG_PY)
# enable v2 API unittest only when paddle swig api is compiled
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/
DESTINATION opt/paddle/share/wheels
......
......@@ -3563,9 +3563,15 @@ def beam_search(step,
simple_rnn += last_time_step_output
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",
step=rnn_step,
input=[StaticInput(encoder_last)],
input=[StaticInput(encoder_last),
generated_word_embedding],
bos_id=0,
eos_id=1,
beam_size=5)
......@@ -3584,7 +3590,8 @@ def beam_search(step,
You can refer to the first parameter of recurrent_group, or
demo/seqToseq/seqToseq_net.py for more details.
: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
:param bos_id: Index of the start symbol in the dictionary. The start symbol
is a special token for NLP task, which indicates the
......
......@@ -13,6 +13,9 @@ packages=['paddle',
setup(name='paddle',
version='${PADDLE_VERSION}',
description='Parallel Distributed Deep Learning',
install_requires=[
"requests",
],
packages=packages,
package_dir={
'': '${CMAKE_CURRENT_SOURCE_DIR}'
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册