提交 0dc7c256 编写于 作者: T typhoonzero

Merge branch 'develop' of https://github.com/PaddlePaddle/FluidDoc into add_dist_howto

.. _api_guide_executor:
########
Executor
########
......@@ -5,7 +7,7 @@ Executor
:code:`Executor` 即 :code:`执行器` 。PaddlePaddle Fluid中有两种执行器可以选择。
:code:`Executor` 实现了一个简易的执行器,所有Operator会被顺序执行。用户可以使用
Python脚本驱动 :code:`Executor` 执行。默认情况下 :code:`Executor` 是单线程的,如果
想使用数据并行,请参考另一个执行器, :ref:`api_guide_low_level_parallel_executor` 。
想使用数据并行,请参考另一个执行器, :ref:`api_guide_parallel_executor` 。
:code:`Executor` 的代码逻辑非常简单。建议用户在调试过程中,先使用
:code:`Executor` 跑通模型,再切换到多设备计算,甚至多机计算。
......
.. _api_guide_low_level_parallel_executor:
.. _api_guide_parallel_executor:
################
ParallelExecutor
......
########
输入输出
########
.. _api_guide_reader:
Reader相关API
#############
\ No newline at end of file
.. _api_guide_lod_tensor:
#########
LoDTensor
#########
############
RecordIO文件
############
RecordIO转换API
###############
.. _api_guide_recordio_file_format:
RecordIO文件格式
################
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_average:
=============
fluid.average
=============
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_backward:
==============
fluid.backward
==============
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_clip:
==========
fluid.clip
==========
......@@ -41,19 +43,3 @@ GradientClipByGlobalNorm
:members:
:noindex:
.. _api_fluid_clip_append_gradient_clip_ops:
append_gradient_clip_ops
------------------------
.. autofunction:: paddle.fluid.clip.append_gradient_clip_ops
:noindex:
.. _api_fluid_clip_error_clip_callback:
error_clip_callback
-------------------
.. autofunction:: paddle.fluid.clip.error_clip_callback
:noindex:
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_data_feeder:
=================
fluid.data_feeder
=================
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_executor:
==============
fluid.executor
==============
......@@ -30,12 +32,12 @@ scope_guard
.. autofunction:: paddle.fluid.executor.scope_guard
:noindex:
.. _api_fluid_executor_switch_scope:
.. _api_fluid_executor__switch_scope:
switch_scope
------------
_switch_scope
-------------
.. autofunction:: paddle.fluid.executor.switch_scope
.. autofunction:: paddle.fluid.executor._switch_scope
:noindex:
.. _api_fluid_executor_fetch_var:
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid:
=====
fluid
=====
......@@ -65,22 +67,6 @@ program_guard
.. autofunction:: paddle.fluid.program_guard
:noindex:
.. _api_fluid_switch_startup_program:
switch_startup_program
----------------------
.. autofunction:: paddle.fluid.switch_startup_program
:noindex:
.. _api_fluid_switch_main_program:
switch_main_program
-------------------
.. autofunction:: paddle.fluid.switch_main_program
:noindex:
.. _api_fluid_get_var:
get_var
......@@ -114,12 +100,12 @@ scope_guard
.. autofunction:: paddle.fluid.scope_guard
:noindex:
.. _api_fluid_switch_scope:
.. _api_fluid__switch_scope:
switch_scope
------------
_switch_scope
-------------
.. autofunction:: paddle.fluid.switch_scope
.. autofunction:: paddle.fluid._switch_scope
:noindex:
.. _api_fluid_fetch_var:
......@@ -243,6 +229,15 @@ Inferencer
:members:
:noindex:
.. _api_fluid_DistributeTranspiler:
DistributeTranspiler
--------------------
.. autoclass:: paddle.fluid.DistributeTranspiler
:members:
:noindex:
.. _api_fluid_memory_optimize:
memory_optimize
......@@ -374,3 +369,12 @@ DataFeeder
:members:
:noindex:
.. _api_fluid_Scope:
Scope
-----
.. autoclass:: paddle.fluid.Scope
:members:
:noindex:
......@@ -48,7 +48,7 @@ class DocGenerator(object):
!DO NOT EDIT THIS FILE MANUALLY!
''')
self._print_ref_raw_("_".join(self.module_name.split(".")))
self._print_header_(self.module_name, dot='=', is_title=True)
def print_submodule(self, submodule_name):
......@@ -107,9 +107,10 @@ class DocGenerator(object):
self.stream.write('\n')
def _print_ref_(self, name):
self.stream.write(".. _api_{0}_{1}:\n\n".format(
"_".join(self.module_name.split(".")), name
))
self._print_ref_raw_("_".join(self.module_name.split(".") + [name]))
def _print_ref_raw_(self, anchor):
self.stream.write(".. _api_{0}:\n\n".format(anchor))
def main():
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_initializer:
=================
fluid.initializer
=================
......@@ -50,6 +52,15 @@ Bilinear
:members:
:noindex:
.. _api_fluid_initializer_MSRA:
MSRA
----
.. autoclass:: paddle.fluid.initializer.MSRA
:members:
:noindex:
.. _api_fluid_initializer_force_init_on_cpu:
force_init_on_cpu
......@@ -111,3 +122,12 @@ BilinearInitializer
:members:
:noindex:
.. _api_fluid_initializer_MSRAInitializer:
MSRAInitializer
---------------
.. autoclass:: paddle.fluid.initializer.MSRAInitializer
:members:
:noindex:
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_io:
========
fluid.io
========
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_layers:
============
fluid.layers
============
......@@ -910,6 +912,14 @@ log
.. autofunction:: paddle.fluid.layers.log
:noindex:
.. _api_fluid_layers_crop:
crop
----
.. autofunction:: paddle.fluid.layers.crop
:noindex:
ops
===
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_metrics:
=============
fluid.metrics
=============
......@@ -23,6 +25,24 @@ CompositeMetric
:members:
:noindex:
.. _api_fluid_metrics_Precision:
Precision
---------
.. autoclass:: paddle.fluid.metrics.Precision
:members:
:noindex:
.. _api_fluid_metrics_Recall:
Recall
------
.. autoclass:: paddle.fluid.metrics.Recall
:members:
:noindex:
.. _api_fluid_metrics_Accuracy:
Accuracy
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_nets:
==========
fluid.nets
==========
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_optimizer:
===============
fluid.optimizer
===============
......@@ -59,6 +61,15 @@ DecayedAdagrad
:members:
:noindex:
.. _api_fluid_optimizer_Ftrl:
Ftrl
----
.. autoclass:: paddle.fluid.optimizer.Ftrl
:members:
:noindex:
.. _api_fluid_optimizer_SGDOptimizer:
SGDOptimizer
......@@ -122,6 +133,15 @@ RMSPropOptimizer
:members:
:noindex:
.. _api_fluid_optimizer_FtrlOptimizer:
FtrlOptimizer
-------------
.. autoclass:: paddle.fluid.optimizer.FtrlOptimizer
:members:
:noindex:
.. _api_fluid_optimizer_Adadelta:
Adadelta
......@@ -149,3 +169,12 @@ Optimizer
:members:
:noindex:
.. _api_fluid_optimizer_RMSPropOptimizer:
RMSPropOptimizer
----------------
.. autoclass:: paddle.fluid.optimizer.RMSPropOptimizer
:members:
:noindex:
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_param_attr:
================
fluid.param_attr
================
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_profiler:
==============
fluid.profiler
==============
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_recordio_writer:
=====================
fluid.recordio_writer
=====================
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_regularizer:
=================
fluid.regularizer
=================
......@@ -13,15 +15,6 @@ append_regularization_ops
.. autofunction:: paddle.fluid.regularizer.append_regularization_ops
:noindex:
.. _api_fluid_regularizer_WeightDecayRegularizer:
WeightDecayRegularizer
----------------------
.. autoclass:: paddle.fluid.regularizer.WeightDecayRegularizer
:members:
:noindex:
.. _api_fluid_regularizer_L1Decay:
L1Decay
......
.. THIS FILE IS GENERATED BY `gen_doc.{py|sh}`
!DO NOT EDIT THIS FILE MANUALLY!
.. _api_fluid_transpiler:
================
fluid.transpiler
================
.. _api_fluid_transpiler_DistributeTranspiler:
DistributeTranspiler
--------------------
.. autoclass:: paddle.fluid.transpiler.DistributeTranspiler
:members:
:noindex:
.. _api_fluid_transpiler_memory_optimize:
memory_optimize
......
......@@ -7,6 +7,6 @@
.. toctree::
:maxdepth: 2
install/index.rst
install/install_doc.rst
quick_start/quick_start.rst
basics/theoretical_background.rst
../../../paddle/doc/fluid/build_and_install/build_from_source_cn.rst
\ No newline at end of file
../../../paddle/doc/fluid/build_and_install/docker_install_cn.rst
\ No newline at end of file
.. _quick_start_install:
安装与编译
==========
.. _install_steps:
PaddlePaddle针对不同的用户群体提供了多种安装方式。
专注深度学习模型开发
--------------------
PaddlePaddle提供了多种python wheel包,可通过pip一键安装:
.. toctree::
:maxdepth: 1
pip_install_cn.rst
这是最便捷的安装方式,请根据机器配置和系统选择对应的安装包。
关注底层框架
-------------
PaddlePaddle提供了基于Docker的安装方式,请参照以下教程:
.. toctree::
:maxdepth: 1
docker_install_cn.rst
我们推荐在Docker中运行PaddlePaddle,该方式具有以下优势:
- 无需单独安装第三方依赖
- 方便分享运行时环境,易于问题的复现
对于有定制化二进制文件需求的用户,我们同样提供了从源码编译安装PaddlePaddle的方法:
.. toctree::
:maxdepth: 1
build_from_source_cn.rst
.. warning::
需要提醒的是,这种安装方式会涉及到一些第三方库的下载、编译及安装,整个安装过程耗时较长。
常见问题汇总
--------------
如果在安装过程中遇到了问题,请先尝试在下面的页面寻找答案:
:ref:`常见问题解答 <install_faq>`
如果问题没有得到解决,欢迎向PaddlePaddle社区反馈问题:
`创建issue <https://github.com/PaddlePaddle/Paddle/issues/new>`_
此差异已折叠。
../../../paddle/doc/fluid/build_and_install/pip_install_cn.rst
\ No newline at end of file
.. _user_guide_configure_simple_model:
##############
配置简单的网络
##############
在解决实际问题时,可以先从逻辑层面对问题进行建模,明确模型所需要的 **输入数据类型**、**计算逻辑**、**求解目标** 以及 **优化算法**。PaddlePaddle提供了丰富的算子来实现模型逻辑。下面以一个简单回归任务举例说明如何使用PaddlePaddle构建模型。该例子完整代码参见 `fit_a_line <https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/fluid/tests/book/test_fit_a_line.py>`_。
问题描述及定义
##############
问题描述: 给定一组数据 :math:`<X, Y>`,求解出函数 :math:`f`,使得 :math:`y=f(x)`,其中 :math:`x\subset X` 表示一条样本的特征,为 :math:`13` 维的实数向量;:math:`y \subset Y` 为一实数表示该样本对应的值。
我们可以尝试用回归模型来对问题建模,回归问题的损失函数有很多,这里选择常用的均方误差。为简化问题,这里假定 :math:`f` 为简单的线性变换函数,同时选用随机梯度下降算法来求解模型。
+----------------+----------------------------------------------+
| 输入数据类型 | 样本特征: 13 维 实数 |
+ +----------------------------------------------+
| | 样本标签: 1 维 实数 |
+----------------+----------------------------------------------+
| 计算逻辑 | 使用线性模型,产生 1维实数作为模型的预测输出 |
+----------------+----------------------------------------------+
| 求解目标 | 最小化模型预测输出与样本标签间的均方误差 |
+----------------+----------------------------------------------+
| 优化算法 | 随机梯度下降 |
+----------------+----------------------------------------------+
使用PaddlePadle建模
###################
从逻辑层面明确了输入数据格式、模型结构、损失函数以及优化算法后,需要使用PaddlePaddle提供的API及算子来实现模型逻辑。一个典型的模型主要包含4个部分,分别是:输入数据格式定义,模型前向计算逻辑,损失函数以及优化算法。
数据层
------
PaddlePaddle提供了 :ref:`api_fluid_layers_data` 算子来描述输入数据的格式。
:ref:`api_fluid_layers_data` 算子的输出是一个Variable。这个Variable的实际类型是Tensor。Tensor具有强大的表征能力,可以表示多维数据。为了精确描述数据结构,通常需要指定数据shape以及数值类型type。其中shape为一个整数向量,type可以是一个字符串类型。目前支持的数据类型参考 :ref:`user_guide_paddle_support_data_types` 。 模型训练一般会使用batch的方式读取数据,而batch的size在训练过程中可能不固定。data算子会依据实际数据来推断batch size,所以这里提供shape时不用关心batch size,只需关心一条样本的shape即可,更高级用法请参考 :ref:`user_guide_customize_batch_size_rank`。从上知,:math:`x` 为 :math:`13` 维的实数向量,:math:`y` 为实数,可使用下面代码定义数据层:
.. code-block:: python
x = fluid.layers.data(name='x', shape=[13], dtype='float32')
y = fluid.layers.data(name='y', shape=[1], dtype='float32')
该模型使用的数据比较简单,事实上data算子还可以描述变长的、嵌套的序列数据。也可以使用 :code:`open_files` 打开文件进行训练。更详细的文档可参照 :ref:`user_guide_prepare_data`。
前向计算逻辑
------------
实现一个模型最重要的部分是实现计算逻辑,PaddlePaddle提供了丰富的算子。这些算子的封装粒度不同,通常对应一种或一组变换逻辑。算子输出即为对输入数据执行变换后的结果。用户可以灵活使用算子来完成复杂的模型逻辑。比如图像相关任务中会使用较多的卷积算子、序列任务中会使用LSTM/GRU等算子。复杂模型通常会组合多种算子,以完成复杂的变换。PaddlePaddle提供了非常自然的方式来组合算子,一般地可以使用下面的方式:
.. code-block:: python
op_1_out = fluid.layers.op_1(input=op_1_in, ...)
op_2_out = fluid.layers.op_2(input=op_1_out, ...)
...
其中op_1和op_2表示算子类型,可以是fc来执行线性变换(全连接),也可以是conv来执行卷积变换等。通过算子的输入输出的连接来定义算子的计算顺序以及数据流方向。上面的例子中,op_1的输出是op_2的输入,那么在执行计算时,会先计算op_1,然后计算op_2。更复杂的模型可能需要使用控制流算子,依据输入数据来动态执行,针对这种情况,PaddlePaddle提供了IfElseOp和WhileOp等。算子的文档可参考 :ref:`api_fluid_layers`。具体到这个任务, 我们使用一个fc算子:
.. code-block:: python
y_predict = fluid.layers.fc(input=x, size=1, act=None)
损失函数
--------
损失函数对应求解目标,我们可以通过最小化损失来求解模型。大多数模型使用的损失函数,输出是一个实数值。但是PaddlePaddle提供的损失算子一般是针对一条样本计算。当输入一个batch的数据时,损失算子的输出有多个值,每个值对应一条样本的损失,所以通常会在损失算子后面使用mean等算子,来对损失做归约。模型在一次前向迭代后会得到一个损失值,PaddlePaddle会自动执行链式求导法则计算模型里面每个参数和变量对应的梯度值。这里使用均方误差损失:
.. code-block:: python
cost = fluid.layers.square_error_cost(input=y_predict, label=y)
avg_cost = fluid.layers.mean(cost)
优化方法
--------
确定损失函数后,可以通过前向计算得到损失值,然后通过链式求导法则得到参数的梯度值。获取梯度值后需要更新参数,最简单的算法是随机梯度下降法::math:`w=w - \eta \cdot g`。但是普通的随机梯度下降算法存在一些问题: 比如收敛不稳定等。为了改善模型的训练速度以及效果,学术界先后提出了很多优化算法,包括: :code:`Momentum`、:code:`RMSProp`、:code:`Adam` 等。这些优化算法采用不同的策略来更新模型参数,一般可以针对具体任务和具体模型来选择优化算法。不管使用何种优化算法,学习率一般是一个需要指定的比较重要的超参数,需要通过实验仔细调整。这里采用随机梯度下降算法:
.. code-block:: python
sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.001)
更多优化算子可以参考 :ref:`api_fluid_optimizer` 。
下一步做什么?
##############
使用PaddlePaddle实现模型时需要关注 **数据层**、**前向计算逻辑**、**损失函数** 和 **优化方法**。不同的任务需要的数据格式不同,涉及的计算逻辑不同,损失函数不同,优化方法也不同。PaddlePaddle提供了丰富的模型示例,可以以这些示例为参考来构建自己的模型结构。用户可以访问 `模型库 <https://github.com/PaddlePaddle/models/tree/develop/fluid>`_ 查看官方提供的示例。
......@@ -2,28 +2,11 @@
如何使用PaddlePaddle
####################
.. toctree::
:maxdepth: 2
概述
####
数据预处理
##########
配置简单的网络
##############
训练
####
调试
####
模型评估
########
prepare_data/index
configure_simple_model/index
training/index
.. _user_guide_use_numpy_array_as_train_data:
###########################
使用Numpy Array作为训练数据
###########################
PaddlePaddle Fluid支持使用 :ref:`api_fluid_layers_data` 配置数据层;
再使用 Numpy Array 或者直接使用Python创建C++的
:ref:`api_guide_lod_tensor` , 通过 :code:`Executor.run(feed=...)` 传给
:ref:`api_guide_executor` 或 :ref:`api_guide_parallel_executor` 。
数据层配置
##########
通过 :ref:`api_fluid_layers_data` 可以配置神经网络中需要的数据层。具体方法为:
.. code-block:: python
import paddle.fluid as fluid
image = fluid.layers.data(name="image", shape=[3, 224, 224])
label = fluid.layers.data(name="label", shape=[1], dtype="int64")
# use image/label as layer input
prediction = fluid.layers.fc(input=image, size=1000, act="softmax")
loss = fluid.layers.cross_entropy(input=prediction, label=label)
...
上段代码中,:code:`image` 和 :code:`label` 是通过 :code:`fluid.layers.data`
创建的两个输入数据层。其中 :code:`image` 是 :code:`[3, 224, 224]` 维度的浮点数据;
:code:`label` 是 :code:`[1]` 维度的整数数据。这里需要注意的是:
1. Fluid中默认使用 :code:`-1` 表示 batch size 维度,默认情况下会在 :code:`shape`
的第一个维度添加 :code:`-1` 。 所以 上段代码中, 我们可以接受将一个
:code:`[32, 3, 224, 224]` 的numpy array传给 :code:`image` 。 如果想自定义batch size
维度的位置的话,请设置 :code:`fluid.layers.data(append_batch_size=False)` 。
请参考进阶使用中的 :ref:`user_guide_customize_batch_size_rank` 。
2. Fluid中用来做类别标签的数据类型是 :code:`int64`,并且标签从0开始。可用数据类型请参考 :ref:`user_guide_paddle_support_data_types`。
.. _user_guide_feed_data_to_executor:
传递训练数据给执行器
####################
:code:`Executor.run` 和 :code:`ParallelExecutor.run` 都接受一个 :code:`feed` 参数。
这个参数是一个Python的字典。它的键是数据层的名字,例如上文代码中的 :code:`image`。
它的值是对应的numpy array。
例如:
.. code-block:: python
exe = fluid.Executor(fluid.CPUPlace())
exe.run(feed={
"image": numpy.random.random(size=(32, 3, 224, 224)).astype('float32'),
"label": numpy.random.random(size=(32, 1)).astype('int64')
})
进阶使用
########
如何传入序列数据
----------------
序列数据是PaddlePaddle Fluid支持的特殊数据类型,可以使用 :code:`LoDTensor` 作为
输入数据类型。它需要用户: 1. 传入一个mini-batch需要被训练的所有数据;
2.每个序列的长度信息。
用户可以使用 :code:`fluid.create_lod_tensor` 来创建 :code:`LoDTensor`。
传入序列信息的时候,需要设置序列嵌套深度,:code:`lod_level`。
例如训练数据是词汇组成的句子,:code:`lod_level=1`;训练数据是 词汇先组成了句子,
句子再组成了段落,那么 :code:`lod_level=2`。
例如:
.. code-block:: python
sentence = fluid.layers.data(name="sentence", dtype="int64", shape=[1], lod_level=1)
...
exe.run(feed={
"sentence": create_lod_tensor(
data=numpy.array([1, 3, 4, 5, 3, 6, 8], dtype='int64').reshape(-1, 1),
lod=[4, 1, 2],
place=fluid.CPUPlace()
)
})
训练数据 :code:`sentence` 包含三个样本,他们的长度分别是 :code:`4, 1, 2`。
他们分别是 :code:`data[0:4]`, :code:`data[4:5]` 和 :code:`data[5:7]`。
如何分别设置ParallelExecutor中每个设备的训练数据
------------------------------------------------
用户将数据传递给使用 :code:`ParallelExecutor.run(feed=...)` 时,
可以显示指定每一个训练设备(例如GPU)上的数据。
用户需要将一个列表传递给 :code:`feed` 参数,列表中的每一个元素都是一个字典。
这个字典的键是数据层的名字,值是数据层的值。
例如:
.. code-block:: python
parallel_executor = fluid.ParallelExecutor()
parallel_executor.run(
feed=[
{
"image": numpy.random.random(size=(32, 3, 224, 224)).astype('float32'),
"label": numpy.random.random(size=(32, 1)).astype('int64')
},
{
"image": numpy.random.random(size=(16, 3, 224, 224)).astype('float32'),
"label": numpy.random.random(size=(16, 1)).astype('int64')
},
]
)
上述代码中,GPU0会训练 32 个样本,而 GPU1训练 16 个样本。
.. _user_guide_customize_batch_size_rank:
自定义BatchSize维度
-------------------
PaddlePaddle Fluid默认batch size是数据的第一维度,以 :code:`-1` 表示。但是在高级
使用中,batch_size 可以固定,也可以是其他维度或者多个维度来表示。这都需要设置
:code:`fluid.layers.data(append_batch_size=False)` 来完成。
1. 固定batch size维度
.. code-block:: python
image = fluid.layers.data(name="image", shape=[32, 784], append_batch_size=False)
这里,:code:`image` 永远是一个 :code:`[32, 784]` 大小的矩阵。
2. 使用其他维度表示batch size
.. code-block:: python
sentence = fluid.layers.data(name="sentence",
shape=[80, -1, 1],
append_batch_size=False,
dtype="int64")
这里 :code:`sentence` 的中间维度是batch size。这种数据排布会用在定长的循环神经
网络中。
.. _user_guide_paddle_support_data_types:
Fluid目前支持的数据类型
-----------------------
PaddlePaddle Fluid目前支持的数据类型包括:
* float16: 部分操作支持
* float32: 主要实数类型
* float64: 次要实数类型,支持大部分操作
* int32: 次要标签类型
* int64: 主要标签类型
* uint64: 次要标签类型
* bool: 控制流数据类型
* int16: 次要标签类型
* uint8: 输入数据类型,可用于图像像素
\ No newline at end of file
.. _user_guide_prepare_data:
########
准备数据
########
PaddlePaddle Fluid支持两种传入数据的方式:
1. 用户需要使用 :code:`fluid.layers.data`
配置数据输入层,并在 :ref:`api_guide_executor` 或 :ref:`api_guide_parallel_executor`
中,使用 :code:`executor.run(feed=...)` 传入训练数据。
2. 用户需要先将训练数据
转换成 Paddle 识别的 :ref:`api_guide_recordio_file_format` , 再使用
:code:`fluid.layers.open_files` 以及 :ref:`api_guide_reader` 配置数据读取。
这两种准备数据方法的比较如下:
.. _user_guide_prepare_data_comparision:
+------------+----------------------------------+---------------------------------------+
| | Feed数据 | 使用Reader |
+============+==================================+=======================================+
| API接口 | :code:`executor.run(feed=...)` | :ref:`api_guide_reader` |
+------------+----------------------------------+---------------------------------------+
| 数据格式 | Numpy Array | :ref:`api_guide_recordio_file_format` |
+------------+----------------------------------+---------------------------------------+
| 数据增强 | Python端使用其他库完成 | 使用Fluid中的Operator 完成 |
+------------+----------------------------------+---------------------------------------+
| 速度 | 慢 | 快 |
+------------+----------------------------------+---------------------------------------+
| 推荐用途 | 调试模型 | 工业训练 |
+------------+----------------------------------+---------------------------------------+
这些准备数据的详细使用方法,请参考:
.. toctree::
:maxdepth: 2
feeding_data
use_recordio_reader
Python Reader
#############
为了方便用户在Python中定义数据处理流程,PaddlePaddle Fluid支持 Python Reader,
具体请参考:
.. toctree::
:maxdepth: 2
reader.md
```eval_rst
.. _user_guide_reader:
```
# Python Reader
During the training and testing phases, PaddlePaddle programs need to read data. To help the users write code that performs reading input data, we define the following:
- A *reader*: A function that reads data (from file, network, random number generator, etc) and yields the data items.
- A *reader creator*: A function that returns a reader function.
- A *reader decorator*: A function, which takes in one or more readers, and returns a reader.
- A *batch reader*: A function that reads data (from *reader*, file, network, random number generator, etc) and yields a batch of data items.
and also provide a function which can convert a reader to a batch reader, frequently used reader creators and reader decorators.
## Data Reader Interface
*Data reader* doesn't have to be a function that reads and yields data items. It can just be any function without any parameters that creates an iterable (anything can be used in `for x in iterable`) as follows:
```
iterable = data_reader()
```
The item produced from the iterable should be a **single** entry of data and **not** a mini batch. The entry of data could be a single item or a tuple of items. Item should be of one of the [supported types](http://www.paddlepaddle.org/doc/ui/data_provider/pydataprovider2.html?highlight=dense_vector#input-types) (e.g., numpy 1d array of float32, int, list of int etc.)
An example implementation for single item data reader creator is as follows:
```python
def reader_creator_random_image(width, height):
def reader():
while True:
yield numpy.random.uniform(-1, 1, size=width*height)
return reader
```
An example implementation for multiple item data reader creator is as follows:
```python
def reader_creator_random_image_and_label(width, height, label):
def reader():
while True:
yield numpy.random.uniform(-1, 1, size=width*height), label
return reader
```
## Batch Reader Interface
*Batch reader* can be any function without any parameters that creates an iterable (anything can be used in `for x in iterable`). The output of the iterable should be a batch (list) of data items. Each item inside the list should be a tuple.
Here are some valid outputs:
```python
# a mini batch of three data items. Each data item consist three columns of data, each of which is 1.
[(1, 1, 1),
(2, 2, 2),
(3, 3, 3)]
# a mini batch of three data items, each data item is a list (single column).
[([1,1,1],),
([2,2,2],),
([3,3,3],)]
```
Please note that each item inside the list must be a tuple, below is an invalid output:
```python
# wrong, [1,1,1] needs to be inside a tuple: ([1,1,1],).
# Otherwise it is ambiguous whether [1,1,1] means a single column of data [1, 1, 1],
# or three columns of data, each of which is 1.
[[1,1,1],
[2,2,2],
[3,3,3]]
```
It is easy to convert from a reader to a batch reader:
```python
mnist_train = paddle.dataset.mnist.train()
mnist_train_batch_reader = paddle.batch(mnist_train, 128)
```
It is also straight forward to create a custom batch reader:
```python
def custom_batch_reader():
while True:
batch = []
for i in xrange(128):
batch.append((numpy.random.uniform(-1, 1, 28*28),)) # note that it's a tuple being appended.
yield batch
mnist_random_image_batch_reader = custom_batch_reader
```
## Usage
Following is how we can use the reader with PaddlePaddle:
The batch reader, a mapping from item(s) to data layer, the batch size and the number of total passes will be passed into `paddle.train` as follows:
```python
# two data layer is created:
image_layer = paddle.layer.data("image", ...)
label_layer = paddle.layer.data("label", ...)
# ...
batch_reader = paddle.batch(paddle.dataset.mnist.train(), 128)
paddle.train(batch_reader, {"image":0, "label":1}, 128, 10, ...)
```
## Data Reader Decorator
The *Data reader decorator* takes in a single reader or multiple data readers and returns a new data reader. It is similar to a [python decorator](https://wiki.python.org/moin/PythonDecorators), but it does not use `@` in the syntax.
Since we have a strict interface for data readers (no parameters and return a single data item), a data reader can be used in a flexible way using data reader decorators. Following are a few examples:
### Prefetch Data
Since reading data may take some time and training can not proceed without data, it is generally a good idea to prefetch the data.
Use `paddle.reader.buffered` to prefetch data:
```python
buffered_reader = paddle.reader.buffered(paddle.dataset.mnist.train(), 100)
```
`buffered_reader` will try to buffer (prefetch) `100` data entries.
### Compose Multiple Data Readers
For example, if we want to use a source of real images (say reusing mnist dataset), and a source of random images as input for [Generative Adversarial Networks](https://arxiv.org/abs/1406.2661).
We can do the following :
```python
def reader_creator_random_image(width, height):
def reader():
while True:
yield numpy.random.uniform(-1, 1, size=width*height)
return reader
def reader_creator_bool(t):
def reader:
while True:
yield t
return reader
true_reader = reader_creator_bool(True)
false_reader = reader_creator_bool(False)
reader = paddle.reader.compose(paddle.dataset.mnist.train(), data_reader_creator_random_image(20, 20), true_reader, false_reader)
# Skipped 1 because paddle.dataset.mnist.train() produces two items per data entry.
# And we don't care about the second item at this time.
paddle.train(paddle.batch(reader, 128), {"true_image":0, "fake_image": 2, "true_label": 3, "false_label": 4}, ...)
```
### Shuffle
Given the shuffle buffer size `n`, `paddle.reader.shuffle` returns a data reader that buffers `n` data entries and shuffles them before a data entry is read.
Example:
```python
reader = paddle.reader.shuffle(paddle.dataset.mnist.train(), 512)
```
## Q & A
### Why does a reader return only a single entry, and not a mini batch?
Returning a single entry makes reusing existing data readers much easier (for example, if an existing reader returns 3 entries instead if a single entry, the training code will be more complicated because it need to handle cases like a batch size 2).
We provide a function: `paddle.batch` to turn (a single entry) reader into a batch reader.
### Why do we need a batch reader, isn't is sufficient to give the reader and batch_size as arguments during training ?
In most of the cases, it would be sufficient to give the reader and batch_size as arguments to the train method. However sometimes the user wants to customize the order of data entries inside a mini batch, or even change the batch size dynamically. For these cases using a batch reader is very efficient and helpful.
### Why use a dictionary instead of a list to provide mapping?
Using a dictionary (`{"image":0, "label":1}`) instead of a list (`["image", "label"]`) gives the advantage that the user can easily reuse the items (e.g., using `{"image_a":0, "image_b":0, "label":1}`) or even skip an item (e.g., using `{"image_a":0, "label":2}`).
### How to create a custom data reader creator ?
```python
def image_reader_creator(image_path, label_path, n):
def reader():
f = open(image_path)
l = open(label_path)
images = numpy.fromfile(
f, 'ubyte', count=n * 28 * 28).reshape((n, 28 * 28)).astype('float32')
images = images / 255.0 * 2.0 - 1.0
labels = numpy.fromfile(l, 'ubyte', count=n).astype("int")
for i in xrange(n):
yield images[i, :], labels[i] # a single entry of data is created each time
f.close()
l.close()
return reader
# images_reader_creator creates a reader
reader = image_reader_creator("/path/to/image_file", "/path/to/label_file", 1024)
paddle.train(paddle.batch(reader, 128), {"image":0, "label":1}, ...)
```
### How is `paddle.train` implemented
An example implementation of paddle.train is:
```python
def train(batch_reader, mapping, batch_size, total_pass):
for pass_idx in range(total_pass):
for mini_batch in batch_reader(): # this loop will never end in online learning.
do_forward_backward(mini_batch, mapping)
```
.. _user_guide_use_recordio_as_train_data:
############################
使用RecordIO文件作为训练数据
############################
相比于 :ref:`user_guide_use_numpy_array_as_train_data`,
:ref:`user_guide_use_recordio_as_train_data` 的性能更好;
但是用户需要先将训练数据集转换成RecordIO文件格式,再使用
:ref:`api_fluid_layers_open_files` 层在神经网络配置中导入 RecordIO 文件。
用户还可以使用 :ref:`api_fluid_layers_double_buffer` 加速数据从内存到显存的拷贝,
使用 :ref:`api_fluid_layers_Preprocessor` 工具进行数据增强。
将训练数据转换成RecordIO文件格式
################################
:ref:`api_guide_recordio_file_format` 中,每个记录都是一个
:code:`vector<LoDTensor>`, 即一个支持序列信息的Tensor数组。这个数组包括训练所需
的所有特征。例如对于图像分类来说,这个数组可以包含图片和分类标签。
用户可以使用 :ref:`api_fluid_recordio_writer_convert_reader_to_recordio_file` 可以将
:ref:`user_guide_reader` 转换成一个RecordIO文件。或者可以使用
:ref:`api_fluid_recordio_writer_convert_reader_to_recordio_files` 将一个
:ref:`user_guide_reader` 转换成多个RecordIO文件。
具体使用方法为:
.. code-block:: python
import paddle.fluid as fluid
import numpy
def reader_creator():
def __impl__():
for i in range(1000):
yield [
numpy.random.random(size=[3,224,224], dtype="float32"),
numpy.random.random(size=[1], dtype="int64")
]
return __impl__
img = fluid.layers.data(name="image", shape=[3, 224, 224])
label = fluid.layers.data(name="label", shape=[1], dtype="int64")
feeder = fluid.DataFeeder(feed_list=[img, label], place=fluid.CPUPlace())
BATCH_SIZE = 32
reader = paddle.batch(reader_creator(), batch_size=BATCH_SIZE)
fluid.recordio_writer.convert_reader_to_recordio_file(
"train.recordio", feeder=feeder, reader_creator=reader)
其中 :code:`reader_creator` 创建了一个 :code:`Reader`。
:ref:`_api_fluid_data_feeder_DataFeeder`
是将 :code:`Reader` 转换成 :code:`LoDTensor` 的工具。详细请参考
:ref:`user_guide_reader` 。
上述程序将 :code:`reader_creator` 的数据转换成了 :code:`train.recordio` 文件,
其中每一个record 含有 32 条样本。如果batch size会在训练过程中调整,
用户可以将每一个Record的样本数设置成1。并参考
:ref:`user_guide_use_recordio_as_train_data_use_op_create_batch`。
配置神经网络, 打开RecordIO文件
##############################
RecordIO文件转换好之后,用户可以使用 :ref:`api_fluid_layers_open_files`
打开文件,并使用 :ref:`api_fluid_layers_read_file` 读取文件内容。
简单使用方法如下:
.. code-block:: python
import paddle.fluid as fluid
file_obj = fluid.layers.open_files(
filenames=["train.recordio"],
shape=[[3, 224, 224], [1]],
lod_levels=[0, 0],
dtypes=["float32", "int64"],
pass_num=100
)
image, label = fluid.layers.read_file(file_obj)
其中如果设置了 :code:`pass_num` ,那么当所有数据读完后,会重新读取数据,
直到读取了 :code:`pass_num` 遍。
进阶使用
########
使用 :ref:`api_fluid_layers_double_buffer`
------------------------------------------
:code:`Double buffer` 使用双缓冲技术,将训练数据从内存中复制到显存中。配置双缓冲
需要使用 :ref:`api_fluid_layers_double_buffer` 修饰文件对象。 例如:
.. code-block:: python
import paddle.fliud as fluid
file_obj = fluid.layers.open_files(...)
file_obj = fluid.layers.double_buffer(file_obj)
image, label = fluid.layers.read_file(file_obj)
双缓冲技术可以参考
`Multiple buffering <https://en.wikipedia.org/wiki/Multiple_buffering>`_ 。
配置数据增强
------------
使用 :ref:`api_fluid_layers_Preprocessor` 可以配置文件的数据增强方法。例如
.. code-block:: python
import paddle.fluid as fluid
file_obj = fluid.layers.open_files(...)
preprocessor = fluid.layers.Preprocessor(reader=data_file)
with preprocessor.block():
image, label = preprocessor.inputs()
image = image / 2
label = label + 1
preprocessor.outputs(image, label)
如上代码所示,使用 :code:`Preprocessor` 定义了一个数据增强模块,并在
:code:`with preprocessor.block()` 中定义了数据增强的具体操作。 用户通过配置
:code:`preprocessor.inputs()` 获得数据文件中的各个字段。 并用
:code:`preprocessor.outputs()` 标记预处理后的输出。
.. _user_guide_use_recordio_as_train_data_use_op_create_batch:
使用Op组batch
-------------
使用 :ref:`api_fluid_layers_batch` 可以在训练的过程中动态的组batch。例如
.. code-block:: python
import paddle.fluid as fluid
file_obj = fluid.layers.open_files(...)
file_obj = fluid.layers.batch(file_obj, batch_size=32)
img, label = fluid.layers.read_file(file_obj)
需要注意的是,如果数据集中的最后几个样本不能组成 :code:`batch_size` 大小的批量数据,
那么这几个样本直接组成一个批量数据进行训练。
读入数据的shuffle
-----------------
使用 :ref:`api_fluid_layers_shuffle` 可以在训练过程中动态重排训练数据。例如
.. code-block:: python
import paddle.fluid as fluid
file_obj = fluid.layers.open_files(...)
file_obj = fliud.layers.shuffle(file_obj, buffer_size=8192)
img, label = fliud.layers.read_file(file_obj)
需要注意的是:
1. :code:`shuffle` 实现方法是:
先读入 :code:`buffer_size` 条样本,再随机的选出样本进行训练。
2. :code:`shuffle` 中 :code:`buffer_size` 会占用训练内存,需要确定训练过程中内存
足够支持缓存 :code:`buffer_size` 条数据。
.. _cluster_quick_start:
分布式训练快速开始
==================
准备工作
--------
在本篇文章中,我们将会在介绍如何快速在一个集群中启动一个 PaddlePaddle
的分布式训练任务,在开始之前,请按如下步骤做些准备工作:
1. 准备一个至少4个节点的集群,并且保证网络可以联通,在本文中我们使用
``*.paddlepaddle.com`` 来表示每个节点的主机名称,您可以根据集群的实际情况来修改它。
2. 在开始之前确保已经阅读过 :ref:`how_to_install`
并且可以在集群的所有节点上可以正常运行 PaddlePaddle。
启动集群训练任务
----------------
在启动集群训练脚本时,需要在不同的节点上指定不同的环境变量,具体如下:
+-----------------+-----------------+-----------------+---------------------+
| 环境变量 | 数据类型 | 样例 | 描述 |
+=================+=================+=================+=====================+
| PADDLE_TRAINING | str | PSERVER,TRAINER | 训练节点的角色 |
| _ROLE | | | |
+-----------------+-----------------+-----------------+---------------------+
| PADDLE_PSERVER_ | str | ps0.paddlepaddl | 所有 pserver |
| IPS | | e.com,ps1.paddl | 节点的 IP |
| | | epaddle.com… | 地址或 |
| | | | hostname, |
| | | | 用“,”分隔 |
+-----------------+-----------------+-----------------+---------------------+
| PADDLE_PSERVER_ | int | 6174 | pserver |
| PORT | | | 节点监听的端口 |
+-----------------+-----------------+-----------------+---------------------+
| PADDLE_TRAINERS | int | 2 | 训练任务中 |
| | | | trainer |
| | | | 节点的数量 |
+-----------------+-----------------+-----------------+---------------------+
| PADDLE_CURRENT_ | str | ps0.paddlepaddl | 当前 pserver |
| IP | | e.com | 节点的 IP |
| | | | 地址或 hostanme |
+-----------------+-----------------+-----------------+---------------------+
| PADDLE_TRAINER_ | int | 0 | 当前 trainer |
| ID | | | 节点的唯一 ID, |
| | | | 取值范围为从0开始到 |
| | | | PADDLE_TRAINERS-1 |
+-----------------+-----------------+-----------------+---------------------+
样例代码
~~~~~~~~
将下面程序代码保存为 ``fluid_dist.py``
.. code:: python
import paddle
import paddle.fluid as fluid
import contextlib
import numpy
import unittest
# train reader
BATCH_SIZE = 20
train_reader = paddle.batch(
paddle.reader.shuffle(
paddle.dataset.uci_housing.train(), buf_size=500),
batch_size=BATCH_SIZE)
test_reader = paddle.batch(
paddle.reader.shuffle(
paddle.dataset.uci_housing.test(), buf_size=500),
batch_size=BATCH_SIZE)
def train_program():
y = fluid.layers.data(name='y', shape=[1], dtype='float32')
x = fluid.layers.data(name='x', shape=[13], dtype='float32')
y_predict = fluid.layers.fc(input=x, size=1, act=None)
loss = fluid.layers.square_error_cost(input=y_predict, label=y)
avg_loss = fluid.layers.mean(loss)
return avg_loss
def optimizer_func():
return fluid.optimizer.SGD(learning_rate=0.001)
def train(use_cuda, train_program):
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
trainer = fluid.Trainer(
train_func=train_program, place=place, optimizer_func=optimizer_func)
def event_handler(event):
if isinstance(event, fluid.EndStepEvent):
if event.step == 10:
test_metrics = trainer.test(
reader=test_reader, feed_order=['x', 'y'])
print("step {0}, loss: {1}".format(event.step, test_metrics))
trainer.stop()
trainer.train(
reader=train_reader,
num_epochs=100,
event_handler=event_handler,
feed_order=['x', 'y'])
train(False, train_program)
启动trainer节点和pserver节点
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. list-table::
:header-rows: 1
* - 启动节点
- 启动命令
- 说明
* - ps0.paddlepaddle.com
- :code:`PADDLE_TRAINING_ROLE=PSERVER PADDLE_CURRENT_IP=ps0.paddlepaddle.com PADDLE_PSERVER_IPS=ps0.paddlepaddle.com,ps1.paddlepaddle.com PADDLE_TRAINERS=2 PADDLE_PSERVER_PORT=6174 python fluid_dist.py`
- 启动 pserver 节点
* - ps1.paddlepaddle.com
- :code:`PADDLE_TRAINING_ROLE=PSERVER PADDLE_CURRENT_IP=ps1.paddlepaddle.com PADDLE_PSERVER_IPS=ps0.paddlepaddle.com,ps1.paddlepaddle.com PADDLE_TRAINERS=2 PADDLE_PSERVER_PORT=6174 python fluid_dist.py`
- 启动 pserver 节点
* - trainer0.paddlepaddle.com
- :code:`PADDLE_TRAINING_ROLE=TRAINER PADDLE_CURRENT_IP=ps0.paddlepaddle.com PADDLE_PSERVER_IPS=ps0.paddlepaddle.com,ps1.paddlepaddle.com PADDLE_TRAINERS=2 PADDLE_TRAINER_ID=0 PADDLE_PSERVER_PORT=6174 python fluid_dist.py`
- 启动第0号 trainer 节点
* - trainer1.paddlepaddle.com
- :code:`PADDLE_TRAINING_ROLE=TRAINER PADDLE_CURRENT_IP=ps0.paddlepaddle.com PADDLE_PSERVER_IPS=ps0.paddlepaddle.com,ps1.paddlepaddle.com PADDLE_TRAINERS=2 PADDLE_TRAINER_ID=1 PADDLE_PSERVER_PORT=6174 python fluid_dist.py`
- 启动第1号 trainer 节点
**注意**
- 需要先启动pserver节点再启动trainer节点
- 看到trainer节点输出如下日志表示训练任务执行正确
.. code:: bash
step 10, loss: [258.2326202392578]
############
训练神经网络
############
PaddlePaddle Fluid支持单机训练,和多节点训练。每种训练模式下,都支持多种训练方法。
.. toctree::
:maxdepth: 2
single_node
multi_node
########
多机训练
########
.. toctree::
:maxdepth: 2
cluster_quick_start.md
\ No newline at end of file
.. _user_guide_save_load_vars:
##################
保存与载入模型变量
##################
模型变量分类
############
在PaddlePaddle Fluid中,所有的模型变量都用 :ref:`api_fluid_Variable` 作为基类进行表示。
在该基类之下,模型变量主要可以分为以下几种类别:
1. 模型参数
模型参数是深度学习模型中被训练和学习的变量,在训练过程中,训练框架根据反向传播算法计算出每一个模型参数当前的梯度,
并用优化器根据梯度对参数进行更新。模型的训练过程本质上可以看做是模型参数不断迭代更新的过程。
在PaddlePaddle Fluid中,模型参数用 :code:`fluid.framework.Parameter` 来表示,
这是一个 :ref:`api_fluid_Variable` 的派生类,除了 :ref:`api_fluid_Variable` 具有的各项性质以外,
:code:`fluid.framework.Parameter` 还可以配置自身的初始化方法、更新率等属性。
2. 长期变量
长期变量指的是在整个训练过程中持续存在、不会因为一个迭代的结束而被销毁的变量,例如动态调节的全局学习率等。
在PaddlePaddle Fluid中,长期变量通过将 :ref:`api_fluid_Variable` 的 :code:`persistable`
属性设置为 :code:`True` 来表示。所有的模型参数都是长期变量,但并非所有的长期变量都是模型参数。
3. 临时变量
不属于上面两个类别的所有模型变量都是临时变量,这种类型的变量只在一个训练迭代中存在,在每一个迭代结束后,
所有的临时变量都会被销毁,然后在下一个迭代开始之前,又会先构造出新的临时变量供本轮迭代使用。
一般情况下模型中的大部分变量都属于这一类别,例如输入的训练数据、一个普通的layer的输出等等。
如何保存模型变量
################
根据用途的不同,我们需要保存的模型变量也是不同的。例如,如果我们只是想保存模型用来进行以后的预测,
那么只保存模型参数就够用了。但如果我们需要保存一个checkpoint以备将来恢复训练,
那么我们应该将各种长期变量都保存下来,甚至还需要记录一下当前的epoch和step的id。
因为一些模型变量虽然不是参数,但对于模型的训练依然必不可少。
因此,根据需求的不同,我们提供了两套API来分别进行模型的参数和checkpoint的保存。
保存模型用于对新样本的预测
==========================
如果我们保存模型的目的是用于对新样本的预测,那么只保存模型参数就足够了。我们可以使用
:ref:`api_fluid_io_save_params` 接口来进行模型参数的保存。
例如:
.. code-block:: python
import paddle.fluid as fluid
exe = fluid.Executor(fluid.CPUPlace())
param_path = "./my_paddle_model"
prog = fluid.default_main_program()
fluid.io.save_params(executor=exe, dirname=param_path, main_program=None)
上面的例子中,通过调用 :code:`fluid.io.save_params` 函数,PaddlePaddle Fluid会对默认
:ref:`api_fluid_Program` 也就是 :code:`prog` 中的所有模型变量进行扫描,
筛选出其中所有的模型参数,并将这些模型参数保存到指定的 :code:`param_path` 之中。
保存checkpoint用于将来恢复训练
==============================
在训练过程中,我们可能希望在一些节点上将当前的训练状态保存下来,
以便在将来需要的时候恢复训练环境继续进行训练。这一般被称作“checkpoint”。
想要保存checkpoint,可以使用 :ref:`api_fluid_io_save_checkpoint` 接口。
例如:
.. code-block:: python
import paddle.fluid as fluid
exe = fluid.Executor(fluid.CPUPlace())
path = "./checkpoints"
prog = fluid.default_main_program()
trainer_args = {"epoch_id": 200,
"step_id": 20} # just an example
fluid.io.save_checkpoint(executor=exe,
checkpoint_dir=path,
trainer_id=0,
trainer_args=trainer_args,
main_program=prog,
max_num_checkpoints=3)
上面的例子中,通过调用 :code:`fluid.io.save_checkpoint` 函数,PaddlePaddle Fluid会对默认
:ref:`api_fluid_Program` 也就是 :code:`prog` 中的所有模型变量进行扫描,
根据一系列内置的规则自动筛选出其中所有需要保存的变量,并将他们保存到指定的 :code:`path` 目录下。
:code:`fluid.io.save_checkpoint` 的各个参数中, :code:`trainer_id` 在单机情况下设置为0即可; :code:`trainer_args`
为一个Python dict,用于给定当前的epoch_id和step_id;
:code:`max_num_checkpoints` 用于表示的最大checkpoint数量,
如果目录中已经存在的checkpoint数量超过这个值,那最早的checkpoint将被删除。
如何载入模型变量
################
与模型变量的保存相对应,我们提供了两套API来分别载入模型的参数和载入模型的checkpoint。
载入模型用于对新样本的预测
==========================
对于通过 :code:`fluid.io.save_params` 保存的模型,可以使用 :code:`fluid.io.load_params`
来进行载入。
例如:
.. code-block:: python
import paddle.fluid as fluid
exe = fluid.Executor(fluid.CPUPlace())
param_path = "./my_paddle_model"
prog = fluid.default_main_program()
fluid.io.load_params(executor=exe, dirname=param_path,
main_program=prog)
上面的例子中,通过调用 :code:`fluid.io.load_params` 函数,PaddlePaddle Fluid会对
:code:`prog` 中的所有模型变量进行扫描,筛选出其中所有的模型参数,
并尝试从 :code:`param_path` 之中读取加载它们。
需要格外注意的是,这里的 :code:`prog` 必须和调用 :code:`fluid.io.save_params`
时所用的 :code:`prog` 中的前向部分完全一致,且不能包含任何参数更新的操作。如果两者存在不一致,
那么可能会导致一些变量未被正确加载;如果错误地包含了参数更新操作,那可能会导致正常预测过程中参数被更改。
这两个 :ref:`api_fluid_Program` 之间的关系类似于训练 :ref:`api_fluid_Program`
和测试 :ref:`api_fluid_Program` 之间的关系,详见: :ref:`user_guide_test_while_training`。
另外,需特别注意运行 :code:`fluid.default_startup_program()` 必须在调用 :code:`fluid.io.load_params`
之前。如果在之后运行,可能会覆盖已加载的模型参数导致错误。
载入checkpoint用于恢复训练
==========================
对于通过 :code:`fluid.io.save_checkpoint` 保存的模型,可以使用 :code:`fluid.io.load_checkpoint`
来进行载入。
例如:
.. code-block:: python
import paddle.fluid as fluid
exe = fluid.Executor(fluid.CPUPlace())
path = "./checkpoints"
prog = fluid.default_main_program()
fluid.io.load_checkpoint(executor=exe, checkpoint_dir=path,
serial=9, main_program=prog)
上面的例子中,通过调用 :code:`fluid.io.save_checkpoint` 函数,PaddlePaddle Fluid会对
:code:`prog` 中的所有模型变量进行扫描,根据内置规则自动筛选出需要加载的变量,
并尝试从 :code:`path` 之中加载它们。
参数 :code:`serial` 用来标记具体要加载的checkpoint的版本号。在保存checkpoint的时候,
一个checkpoint会被保存在一个子目录中,并在目录名上体现出自己的版本号。
一般越大的版本号表示这个checkpoint越新。
这里的 :code:`prog` 必须和调用 :code:`fluid.io.save_checkpoint` 时所用的 :code:`prog`
完全一致,否则会导致变量加载错误或者未加载。另外,与 :code:`fluid.io.save_params` 类似,
运行 :code:`fluid.default_startup_program()` 也必须在 :code:`fluid.io.load_checkpoint`
之前进行。
########
单机训练
########
准备工作
########
要进行PaddlePaddle Fluid单机训练,需要先 :ref:`user_guide_prepare_data` 和
:ref:`user_guide_configure_simple_model` 。当\
:ref:`user_guide_configure_simple_model` 完毕后,可以得到两个\
:ref:`api_fluid_Program`, :code:`startup_program` 和 :code:`main_program`。
默认情况下,可以使用 :ref:`api_fluid_default_startup_program` 与\ :ref:`api_fluid_default_main_program` 获得全局的 :ref:`api_fluid_Program`。
例如:
.. code-block:: python
import paddle.fluid as fluid
image = fluid.layers.data(name="image", shape=[784])
label = fluid.layers.data(name="label", shape=[1])
hidden = fluid.layers.fc(input=image, size=100, act='relu')
prediction = fluid.layers.fc(input=hidden, size=10, act='softmax')
loss = fluid.layers.mean(
fluid.layers.cross_entropy(
input=prediction,
label=label
)
)
sgd = fluid.optimizer.SGD(learning_rate=0.001)
sgd.minimize(loss)
# Here the fluid.default_startup_program() and fluid.default_main_program()
# has been constructed.
在上述模型配置执行完毕后, :code:`fluid.default_startup_program()` 与\
:code:`fluid.default_main_program()` 配置完毕了。
初始化参数
##########
参数随机初始化
==============
用户配置完模型后,参数初始化操作会被写入到\
:code:`fluid.default_startup_program()` 中。使用 :ref:`api_fluid_Executor` 运行
这一程序,即可在全局 :ref:`api_fluid_global_scope` 中随机初始化参数。例如:
.. code-block:: python
exe = fluid.Executor(fluid.CUDAPlace(0))
exe.run(program=fluid.default_startup_program())
值得注意的是: 如果使用多GPU训练,参数需要先在GPU0上初始化,再经由\
:ref:`api_fluid_ParallelExecutor` 分发到多张显卡上。
载入预定义参数
==============
在神经网络训练过程中,经常会需要载入预定义模型,进而继续进行训练。\
如何载入预定义参数,请参考 :ref:`user_guide_save_load_vars`。
单卡训练
########
执行单卡训练可以使用 :ref:`api_fluid_Executor` 中的 :code:`run()` 方法,运行训练\
:ref:`api_fluid_Program` 即可。在运行的时候,用户可以通过 :code:`run(feed=...)`\
参数传入数据;用户可以通过 :code:`run(fetch=...)` 获取持久的数据。例如:\
.. code-block:: python
...
loss = fluid.layers.mean(...)
exe = fluid.Executor(...)
# the result is an numpy array
result = exe.run(feed={"image": ..., "label": ...}, fetch_list=[loss])
这里有几点注意事项:
1. feed的数据格式,请参考文章 :ref:`user_guide_feed_data_to_executor`。
2. :code:`Executor.run` 的返回值是 :code:`fetch_list=[...]` 的variable值。被fetch\
的Variable必须是persistable的。 :code:`fetch_list` 可以传入Variable的列表,\
也可以传入Variable的名字列表。:code:`Executor.run` 返回Fetch结果列表。
3. 如果需要取回的数据包含序列信息,可以设置
:code:`exe.run(return_numpy=False, ...)` 直接返回 :ref:`api_guide_lod_tensor`
。用户可以直接访问 :ref:`api_guide_lod_tensor` 中的信息。
多卡训练
########
执行多卡训练可以使用 :ref:`api_fluid_ParallelExecutor` 运行训练
:ref:`api_fluid_Program`。例如:
.. code-block:: python
train_exe = fluid.ParallelExecutor(use_cuda=True, loss_name=loss.name,
main_program=fluid.default_main_program())
train_exe.run(fetch_list=[loss.name], feed={...})
这里有几点注意事项:
1. :code:`ParallelExecutor` 的构造函数需要指明要执行的 :ref:`api_fluid_Program` ,
并在执行过程中不能修改。默认值是 :ref:`api_fluid_default_main_program` 。
2. :code:`ParallelExecutor` 需要明确指定是否使用 CUDA 显卡进行训练。在显卡训练\
模式下会占用全部显卡。用户可以配置 `CUDA_VISIBLE_DEVICES <http://www.acceleware.com/blog/cudavisibledevices-masking-gpus>`_ 来修改占用\
的显卡。
进阶使用
########
.. toctree::
:maxdepth: 2
test_while_training
save_load_variables
.. _user_guide_test_while_training:
##################
训练过程中评测模型
##################
模型的测试评价与训练的 :ref:`api_fluid_Program` 不同。在测试评价中:
1. 评价测试不进行反向传播,不优化更新参数。
2. 评价测试执行的操作可以不同。
* 例如 BatchNorm 操作,在训练和测试时执行不同的算法。
* 评价模型与训练相比可以是完全不同的模型。
生成测试 :ref:`api_fluid_Program`
#################################
通过克隆训练 :ref:`api_fluid_Program` 生成测试 :ref:`api_fluid_Program`
=======================================================================
:code:`Program.clone()` 方法可以复制出新的 :ref:`api_fluid_Program` 。 通过设置
:code:`Program.clone(for_test=True)` 复制含有用于测试的操作Program。简单的使用方法如下:
.. code-block:: python
import paddle.fluid as fluid
img = fluid.layers.data(name="image", shape=[784])
prediction = fluid.layers.fc(
input=fluid.layers.fc(input=img, size=100, act='relu'),
size=10,
act='softmax'
)
label = fluid.layers.data(name="label", shape=[1], dtype="int64")
loss = fluid.layers.mean(fluid.layers.cross_entropy(input=prediction, label=label))
acc = fluid.layers.accuracy(input=prediction, label=label)
test_program = fluid.default_main_program().clone(for_test=True)
adam = fluid.optimizer.Adam(learning_rate=0.001)
adam.minimize(loss)
在使用 :code:`Optimizer` 之前,将 :code:`fluid.default_main_program()` 复制\
成一个 :code:`test_program` 。之后使用测试数据运行 :code:`test_program`,\
就可以做到运行测试程序,而不影响训练结果。
分别配置训练 :ref:`api_fluid_Program` 和测试 :ref:`api_fluid_Program`
=====================================================================
如果训练程序和测试程序相差较大时,用户也可以通过完全定义两个不同的
:ref:`api_fluid_Program`,分别进行训练和测试。在PaddlePaddle Fluid中,\
所有的参数都有名字。如果两个不同的操作,甚至两个不同的网络使用了同样名字的参数,\
那么他们的值和内存空间都是共享的。
PaddlePaddle Fluid中使用 :code:`fluid.unique_name` 包来随机初始化用户未定义的\
参数名称。通过 :code:`fluid.unique_name.guard` 可以确保多次调用某函数\
参数初始化的名称一致。
例如:
.. code-block:: python
import paddle.fluid as fluid
def network(is_test):
file_obj = fluid.layers.open_files(filenames=["test.recordio"] if is_test else ["train.recordio"], ...)
img, label = fluid.layers.read_file(file_obj)
hidden = fluid.layers.fc(input=img, size=100, act="relu")
hidden = fluid.layers.batch_norm(input=hidden, is_test=is_test)
...
return loss
with fluid.unique_name.guard():
train_loss = network(is_test=False)
sgd = fluid.optimizer.SGD(0.001)
sgd.minimize(train_loss)
test_program = fluid.Program()
with fluid.unique_name.guard():
with fluid.program_gurad(test_program, fluid.Program()):
test_loss = network(is_test=True)
# fluid.default_main_program() is the train program
# fluid.test_program is the test program
执行测试 :ref:`api_fluid_Program`
#################################
使用 :code:`Executor` 执行测试 :ref:`api_fluid_Program`
=======================================================
用户可以使用 :code:`Executor.run(program=...)` 来执行测试
:ref:`api_fluid_Program`。
例如
.. code-block:: python
exe = fluid.Executor(fluid.CPUPlace())
test_acc = exe.run(program=test_program, feed=test_data_batch, fetch_list=[acc])
print 'Test accuracy is ', test_acc
使用 :code:`ParallelExecutor` 执行测试 :ref:`api_fluid_Program`
===============================================================
用户可以使用训练用的 :code:`ParallelExecutor` 与测试 :ref:`api_fluid_Program`
一起新建一个测试的 :code:`ParallelExecutor` ;再使用测试
:code:`ParallelExecutor.run` 来执行测试。
例如:
.. code-block:: python
train_exec = fluid.ParallelExecutor(use_cuda=True, loss_name=loss.name)
test_exec = fluid.ParallelExecutor(use_cuda=True, share_vars_from=train_exec,
main_program=test_program)
test_acc = test_exec.run(fetch_list=[acc], ...)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册