mirror of
https://github.com/openmlsys/openmlsys-zh.git
synced 2026-04-09 05:38:52 +08:00
clean commit messages.
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
## 经典机器学习方法
|
||||
|
||||
大量经典机器学习算法,如 支持向量机(Support Vector Machine,SVM),
|
||||
K最近邻(K-Nearest Neighbor, KNN)分类算法 和K均值聚类算法(K-Means
|
||||
Clustering Algorithm)等,
|
||||
虽然它们有的有网络参数,有的没有网络参数,有的是监督学习算法,有的是无监督学习算法,
|
||||
训练过程也不一样,但是从系统的角度,它们都是以矩阵运算为基础的。下面,我们来简要介绍一下这些算法。
|
||||
|
||||
### 支持向量机
|
||||
|
||||
**支持向量机**(Support Vector
|
||||
Machine,SVM),是一种经典的机器学习分类算法,其核心思想在于最大化决策边界到数据点的距离。在这里,我们以线性可分数据为例;对于非线性可分的数据,运用**核方法**(Kernel
|
||||
Method)即可类似处理。
|
||||
|
||||
如果训练数据是线性可分的,SVM的目标则是最大化**间隔**(Margin)。首先,我们先来定义最大化间隔的分类器,如下:
|
||||
$$\min_{{w},b} ~~~\frac{1}{2} ||{w}||^2$$
|
||||
$$s.t. ~~~y_i ({w}^T {x_i} + b) \geq 1, ~~~\forall 1 \leq i \leq n$$
|
||||
其拉格朗日乘子为
|
||||
$$L({w},b,{\lambda}) = \frac{1}{2} ||{w}||^2 + \sum_{i=1}^n \lambda_i (1-y_i({w}^T {x_i} + b))$$
|
||||
由于$\frac{1}{2} ||{w}||^2$是凸的,并且$\lambda_i (1-y_i({w}^T {x_i} + b))$是线性的(也是凸的),所以优化问题的解为
|
||||
$$\max_{\lambda>0} \min_{{w},b} L({w},b, {\lambda})$$
|
||||
求$L$关于${w},b$的导数有
|
||||
$$\nabla_{{w}} L= {w} - \sum_{i=1}^n \lambda_i y_i {x_i}$$
|
||||
$$\nabla_b L = - \sum_{i=1}^n \lambda_i y_i$$
|
||||
令$L$关于${w},b$的导数均为0得到,${w}^* = \sum_{i=1}^n \lambda_i y_i {x_i}$以及$\sum_{i=1}^n \lambda_i y_i = 0$。
|
||||
由于当$\lambda$固定的时候,$b$的值对目标函数无贡献,所以可以令$b^* = 0$。
|
||||
这时,由对偶性理论和KTT条件,我们得到:
|
||||
$$y_i ({w}^{*T} {x_i} + b^*) > 1 \Rightarrow \lambda_i^* = 0$$
|
||||
$$\lambda_i^* > 0 \Rightarrow y_i ({w}^{*T} {x_i} + b^*) = 1$$
|
||||
$${w}^* = \sum_{i=1}^n \lambda_i^* y_i {x_i}$$
|
||||
如果$y_i ({w}^{*T} {x_i} + b^*) = 1$,那么${x_i}$就是离超平面$({w}^*,b^*)$最近的点之一,否则就不是。因此,${w}^*$就是离超平面$({w}^*,b^*)$最近的点${x_i}$的线性组合。
|
||||
|
||||
如此,通过SVM算法,我们实现了数据的分类,并且能够最大化了决策边界到最近点的距离。
|
||||
我们定义满足$y_i ({w}^{*T} {x_i} + b^*) = 1$的${x_i}$为**支持向量**(Support
|
||||
Vectors),同时把分类器$\hat{y}=sgn({w}^{*T} {x_i} + b^*)$称为支持向量机。
|
||||
|
||||
### K最近邻算法
|
||||
|
||||
**K最近邻算法**(K-Nearest
|
||||
Neighbor,KNN)也是一种传统的机器学习算法,可用于分类、回归等基本的机器学习任务。和上面介绍的SVM算法不同,K最近邻算法的核心思想并不是用一个决策边界把属于不同类的数据分开,而是依靠每个数据点周围几个距离最近的数据的性质,来预测数据点本身的性质。
|
||||
|
||||
KNN用于分类时,为了预测某个样本点的类别,会进行一次投票。投票的对象为离这个观测样本点最近的K个样本点,每个要投票的样本点可能会被赋予不同的权重,而投票的"内容"则是样本点的类别。处理投票结果的时候,采用的是少数服从多数的决策方法(Majority
|
||||
Vote)。也就是说,若一个样本点最近的K个样本点中大多数属于某个类别,那么该样本点也属于这个类别。
|
||||
|
||||
KNN算法的具体描述如下:(1)计算待分类点到各已知类别点的距离;(2)将这些点按照距离排序,并按照距离挑选出最近的K个点;(3)按照每个点的权重进行"统票",票面内容为点所处的类别;(4)返回得票最高的类别,并作为待分类点的预测类别。
|
||||
|
||||
KNN算法有几个需要注意的关键问题,包括超参数K的选择,距离的度量方式,还有分类决策规则。对于超参数K,不宜过大,否则会导致很大的近似误差,反之亦不宜过小,否则会导致很大的估计误差。距离的度量,则可以选择曼哈顿距离、欧式距离和闵可夫斯基距离等等。为了降低K值对于预测结果产生的误差和影响,我们通常可以对分类决策规则做一定的规定,比如在投票决策时让距离小的点有更大的权重,距离较大的点权重较小。在编程实现KNN算法的时候,权重等参数都会以矩阵的形式进行运算,以提高运算效率。
|
||||
|
||||
### K均值聚类算法
|
||||
|
||||
**K均值聚类算法**(K-Means Clustering
|
||||
Algorithm)是机器学习中一种常见的无监督聚类算法。在这里,我们首先定义聚类问题:给定数据点${x_1},\cdots, {x_n} \in \mathbb{R}^d$和$K\in \mathbb{N}$,需要划分为$K$个簇${C_1}, \cdots, {C_K} \in \mathbb{R}^d$以及每个数据点所对应的分类中心点${ C_{(1)}}, \cdots, {C_{(n)}}$,以最小化距离和$\sum_i ||{x_i} - {C_{(i)}}||^2$。
|
||||
|
||||
K均值聚类算法是一种解决聚类问题的算法,算法过程如下:
|
||||
|
||||
- 随机选择${C_1}, \cdots, {C_K}$
|
||||
|
||||
- 把${x_i}$所对应的分类置为距离其最近的聚类中心点的分类
|
||||
|
||||
- 计算并赋值${C_K} = \frac{\sum_{{C_{(i)}}={C_K}} {x_i}}{\sum_{{C_{(i)}}={C_K}} 1}$
|
||||
|
||||
- 重复以上步骤直到算法收敛
|
||||
|
||||
可以证明,K均值聚类算法会使得距离和$\sum_i ||{x_i} - {C_{(i)}}||^2$不断地单调减小,并且最终能够收敛。不过,算法可能收敛到局部最小值。
|
||||
|
||||
本章结束语:
|
||||
|
||||
在系统角度,机器学习的算法无论是什么算法,涉及到高维数据任务的现都是矩阵运算实现的。
|
||||
94
appendix_Introduction_machine_learning/gradient_descent.md
Normal file
94
appendix_Introduction_machine_learning/gradient_descent.md
Normal file
@@ -0,0 +1,94 @@
|
||||
## 梯度下降与反向传播
|
||||
|
||||
上面大体上介绍了经典神经网络的内容,那么现在有一个问题,这些网络中的参数是如何确定的呢?如果要解决的问题是一个小感知器就能解决的话,参数可以人为地去确定。但是如果是一个深度网络的话,参数的确定需要自动化,也就是所谓的网络训练,而这个过程需要我们设定一个**损失函数**(Loss
|
||||
Function)来作为训练优化的一个方向。
|
||||
常见的损失函数有:1)用来衡量向量之间距离的均方误差(Mean Squared
|
||||
Error,MSE)
|
||||
$\mathcal{L} = \frac{1}{N}\|{y}-\hat{{y}}\|^{2}_{2} = \frac{1}{N}\sum_{i=1}^N(y_{i}-\hat{y}_{i})^{2}$
|
||||
和 平均绝对误差(Mean Absolute Error,MAE)
|
||||
$\mathcal{L} = \frac{1}{N}\sum_{i=1}^{N}|y_{i}-\hat{y}_{i}|$
|
||||
,其中$N$代表数据样本的数量,用以求平均用,而$y$代表真实标签(Ground
|
||||
Truth)、$\hat{y}$代表网络输出的预测标签。
|
||||
2)分类任务可以用的交叉熵损失(Cross Entropy)
|
||||
$\mathcal{L} = - \frac{1}{N} \sum_{i=1}^N \bigg(y_{i}\log\hat{y}_{i} + (1 - y_{i})\log(1 - \hat{y}_{i})\bigg)$来作为损失数,当且仅当输出标签和预测标签一样的时候损失值才为零。
|
||||
|
||||
有了损失值之后,我们就可以利用大量真实标签的数据和优化方法来更新模型参数了,其中最常用的方法是**梯度下降**(Gradient
|
||||
Descent)。如 :numref:`gradient_descent2`所示,
|
||||
开始的时候,模型的参数${w}$是随机选取的,然后求出损失值对参数的偏导数$\frac{\partial \mathcal{L}}{\partial {w}}$,通过反复迭代
|
||||
${w}:={w}-\alpha\frac{\partial \mathcal{L}}{\partial {w}}$完成优化。这个优化的过程其实就可以降低损失值以达到任务目标,其中$\alpha$是控制优化幅度的**学习率**(Learning
|
||||
Rate)。
|
||||
在实践中,梯度下降最终得到的最小值很大可能是一个局部最小值,而不是全局最小值。不过由于深度神经网络能提供一个很强的数据表达能力,所以局部最小值可以很接近全局最小值,损失值可以足够小。
|
||||
|
||||
![梯度下降介绍。(左图)只有一个可以训练的参数$w$;(右图)有两个可以训练的参数${w}=[w_1,w_2]$。在不断更新迭代参数后,损失值$\mathcal{L}$会逐渐地减小。但是由于存在很多局部最优解,我们往往不能更新到全局最优解。](../img/ch_basic/gradient_descent2.png)
|
||||
:width:`600px`
|
||||
:label:`gradient_descent2`
|
||||
|
||||
那么接下来,在深度神经网络中如何实现梯度下降呢,这需要计算出网络中每层参数的偏导数$\frac{\partial \mathcal{L}}{\partial {w}}$,我们可以用**反向传播**(Back-Propagation)[@rumelhart1986learning; @lecun2015deep]来实现。
|
||||
接下来,
|
||||
我们引入一个中间量${\delta}=\frac{\partial \mathcal{L}}{\partial {z}}$来表示损失函数$\mathcal{L}$
|
||||
对于神经网络输出${z}$(未经过激活函数,不是$a$)的偏导数,
|
||||
并最终得到$\frac{\partial \mathcal{L}}{\partial {w}}$。
|
||||
|
||||
我们下面用一个例子来介绍反向传播算法,
|
||||
我们设层序号为$l=1, 2, \ldots L$(输出层(最后一层)序号为$L$)。
|
||||
对于每个网络层,我们有输出${z}^l$,中间值${\delta}^l=\frac{\partial \mathcal{L}}{\partial {z}^l}$和一个激活值输出${a}^l=f({z}^l)$
|
||||
(其中$f$为激活函数)。
|
||||
我们假设模型是使用Sigmoid激活函数的多层感知器,损失函数是均方误差(MSE)。也就是说,我们设定:
|
||||
|
||||
- 网络结构${z}^{l}={W}^{l}{a}^{l-1}+{b}^{l}$
|
||||
|
||||
- 激活函数${a}^l=f({z}^l)=\frac{1}{1+{\rm e}^{-{z}^l}}$
|
||||
|
||||
- 损失函数$\mathcal{L}=\frac{1}{2}\|{y}-{a}^{L}\|^2_2$
|
||||
|
||||
我们可以直接算出激活输出对于原输出的偏导数:
|
||||
|
||||
- $\frac{\partial {a}^l}{\partial {z}^l}=f'({z}^l)=f({z}^l)(1-f({z}^l))={a}^l(1-{a}^l)$
|
||||
|
||||
和损失函数对于激活输出的偏导数:
|
||||
|
||||
- $\frac{\partial \mathcal{L}}{\partial {a}^{L}}=({a}^{L}-{y})$
|
||||
|
||||
有了这些后,为了进一步得到损失函数对于每一个参数的偏导数,可以使用**链式法则**(Chain
|
||||
Rule),细节如下:
|
||||
|
||||
首先,从输出层($l=L$,最后一层)开始向后方传播误差,根据链式法则,我们先计算输出层的中间量:
|
||||
|
||||
- ${\delta}^{L}
|
||||
=\frac{\partial \mathcal{L}}{\partial {z}^{L}}
|
||||
=\frac{\partial \mathcal{L}}{\partial {a}^{L}}\frac{\partial {a}^L}{\partial {z}^{L}}=({a}^L-{y})\odot({a}^L(1-{a}^L))$
|
||||
|
||||
除了输出层($l=L$)的中间值${\delta}^{L}$,其他层($l=1, 2, \ldots , L-1$)的中间值${\delta}^{l}$如何计算呢?
|
||||
|
||||
- 已知模型结构${z}^{l+1}={W}^{l+1}{a}^{l}+{b}^{l+1}$,我们可以直接得到$\frac{\partial {z}^{l+1}}{\partial {a}^{l}}={W}^{l+1}$;而且我们已知$\frac{\partial {a}^l}{\partial {z}^l}={a}^l(1-{a}^l)$
|
||||
|
||||
- 那么根据链式法则,我们可以得到 ${\delta}^{l}
|
||||
=\frac{\partial \mathcal{L}}{\partial {z}^{l}}
|
||||
=\frac{\partial \mathcal{L}}{\partial {z}^{l+1}}\frac{\partial {z}^{l+1}}{\partial {a}^{l}}\frac{\partial {a}^{l}}{\partial {z}^{l}}
|
||||
=({W}^{l+1})^\top{\delta}^{l+1}\odot({a}^l(1-{a}^l))$
|
||||
|
||||
根据上面的计算有所有层的中间值${\delta}^l, l=1, 2, \ldots , L$后,我们就可以在此基础上求出损失函数对于每层参数的偏导数:$\frac{\partial \mathcal{L}}{\partial {W}^l}$和$\frac{\partial \mathcal{L}}{\partial {b}^l}$,以此来根据梯度下降的方法来更新每一层的参数。
|
||||
|
||||
- 已知模型结构${z}^l={W}^l{a}^{l-1}+{b}^l$,我们可以求出
|
||||
$\frac{\partial {z}^{l}}{\partial {W}^l}={a}^{l-1}$ 和
|
||||
$\frac{\partial {z}^{l}}{\partial {b}^l}=1$
|
||||
|
||||
- 那么根据链式法则,我们可以得到$\frac{\partial \mathcal{L}}{\partial {W}^l}=\frac{\partial \mathcal{L}}{\partial {z}^l}\frac{\partial {z}^l}{\partial {W}^l}={\delta}^l({a}^{l-1})^\top$
|
||||
,
|
||||
$\frac{\partial \mathcal{L}}{\partial {b}^l}=\frac{\partial \mathcal{L}}{\partial {z}^l}\frac{\partial {z}^l}{\partial {b}^l}={\delta}^l$
|
||||
|
||||
求得所有偏导数$\frac{\partial \mathcal{L}}{\partial {W}^l}$ 和
|
||||
$\frac{\partial \mathcal{L}}{\partial {b}^l}$后,我们就可以用梯度下降更新所有参数${W}^l$
|
||||
和 ${b}^l$:
|
||||
|
||||
- ${W}^l:={W}^l-\alpha\frac{\partial \mathcal{L}}{\partial {W}^l}$,
|
||||
${b}^l:={b}^l-\alpha\frac{\partial \mathcal{L}}{\partial {b}^l}$
|
||||
|
||||
但是还有一个问题需要解决,那就是梯度下降的时候每更新一次参数,都需要计算一次当前参数下的损失值。然而,当训练数据集很大时($N$很大),若每次更新都用整个训练集来计算损失值的话,计算量会非常巨大。
|
||||
为了减少计算量,我们使用**随机梯度下降**(Stochastic Gradient
|
||||
Descent,SGD)来计算损失值。具体来说,我们计算损失值不用全部训练数据,而是从训练集中随机选取一些数据样本来计算损失值,比如选取16、32、64或者128个数据样本,样本的数量被称为**批大小**(Batch
|
||||
Size)。
|
||||
此外,学习率的设定也非常重要。如果学习率太大,可能无法接近最小值的山谷,如果太小,训练又太慢。
|
||||
自适应学习率,例如Adam [@KingmaAdam2014]、RMSProp [@tieleman2012rmsprop]
|
||||
和
|
||||
Adagrad [@duchi2011adagrad] 等,在训练的过程中通过自动的方法来修改学习率,实现训练的快速收敛,到达最小值点。
|
||||
@@ -1,10 +1,12 @@
|
||||
# 附录:机器学习介绍
|
||||
|
||||
|
||||
本书假设读者有一定的机器学习算法基础,因此本章只会简略地介绍一下机器学习,其中的梯度下降方法对本书机器学习系统来说尤为重要,是必须掌握的内容。
|
||||
|
||||
```toc
|
||||
:maxdepth: 2
|
||||
:numbered:
|
||||
|
||||
|
||||
neural_network
|
||||
gradient_descent
|
||||
classic_machine_learning
|
||||
```
|
||||
179
appendix_Introduction_machine_learning/neural_network.md
Normal file
179
appendix_Introduction_machine_learning/neural_network.md
Normal file
@@ -0,0 +1,179 @@
|
||||
## 神经网络
|
||||
|
||||
### 感知器
|
||||

