提交 f4cb6d34 编写于 作者: Y Youwei Song 提交者: hong

cherry-pick #1519 #1530 (#1540)

test=document_fix
上级 9663ac92
.vscode/
/doc/fluid/menu.zh.json
/doc/fluid/menu.en.json
.idea
......@@ -2,15 +2,15 @@
进阶使用
########
如果您非常熟悉 Fluid,期望获得更高效的模型或者定义自己的Operator,请阅读:
如果您已比较熟练使用PaddlePaddle来完成常规任务,期望获得更高效的模型或者定义自己的Operator,请阅读:
- `Fluid 设计思想 <../advanced_usage/design_idea/fluid_design_idea.html>`_:介绍 Fluid 底层的设计思想,帮助您更好的理解框架运作过程
- `设计思想 <../advanced_usage/design_idea/fluid_design_idea.html>`_:介绍 Paddle 底层的设计思想,帮助您更好的理解框架运作过程
- `预测部署 <../advanced_usage/deploy/index_cn.html>`_ :介绍如何应用训练好的模型进行预测
- `新增OP <../advanced_usage/development/new_op/index_cn.html>`_ :介绍新增operator的方法及注意事项
- `性能调优 <../advanced_usage/development/profiling/index_cn.html>`_ :介绍 Fluid 使用过程中的调优方法
- `性能调优 <../advanced_usage/development/profiling/index_cn.html>`_ :介绍 Paddle 使用过程中的调优方法
- `优秀实践 <../advanced_usage/best_practice/index_cn.html>`_
......
......@@ -25,7 +25,7 @@ fluid.dygraph
dygraph_cn/InverseTimeDecay_cn.rst
dygraph_cn/Layer_cn.rst
dygraph_cn/LayerNorm_cn.rst
dygraph_cn/load_persistables_cn.rst
dygraph_cn/load_dygraph_cn.rst
dygraph_cn/NaturalExpDecay_cn.rst
dygraph_cn/NCE_cn.rst
dygraph_cn/NoamDecay_cn.rst
......@@ -34,7 +34,7 @@ fluid.dygraph
dygraph_cn/PolynomialDecay_cn.rst
dygraph_cn/Pool2D_cn.rst
dygraph_cn/PRelu_cn.rst
dygraph_cn/save_persistables_cn.rst
dygraph_cn/save_dygraph_cn.rst
dygraph_cn/SpectralNorm_cn.rst
dygraph_cn/to_variable_cn.rst
dygraph_cn/TreeConv_cn.rst
.. _cn_api_fluid_dygraph_load_dygraph:
load_dygraph
-------------------------------
.. py:function:: paddle.fluid.dygraph.load_dygraph(model_path)
该接口尝试从磁盘中加载参数或优化器的 ``dict`` 。
该接口会同时加载 ``model_path + ".pdparams"`` 和 ``model_path + ".pdopt"`` 中的内容。
参数:
- **model_path** (str) – 保存state_dict的文件前缀。该路径不应该包括后缀 ``.pdparams`` 或 ``.pdopt``。
返回: 两个 ``dict`` ,即从文件中恢复的参数 ``dict`` 和优化器 ``dict``
- para_dict: 从文件中恢复的参数 ``dict``
- opti_dict: 从文件中恢复的优化器 ``dict``
返回类型: tuple(dict, dict)
**代码示例**
.. code-block:: python
import paddle.fluid as fluid
with fluid.dygraph.guard():
emb = fluid.dygraph.Embedding( "emb", [10, 10])
state_dict = emb.state_dict()
fluid.save_dygraph( state_dict, "paddle_dy")
adam = fluid.optimizer.Adam( learning_rate = fluid.layers.noam_decay( 100, 10000) )
state_dict = adam.state_dict()
fluid.save_dygraph( state_dict, "padle_dy")
para_state_dict, opti_state_dict = fluid.load_dygraph( "paddle_dy")
.. _cn_api_fluid_dygraph_load_persistables:
load_persistables
-------------------------------
.. py:function:: paddle.fluid.dygraph.load_persistables(dirname='save_dir')
该函数尝试从dirname中加载持久性变量。
参数:
- **dirname** (str) – 目录路径。默认为save_dir
返回: 两个字典:从文件中恢复的参数字典;从文件中恢复的优化器字典
返回类型: dict
**代码示例**
.. code-block:: python
my_layer = layer(fluid.Layer)
param_path = "./my_paddle_model"
sgd = SGDOptimizer(learning_rate=1e-3)
param_dict, optimizer_dict = fluid.dygraph.load_persistables(my_layer.parameters(), param_path)
param_1 = param_dict['PtbModel_0.w_1']
sgd.load(optimizer_dict)
.. _cn_api_fluid_dygraph_save_dygraph:
save_dygraph
-------------------------------
.. py:function:: paddle.fluid.dygraph.save_dygraph(state_dict, model_path)
该接口将传入的参数或优化器的 ``dict`` 保存到磁盘上。
``state_dict`` 是通过 :ref:`cn_api_fluid_dygraph_Layer` 的 ``state_dict()`` 方法得到的。
注: ``model_path`` 不可以是一个目录。
该接口会根据 ``state_dict`` 的内容,自动给 ``model_path`` 添加 ``.pdparams`` 或者 ``.pdopt`` 后缀,
生成 ``model_path + ".pdparms"`` 或者 ``model_path + ".pdopt"`` 文件。
参数:
- **state_dict** (dict of Parameters) – 要保存的模型参数的 ``dict`` 。
- **model_path** (str) – 保存state_dict的文件前缀。格式为 ``目录名称/文件前缀``。如果文件前缀为空字符串,会引发异常。
返回: 无
**代码示例**
.. code-block:: python
import paddle.fluid as fluid
with fluid.dygraph.guard():
emb = fluid.dygraph.Embedding( "emb", [10, 10])
state_dict = emb.state_dict()
fluid.save_dygraph(state_dict, "paddle_dy") # 会保存为 paddle_dy.pdparams
adam = fluid.optimizer.Adam( learning_rate = fluid.layers.noam_decay( 100, 10000) )
state_dict = adam.state_dict()
fluid.save_dygraph(state_dict, "paddle_dy") # 会保存为 paddle_dy.pdopt
.. _cn_api_fluid_dygraph_save_persistables:
save_persistables
-------------------------------
.. py:function:: paddle.fluid.dygraph.save_persistables(model_dict, dirname='save_dir', optimizers=None)
该函数把传入的层中所有参数以及优化器进行保存。
``dirname`` 用于指定保存长期变量的目录。
参数:
- **model_dict** (dict of Parameters) – 参数将会被保存,如果设置为None,不会处理。
- **dirname** (str) – 目录路径
- **optimizers** (fluid.Optimizer|list(fluid.Optimizer)|None) – 要保存的优化器。
返回: None
**代码示例**
.. code-block:: python
import paddle.fluid as fluid
ptb_model = PtbModel(
hidden_size=hidden_size,
vocab_size=vocab_size,
num_layers=num_layers,
num_steps=num_steps,
init_scale=init_scale)
sgd = fluid.optimizer.SGD(learning_rate=0.01)
x_data = np.arange(12).reshape(4, 3).astype('int64')
y_data = np.arange(1, 13).reshape(4, 3).astype('int64')
x_data = x_data.reshape((-1, num_steps, 1))
y_data = y_data.reshape((-1, 1))
init_hidden_data = np.zeros(
(num_layers, batch_size, hidden_size), dtype='float32')
init_cell_data = np.zeros(
(num_layers, batch_size, hidden_size), dtype='float32')
x = to_variable(x_data)
y = to_variable(y_data)
init_hidden = to_variable(init_hidden_data)
init_cell = to_variable(init_cell_data)
dy_loss, last_hidden, last_cell = ptb_model(x, y, init_hidden,
init_cell)
dy_loss.backward()
sgd.minimize(dy_loss)
ptb_model.clear_gradient()
param_path = "./my_paddle_model"
fluid.dygraph.save_persistables(ptb_model.state_dict(), dirname=param_path, sgd)
......@@ -16,6 +16,7 @@ fluid.io
io_cn/compose_cn.rst
io_cn/Fake_cn.rst
io_cn/firstn_cn.rst
io_cn/load_cn.rst
io_cn/load_inference_model_cn.rst
io_cn/load_params_cn.rst
io_cn/load_persistables_cn.rst
......@@ -24,6 +25,7 @@ fluid.io
io_cn/multiprocess_reader_cn.rst
io_cn/PipeReader_cn.rst
io_cn/PyReader_cn.rst
io_cn/save_cn.rst
io_cn/save_inference_model_cn.rst
io_cn/save_params_cn.rst
io_cn/save_persistables_cn.rst
......
.. _cn_api_fluid_io_load:
load
-------------------------------
.. py:function:: paddle.fluid.io.load(program, model_path)
该接口从Program中过滤出参数和优化器信息,然后从文件中获取相应的值。
如果Program和加载的文件之间参数的维度或数据类型不匹配,将引发异常。
**注意:此函数必须在运行启动程序(start_up_program)之后再调用。**
参数:
- **program** ( :ref:`cn_api_fluid_Program` ) – 要加载的Program。
- **model_path** (str) – 保存program的文件前缀。格式为 ``目录名称/文件前缀``。
返回: 无
**代码示例**
.. code-block:: python
import paddle.fluid as fluid
x = fluid.data( name="x", shape=[10, 10], dtype='float32')
y = fluid.layers.fc(x, 10)
z = fluid.layers.fc(y, 10)
place = fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
fluid.save(fluid.default_main_program(), "./test_path")
fluid.load(fluid.default_main_program(), "./test_path")
.. _cn_api_fluid_io_save:
save
-------------------------------
.. py:function:: paddle.fluid.io.save(program, model_path)
该接口将传入的参数、优化器信息和网络描述保存到 ``model_path`` 。
参数包含所有的可训练 :ref:`cn_api_fluid_Variable` ,将保存到后缀为 ``.pdparams`` 的文件中。
优化器信息包含优化器使用的所有变量。对于Adam优化器,包含beta1、beta2、momentum等。
所有信息将保存到后缀为 ``.pdopt`` 的文件中。(如果优化器没有需要保存的变量(如sgd),则不会生成)。
网络描述是程序的描述。它只用于部署。描述将保存到后缀为 ``.pdmodel`` 的文件中。
参数:
- **program** ( :ref:`cn_api_fluid_Program` ) – 要保存的Program。
- **model_path** (str) – 保存program的文件前缀。格式为 ``目录名称/文件前缀``。如果文件前缀为空字符串,会引发异常。
返回: 无
**代码示例**
.. code-block:: python
import paddle.fluid as fluid
x = fluid.data(name="x", shape=[10, 10], dtype='float32')
y = fluid.layers.fc(x, 10)
z = fluid.layers.fc(y, 10)
place = fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
fluid.save(fluid.default_main_program(), "./test_path")
......@@ -16,9 +16,9 @@ PaddlePaddle (PArallel Distributed Deep LEarning)是一个易用、高效、灵
这里为您提供了更多学习资料:
- `深度学习基础 <../beginners_guide/basics/index_cn.html>`_:覆盖图像分类、个性化推荐、机器翻译等多个深度领域的基础知识,提供 Fluid 实现案例
- `深度学习基础 <../beginners_guide/basics/index_cn.html>`_:覆盖图像分类、个性化推荐、机器翻译等多个深度领域的基础知识,提供 Paddle 实现案例
- `Fluid编程指南 <../beginners_guide/programming_guide/programming_guide.html>`_:介绍 Fluid 的基本概念和使用方法
- `编程指南 <../beginners_guide/programming_guide/programming_guide.html>`_:介绍 Paddle 的基本概念和使用方法
.. toctree::
:hidden:
......
.. _cn_user_guide_Executor:
=======
Executor
=======
飞桨(PaddlePaddle,以下简称Paddle)的设计思想类似于高级编程语言C++和JAVA等。程序的执行过程被分为编译和执行两个阶段。
用户完成对 Program 的定义后,Executor 接受这段 Program 并转化为C++后端真正可执行的 FluidProgram,这一自动完成的过程叫做编译。
编译过后需要 Executor 来执行这段编译好的 FluidProgram。
例如上文实现的加法运算,当构建好 Program 后,需要创建 Executor,执行startup Program 和训练 Program:
.. code-block:: python
import paddle.fluid as fluid
import numpy
a = fluid.data(name="a",shape=[1],dtype='float32')
b = fluid.data(name="b",shape=[1],dtype='float32')
result = fluid.layers.elementwise_add(a,b)
# 定义执行器,并且制定执行的设备为CPU
cpu = fluid.core.CPUPlace()
exe = fluid.Executor(cpu)
exe.run(fluid.default_startup_program())
x = numpy.array([5]).astype("float32")
y = numpy.array([7]).astype("float32")
outs = exe.run(
feed={'a':x,'b':y},
fetch_list=[result])
# 打印输出结果,[array([12.], dtype=float32)]
print( outs )
.. _cn_user_guide_lod_tensor:
##################
LoD-Tensor使用说明
##################
LoD(Level-of-Detail) Tensor是Fluid中特有的概念,它在Tensor基础上附加了序列信息。Fluid中可传输的数据包括:输入、输出、网络中的可学习参数,全部统一使用LoD-Tensor表示。
阅读本文档将帮助您了解 Fluid 中的 LoD-Tensor 设计思想,以便您更灵活的使用这一数据类型。
变长序列的挑战
================
大多数的深度学习框架使用Tensor表示一个mini-batch。
例如一个mini-batch中有10张图片,每幅图片大小为32x32,则这个mini-batch是一个10x32x32的 Tensor。
或者在处理NLP任务中,一个mini-batch包含N个句子,每个字都用一个D维的one-hot向量表示,假设所有句子都用相同的长度L,那这个mini-batch可以被表示为NxLxD的Tensor。
上述两个例子中序列元素都具有相同大小,但是在许多情况下,训练数据是变长序列。基于这一场景,大部分框架采取的方法是确定一个固定长度,对小于这一长度的序列数据以0填充。
在Fluid中,由于LoD-Tensor的存在,我们不要求每个mini-batch中的序列数据必须保持长度一致,因此您不需要执行填充操作,也可以满足处理NLP等具有序列要求的任务需求。
Fluid引入了一个索引数据结构(LoD)来将张量分割成序列。
LoD 索引
===========
为了更好的理解LoD的概念,本节提供了几个例子供您参考:
**句子组成的 mini-batch**
假设一个mini-batch中有3个句子,每个句子中分别包含3个、1个和2个单词。我们可以用(3+1+2)xD维Tensor 加上一些索引信息来表示这个mini-batch:
.. code-block :: text
3 1 2
| | | | | |
上述表示中,每一个 :code:`|` 代表一个D维的词向量,数字3,1,2构成了 1-level LoD。
**递归序列**
让我们来看另一个2-level LoD-Tensor的例子:假设存在一个mini-batch中包含3个句子、1个句子和2个句子的文章,每个句子都由不同数量的单词组成,则这个mini-batch的样式可以看作:
.. code-block:: text
3 1 2
3 2 4 1 2 3
||| || |||| | || |||
表示的LoD信息为:
.. code-block:: text
[[3,1,2]/*level=0*/,[3,2,4,1,2,3]/*level=1*/]
**视频的mini-batch**
在视觉任务中,时常需要处理视频和图像这些元素是高维的对象,假设现存的一个mini-batch包含3个视频,分别有3个,1个和2个帧,每个帧都具有相同大小:640x480,则这个mini-batch可以被表示为:
.. code-block:: text
3 1 2
口口口 口 口口
最底层tensor大小为(3+1+2)x640x480,每一个 :code:`口` 表示一个640x480的图像
**图像的mini-batch**
在传统的情况下,比如有N个固定大小的图像的mini-batch,LoD-Tensor表示为:
.. code-block:: text
1 1 1 1 1
口口口口 ... 口
在这种情况下,我们不会因为索引值都为1而忽略信息,仅仅把LoD-Tensor看作是一个普通的张量:
.. code-block:: text
口口口口 ... 口
**模型参数**
模型参数只是一个普通的张量,在Fluid中它们被表示为一个0-level LoD-Tensor。
LoDTensor的偏移表示
=====================
为了快速访问基本序列,Fluid提供了一种偏移表示的方法——保存序列的开始和结束元素,而不是保存长度。
在上述例子中,您可以计算基本元素的长度:
.. code-block:: text
3 2 4 1 2 3
将其转换为偏移表示:
.. code-block:: text
0 3 5 9 10 12 15
= = = = = =
3 2+3 4+5 1+9 2+10 3+12
所以我们知道第一个句子是从单词0到单词3,第二个句子是从单词3到单词5。
类似的,LoD的顶层长度
.. code-block:: text
3 1 2
可以被转化成偏移形式:
.. code-block:: text
0 3 4 6
= = =
3 3+1 4+2
因此该LoD-Tensor的偏移表示为:
.. code-block:: text
0 3 4 6
3 5 9 10 12 15
LoD-Tensor
=============
一个LoD-Tensor可以被看作是一个树的结构,树叶是基本的序列元素,树枝作为基本元素的标识。
在 Fluid 中 LoD-Tensor 的序列信息有两种表述形式:原始长度和偏移量。在 Paddle 内部采用偏移量的形式表述 LoD-Tensor,以获得更快的序列访问速度;在 python API中采用原始长度的形式表述 LoD-Tensor 方便用户理解和计算,并将原始长度称为: :code:`recursive_sequence_lengths` 。
以上文提到的一个2-level LoD-Tensor为例:
.. code-block:: text
3 1 2
3 2 4 1 2 3
||| || |||| | || |||
- 以偏移量表示此 LoD-Tensor:[ [0,3,4,6] , [0,3,5,9,10,12,15] ],
- 以原始长度表达此 Lod-Tensor:recursive_sequence_lengths=[ [3-0 , 4-3 , 6-4] , [3-0 , 5-3 , 9-5 , 10-9 , 12-10 , 15-12] ]。
以文字序列为例: [3,1,2] 可以表示这个mini-batch中有3篇文章,每篇文章分别有3、1、2个句子,[3,2,4,1,2,3] 表示每个句子中分别含有3、2、4、1、2、3个字。
recursive_seq_lens 是一个双层嵌套列表,也就是列表的列表,最外层列表的size表示嵌套的层数,也就是lod-level的大小;内部的每个列表,对应表示每个lod-level下,每个元素的大小。
下面三段代码分别介绍如何创建一个LoD-Tensor,如何将LoD-Tensor转换成Tensor,如何将Tensor转换成LoD-Tensor:
* 创建 LoD-Tensor
.. code-block:: python
#创建lod-tensor
import paddle.fluid as fluid
import numpy as np
a = fluid.create_lod_tensor(np.array([[1],[1],[1],
[1],[1],
[1],[1],[1],[1],
[1],
[1],[1],
[1],[1],[1]]).astype('int64') ,
[[3,1,2] , [3,2,4,1,2,3]],
fluid.CPUPlace())
#查看lod-tensor嵌套层数
print (len(a.recursive_sequence_lengths()))
# output:2
#查看最基础元素个数
print (sum(a.recursive_sequence_lengths()[-1]))
# output:15 (3+2+4+1+2+3=15)
* LoD-Tensor 转 Tensor
.. code-block:: python
import paddle.fluid as fluid
import numpy as np
# 创建一个 LoD-Tensor
a = fluid.create_lod_tensor(np.array([[1.1], [2.2],[3.3],[4.4]]).astype('float32'), [[1,3]], fluid.CPUPlace())
def LodTensor_to_Tensor(lod_tensor):
# 获取 LoD-Tensor 的 lod 信息
lod = lod_tensor.lod()
# 转换成 array
array = np.array(lod_tensor)
new_array = []
# 依照原LoD-Tensor的层级信息,转换成Tensor
for i in range(len(lod[0]) - 1):
new_array.append(array[lod[0][i]:lod[0][i + 1]])
return new_array
new_array = LodTensor_to_Tensor(a)
# 输出结果
print(new_array)
* Tensor 转 LoD-Tensor
.. code-block:: python
import paddle.fluid as fluid
import numpy as np
def to_lodtensor(data, place):
# 存储Tensor的长度作为LoD信息
seq_lens = [len(seq) for seq in data]
cur_len = 0
lod = [cur_len]
for l in seq_lens:
cur_len += l
lod.append(cur_len)
# 对待转换的 Tensor 降维
flattened_data = np.concatenate(data, axis=0).astype("int64")
flattened_data = flattened_data.reshape([len(flattened_data), 1])
# 为 Tensor 数据添加lod信息
res = fluid.LoDTensor()
res.set(flattened_data, place)
res.set_lod([lod])
return res
# new_array 为上段代码中转换的Tensor
lod_tensor = to_lodtensor(new_array,fluid.CPUPlace())
# 输出 LoD 信息
print("The LoD of the result: {}.".format(lod_tensor.lod()))
# 检验与原Tensor数据是否一致
print("The array : {}.".format(np.array(lod_tensor)))
代码示例
===========
本节代码将根据指定的级别y-lod,扩充输入变量x。本例综合了LoD-Tensor的多个重要概念,跟随代码实现,您将:
- 直观理解Fluid中 :code:`fluid.layers.sequence_expand` 的实现过程
- 掌握如何在Fluid中创建LoD-Tensor
- 学习如何打印LoDTensor内容
**定义计算过程**
layers.sequence_expand通过获取 y 的 lod 值对 x 的数据进行扩充,关于 :code:`fluid.layers.sequence_expand` 的功能说明,请先阅读 :ref:`cn_api_fluid_layers_sequence_expand` 。
序列扩充代码实现:
.. code-block:: python
x = fluid.layers.data(name='x', shape=[1], dtype='float32', lod_level=1)
y = fluid.layers.data(name='y', shape=[1], dtype='float32', lod_level=2)
out = fluid.layers.sequence_expand(x=x, y=y, ref_level=0)
*说明*:输出LoD-Tensor的维度仅与传入的真实数据维度有关,在定义网络结构阶段为x、y设置的shape值,仅作为占位,并不影响结果。
**创建Executor**
.. code-block:: python
place = fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
**准备数据**
这里我们调用 :code:`fluid.create_lod_tensor` 创建 :code:`sequence_expand` 的输入数据,通过定义 y_d 的 LoD 值,对 x_d 进行扩充。其中,输出值只与 y_d 的 LoD 值有关,y_d 的 data 值在这里并不参与计算,维度上与LoD[-1]一致即可。
:code:`fluid.create_lod_tensor()` 的使用说明请参考 :ref:`cn_api_fluid_create_lod_tensor` 。
实现代码如下:
.. code-block:: python
x_d = fluid.create_lod_tensor(np.array([[1.1],[2.2],[3.3],[4.4]]).astype('float32'), [[1,3]], place)
y_d = fluid.create_lod_tensor(np.array([[1.1],[1.1],[1.1],[1.1],[1.1],[1.1]]).astype('float32'), [[1,3], [2,1,2,1]],place)
**执行运算**
在Fluid中,LoD>1的Tensor与其他类型的数据一样,使用 :code:`feed` 定义数据传入顺序。此外,由于输出results是带有LoD信息的Tensor,需在exe.run( )中添加 :code:`return_numpy=False` 参数,获得LoD-Tensor的输出结果。
.. code-block:: python
results = exe.run(fluid.default_main_program(),
feed={'x':x_d, 'y': y_d },
fetch_list=[out],return_numpy=False)
**查看LodTensor结果**
由于LoDTensor的特殊属性,无法直接print查看内容,常用操作时将LoD-Tensor作为网络的输出fetch出来,然后执行 numpy.array(lod_tensor), 就能转成numpy array:
.. code-block:: python
np.array(results[0])
输出结果为:
.. code-block:: text
array([[1.1],[2.2],[3.3],[4.4],[2.2],[3.3],[4.4],[2.2],[3.3],[4.4]])
**查看序列长度**
可以通过查看序列长度得到 LoDTensor 的递归序列长度:
.. code-block:: python
results[0].recursive_sequence_lengths()
输出结果为:
.. code-block:: text
[[1L, 3L, 3L, 3L]]
**完整代码**
您可以运行下列完整代码,观察输出结果:
.. code-block:: python
#加载库
import paddle
import paddle.fluid as fluid
import numpy as np
#定义前向计算
x = fluid.layers.data(name='x', shape=[1], dtype='float32', lod_level=1)
y = fluid.layers.data(name='y', shape=[1], dtype='float32', lod_level=2)
out = fluid.layers.sequence_expand(x=x, y=y, ref_level=0)
#定义运算场所
place = fluid.CPUPlace()
#创建执行器
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())
#创建LoDTensor
x_d = fluid.create_lod_tensor(np.array([[1.1], [2.2],[3.3],[4.4]]).astype('float32'), [[1,3]], place)
y_d = fluid.create_lod_tensor(np.array([[1.1],[1.1],[1.1],[1.1],[1.1],[1.1]]).astype('float32'), [[1,3], [1,2,1,2]], place)
#开始计算
results = exe.run(fluid.default_main_program(),
feed={'x':x_d, 'y': y_d },
fetch_list=[out],return_numpy=False)
#输出执行结果
print("The data of the result: {}.".format(np.array(results[0])))
#输出 result 的序列长度
print("The recursive sequence lengths of the result: {}.".format(results[0].recursive_sequence_lengths()))
#输出 result 的 LoD
print("The LoD of the result: {}.".format(results[0].lod()))
总结
========
至此,相信您已经基本掌握了LoD-Tensor的概念,尝试修改上述代码中的 x_d 与 y_d,观察输出结果,有助于您更好的理解这一灵活的结构。
更多LoDTensor的模型应用,可以参考新手入门中的 `词向量 <../../../beginners_guide/basics/word2vec/index.html>`_ 、`个性化推荐 <../../../beginners_guide/basics/recommender_system/index.html>`_、`情感分析 <../../../beginners_guide/basics/understand_sentiment/index.html>`_ 等指导教程。
更高阶的应用案例,请参考 `模型库 <../../../user_guides/models/index_cn.html>`_ 中的相关内容。
############
基本概念
############
本文介绍 Paddle 中的基本概念:
- `Variable <variable.html>`_ : Variable表示变量,在Paddle中可以包含任何类型的值,在大多数情况下是一个Lod-Tensor。
- `Tensor <tensor.html>`_ : Tensor表示数据。
- `LoD-Tensor <lod_tensor.html>`_ : LoD-Tensor是Paddle的高级特性,它在Tensor基础上附加了序列信息,支持处理变长数据。
- `Operator <operator.html>`_ : Operator表示对数据的操作。
- `Program <program.html>`_ : Program表示对计算过程的描述。
- `Executor <executor.html>`_ : Executor表示执行引擎。
.. toctree::
:hidden:
variable.rst
tensor.rst
lod_tensor.rst
operator.rst
program.rst
executor.rst
.. _cn_user_guide_lod_tensor:
##################
LoD-Tensor使用说明
##################
=========
LoDTensor
=========
LoD(Level-of-Detail) Tensor是Fluid中特有的概念,它在Tensor基础上附加了序列信息。Fluid中可传输的数据包括:输入、输出、网络中的可学习参数,全部统一使用LoD-Tensor表示。
LoD(Level-of-Detail) Tensor是Paddle的高级特性,是对Tensor的一种扩充。LoDTensor通过牺牲灵活性来提升训练的效率。
阅读本文档将帮助您了解 Fluid 中的 LoD-Tensor 设计思想,以便您更灵活的使用这一数据类型。
**注:对于大部分用户来说,无需关注LoDTensor的用法。**
变长序列的挑战
================
大多数的深度学习框架使用Tensor表示一个mini-batch。
例如一个mini-batch中有10张图片,每幅图片大小为32x32,则这个mini-batch是一个10x32x32的 Tensor。
变长序列的解决方案
================
或者在处理NLP任务中,一个mini-batch包含N个句子,每个字都用一个D维的one-hot向量表示,假设所有句子都用相同的长度L,那这个mini-batch可以被表示为NxLxD的Tensor。
现在主流的训练框架都采用batch的训练方式,即一个batch中包含多个样本。在nlp的任务中,一个batch中包含N个句子,句子的长度可能会不一致,为了解决这种长度不一致问题,Paddle提供了两种解决方案:1)padding,即在句子的结尾(或开头)添加padding id(建议的方式);2)LoDTensor,tensor中同时保存序列的长度信息。
上述两个例子中序列元素都具有相同大小,但是在许多情况下,训练数据是变长序列。基于这一场景,大部分框架采取的方法是确定一个固定长度,对小于这一长度的序列数据以0填充。
对于padding的方式,会增加框架的计算量,但是对于大部分nlp任务,可以通过分桶、排序等机制,使得一个batch内的句子长度尽可能接近、能够降低padding id的比例,padding对于训练的计算量影响可以忽略。而且可以通过引入mask(记录哪些位置是padding id)信息,来移除padding id对于训练效果的影响。
在Fluid中,由于LoD-Tensor的存在,我们不要求每个mini-batch中的序列数据必须保持长度一致,因此您不需要执行填充操作,也可以满足处理NLP等具有序列要求的任务需求。
但是对于一部分nlp任务来说,一个batch内的句子长度无法做到接近,比如聊天任务,需要计算query和多个答案之间的相似度,答案必须在一个batch中,这些答案的长度差异可能会非常大,最长的几百个token,最短的10几个token,如果采用padding的方式,计算量会增加几十倍,这种场景非常适合LoDTensor。LoDTensor存储了样本的长度信息,不需要增加padding的词,能给大幅减少计算量,从而提高训练的速度。
Fluid引入了一个索引数据结构(LoD)来将张量分割成序列。
LoDTensor将长度不一致的维度拼接为一个大的维度,并引入了一个索引数据结构(LoD)来将张量分割成序列。LoDTensor进行了维度拼接之后,rank大小和之前padding的方式不一致,在一些运算(如dot attention)逻辑比padding方式要复杂。
**注:如果训练样本无法通过排序、分桶等手段,使得一个batch内的样本的长度非常接近,推荐用户使用LoDTensor;其他情况下,建议用户使用padding的组网方式。**
LoD 索引
===========
......@@ -301,7 +299,7 @@ layers.sequence_expand通过获取 y 的 lod 值对 x 的数据进行扩充,
feed={'x':x_d, 'y': y_d },
fetch_list=[out],return_numpy=False)
**查看LodTensor结果**
**查看LoDTensor结果**
由于LoDTensor的特殊属性,无法直接print查看内容,常用操作时将LoD-Tensor作为网络的输出fetch出来,然后执行 numpy.array(lod_tensor), 就能转成numpy array:
......
.. _cn_user_guide_Operator:
=======
Operator
=======
在飞桨(PaddlePaddle,以下简称Paddle)中,所有对数据的操作都由Operator表示
为了便于用户使用,在Python端,Paddle中的Operator被封装入 :code:`paddle.fluid.layers` , :code:`paddle.fluid.nets` 等模块。
因为一些常见的对Tensor的操作可能是由更多基础操作构成,为了提高使用的便利性,框架内部对基础 Operator 进行了一些封装,包括创建 Operator 依赖可学习参数,可学习参数的初始化细节等,减少用户重复开发的成本。
例如用户可以利用 :code:`paddle.fluid.layers.elementwise_add()` 实现两个输入Tensor的加法运算:
.. code-block:: python
import paddle.fluid as fluid
import numpy
a = fluid.data(name="a",shape=[1],dtype='float32')
b = fluid.data(name="b",shape=[1],dtype='float32')
result = fluid.layers.elementwise_add(a,b)
# 定义执行器,并且制定执行的设备为CPU
cpu = fluid.core.CPUPlace()
exe = fluid.Executor(cpu)
exe.run(fluid.default_startup_program())
x = numpy.array([5]).astype("float32")
y = numpy.array([7]).astype("float32")
outs = exe.run(
feed={'a':x,'b':y},
fetch_list=[result])
# 打印输出结果,[array([12.], dtype=float32)]
print( outs )
如果想获取网络执行过程中的a,b的具体值,可以将希望查看的变量添加在fetch_list中。
.. code-block:: python
#执行计算
outs = exe.run(
feed={'a':x,'b':y},
fetch_list=[a,b,result])
#查看输出结果
print( outs )
输出结果:
.. code-block:: python
[array([5.], dtype=float32), array([7.], dtype=float32), array([12.], dtype=float32)]
.. _cn_user_guide_Program:
=======
Program
=======
飞桨(PaddlePaddle,以下简称Paddle)用Program的形式动态描述整个计算过程。这种描述方式,兼具网络结构修改的灵活性和模型搭建的便捷性,在保证性能的同时极大地提高了框架对模型的表达能力。
用户定义Operator会被顺序的放入Program中,在网络搭建过程中,由于不能使用python 的控制流,Paddle通过同时提供分支和循环两类控制流op结构的支持,让用户可以通过组合描述任意复杂的模型。
**顺序执行:**
用户可以使用顺序执行的方式搭建网络:
.. code-block:: python
x = fluid.data(name='x',shape=[None, 13], dtype='float32')
y_predict = fluid.layers.fc(input=x, size=1, act=None)
y = fluid.layers.data(name='y', shape=[1], dtype='float32')
cost = fluid.layers.square_error_cost(input=y_predict, label=y)
**条件分支——switch、if else:**
Fluid 中有 switch 和 if-else 类来实现条件选择,用户可以使用这一执行结构在学习率调节器中调整学习率或其他希望的操作:
.. code-block:: python
lr = fluid.layers.tensor.create_global_var(
shape=[1],
value=0.0,
dtype='float32',
persistable=True,
name="learning_rate")
one_var = fluid.layers.fill_constant(
shape=[1], dtype='float32', value=1.0)
two_var = fluid.layers.fill_constant(
shape=[1], dtype='float32', value=2.0)
with fluid.layers.control_flow.Switch() as switch:
with switch.case(global_step == zero_var):
fluid.layers.tensor.assign(input=one_var, output=lr)
with switch.default():
fluid.layers.tensor.assign(input=two_var, output=lr)
关于 Padldle 中 Program 的详细设计思想,可以参考阅读 `Fluid设计思想 <../../../advanced_usage/design_idea/fluid_design_idea.html>`_ 。
更多 Paddle 中的控制流,可以参考阅读 `API文档 <../../../api_guides/low_level/layers/control_flow.html>`_ 。
.. _cn_user_guide_tensor:
=========
Tensor
=========
飞桨(PaddlePaddle,以下简称Paddle)和其他框架一样,使用Tensor来表示数据。
在神经网络中传递的数据都是Tensor。Tensor可以简单理解成一个多维数组,一般而言可以有任意多的维度。
不同的Tensor可以具有自己的数据类型和形状,同一Tensor中每个元素的数据类型是一样的,Tensor的形状就是Tensor的维度。
下图直观地表示1~6维的Tensor:
.. image:: ../../../beginners_guide/image/tensor.jpg
**Paddle 高级特性**
:ref:`Lod-Tensor <cn_user_guide_lod_tensor>`
对于一些任务中batch内样本大小不一致的问题,Paddle提供了两种解决方案:
1. padding, 将大小不一致的样本padding到同样的大小,这是一种常用且推荐的使用方式;
2. :ref:`Lod-Tensor <cn_user_guide_lod_tensor>` ,记录每一个样本的大小,减少无用的计算量,LoD 牺牲灵活性来提升性能。
如果一个batch内的样本无法通过分桶、排序等方式使得大小接近, 建议使用 :ref:`Lod-Tensor <cn_user_guide_lod_tensor>` 。
.. _cn_user_guide_Variable:
=========
Variable
=========
飞桨(PaddlePaddle,以下简称Paddle)中的 :code:`Variable` 可以包含任何类型的值变量,提供的API中用到的类型是 :ref:`Tensor <cn_user_guide_tensor>` 。
后续的文档介绍中提到的 :code:`Variable` 基本等价于 :ref:`Tensor <cn_user_guide_tensor>` (特殊的地方会标注说明)。
在 Paddle 中存在三种 :code:`Variable`:
**1. 模型中的可学习参数**
模型中的可学习参数(包括网络权重、偏置等)生存期和整个训练任务一样长,会接受优化算法的更新,在 Paddle中以 Variable 的子类 Parameter 表示。
在Paddle中可以通过 :code:`fluid.layers.create_parameter` 来创建可学习参数:
.. code-block:: python
w = fluid.layers.create_parameter(name="w",shape=[1],dtype='float32')
Paddle 为大部分常见的神经网络基本计算模块都提供了封装。以最简单的全连接模型为例,下面的代码片段会直接为全连接层创建连接权值(W)和偏置( bias )两个可学习参数,无需显式地调用 Parameter 相关接口来创建。
.. code-block:: python
import paddle.fluid as fluid
y = fluid.layers.fc(input=x, size=128, bias_attr=True)
**2. 占位 Variable**
在静态图模式下,组网的时候通常不知道实际输入的信息,此刻需要一个占位的 :code:`Variable`,表示一个待提供输入的 :code:`Variable`
Paddle 中使用 :code:`fluid.data` 来接收输入数据, :code:`fluid.data` 需要提供输入 Tensor 的形状信息,当遇到无法确定的维度时,相应维度指定为 None ,如下面的代码片段所示:
.. code-block:: python
import paddle.fluid as fluid
#定义x的维度为[3,None],其中我们只能确定x的第一的维度为3,第二个维度未知,要在程序执行过程中才能确定
x = fluid.data(name="x", shape=[3,None], dtype="int64")
#若图片的宽度和高度在运行时可变,将宽度和高度定义为None。
#shape的三个维度含义分别是:batch_size, channel、图片的宽度、图片的高度
b = fluid.data(name="image",shape=[None, 3,None,None],dtype="float32")
其中,dtype=“int64”表示有符号64位整数数据类型,更多Fluid目前支持的数据类型请查看: :ref:`Paddle目前支持的数据类型 <user_guide_use_numpy_array_as_train_data>` 。
**3. 常量 Variable**
Fluid 通过 :code:`fluid.layers.fill_constant` 来实现常量Variable,用户可以指定内部包含Tensor的形状,数据类型和常量值。代码实现如下所示:
.. code-block:: python
import paddle.fluid as fluid
data = fluid.layers.fill_constant(shape=[1], value=0, dtype='int64')
......@@ -611,23 +611,21 @@ Loss at epoch 0 step 0: [0.5767452]
## 模型参数的保存
动态图由于模型和优化器在不同的对象中存储,模型参数和优化器信息要分别存储。

