目标

输入:一个单色图像

输出:一个 0~9 之间的数字

数据源(MNIST):

kaggle competitions download -c digit-recognizer

问题分析

输入的图像可以看作一个 $28 \times 28$ 的方阵。将其平铺为一个向量,则是 $784$ 维的二值向量(数组)。

手写识别的网络可以看作一个比较复杂的复合函数。

输出可以看作一个 $10$ 维二值向量。若 $\text {output}[i] = 1$,则识别结果为 $i$。

神经网络的推导

下面仅仅针对最简单的反向传播分层神经网络进行了推导,旨在理解基本原理。实际中我们使用开源的神经网络库,其底层原理会远远复杂于此。

M-P 神经元

每个神经元相当于一个运算单元。

参数:

  • $w_i$ ,表示第 $i$ 个连进来的神经元的连接权重(weight)。
  • $\theta$,表示激活阈值(threshold)。
  • $f$,表示激活函数(activation function)

输入:

  • $x_i$,表示第 $i$ 个连进来的神经元的输出值。
$$ y=f\left(\sum_{i=1}^{n} w_{i} x_{i}-\theta\right) $$

向量形式:

$$ y = f(\mathbf{w} \cdot \mathbf{x} - \theta ) $$

激活函数

常用的激活函数:

  • Sigmoid
  • Sgn
  • ReLU
  • Tanh

image_up_1639668343d1cf2775.jpg

神经网络

神经网络就是若干个上述函数复合的结果。

哑结点

令 $(w_n,x_n) = (-1,\theta)$,则

$$ y=f\left(\sum_{i=1}^{n} w_{i} x_{i}-\theta\right) = f(\sum_{i=1}^{n+1}w_ix_i) $$

这样权重和偏置量($\theta$)的学习的过程统一成了权重的学习。

分层网络

理论上节点间可以任意连接。考虑到实用性,一种连接方式是分层,然后各层之间全连接。

  • 输入层:负责直接处理输入的数据。
  • 中间层:也叫隐藏层。
  • 输出层:负责输出到我们限定的值域。

image_up_16396695757344441b.jpg

BP 算法

BP 算法是多层网络的一种训练方法。

误差估计

损失(loss or cost)采用均方误差(MSE):

$$ C =\operatorname{MSE} = \mathbb{E}[(\hat{y} - y)^2] $$

其中 $\hat {y}$ 是估计器(也称估计量),$y$ 是参数真实值。

参数更新

即将参数更新到更好的值:

$$ v \leftarrow v + \Delta v $$

学习速率为 $\mu$,则参数调整量为:

$$ \Delta w_{h j}=-\eta \frac{\partial C}{\partial w} $$

其中:

  • $C$ 是均方误差

  • $w$ 是连到上一个结点的权重

我们希望调整一个很小的权重,就能导致误差的很大变化(让损失最快地变小),即希望向损失减小最快方向调整,这就是 $\dfrac {\partial C}{\partial w}$ 的含义。

  • $\mu$ 是用来整体控制调整的快慢的。

具体更新权重的公式

问题在于,我们没有 $C (w)$ 的解析式。但根据链式法则:

$$ \dfrac{\partial C}{\partial w} = \dfrac{\partial C}{\partial \hat y} \cdot \dfrac{\partial \hat y}{\partial \beta} \cdot{ \color{blue}{ \dfrac{\partial \beta}{\partial w} } } $$

$\beta $ 表示神经元接收到的加权输入,$\beta = \sum_{}^{} wb = \mathbf {w} \cdot \mathbf {b}$ ($\mathbf {b}$ 表示输出值 ),即收到的各个连接的期望。因此:

$$ { \color{blue}{ \dfrac{\partial \beta}{\partial w} } } = b $$

更新公式的具体表达式则需要根据激活函数计算。

设 $g = -\dfrac {\partial C}{\partial \hat y} \cdot \dfrac {\partial \hat y}{\partial \beta}$,假设使用 ReLU: $ f (x)=\max (0,x)$ 作为激活函数。

误差 $C = \dfrac {1}{2} \sum (\hat y - y) ^2$,则

  • $\dfrac{\partial C}{\partial \hat y} = \dfrac{1}{2} \cdot 1 \cdot 2(\hat{y} - y) = \hat{y} - y$
  • $\hat {y} = f (\mathbf {w} \cdot \mathbf {b} - \theta ) = f (\beta - \theta $),因此 $\dfrac {\partial \hat y}{\partial \beta} = f'(\beta - \theta) = \left{\begin {array}{cc} 1 \quad \text{when } f(\beta - \theta , 0) > 0 \
    0 \quad \text{when } f(\beta - \theta , 0) = 0 \end{array}\right.$

因此 $g = \left{\begin {array}{cc} & - (\hat{y} - y) & \quad \text{when } f(\beta - \theta , 0) > 0 \
& 0 & \quad \text{when } f(\beta - \theta , 0) = 0 \end{array}\right.$

从而

$$ \begin{align} \Delta w = \eta gb \\ \Delta \theta = - \eta g \\ \Delta v = \eta ex \\ \Delta \gamma = -\eta e \end{align} $$

数字识别的实现

查看数据集

# example of loading the mnist dataset
from tensorflow.keras.datasets import mnist
from matplotlib import pyplot as plt
# load dataset
(trainX, trainy), (testX, testy) = mnist.load_data()
# summarize loaded dataset
print('Train: X=%s, y=%s' % (trainX.shape, trainy.shape))
print('Test: X=%s, y=%s' % (testX.shape, testy.shape))
# plot first few images
for i in range(6):
	# define subplot
	plt.subplot(320 + 1 + i)
	# plot raw pixel data
	plt.imshow(trainX[i], cmap=plt.get_cmap('gray'))
# show the figure
plt.show()

image_up_16397426440b4b21fc.jpg

Figure_1.png

Figure_1.jpeg

输出:

> 98.625
> 98.725
> 98.733
> 98.800
> 98.767

image_up_16397980812460514b.jpg

image_up_1639798792458bde22.jpg

Digits Recognition with CNN Keras | Kaggle

未完待续……

参考资料

周志华《机器学习》

用 tf.data 加载 CSV 数据 | TensorFlow Core

Neural networks and deep learning

深度学习之反向传播算法 上 / 下 Part 3 ver 0.9 beta_哔哩哔哩_bilibili

How to Develop a CNN for MNIST Handwritten Digit Classification (machinelearningmastery.com)