|
||||
:width:`600px`
|
||||
:label:`single_neuron`
|
||||
|
||||
:numref:`single_neuron`是一个神经元的例子,输入数据$x$根据连线上的权重$w$做加权求和得到输出$z$,我们把这样的模型叫作**感知器**(Perceptron)。
|
||||
因为输入和输出之间只有一层神经连接,这个模型也叫做单层感知器。 :numref:`single_neuron`的模型计算可以写为:$z = w_{1}x_{1}+ w_{2}x_{2} + w_{3}x_{3}$。
|
||||
|
||||
当输入数据用列向量${x}=[x_1,x_2,x_3]^T$表示,模型权重用行向量${w}=[w_1,w_2,w_3]$表示,那么输出的标量$z$可以写为:
|
||||
|
||||
$$z =
|
||||
\begin{bmatrix}
|
||||
w_1,w_2,w_3\\
|
||||
\end{bmatrix}
|
||||
\begin{bmatrix}
|
||||
x_1\\
|
||||
x_2\\
|
||||
x_3
|
||||
\end{bmatrix}
|
||||
={w}{x}$$
|
||||
|
||||
我们可以利用输出标量$z$为输入的加权组合来实现特定任务。
|
||||
比如,可以对"好苹果"和"坏苹果"进行分类,输入的$x_1,x_2,x_3$分别代表三种不同的特征:1)红色的程度,2)有没有洞,3)大小。如果苹果的大小对这个判断没有影响,那么对应的权重就为零。
|
||||
这个神经网络的训练,其实就是选择合适的权重,来实现我们的任务。比如我们可以选择合适的权重,使得当$z$小于等于$0$时代表"坏苹果",而当$z$大于$0$时则是"好苹果"。
|
||||
则最终的分类输出标签$y$如下,为$1$时代表好,$0$代表坏。这个神经元的输入和输出之间只有一层,所以可以成为单层神经网络。
|
||||
|
||||
$$
|
||||
y =
|
||||
\begin{cases}
|
||||
1 & z>0 \\
|
||||
0 & z \leq 0 \\
|
||||
\end{cases}$$
|
||||
|
||||
### 决策边界vs.偏置
|
||||
|
||||
通过选择合适的权重以$z$大于或小于$0$来对输入数据做分类的话,可以在数据空间上获得一个**决策边界**
|
||||
(Decision
|
||||
Boundary)。如 :numref:`single_neuron_decision_boundary2`所示,以神经元输出$z=0$作为输出标签$y$的决策边界,没有偏置时决策边界必然经过坐标原点,如果数据样本点不以原点来分开,会导致分类错误。
|
||||
为了解决这个问题,可以在神经元上加入一个**偏置**(Bias)。 :numref:`single_neuron_bias2`
|
||||
是一个有偏置$b$的神经元模型,可以用 :eqref:`singleneuron_bias`表达:
|
||||
$$z = w_{1}x_{1}+ w_{2}x_{2}+ w_{3}x_{3} + b$$
|
||||
:eqlabel:`singleneuron_bias`
|
||||
|
||||

