提交 44d95a76 编写于 作者: C cgwang 提交者: Aston Zhang

Fix typos in the mlp chapters (#258)

上级 9723fba4
# 多层感知机——使用Gluon
下面我们使用Gluon来实现上一节中的多层感知机。导入所需的包或模块。
下面我们使用Gluon来实现上一节中的多层感知机。首先我们导入所需的包或模块。
```{.python .input}
import sys
......@@ -12,7 +12,7 @@ from mxnet.gluon import loss as gloss, nn
## 定义模型
和Softmax回归唯一的不同在于,我们多加了一个全连接层作为隐藏层。我们指定了该层的隐藏单元个数为256,并使用ReLU作为激活函数。
和Softmax回归唯一的不同在于,我们多加了一个全连接层作为隐藏层,其中该层的隐藏单元个数为256,并使用ReLU作为激活函数。
```{.python .input n=5}
net = nn.Sequential()
......
# 多层感知机——从零开始
我们已经从上一章里了解了多层感知机的原理。下面我们一起来动手实现一个多层感知机。首先导入实现所需的包或模块。
我们已经从上一章里了解了多层感知机的原理。下面我们一起来动手实现一个多层感知机。首先导入实现所需的包或模块。
```{.python .input}
import sys
......@@ -70,7 +70,7 @@ loss = gloss.SoftmaxCrossEntropyLoss()
训练多层感知机的步骤和之前训练Softmax回归的步骤没什么区别。我们直接调用`gluonbook`包中的`train_cpu`函数,它的实现已经在[“Softmax回归——从零开始”](softmax-regression-scratch.md)一节里介绍了。
这里设超参数迭代周期为5,学习率为0.5。
这里我们设超参数迭代周期为5,学习率为0.5。
```{.python .input n=8}
num_epochs = 5
......@@ -82,7 +82,7 @@ gb.train_cpu(net, train_iter, test_iter, loss, num_epochs, batch_size,
## 小结
* 我们可以通过手动定义模型及其参数来实现简单的多层感知机。
* 当多层感知机的层数较多时,本节的实现方法会显得较繁琐,特别在定义模型参数上
* 当多层感知机的层数较多时,本节的实现方法会显得较繁琐,例如在定义模型参数的时候
## 练习
......
......@@ -28,19 +28,19 @@ $$
那么,如果隐藏层也只对输入做仿射变换会怎么样呢?设单个样本的特征为$\boldsymbol{x} \in \mathbb{R}^{1 \times x}$,隐藏层的权重参数和偏差参数分别为$\boldsymbol{W}_h \in \mathbb{R}^{x \times h}, \boldsymbol{b}_h \in \mathbb{R}^{1 \times h}$。
假设$\boldsymbol{h} = \boldsymbol{x} \boldsymbol{W}_h + \boldsymbol{b}_h$且$\boldsymbol{o} = \boldsymbol{h} \boldsymbol{W}_o + \boldsymbol{b}_o$,联立两式可得$\boldsymbol{o} = \boldsymbol{x} \boldsymbol{W}_h \boldsymbol{W}_o + \boldsymbol{b}_h \boldsymbol{W}_o + \boldsymbol{b}_o$:它等价于单层神经网络的输出$\boldsymbol{o} = \boldsymbol{x} \boldsymbol{W}^\prime + \boldsymbol{b}^\prime$,其中$\boldsymbol{W}^\prime = \boldsymbol{W}_h \boldsymbol{W}_o, \boldsymbol{b}^\prime = \boldsymbol{b}_h \boldsymbol{W}_o + \boldsymbol{b}_o$。因此,仅使用仿射变换的隐藏层使多层感知机与前面介绍的单层神经网络没什么区别。
假设$\boldsymbol{h} = \boldsymbol{x} \boldsymbol{W}_h + \boldsymbol{b}_h$且$\boldsymbol{o} = \boldsymbol{h} \boldsymbol{W}_o + \boldsymbol{b}_o$,联立两式可得$\boldsymbol{o} = \boldsymbol{x} \boldsymbol{W}_h \boldsymbol{W}_o + \boldsymbol{b}_h \boldsymbol{W}_o + \boldsymbol{b}_o$:它等价于单层神经网络的输出$\boldsymbol{o} = \boldsymbol{x} \boldsymbol{W}^\prime + \boldsymbol{b}^\prime$,其中$\boldsymbol{W}^\prime = \boldsymbol{W}_h \boldsymbol{W}_o, \boldsymbol{b}^\prime = \boldsymbol{b}_h \boldsymbol{W}_o + \boldsymbol{b}_o$。因此,在隐藏层中使用仿射变换的多层感知机与前面介绍的单层神经网络没什么区别。
## 激活函数
由上面的例子可以看出,我们必须在隐藏层中使用其他变换,例如添加非线性变换,这样才能使多层感知机变得有意义。我们将这些非线性变换称为激活函数(activation function)。激活函数能对任意形状的输入按元素操作且不改变输入的形状。以下列举了三种常用的激活函数。
通过上面的例子我们发现,必须在隐藏层中使用其他变换,例如添加非线性变换,才能使多层感知机变得有意义。我们将这些非线性变换称为激活函数(activation function)。激活函数能对任意形状的输入都按元素操作且不改变输入的形状。以下列举三种常用的激活函数。
### ReLU函数
ReLU(rectified linear unit)函数提供了一个很简单的非线性变换。给定元素$x$,该函数的输出
ReLU(rectified linear unit)函数提供了一个很简单的非线性变换。给定元素$x$,函数定义
$$\text{relu}(x) = \max(x, 0).$$
ReLU函数只保留正数元素,并将负数元素清零。为了直观地观察这一非线性变换,让我们先定义一个绘图函数`xyplot`
可以看出,ReLU函数只保留正数元素,并将负数元素清零。为了直观地观察这一非线性变换,我们先定义一个绘图函数`xyplot`
```{.python .input}
import sys
......@@ -57,7 +57,7 @@ def xyplot(x_vals, y_vals, x_label, y_label):
gb.plt.show()
```
让我们绘制ReLU函数。当元素值非负时,ReLU函数实际上在做线性变换。
我们接下来绘制ReLU函数。当元素值非负时,ReLU函数实际上在做线性变换。
```{.python .input n=2}
x = nd.arange(-5.0, 5.0, 0.1)
......@@ -72,7 +72,7 @@ $$\text{sigmoid}(x) = \frac{1}{1 + \exp(-x)}.$$
我们会在后面“循环神经网络”一章中介绍如何利用sigmoid函数值域在0到1之间这一特性来控制信息在神经网络中的流动。
下面绘制了sigmoid函数。当元素值接近0时,sigmoid函数接近线性变换。
我们下面绘制sigmoid函数。当元素值接近0时,sigmoid函数接近线性变换。
```{.python .input n=3}
xyplot(x.asnumpy(), x.sigmoid().asnumpy(), 'x', 'sigmoid(x)')
......@@ -84,13 +84,13 @@ Tanh(双曲正切)函数可以将元素的值变换到-1和1之间:
$$\text{tanh}(x) = \frac{1 - \exp(-2x)}{1 + \exp(-2x)}.$$
下面绘制了tanh函数。当元素值接近0时,tanh函数接近线性变换。值得一提的是,它的形状和sigmoid函数很像,且当元素在实数域上均匀分布时,tanh函数值的均值为0。
我们接着绘制tanh函数。当元素值接近0时,tanh函数接近线性变换。值得一提的是,它的形状和sigmoid函数很像,且当元素在实数域上均匀分布时,tanh函数值的均值为0。
```{.python .input n=4}
xyplot(x.asnumpy(), x.tanh().asnumpy(), 'x', 'tanh(x)')
```
下面,我们使用三种激活函数来变换输入。按元素操作后,输入和输出形状相同。
然后,我们使用三种激活函数来变换输入。按元素操作后,输入和输出形状相同。
```{.python .input n=5}
X = nd.array([[[0,1], [-2,3], [4,-5]], [[6,-7], [8,-9], [10,-11]]])
......@@ -102,8 +102,7 @@ X.relu(), X.sigmoid(), X.tanh()
现在,我们可以给出多层感知机的矢量计算表达式了。
给定一个小批量样本$\boldsymbol{X} \in \mathbb{R}^{n \times x}$,其批量大小为$n$,输入个数为$x$,输出个数为$y$。
假设多层感知机只有一个隐藏层,其中隐藏单元个数为$h$,激活函数为$\phi$。假设
隐藏层的权重和偏差参数分别为$\boldsymbol{W}_h \in \mathbb{R}^{x \times h}, \boldsymbol{b}_h \in \mathbb{R}^{1 \times h}$,
假设多层感知机只有一个隐藏层,其中隐藏单元个数为$h$,激活函数为$\phi$。假设隐藏层的权重和偏差参数分别为$\boldsymbol{W}_h \in \mathbb{R}^{x \times h}, \boldsymbol{b}_h \in \mathbb{R}^{1 \times h}$,
输出层的权重和偏差参数分别为$\boldsymbol{W}_o \in \mathbb{R}^{h \times y}, \boldsymbol{b}_o \in \mathbb{R}^{1 \times y}$。
多层感知机的矢量计算表达式为
......@@ -121,29 +120,29 @@ $$
## 计算梯度
有了多层感知机的损失函数后,优化算法将迭代模型参数从而不断降低损失函数的值。我们在前面章节里用了小批量随机梯度下降,和大多数其他优化算法一样,它需要计算损失函数有关模型参数的梯度。我们可以把数学上对复合函数求梯度的链式法则应用于多层感知机的梯度计算。我们将在后面章节详细介绍深度学习模型中的梯度计算,例如多层感知机的正向传播和反向传播。
有了多层感知机的损失函数后,优化算法将更新模型参数从而不断降低损失函数的值。我们在前面章节里用了小批量随机梯度下降,和大多数其他优化算法一样,它需要计算损失函数有关的模型参数的梯度。我们可以把数学上对复合函数求梯度的链式法则应用于多层感知机的梯度计算。我们将在后面章节详细介绍深度学习模型中的梯度计算,例如多层感知机的反向传播。
## 衰减和爆炸
需要注意的是,当深度学习模型的层数较多时,模型的数值稳定性容易变得较差。假设一个层数为$L$的多层感知机的第$l$层$\boldsymbol{H}^{(l)}$的权重参数为$\boldsymbol{W}^{(l)}$,输出层$\boldsymbol{H}^{(L)}$的权重参数为$\boldsymbol{W}^{(L)}$。为了便于讨论,假设不考虑偏差参数,且所有隐藏层的激活函数为$\phi(x) = x$。给定输入$\boldsymbol{X}$,多层感知机的第$l$层的输出$\boldsymbol{H}^{(l)} = \boldsymbol{X} \boldsymbol{W}^{(1)} \boldsymbol{W}^{(2)} \ldots \boldsymbol{W}^{(l)}$。这时候,如果层数$l$较大,$\boldsymbol{H}^{(l)}$的计算可能会出现衰减(vanishing)或爆炸(explosion)。举个例子,假如输入和所有层的权重参数都是标量的话,比如0.5和2,多层感知机的第50层输出在输入前的系数分别为$0.5^{50}$(衰减)和$2^{50}$(爆炸)。类似地,当层数较多时,梯度的计算也更容易出现衰减或爆炸。我们会在后面章节还会介绍梯度的衰减或爆炸,例如循环神经网络的通过时间反向传播。
需要注意的是,当深度学习模型的层数较多时,模型的数值稳定性容易变差。假设一个层数为$L$的多层感知机的第$l$层$\boldsymbol{H}^{(l)}$的权重参数为$\boldsymbol{W}^{(l)}$,输出层$\boldsymbol{H}^{(L)}$的权重参数为$\boldsymbol{W}^{(L)}$。为了便于讨论,我们也假设不考虑偏差参数,且所有隐藏层的激活函数为$\phi(x) = x$。给定输入$\boldsymbol{X}$,多层感知机的第$l$层的输出$\boldsymbol{H}^{(l)} = \boldsymbol{X} \boldsymbol{W}^{(1)} \boldsymbol{W}^{(2)} \ldots \boldsymbol{W}^{(l)}$,如果层数$l$较大,$\boldsymbol{H}^{(l)}$的计算可能会出现衰减(vanishing)或爆炸(explosion)。举个例子,假如输入和所有层的权重参数都是标量的话,比如0.5和2,多层感知机的第50层输出在输入前的系数分别为$0.5^{50}$(衰减)和$2^{50}$(爆炸)。类似地,当层数较多时,梯度的计算也更容易出现衰减或爆炸。我们会在后面章节介绍梯度的衰减或爆炸,例如循环神经网络的通过时间反向传播。
## 随机初始化模型参数
在神经网络中,我们需要随机初始化模型参数。下面我们来解释这一点。
在神经网络中,我们需要随机初始化模型参数。
以图3.3为例,假设输出层只保留一个输出单元$o_1$(删去$o_2, o_3$和指向它们的箭头),且隐藏层使用相同的激活函数。如果初始化后每个隐藏单元的参数都相同,那么在模型训练时每个隐藏单元将根据相同输入计算出相同的值。接下来输出层也将从各个隐藏单元拿到完全一样的值。在迭代每个隐藏单元的参数时,这些参数在每轮迭代的值都相同。那么,由于每个隐藏单元拥有相同激活函数和相同参数,所有隐藏单元将继续根据下一次迭代时的相同输入计算出相同的值。如此周而复始。这种情况下,无论隐藏单元个数有多大,隐藏层本质上只有1个隐藏单元在发挥作用。因此,我们通常会随机初始化神经网络的模型参数,例如每个神经元的权重参数。
### MXNet的默认随机初始化
随机初始化模型参数的方法有很多。在[“线性回归——使用Gluon”](linear-regression-gluon.md)一节中,我们使用`net.initialize(init.Normal(sigma=0.01))`令模型`net`的权重参数采用正态分布的随机初始化方式。如果不指定初始化方法,例如`net.initialize()`,我们将使用MXNet的默认随机初始化方法。在默认条件下的初始化时,权重参数每个元素随机采样于-0.07到0.07之间的均匀分布,偏差参数全部元素清零。
随机初始化模型参数的方法有很多。在[“线性回归——使用Gluon”](linear-regression-gluon.md)一节中,我们使用`net.initialize(init.Normal(sigma=0.01))`使模型`net`的权重参数采用正态分布的随机初始化方式。如果不指定初始化方法,例如`net.initialize()`,我们将使用MXNet的默认随机初始化方法。默认的随机初始化方法使得权重参数每个元素服从-0.07到0.07之间的均匀分布,偏差参数全部清零。
### Xavier随机初始化
还有一种比较常用的随机初始化方法叫做Xavier随机初始化 [1]。假设某全连接层的输入个数为$a$,输出个数为$b$,Xavier随机初始化将该层权重参数的每个元素随机采样于均匀分布
还有一种比较常用的随机初始化方法叫做Xavier随机初始化 [1]。假设某全连接层的输入个数为$a$,输出个数为$b$,Xavier随机初始化将使得该层中每个权重参数都随机采样于均匀分布
$$U\left(-\sqrt{\frac{6}{a+b}}, \sqrt{\frac{6}{a+b}}\right).$$
......@@ -159,7 +158,7 @@ $$U\left(-\sqrt{\frac{6}{a+b}}, \sqrt{\frac{6}{a+b}}\right).$$
## 练习
* 有人说随机初始化模型参数为了“打破对称性”。这里的“对称”应如何理解?
* 有人说随机初始化模型参数为了“打破对称性”。这里的“对称”应如何理解?
## 扫码直达[讨论区](https://discuss.gluon.ai/t/topic/6447)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册