Skip to content

Commit

Permalink
[1e feedback] ch3
Browse files Browse the repository at this point in the history
  • Loading branch information
astonzhang committed Jan 14, 2019
1 parent c22eb20 commit 133266e
Show file tree
Hide file tree
Showing 12 changed files with 106 additions and 106 deletions.
30 changes: 15 additions & 15 deletions chapter_deep-learning-basics/backprop.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
# 正向传播、反向传播和计算图

前面几节里我们使用了小批量随机梯度下降的优化算法来训练模型。在实现中,我们只提供了模型的正向传播(forward propagation)的计算,即对输入计算模型输出,然后通过`autograd`模块来调用系统自动生成的`backward`函数计算梯度。基于反向传播算法(back-propagation)的自动求梯度极大简化了深度学习模型训练算法的实现。这一节我们将使用数学和计算图(computational graph)两个方式来描述正向传播和反向传播。具体地,我们将以带$L_2$范数正则化的单隐藏层感知机为样例模型解释正向传播和反向传播
前面几节里我们使用了小批量随机梯度下降的优化算法来训练模型。在实现中,我们只提供了模型的正向传播(forward propagation)的计算,即对输入计算模型输出,然后通过`autograd`模块来调用系统自动生成的`backward`函数计算梯度。基于反向传播(back-propagation)算法的自动求梯度极大简化了深度学习模型训练算法的实现。本节我们将使用数学和计算图(computational graph)两个方式来描述正向传播和反向传播。具体来说,我们将以带$L_2$范数正则化的含单隐藏层的多层感知机为样例模型解释正向传播和反向传播

## 正向传播

正向传播是指对神经网络沿着从输入层到输出层的顺序,依次计算并存储模型的中间变量(包括输出)。为简单起见,假设输入是一个特征为$\boldsymbol{x} \in \mathbb{R}^d$的样本,且不考虑偏差项,那么中间变量

$$\boldsymbol{z} = \boldsymbol{W}^{(1)} \boldsymbol{x},$$

其中$\boldsymbol{W}^{(1)} \in \mathbb{R}^{h \times d}$是隐藏层的权重参数。把中间变量$\boldsymbol{z} \in \mathbb{R}^h$输入按元素操作的激活函数$\phi$后,我们将得到向量长度为$h$的隐藏层变量
其中$\boldsymbol{W}^{(1)} \in \mathbb{R}^{h \times d}$是隐藏层的权重参数。把中间变量$\boldsymbol{z} \in \mathbb{R}^h$输入按元素运算的激活函数$\phi$后,将得到向量长度为$h$的隐藏层变量

$$\boldsymbol{h} = \phi (\boldsymbol{z}).$$

隐藏变量$\boldsymbol{h}$也是一个中间变量。假设输出层参数只有权重$\boldsymbol{W}^{(2)} \in \mathbb{R}^{q \times h}$,我们可以得到向量长度为$q$的输出层变量
隐藏层变量$\boldsymbol{h}$也是一个中间变量。假设输出层参数只有权重$\boldsymbol{W}^{(2)} \in \mathbb{R}^{q \times h}$,可以得到向量长度为$q$的输出层变量

$$\boldsymbol{o} = \boldsymbol{W}^{(2)} \boldsymbol{h}.$$

假设损失函数为$\ell$,且样本标签为$y$,我们可以计算出单个数据样本的损失项
假设损失函数为$\ell$,且样本标签为$y$,可以计算出单个数据样本的损失项

$$L = \ell(\boldsymbol{o}, y).$$

Expand All @@ -33,20 +33,20 @@ $$J = L + s.$$

## 正向传播的计算图

我们通常绘制计算图来可视化运算符和变量在计算中的依赖关系。图3.6绘制了本节中样例模型正向传播的计算图其中左下角是输入,右上角是输出。可以看到,图中箭头方向大多是向右和向上。
我们通常绘制计算图来可视化运算符和变量在计算中的依赖关系。图3.6绘制了本节中样例模型正向传播的计算图其中左下角是输入,右上角是输出。可以看到,图中箭头方向大多是向右和向上,其中方框代表变量,圆圈代表运算符,箭头表示从输入到输出之间的依赖关系

![正向传播的计算图。其中方框代表变量,圆圈代表运算符,箭头表示从输入到输出之间的依赖关系。](../img/forward.svg)
![正向传播的计算图](../img/forward.svg)


## 反向传播