|
||||
:width:`600px`
|
||||
:label:`single_neuron_decision_boundary2`
|
||||
|
||||

|
||||
:width:`600px`
|
||||
:label:`single_neuron_bias2`
|
||||
|
||||
有了偏置以后,决策边界(直线、平面或超平面)可以不经过坐标原点,因此能更好地分类样本。
|
||||
准确来说,决策边界把这些样本数据分成两个不同的类别,这个边界是
|
||||
$\{x_1, x_2, x_3 | w_{1}x_{1}+ w_{2}x_{2}+ w_{3}x_{3} + b = 0\}$。
|
||||
|
||||
### 逻辑回归
|
||||
|
||||
上述神经元的输入和输出是线性关系,为了提供非线性的数据表达能力,可以在神经元输出上加上**激活函数**(Activation
|
||||
Function),最常见的激活函数有Sigmoid、Tanh、ReLU和Softmax等。
|
||||
比如,上述神经元以$z=0$为分界来做分类任务,那么我们可不可以让神经元输出一个概率呢?比如输出$0~1$,$1$代表输入数据$100\%$为某一类。
|
||||
为了让神经元输出$0~1$,可以在$z$上加一个逻辑函数**Sigmoid**,
|
||||
如 :eqref:`sigmoid`所示,Sigmoid把数值限制在0和1之中,通过一个简单的临界值(如:0.5)来决定最终输出的标签是否属于某个类别。这个方法叫做**逻辑回归**(Logistic
|
||||
Regression)。
|
||||
|
||||
$$a = f({z}) = \frac{1}{1+{\rm e}^{-{z}}}$$
|
||||
:eqlabel:`sigmoid`
|
||||
|
||||
### 多个神经元
|
||||
|
||||