在模型训练中可以使用` fluid.dygraph.save_persistables(your_model_object.state_dict(), "save_dir", optimizers=None)`来保存`your_model_object`中所有的模型参数, 以及使用`learning rate decay`的优化器。也可以自定义需要保存的“参数名” - “参数对象”的Python Dictionary传入。
同样可以使用`models,optimizers = fluid.dygraph.load_persistables("save_dir")`获取保存的模型参数和优化器。
再使用`your_modle_object.load_dict(models)`接口来恢复保存的模型参数从而达到继续训练的目的。
以及使用`your_optimizer_object.load(optimizers)`接口来恢复保存的优化器中的`learning rate decay`

在模型训练中可以使用 `paddle.fluid.dygraph.save_dygraph(state_dict, model_path)` 来保存模型参数的dict或优化器信息的dict。
同样可以使用 `paddle.fluid.dygraph.load_dygraph(model_path)` 获取保存的模型参数的dict和优化器信息的dict。
再使用`your_modle_object.set_dict(para_dict)`接口来恢复保存的模型参数从而达到继续训练的目的。
以及使用`your_optimizer_object.set_dict(opti_dict)`接口来恢复保存的优化器中的`learning rate decay`值。
下面的代码展示了如何在“手写数字识别”任务中保存参数并且读取已经保存的参数来继续训练。
```python
import paddle.fluid as fluid
with fluid.dygraph.guard():
epoch_num = 5
BATCH_SIZE = 64
......@@ -660,14 +658,14 @@ with fluid.dygraph.guard():
avg_loss.backward()
adam.minimize(avg_loss)
if batch_id == 20:
fluid.dygraph.save_persistables(mnist.state_dict(), "save_dir", adam)
fluid.dygraph.save_dygraph(mnist.state_dict(), "paddle_dy")
mnist.clear_gradients()
if batch_id == 20:
for param in mnist.parameters():
dy_param_init_value[param.name] = param.numpy()
model, _ = fluid.dygraph.load_persistables("save_dir")
mnist.load_dict(model)
model, _ = fluid.dygraph.load_dygraph("paddle_dy")
mnist.set_dict(model)
break
if epoch == 0:
break
......@@ -685,7 +683,7 @@ with fluid.dygraph.guard():
```python
if fluid.dygraph.parallel.Env().local_rank == 0:
fluid.dygraph.save_persistables(mnist.state_dict(), "save_dir")
fluid.dygraph.save_dygraph(mnist.state_dict(), "paddle_dy")
```
## 模型评估
......@@ -728,7 +726,7 @@ def inference_mnist():
with fluid.dygraph.guard():
mnist_infer = MNIST("mnist")
# load checkpoint
model_dict, _ = fluid.dygraph.load_persistables("save_dir")
model_dict, _ = fluid.dygraph.load_dygraph("paddle_dy")
mnist_infer.load_dict(model_dict)
print("checkpoint loaded")
......@@ -794,7 +792,7 @@ with fluid.dygraph.guard():
print("Loss at epoch {} , Test avg_loss is: {}, acc is: {}".format(
epoch, test_cost, test_acc))
fluid.dygraph.save_persistables(mnist.state_dict(), "save_dir")
fluid.dygraph.save_dygraph(mnist.state_dict(), "paddle_dy")
print("checkpoint saved")
inference_mnist()
......
......@@ -4,23 +4,23 @@
.. todo::
如果您已经掌握了新手入门阶段的内容,期望可以针对实际问题建模、搭建自己网络,本模块提供了一些 Fluid 的使用细节供您参考:
如果您已经掌握了新手入门阶段的内容,期望可以针对实际问题建模、搭建自己网络,本模块提供了一些 Paddle 的使用细节供您参考:
- `LoD-Tensor概念 <../user_guides/howto/basic_concept/index_cn.html>`_ :介绍了Fluid LoD-Tensor的基本概念
- `基本概念 <../user_guides/howto/basic_concept/index_cn.html>`_ :介绍了 Paddle 基本概念
- `准备数据 <../user_guides/howto/prepare_data/index_cn.html>`_ :介绍使用 Fluid 训练网络时,数据的支持类型及传输方法
- `准备数据 <../user_guides/howto/prepare_data/index_cn.html>`_ :介绍使用 Paddle 训练网络时,数据的支持类型及传输方法
- `配置简单的网络 <../user_guides/howto/configure_simple_model/index_cn.html>`_: 介绍如何针对问题建模,并利用 Fluid 中相关算子搭建网络
- `配置简单的网络 <../user_guides/howto/configure_simple_model/index_cn.html>`_: 介绍如何针对问题建模,并利用 Paddle 中相关算子搭建网络
- `训练神经网络 <../user_guides/howto/training/index_cn.html>`_:介绍如何使用 Fluid 进行单机训练、多机训练、以及保存和载入模型变量
- `训练神经网络 <../user_guides/howto/training/index_cn.html>`_:介绍如何使用 Paddle 进行单机训练、多机训练、以及保存和载入模型变量
- `DyGraph模式 <../user_guides/howto/dygraph/DyGraph.html>`_:介绍在 Fluid 下使用DyGraph
- `DyGraph模式 <../user_guides/howto/dygraph/DyGraph.html>`_:介绍在 Paddle 下使用DyGraph
- `模型评估与调试 <../user_guides/howto/evaluation_and_debugging/index_cn.html>`_:介绍在 Fluid 下进行模型评估和调试的方法。
- `模型评估与调试 <../user_guides/howto/evaluation_and_debugging/index_cn.html>`_:介绍在 Paddle 下进行模型评估和调试的方法。
基于 Fluid 复现的多领域经典模型:
基于 Paddle 复现的多领域经典模型:
- `Fluid 模型库 <../user_guides/models/index_cn.html>`_
- `模型库 <../user_guides/models/index_cn.html>`_
.. toctree::
:hidden:
......@@ -31,4 +31,4 @@
howto/training/index_cn.rst
howto/evaluation_and_debugging/index_cn.rst
howto/dygraph/DyGraph.md
models/index_cn.md
models/index_cn.rst
`Fluid 模型库 <https://github.com/PaddlePaddle/models>`__
`模型库 <https://github.com/PaddlePaddle/models>`__
============
图像分类
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册