反向传播指的是计算神经网络参数梯度的方法。总的来说,反向传播依据微积分中的链式法则,沿着从输出层到输入层的顺序,依次计算并存储目标函数有关神经网络各层的中间变量以及参数的梯度。对输入输出$\mathsf{X}, \mathsf{Y}, \mathsf{Z}$为任意形状张量的函数$\mathsf{Y}=f(\mathsf{X})$和$\mathsf{Z}=g(\mathsf{Y})$,通过链式法则,我们有
反向传播指的是计算神经网络参数梯度的方法。总的来说,反向传播依据微积分中的链式法则,沿着从输出层到输入层的顺序,依次计算并存储目标函数有关神经网络各层的中间变量以及参数的梯度。对输入或输出$\mathsf{X}, \mathsf{Y}, \mathsf{Z}$为任意形状张量的函数$\mathsf{Y}=f(\mathsf{X})$和$\mathsf{Z}=g(\mathsf{Y})$,通过链式法则,我们有

$$\frac{\partial \mathsf{Z}}{\partial \mathsf{X}} = \text{prod}\left(\frac{\partial \mathsf{Z}}{\partial \mathsf{Y}}, \frac{\partial \mathsf{Y}}{\partial \mathsf{X}}\right),$$

其中$\text{prod}$运算符将根据两个输入的形状,在必要的操作(例如转置和互换输入位置)后对两个输入做乘法。
其中$\text{prod}$运算符将根据两个输入的形状,在必要的操作(如转置和互换输入位置)后对两个输入做乘法。

回顾一下本节中样例模型,它的参数是$\boldsymbol{W}^{(1)}$和$\boldsymbol{W}^{(2)}$,因此反向传播的目标是计算$\partial J/\partial \boldsymbol{W}^{(1)}$和$\partial J/\partial \boldsymbol{W}^{(2)}$。我们将应用链式法则依次计算各中间变量和参数的梯度,其计算次序与前向传播中相应中间变量的计算次序相反。首先,分别计算目标函数$J=L+s$有关损失项$L$和正则项$s$的梯度
回顾一下本节中样例模型,它的参数是$\boldsymbol{W}^{(1)}$和$\boldsymbol{W}^{(2)}$,因此反向传播的目标是计算$\partial J/\partial \boldsymbol{W}^{(1)}$和$\partial J/\partial \boldsymbol{W}^{(2)}$。我们将应用链式法则依次计算各中间变量和参数的梯度,其计算次序与前向传播中相应中间变量的计算次序恰恰相反。首先,分别计算目标函数$J=L+s$有关损失项$L$和正则项$s$的梯度

$$\frac{\partial J}{\partial L} = 1, \quad \frac{\partial J}{\partial s} = 1.$$

Expand All @@ -64,7 +64,7 @@ $$
$$\frac{\partial s}{\partial \boldsymbol{W}^{(1)}} = \lambda \boldsymbol{W}^{(1)},\quad\frac{\partial s}{\partial \boldsymbol{W}^{(2)}} = \lambda \boldsymbol{W}^{(2)}.$$


现在,我们可以计算最靠近输出层的模型参数的梯度$\partial J/\partial \boldsymbol{W}^{(2)} \in \mathbb{R}^{q \times h}$。依据链式法则,我们得到
现在,我们可以计算最靠近输出层的模型参数的梯度$\partial J/\partial \boldsymbol{W}^{(2)} \in \mathbb{R}^{q \times h}$。依据链式法则,得到

$$
\frac{\partial J}{\partial \boldsymbol{W}^{(2)}}
Expand All @@ -82,15 +82,15 @@ $$
$$


由于激活函数$\phi$是按元素操作的,中间变量$\boldsymbol{z}$的梯度$\partial J/\partial \boldsymbol{z} \in \mathbb{R}^h$的计算需要使用按元素乘法符$\odot$:
由于激活函数$\phi$是按元素运算的,中间变量$\boldsymbol{z}$的梯度$\partial J/\partial \boldsymbol{z} \in \mathbb{R}^h$的计算需要使用按元素乘法符$\odot$:

$$
\frac{\partial J}{\partial \boldsymbol{z}}
= \text{prod}\left(\frac{\partial J}{\partial \boldsymbol{h}}, \frac{\partial \boldsymbol{h}}{\partial \boldsymbol{z}}\right)
= \frac{\partial J}{\partial \boldsymbol{h}} \odot \phi'\left(\boldsymbol{z}\right).
$$

最终,我们可以得到最靠近输入层的模型参数的梯度$\partial J/\partial \boldsymbol{W}^{(1)} \in \mathbb{R}^{h \times d}$。依据链式法则,我们得到
最终,我们可以得到最靠近输入层的模型参数的梯度$\partial J/\partial \boldsymbol{W}^{(1)} \in \mathbb{R}^{h \times d}$。依据链式法则,得到

$$
\frac{\partial J}{\partial \boldsymbol{W}^{(1)}}
Expand All @@ -102,11 +102,11 @@ $$

在训练深度学习模型时,正向传播和反向传播之间相互依赖。下面我们仍然以本节中的样例模型分别阐述它们之间的依赖关系。