|
||||
:width:`600px`
|
||||
:label:`two_neurons2`
|
||||
|
||||
上述网络只有一个输出,若多个神经元在一起就可以有多个输出。 :numref:`two_neurons2`是有两个输出的网络,每个输出都和所有输入相连,所以也被称**全连接层**(Fully-Connected(FC) Layer),
|
||||
可由下述式子 :eqref:`fullyconnected`表示X。
|
||||
|
||||
$$
|
||||
z_{1} &= w_{11}x_{1} + w_{12}x_{2} + w_{13}x_{3} + b_1 \notag \\
|
||||
z_{2} &= w_{21}x_{1} + w_{22}x_{2} + w_{23}x_{3} + b_2$$
|
||||
:eqlabel:`fullyconnected`
|
||||
|
||||
如下式子表示了矩阵方法的实现:
|
||||
|
||||
$$
|
||||
{z} =
|
||||
\begin{bmatrix}
|
||||
z_1 \\
|
||||
z_2
|
||||
\end{bmatrix}
|
||||
=
|
||||
\begin{bmatrix}
|
||||
w_{11} & w_{12} & w_{13}\\
|
||||
w_{21} & w_{22} & w_{23}\\
|
||||
\end{bmatrix}
|
||||
\begin{bmatrix}
|
||||
x_1\\
|
||||
x_2\\
|
||||
x_3
|
||||
\end{bmatrix}
|
||||
+
|
||||
\begin{bmatrix}
|
||||
b_1 \\ b_2
|
||||
\end{bmatrix}
|
||||
= {W}{x} + {b}$$
|
||||
|
||||
|
||||
多输出的网络可以实现多分类问题,比如有10个数值输出,每个数值分别代表一类物品的概率,每个输出在$0$到$1$之间,10个输出之和为$1$。
|
||||
可用 :eqref:`e_softmax`的**Softmax** 函数来实现,$K$为输出的个数:
|
||||
|
||||
$$f({z})_{i} = \frac{{\rm e}^{z_{i}}}{\sum_{k=1}^{K}{\rm e}^{z_{k}}}$$
|
||||
:eqlabel:`e_softmax`
|
||||
|
||||
### 多层感知器
|
||||
|
||||

