提交 a0329a8f 编写于 作者: P phlrain

update dygraph doc; test=develop

上级 e604819a
# 动态图使用教程
从编程范式上说,飞桨兼容支持声明式编程和命令式编程,通俗地讲即动态图和静态图。其实飞桨本没有图的概念,在飞桨的设计中,把一个神经网络定义成一段类似程序的描述,也就是用户在写程序的过程中,就定义了模型表达及计算。在声明式编程模式的控制流实现方面,飞桨借助自己实现的控制流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.
先完成此消息的编辑!
想要评论请 注册