一方面,正向传播的计算可能依赖于模型参数的当前值而这些模型参数是在反向传播的梯度计算后通过优化算法迭代的。例如,计算正则化项$s = (\lambda/2) \left(\|\boldsymbol{W}^{(1)}\|_F^2 + \|\boldsymbol{W}^{(2)}\|_F^2\right)$依赖模型参数$\boldsymbol{W}^{(1)}$和$\boldsymbol{W}^{(2)}$的当前值而这些当前值是优化算法最近一次根据反向传播算出梯度后迭代得到的。
一方面,正向传播的计算可能依赖于模型参数的当前值而这些模型参数是在反向传播的梯度计算后通过优化算法迭代的。例如,计算正则化项$s = (\lambda/2) \left(\|\boldsymbol{W}^{(1)}\|_F^2 + \|\boldsymbol{W}^{(2)}\|_F^2\right)$依赖模型参数$\boldsymbol{W}^{(1)}$和$\boldsymbol{W}^{(2)}$的当前值而这些当前值是优化算法最近一次根据反向传播算出梯度后迭代得到的。

另一方面,反向传播的梯度计算可能依赖于各变量的当前值而这些变量的当前值是通过正向传播计算得到的。举例来说,参数梯度$\partial J/\partial \boldsymbol{W}^{(2)} = (\partial J / \partial \boldsymbol{o}) \boldsymbol{h}^\top + \lambda \boldsymbol{W}^{(2)}$的计算需要依赖隐藏层变量的当前值$\boldsymbol{h}$。这个当前值是通过从输入层到输出层的正向传播计算并存储得到的。
另一方面,反向传播的梯度计算可能依赖于各变量的当前值而这些变量的当前值是通过正向传播计算得到的。举例来说,参数梯度$\partial J/\partial \boldsymbol{W}^{(2)} = (\partial J / \partial \boldsymbol{o}) \boldsymbol{h}^\top + \lambda \boldsymbol{W}^{(2)}$的计算需要依赖隐藏层变量的当前值$\boldsymbol{h}$。这个当前值是通过从输入层到输出层的正向传播计算并存储得到的。

因此,在模型参数初始化完成后,我们交替地进行正向传播和反向传播,并根据反向传播计算的梯度迭代模型参数。既然我们在反向传播中使用了正向传播中计算得到的中间变量来避免重复计算,那么这个重用也导致正向传播结束后不能立即释放中间变量内存。这也是训练要比预测占用更多内存的一个重要原因。另外需要指出的是,这些中间变量的个数跟网络层数线性相关,每个变量的大小跟批量大小和输入个数也是线性相关的,它们是导致较深的神经网络使用较大批量训练时更容易超内存的主要原因。
因此,在模型参数初始化完成后,我们交替地进行正向传播和反向传播,并根据反向传播计算的梯度迭代模型参数。既然我们在反向传播中使用了正向传播中计算得到的中间变量来避免重复计算,那么这个复用也导致正向传播结束后不能立即释放中间变量内存。这也是训练要比预测占用更多内存的一个重要原因。另外需要指出的是,这些中间变量的个数大体上与网络层数线性相关,每个变量的大小跟批量大小和输入个数也是线性相关的,它们是导致较深的神经网络使用较大批量训练时更容易超内存的主要原因。


## 小结
Expand Down
14 changes: 7 additions & 7 deletions chapter_deep-learning-basics/dropout.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

$$h_i = \phi\left(x_1 w_{1i} + x_2 w_{2i} + x_3 w_{3i} + x_4 w_{4i} + b_i\right),$$

这里$\phi$是激活函数,$x_1, \ldots, x_4$是输入,隐藏单元$i$的权重参数为$w_{1i}, \ldots, w_{4i}$,偏差参数为$b_i$。当我们对该隐藏层使用丢弃法时,该层的隐藏单元将有一定概率被丢弃掉。设丢弃概率为$p$,
这里$\phi$是激活函数,$x_1, \ldots, x_4$是输入,隐藏单元$i$的权重参数为$w_{1i}, \ldots, w_{4i}$,偏差参数为$b_i$。当对该隐藏层使用丢弃法时,该层的隐藏单元将有一定概率被丢弃掉。设丢弃概率为$p$,
那么有$p$的概率$h_i$会被清零,有$1-p$的概率$h_i$会除以$1-p$做拉伸。丢弃概率是丢弃法的超参数。具体来说,设随机变量$\xi_i$为0和1的概率分别为$p$和$1-p$。使用丢弃法时我们计算新的隐藏单元$h_i'$

$$h_i' = \frac{\xi_i}{1-p} h_i.$$
Expand All @@ -17,7 +17,7 @@ $$h_i' = \frac{\xi_i}{1-p} h_i.$$