|
||||
|
||||
**多层感知器**(Multi-Layer
|
||||
Perceptron,MLP)[@rosenblatt1958perceptron]通过叠加多层全连接层来提升网络的表达能力。相比单层网络,多层感知器有很多中间层的输出并不暴露给最终输出,这些层被称为**隐含层**(Hidden
|
||||
Layers)。这个例子中的网络可以通过下方的串联式矩阵运算实现,其中$W^l$和$b^l$代表不同层的权重矩阵和偏置,$l$代表层号,$L$代表输出层。
|
||||
|
||||
$${z} = f({W^L}f({W^3}f({W^2}f({W^1}{x} + {b^1}) + {b^2}) + {b^3}) + {b^L})$$
|
||||
|
||||
在深度学习时代,网络模型基本都是多层的神经网络层连接起来的,输入数据经过多层的特征提取,可以学到不同抽象层级的**特征向量**(Feature
|
||||
Vector)。下面我们介绍一下其他常用的神经网络层。
|
||||
|
||||
### 卷积网络
|
||||
|
||||

|
||||
:width:`600px`
|
||||
:label:`conv_computation_v4`
|
||||
|
||||
**卷积神经网络** (Convolutional Neural
|
||||
Network,CNN)[@lecun1989backpropagation]由多层**卷积层**(Convolutional
|
||||
Layer)组成,常用于计算机视觉任务 [@krizhevsky2012imagenet; @he2016deep]。
|
||||
:numref:`conv_computation_v4`描述了一个卷积运算的例子。
|
||||
根据卷积的特点,我们可以知道两个事实:1)一个卷积核的通道数,等于输入的通道数;2)输出的通道数,等于卷积核的数量。
|
||||
|
||||
:numref:`conv_computation_v4`例子中,卷积核每次滑动一个数值的范围来进行卷积操作,我们称它的**步长**(Stride)为1。此外,如果希望输入的边缘数值也能被考虑在内的话,则需要对边缘做**填零**(Zero
|
||||
Padding)操作。 :numref:`conv_computation_v4`例子中,如果输入的每个通道上下左右都填充一圈零,那么输出的大小则为$4\times 4\times 1$。填零的圈数取决于卷积核的大小,卷积核越大则填零圈数越大。
|
||||
|
||||
为了对输入的图像数据做特征提取,卷积核数量往往比输入数据的通道数据要多,这样的话输出数据的数值会很多,计算量变大。然而图像数据中相邻像素的特征往往相似,所以我们可以对相邻的输出特征进行聚合操作。**池化层**就是为了实现这个目的,我们通常有两种池化方法最大值池化(Max
|
||||
Pooling)和平均值池化(Mean
|
||||
Pooling)。如 :numref:`pooling_v3`所示,假设池化的卷积核高宽为$2\times2$,输入$4\times4$的数据,步长为2(步长为1时,则输出等于输入),则输出为$2\times2$。
|
||||
|
||||

