手写数字识别-扩展阅读

1. 数据展示

1.1 MNIST简介

MNIST是手写数字数据集,当前Lecun大神为银行能够自动识别数字,而做的。Lecun[1]大神是19年和其他两位共享图灵奖的存在。该数据集包含70,000个灰色手写数字图片,有10类(0-9)。其中训练集60,000张,测试集10,000张。

这些图片是 28 x 28 `像素`。其实就是28 x 28 的矩阵。已将数据集进行了解压和存储。感兴趣的同学可以下载并运行。

1.2 样本格式

样本格式打印代码如下:

打印结果如下:

也就是说,训练集和测试集都是一个大型的`矩阵`。

以训练集为例,x_train是由60,000张图像构成,其中每个图像的大小为28×28(height×width)。我们可以利用以下代码查看前十个样本图像:

结果如下:

以0为例,将将图片转为数字矩阵,并通过excel呈现,更方便理解,如下如所示。

由于数字大小的不同,颜色的深浅也不同。左图为颜色越深的地方,数字越大,最大为255(右图正好相反)。将图像放大,可以看到更为清晰的数字。

y_train则是由60,000个数字构成的向量。可以利用以下代码查看取前十个数值:

结果如下:

将这个结果和x_train的图像对应,发现就是图像的数字表示。其实y_train是由0-9的数字构成的由60,000个数字构成的向量。每个数字对应x_train的每一张图。

1.3 思考与动手

x_test与y_test分别是什么结构,它们之间的对应关系是什么?尝试动手做一做,能够收获更多。

2. 常用的激活函数

2.1 sigmoid

函数:

$$ \sigma(x) = \frac{1}{1+exp(-x)} $$

图示:

优点:便于求导的平滑函数,其导数为:

$$ d{\sigma(x)}/d(x) = \sigma(x)(1-\sigma(x)) $$

缺点[2]:

  • 容易出现梯度消失(gradient vanishing)
  • 函数输出不是以0为中心的(zero-centered)
  • 幂运算相对耗时

深化:

1、梯度消失(待改进)
  • 优化神经网络的方法是反向传播,即导数的后向传递:先计算输出层对应的损失,然后将损失以导数的形式不断向上一层网络传递,修正相应的参数,达到降低损失的目的。 Sigmoid函数在深度网络中常常会导致导数逐渐变为0,使得参数无法被更新,神经网络无法被优化。原因在于两点:(1) 在上图中容易看出,当$\sigmoid(x)$中$x$较大或较小时,导数接近0,而后向传递的数学依据是微积分求导的链式法则,当前层的导数需要之前各层导数的乘积,几个小数的相乘,结果会很接近0 (2) Sigmoid导数的最大值是0.25,这意味着导数在每一层至少会被压缩为原来的1/4,通过两层后被变为1/16,…,通过10层后为1/1048576。实际情况往往比这个还要小,因为我们这里取的是最大值进行计算。