$$\mathbb{E}(h_i') = \frac{\mathbb{E}(\xi_i)}{1-p}h_i = h_i.$$

即丢弃法不改变其输入的期望值。让我们对图3.3中的隐藏层使用丢弃法,一种可能的结果如图3.5所示,其中$h_2$和$h_5$被清零。这时输出值的计算不再依赖$h_2$和$h_5$,在反向传播时,与这两个隐藏单元相关的权重的梯度均为0。由于在训练中隐藏层神经元的丢弃是随机的,即$h_1, \ldots, h_5$都有可能被清零。这样输出层的计算都无法过度依赖$h_1, \ldots, h_5$中的任一个,从而在训练模型时起到正则化的作用,并可以用来应对过拟合。在测试模型时,我们为了拿到更加确定性的结果,一般不使用丢弃法。
即丢弃法不改变其输入的期望值。让我们对图3.3中的隐藏层使用丢弃法,一种可能的结果如图3.5所示,其中$h_2$和$h_5$被清零。这时输出值的计算不再依赖$h_2$和$h_5$,在反向传播时,与这两个隐藏单元相关的权重的梯度均为0。由于在训练中隐藏层神经元的丢弃是随机的,即$h_1, \ldots, h_5$都有可能被清零,输出层的计算无法过度依赖$h_1, \ldots, h_5$中的任一个,从而在训练模型时起到正则化的作用,并可以用来应对过拟合。在测试模型时,我们为了拿到更加确定性的结果,一般不使用丢弃法。

![隐藏层使用了丢弃法的多层感知机。](../img/dropout.svg)

Expand Down Expand Up @@ -57,7 +57,7 @@ dropout(X, 1)

### 定义模型参数

实验中,我们依然使用[“softmax回归的从零开始实现”](softmax-regression-scratch.md)一节中介绍的Fashion-MNIST数据集。我们将定义一个包含两个隐藏层的多层感知机其中两个隐藏层的输出个数都是256。
实验中,我们依然使用[“softmax回归的从零开始实现”](softmax-regression-scratch.md)一节中介绍的Fashion-MNIST数据集。我们将定义一个包含两个隐藏层的多层感知机其中两个隐藏层的输出个数都是256。

```{.python .input}
num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256
Expand All @@ -76,7 +76,7 @@ for param in params:

### 定义模型

以下定义的模型将全连接层和激活函数ReLU串起来,并对每个激活函数的输出使用丢弃法。我们可以分别设置各个层的丢弃概率。通常的建议是把靠近输入层的丢弃概率设的小一点。在这个实验中,我们把第一个隐藏层的丢弃概率设为0.2,把第二个隐藏层的丢弃概率设为0.5。我们可以通过[“自动求梯度”](../chapter_prerequisite/autograd.md)一节中介绍的`is_training`函数来判断运行模式为训练还是测试,并只需在训练模式下使用丢弃法。
下面定义的模型将全连接层和激活函数ReLU串起来,并对每个激活函数的输出使用丢弃法。我们可以分别设置各个层的丢弃概率。通常的建议是把靠近输入层的丢弃概率设得小一点。在这个实验中,我们把第一个隐藏层的丢弃概率设为0.2,把第二个隐藏层的丢弃概率设为0.5。我们可以通过[“自动求梯度”](../chapter_prerequisite/autograd.md)一节中介绍的`is_training`函数来判断运行模式为训练还是测试,并只需在训练模式下使用丢弃法。

```{.python .input}
drop_prob1, drop_prob2 = 0.2, 0.5
Expand All @@ -94,7 +94,7 @@ def net(X):

### 训练和测试模型

这部分和之前多层感知机的训练与测试类似
这部分与之前多层感知机的训练和测试类似

```{.python .input}
num_epochs, lr, batch_size = 5, 0.5, 256
Expand Down Expand Up @@ -129,13 +129,13 @@ d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None,
## 小结

* 我们可以通过使用丢弃法应对过拟合。
* 丢弃法只在在训练模型时使用
* 丢弃法只在训练模型时使用

## 练习

* 如果把本节中的两个丢弃概率超参数对调,会有什么结果?
* 增大迭代周期数,比较使用丢弃法与不使用丢弃法的结果。
* 如果将模型改得更加复杂,例如增加隐藏层单元,使用丢弃法应对过拟合的效果是否更加明显?
* 如果将模型改得更加复杂,如增加隐藏层单元,使用丢弃法应对过拟合的效果是否更加明显?
* 以本节中的模型为例,比较使用丢弃法与权重衰减的效果。如果同时使用丢弃法和权重衰减,效果会如何?

## 扫码直达[讨论区](https://discuss.gluon.ai/t/topic/1278)
Expand Down
Loading

0 comments on commit 133266e

Please sign in to comment.