|
||||
:width:`600px`
|
||||
:label:`pooling_v3`
|
||||
|
||||
卷积层和全连接层都是很常用的,但是卷积层在输入是高维度的图像时,需要的参数量远远小于全连接层。卷积层的运算和全连接层是类似的,前者基于高维度张量运算,后者基于二维矩阵运算。
|
||||
|
||||
### 时序模型
|
||||
|
||||
现实生活中除了图像还有大量时间序列数据,例如视频、股票价格等等。**循环神经网络**(Recurrent
|
||||
Neural Networks,RNN)[@rumelhart1986learning]
|
||||
是一种处理序列数据的深度学习模型结构。序列数据是一串连续的数据$\{x_1, x_2, \dots, x_n\}$,比如每个$x$代表一个句子中的单词。
|
||||
|
||||
为了可以接收一连串的输入序列,如 :numref:`rnn_simple_cell2`所示,朴素循环神经网络使用了循环单元(Cell)作为计算单元,用隐状态(Hidden
|
||||
State)来存储过去输入的信息。具体来说,对输入模型的每个数据$x$,根据公式 :eqref:`aligned`,循环单元会反复计算新的隐状态,用于记录当前和过去输入的信息。而新的隐状态会被用到下一单元的计算中。
|
||||
|
||||
$${h}_t = {W}[{x}_t; {h}_{t-1}] + {b}$$
|
||||
:eqlabel:`aligned`
|
||||
|
||||

|
||||
:width:`600px`
|
||||
:label:`rnn_simple_cell2`
|
||||
|
||||
然而这种简单的朴素循环神经网络有严重的信息遗忘问题。比如说我们的输入是"我是中国人,我的母语是\_\_\_",隐状态记住了"中国人"的信息,使得网络最后可以预测出"中文"一词;但是如果句子很长的时候,隐状态可能记不住太久之前的信息了,比如说"我是中国人,我去英国读书,后来在法国工作,我的母语是\_\_\_",这时候在最后的隐状态中关于"中国人"的信息可能会被因为多次的更新而遗忘了。
|
||||
为了解决这个问题,后面有人提出了各种各样的改进方法,其中最有名的是长短期记忆(Long
|
||||
Short-Term
|
||||
Memory,LSTM)[@Hochreiter1997lstm]。关于时序的模型还有很多很多,比如近年来出现的Transformer [@vaswani2017attention]等等。
|
||||
Reference in New Issue
Block a user