Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
FluidDoc
提交
a0329a8f
F
FluidDoc
项目概览
PaddlePaddle
/
FluidDoc
通知
5
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
23
列表
看板
标记
里程碑
合并请求
111
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
F
FluidDoc
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
23
Issue
23
列表
看板
标记
里程碑
合并请求
111
合并请求
111
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
a0329a8f
编写于
5月 18, 2020
作者:
P
phlrain
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
update dygraph doc; test=develop
上级
e604819a
变更
1
显示空白变更内容
内联
并排
Showing
1 changed file
with
17 addition
and
16 deletion
+17
-16
doc/fluid/beginners_guide/basic_concept/dygraph/DyGraph.md
doc/fluid/beginners_guide/basic_concept/dygraph/DyGraph.md
+17
-16
未找到文件。
doc/fluid/beginners_guide/basic_concept/dygraph/DyGraph.md
浏览文件 @
a0329a8f
# 动态图使用教程
从编程范式上说,飞桨兼容支持声明式编程和命令式编程,通俗地讲即动态图和静态图。其实飞桨本没有图的概念,在飞桨的设计中,把一个神经网络定义成一段类似程序的描述,也就是用户在写程序的过程中,就定义了模型表达及计算。在声明式编程模式的控制流实现方面,飞桨借助自己实现的控制流OP而不是python原生的if else和for循环,这使得在飞桨中的定义的program即一个网络模型,可以有一个内部的表达,是可以全局优化编译执行的。考虑对开发者来讲,更愿意使用python原生控制流,飞桨也做了支持,并通过解释方式执行,这就是命令式编程模式。但整体上,这两种编程范式是相对兼容统一的。飞桨将持续发布更完善的命令式编程模式功能,同时保持更强劲的性能。
飞桨平台中,将神经网络抽象为计算表示
**Operator**
(算子,常简称OP)和数据表示
**Variable**
(变量),如 图1 所示。神经网络的每层操作均由一个或若干
**Operator**
组成,每个
**Operator**
接受一系列的
**Variable**
作为输入,经计算后输出一系列的
**Variable**
。
...
...
@@ -5,14 +7,13 @@
<br>
<center>
图1 Operator和Variable关系示意图
</center>
根据
**Operator**
解析执行方式不同,飞桨支持如下两种编程范式:
*
**声明式编程模式模式(动态图)**
:先编译后执行的方式。用户需预先定义完整的网络结构,再对网络结构进行编译优化后,才能执行获得计算结果。
*
**命令式编程模式模式(静态图)**
:解析式的执行方式。用户无需预先定义完整的网络结构,每写一行网络代码,即可同时获得计算结果。
举例来说,假设用户写了一行代码:y=x+1,在声明式编程模式模式下,运行此代码只会往计算图中插入一个Tensor加1的
**Operator**
,此时
**Operator**
并未真正执行,无法获得y的计算结果。但在命令式编程模式模式下,所有
**Operator**
均是即时执行的,运行完此代码后
**Operator**
已经执行完毕,用户可直接获得y的计算结果。
# 为什么命令式编程模式模式越来越流行?
#
#
为什么命令式编程模式模式越来越流行?
声明式编程模式模式作为较早提出的一种编程范式,提供丰富的 API ,能够快速的实现各种模型;并且可以利用全局的信息进行图优化,优化性能和显存占用;在预测部署方面也可以实现无缝衔接。 但具体实践中声明式编程模式模式存在如下问题:
1.
采用先编译后执行的方式,组网阶段和执行阶段割裂,导致调试不方便。
...
...
@@ -33,7 +34,7 @@
5.
命令式编程模式模式常见的使用技巧,如中间变量值/梯度打印、断点调试、阻断反向传递,以及某些场景下如何改写为声明式编程模式模式运行。
# 1. 开启命令式编程模式模式
#
#
1. 开启命令式编程模式模式
目前飞桨默认的模式是声明式编程模式,采用基于 context (上下文)的管理方式开启命令式编程模式模式:
```
...
...
@@ -119,7 +120,7 @@ with fluid.dygraph.guard():
*
命令式编程模式模式下,所有操作在运行时就已经完成,更接近我们平时的编程方式,可以随时获取每一个操作的执行结果。
*
声明式编程模式模式下,过程中并没有实际执行操作,上述例子中可以看到只能打印声明的类型,最后需要调用执行器来统一执行所有操作,计算结果需要通过执行器统一返回。
# 2. 使用命令式编程模式进行模型训练
#
#
2. 使用命令式编程模式进行模型训练
接下来我们以一个简单的手写体识别任务为例,说明如何使用飞桨的命令式编程模式来进行模型的训练。包括如下步骤:
*
2.1 定义数据读取器:读取数据和预处理操作。
...
...
@@ -135,7 +136,7 @@ with fluid.dygraph.guard():
有关该任务和数据集的详细介绍,可参考:
[
初识飞桨手写数字识别模型
](
https://aistudio.baidu.com/aistudio/projectdetail/224342
)
## 2.1 定义数据读取器
##
#
2.1 定义数据读取器
飞桨提供了多个封装好的数据集API,本任务我们可以通过调用
[
paddle.dataset.mnist
](
https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/data/dataset_cn.html
)
的 train 函数和 test 函数,直接获取处理好的 MNIST 训练集和测试集;然后调用
[
paddle.batch
](
https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/io_cn/batch_cn.html#batch
)
接口返回 reader 的装饰器,该 reader 将输入 reader 的数据打包成指定 BATCH_SIZE 大小的批处理数据。
...
...
@@ -171,7 +172,7 @@ test_reader = paddle.batch(
Download finished
## 2.2 定义模型和优化器
##
#
2.2 定义模型和优化器
本节我们采用如下网络模型,该模型可以很好的完成“手写数字识别”的任务。模型由卷积层 -> 池化层 -> 卷积层 -> 池化层 -> 全连接层组成,池化层即降采样层。
...
...
@@ -317,7 +318,7 @@ with fluid.dygraph.guard():
adam
=
AdamOptimizer
(
learning_rate
=
0.001
,
parameter_list
=
mnist
.
parameters
())
```
## 2.3 训练
##
#
2.3 训练
当我们定义好上述网络结构之后,就可以进行训练了。
...
...
@@ -407,7 +408,7 @@ with fluid.dygraph.guard():
Loss at epoch 2 step 400: [0.0497771]
## 2.4 评估测试
##
#
2.4 评估测试
模型训练完成,我们已经保存了训练好的模型,接下来进行评估测试。某些OP(如 dropout、batch_norm)需要区分训练模式和评估模式,以标识不同的执行状态。飞桨中OP默认采用的是训练模式(train mode),可通过如下方法切换:
...
...
@@ -463,7 +464,7 @@ with fluid.dygraph.guard():
print
(
"Eval avg_loss is: {}, acc is: {}"
.
format
(
avg_loss_val_mean
,
acc_val_mean
))
```
## 2.5 模型参数的保存和加载
##
#
2.5 模型参数的保存和加载
在命令式编程模式模式下,模型和优化器在不同的模块中,所以模型和优化器分别在不同的对象中存储,使得模型参数和优化器信息需分别存储。
因此模型的保存需要单独调用模型和优化器中的 state_dict() 接口,同样模型的加载也需要单独进行处理。
...
...
@@ -497,7 +498,7 @@ with fluid.dygraph.guard():
```
# 3. 多卡训练
#
#
3. 多卡训练
针对数据量、计算量较大的任务,我们需要多卡并行训练,以提高训练效率。目前命令式编程模式模式可支持GPU的单机多卡训练方式,在命令式编程模式中多卡的启动和单卡略有不同,命令式编程模式多卡通过 Python 基础库 subprocess.Popen 在每一张 GPU 上启动单独的 Python 程序的方式,每张卡的程序独立运行,只是在每一轮梯度计算完成之后,所有的程序进行梯度的同步,然后更新训练的参数。
...
...
@@ -640,7 +641,7 @@ if fluid.dygraph.parallel.Env().local_rank == 0:
对模型进行评估测试时,如果需要加载模型,须确保评估和保存的操作在同一个进程中,否则可能出现模型尚未保存完成,即启动评估,造成加载出错的问题。如果不需要加载模型,则没有这个问题,在一个进程或多个进程中评估均可。
# 4. 模型部署
#
#
4. 模型部署
命令式编程模式虽然有非常多的优点,但是如果用户希望使用 C++ 部署已经训练好的模型,会存在一些不便利。比如,命令式编程模式中可使用 Python 原生的控制流,包含 if/else、switch、for/while,这些控制流需要通过一定的机制才能映射到 C++ 端,实现在 C++ 端的部署。
...
...
@@ -776,9 +777,9 @@ with fluid.dygraph.guard():
prog_trans
.
save_inference_model
(
"./mnist_dy2stat"
,
fetch
=
[
0
,
1
])
```
# 5. 使用技巧
#
#
5. 使用技巧
## 5.1 中间变量值、梯度打印
##
#
5.1 中间变量值、梯度打印
1.
用户想要查看任意变量的值,可以使用
[
numpy
](
https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/Variable_cn.html#numpy
)
接口。
...
...
@@ -800,7 +801,7 @@ print(y.gradient())
可以直接打印反向梯度的值
## 5.2 断点调试
##
#
5.2 断点调试
因为命令式编程模式采用了命令似的编程方式,程序在执行之后,可以立马获取到执行的结果,因此在命令式编程模式中,用户可以利用IDE提供的断点调试功能,通过查 Variable 的 shape、真实值等信息,有助于发现程序中的问题。
...
...
@@ -817,7 +818,7 @@ print(y.gradient())
## 5.3 使用声明式编程模式模式运行
##
#
5.3 使用声明式编程模式模式运行
命令式编程模式虽然有友好编写、易于调试等功能,但是命令式编程模式中需要频繁进行 Python 与 C++ 交互,会导致一些任务在命令式编程模式中运行比声明式编程模式慢,根据经验,这类任务中包含了很多小粒度的 OP(指运算量相对比较小的 OP,如加减乘除、sigmoid 等,像 conv、matmul 等属于大粒度的 OP不在此列 )。
...
...
@@ -904,7 +905,7 @@ with fluid.program_guard(main_program=main_program, startup_program=startup_prog
*
需要对网络进行初始化操作。
*
需要使用执行器执行之前已经定义好的网络,需要调用执行器的run方法执行计算过程。
## 5.4 阻断反向传递
##
#
5.4 阻断反向传递
在一些任务中,只希望拿到正向预测的值,但是不希望更新参数,或者在反向的时候剪枝,减少计算量,阻断反向的传播, Paddle提供了两种解决方案:
[
detach
](
https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/Variable_cn.html#detach
)
接口和
[
stop_gradient
](
https://www.paddlepaddle.org.cn/documentation/docs/zh/api_cn/fluid_cn/Variable_cn.html#stop_gradient
)
接口,建议用户使用 detach 接口。
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录