2、函数输出不是以0为中心(待改进)
  • Sigmoid函数的输出值恒大于0,这会导致模型训练的收敛速度变慢。举例来讲,对$\sigmax(\sum_{i}{w_i}{x_i}+w_0)$,如果所有$x_i$均为正数或负数,那么其对$w_i$![[公式]](https://www.zhihu.com/equation?tex=w_i)的导数总是正数或负数,这会导致如下图红色箭头所示的阶梯式更新,这显然并非一个好的优化路径。深度学习往往需要大量时间来处理大量数据,模型的收敛速度是尤为重要的。所以,总体上来讲,训练深度学习网络尽量使用zero-centered数据 (可以经过数据预处理实现) 和zero-centered输出。
3、幂运算相对耗时
  • 目前j计算机的算力能够满足,但是使用ReLU,只需要做一个阈值,更为方便。

应用:最初使用最为广泛的激活函数,目前逐渐被ReLU替代。

2.2 Tanh

函数:

$$
tanh(x) = \frac{exp(x)-exp(-x)}{exp(x)+exp(-x)}
$$

图示:

  • 优点:解决了以0为中心的问题
  • 缺点:梯度消失和幂运算的问题仍然存在

2.3 ReLU

函数: 公式 $$ ReLU(x) =\left\{\begin{aligned}x & & {x >=0}\\0 & & {x <0}​\end{aligned}\right. $$ 图示:

优点:

  • 解决了梯度消失的问题(正区间)

  • 计算简单,运算速度较快

  • 收敛速度比sigmoid和tanh要快

缺点:

  • 不是以0为中心

  • Dead ReLU Problem,也就是指出现神经网络永远不会被激活的情况,参数无法更新。有以下两种情况可能出现这种情况:

    1. 参数初始化,随机参数初始化可能会落入某个区间,使得网络进入这个状态,这种情况比较少见;

    2. 学习率较大导致参数更新太大,也有可能进入这种情况。选择合理的初始化方法和适当的学习率就可以。

应用:目前主流的方法,推荐优先尝试这个方法。

2.4 LeakyReLu

函数:
$$
f(x) = \left\{\begin{align}x && x>=0\\\frac{x}{a} && x<0\end{align}\right.
$$

图示:

优点:理论上解决了Dead ReLU Problem

缺点:实际训练没有体现出优势

应用:可与ReLU进行互换

2.5 ELU

函数:

 
$$
f(x) = \left\{\begin{align}x                 && x>=0\\{a}{(exp(x)-1)}   && x<0\end{align}\right.
$$

图示:

优点:也是为了解决Dead ReLU Problem而提出的。继承了ReLU的所有有点,同时也解决了Dead ReLU和zero-center的问题。

缺点:实际训练中没有体现出优势,而且运算较为费时。

应用:可与ReLU进行互换。

2.6 偏置项的意义

会不会有同学有这样的想法,偏置项就是一个常量,我直接不要了,可不可以?或者说偏置项的存在的意义是什么?

偏置项的作用正如我们初中时的一元一次方程中的常量,它起到了将整条曲线向左或向右平移的作用。这也是神经网络学习能够成功的关键要素。举个简单的例子,如下图所示:

从图中可知,如果没有偏置项,则拟合函数永远是通过原点的,而结果往往是与实际结果有所偏离。因为实际问题不可能都是经过原点。或者更为复杂的非线性问题,更是难以判断其曲线,所以添加偏置项,使得整体的曲线进行平移,有利于曲线的拟合。

2.7 激活函数存在的价值

激活函数看着都麻烦,能不能也不要了?

在实际生活中遇到的问题,往往都是非常复杂的问题,这些复杂的问题抽象成的数学问题也都是非线性的。由上述的公式可知,激活函数是非线性方程。而矩阵的线性变换已经无法满足需求了。因此在线性变换的基础上添加非线性的激活函数,才能够使得神经网络有足够的能力抓取复杂的模式,进而在各个领域取得最好的结果。因此激活函数起着优化整个神经网络的重要作用。

3.1 感知机:前向传播

其结构如下:

多输出的感知机在原有的基础上增加了输出,又被称为称为Dense layers,这个名词将会在以后的代码中经常见到。

3.2多层感知机(Multi layer Perceptron)

简称为MLP。对比一下上述两个感知机,可知多层感知机就是在原有单层的基础上增加一个或者多个隐层(hidden layer)。最为简单的模型就是三层。也就是我们训练数字采用的模型。如下图所示:

其代码模型构建如下:

上述模型只需要将隐藏层的n替换成128,将输出层的2替换成10,即是我们构建的三层模型。

4. 交叉熵与均方差

4.1 交叉熵[3]

交叉熵来源于信息论的概念,本质上就是对信息的量化

首先,我们定义一个事件X=x的自信息(self-information)为:

$$ I(x) = -\ln P(x) \qquad (1) $$ 自信息只处理单个的输出。我们可以使用香农熵(Shannon entropy)对这个概率分布中的不确定性总量进行量化: $$ H(x) = E_{x\sim P}[I(x)] = -E_{x\sim P}[ln P(x)] $$

也就是说,一个分布的香农熵是指遵循这个分布的事件所产生的期望信息总量。也可写为H(P)。x为连续的,香农熵也被称为微分熵(differential entropy)

如果对同一个随机变量x有两个单独的概率分布P(x)和Q(x),可以使用KL散度(Kullback-Leibler divergence)衡量这两个分布的差异:

$$ D_{KL}(P||Q) = E_{x\sim P}[\ln\frac{P(x)}{Q(x)}] = E_{x\sim P}[\ln P(x) – \ln Q(x)] $$

在离散型变量的情况下,KL散度衡量的是,当我们使用一种被设计能够使得概率分布Q产生的消息的长度最小的编码,发送包含由概率分布P产生的符号的信息时,所需要的额外信息量。

交叉熵(cross-entropy)与KL散度有着密切关系,但是又有些不同:

$$ \begin{align}H(P,Q) &= H(P)+D_{KL}(P||Q)\\&= -E_{x\sim P}\ln Q(x)\end{align} $$ 针对Q最小化交叉熵等价于最小化KL散度。

4.2 均方差(mean-square error)

  $$ MSE = \frac{1}{N}\sum_{i=1}^{N}(x_i-\mu)^2\\{\mu: \text{表示样本均值}} $$

4.3 为什么在分类中使用交叉熵而不是均方差

一句话,交叉熵与softmax分类结合,更有利于参数更新,便于模型收敛。我们以mnist的样本为例。
$$
\begin{align}z &= wx + b \qquad (1) \\\hat y &= \sigma(z) \qquad (2)\\l_m(y, \hat y) &= \frac{1}{2N}\sum_{j=1}^{N}(y_j-\hat y_j)^2 \qquad (3)\\l_c(y, \hat y) &= -\sum_{j=1}^{N}(y_j\ln{\hat y_j}) \qquad (4)\\\frac{\partial l_m(y, \hat y)}{\partial w_j} &= \frac{1}{N}|y_j-\hat y_j|\sigma'(z)x\qquad (5)\\\frac{\partial l_m(y, \hat y)}{\partial b_j} &= \frac{1}{N}|y_j-\hat y_j|\sigma'(z) \qquad (6)\\\frac{\partial l_c(y, \hat y)}{\partial w_j} &= \frac{1}{N}(1-\hat y_j)y_jx_j \qquad (7)\\\frac{\partial l_c(y, \hat y)}{\partial b_j} &= \frac{1}{N}(1-\hat y_j)y_j \qquad (8)\\​w &:= w – \frac{\partial L}{\partial w} \qquad (9)\\b &:= b = \frac{\partial L}{\partial b} \qquad (10)\end{align}
$$

由上述公式和sigmoid的导数图可知,当样本在两端时,公式(5)和公式(6)非常小,几乎为零,不利于公式(9)和公式(10)参数的更新,因此,使用均方差对可能会出现权重或者偏置更新较慢,模型收敛较慢的情况;而对交叉熵而言,公式(7)和公式(8)因为没有softmax导数,不会出现这个问题。

5. Adam优化算法[4]

为了能够得到更好的优化方法,前辈们尝试了很多方法。

这里详细介绍Adam

首先计算梯度和梯度平方的衰减平均:

$$ m_t = \beta_{1} m_{t_1} + (1-\beta_1)g_t\\v_t = \beta_{2}v_{t_1} + (1-\beta_{2})g_t^2 $$ 分别是梯度的第一冲量和第二冲量的评估。 之后计算矫正后的第一冲量和第二冲量评估: $$ \hat m_t = \frac{m_t}{1 – \beta_1^{t}} \\\hat v_t = \frac{v_t}{1 – \beta_2^{t}} $$ 更新参数: $$ \theta_{t+1} = \theta – \frac{\eta}{\sqrt{\hat{v_t}}+\epsilon}\hat m_{t} $$

6. 反向传播

我们采用的损失函数是交叉熵: $$ y_{pred} = f(x; W)\\J(W) = -\frac{1}{N}\sum_{i=1}^{N}y_{true}^{(i)}\ln{y_{pred}^{(i)}} $$ 反向传播的目的就是通过不断更新权重,进而最小化损失函数。即: $$ \begin{align}W^* &= argmin_{W}(-\frac{1}{N}\sum_{i=1}^{N}y_{true}^{i}\ln y_{pred}^{i})\\&=argmin_{W}J(W)\end{align} $$ 在上述模块中,只有Dense层含有权重。对于第二层的权重: $$ \frac{\partial J(W)}{\partial W_2} = \frac{\partial J(W)}{\partial y_{pred}}*\frac{\partial y_{pred}}{\partial W_2} $$ 对于第一层的权重: $$ \frac{\partial J(W)}{\partial W_1} = \frac{\partial J(W)}{\partial y_{pred}}*\frac{\partial y_{pred}}{\partial H_2}*\frac{\partial H_2}{\partial H_1}*\frac{\partial H_1}{\partial W_1} $$ 沿着梯度下降的方向更新,有利于快速降低损失函数。更新的跨度需要是多少,在这里我们引入了学习率\(\eta\)。表示每次更新的程度。 $$ W \leftarrow W – \eta\frac{\partial J(W)}{\partial W} $$ 我们希望学习率\(\eta\)在训练过程中可以随着梯度的变化而变化,即具有自适应的能力。这样就不用手动调试每个阶段的学习率的大小。因此,我们使用的是`Adam`优化算法。