写在前面
-
本机系统:macOS Catalina 10.15.6,python3.8.3
-
python2(也是教材官方的github库):neural-networks-and-deep-learning
-
需要的第三方库:
1
2
3import numpy as np
import gzip
import pickle
一、数据导入
在mnist_loader.py
包中,将data目录下的mnist.pkl.gz压缩包解压缩,并以一定的格式传递给python进行计算。
1 | def load_data(): |
使用gzip.open()
命令将.gz文件以二进制只读的格式打开,再用pickle.load()
函数将数据存入变量中。
注意,此时各个变量的格式:
- training_data:元祖的形式(x,y),其中x为一个有50000个元素的numpy矩阵,每一个元素又分别有784个元素,代表28*28的单个MNIST图像。y也是一个有50000个元素的numpy矩阵,每一个元素为MNIST图像所代表的digit数字,范围从0到9.
- validation_data、test_data的形式与上述training_data相同,但只包含10000幅图像。
1 | def load_data_wrapper(): |
转换后各个变量的格式:
-
training_data:一个长度为50000的列表,列表中的每一个元素为元祖(x,y),其中,x是一个包含了输入图片的784维的numpy矩阵,y是一个10维的numpy矩阵,表示该数字的期待输出。
-
validation_data/test_data:一个长度为10000的列表,列表中的每一个元素为元祖(x,y),其中,x是一个包含了输入图片的784维的numpy矩阵,y是MNIST图像所代表的digit数字,范围从0到9。
1 | def vectorized_result(j): |
一个辅助函数,返回一个10维的numpy矩阵。
二、网络学习
1 | import random |
每个函数的具体作用都写在了函数前的注释中,此处不再赘述。
再来看看main.py
里面的内容。
1 | import network |
main函数是python程序运行的主函数,将剩下两个python程序导入后,给各个data赋值,定义一个[784,30,10]的神经网络,最后调用SGD来完成计算。
最终结果是,在我的三十个迭代周期中,分辨准确率的最大值达到了95.2%。
三、步骤总结
使用神经网络视线手写数字识别大概分以下几个步骤。
1.数据导入
使用一个单独的程序将官方提供的MNIST数据导入python程序,以供我们训练使用。
2.定义网络
此处使用的是一个[784,30,10]的神经网络,隐藏层只有30个神经元,学习速率3.0,选取30个迭代周期,每个batch的大小设置为10。
此处的超参数也可以自己设定。
3.随机梯度下降
将训练数据分成相同大小的mini_batch,在每个batch不断迭代得到权重和偏置,称为随机梯度下降算法。
具体来说,在每一个迭代周期内:
-
将training_data打乱,按照mini_batch的步长将training_data分成不同的mini_batchs。
-
在每个mini_batch内,一个一个的输入训练数据,使用反向传播算法,将得到的关于权重和偏置的改变累加起来,最后利用公式
$$w^{l} \rightarrow w^{l}-\frac{\eta}{m} \sum_{x} \delta^{x, l}\left(a^{x, l-1}\right)^{T}$$
$$b^{l} \rightarrow b^{l}-\frac{\eta}{m} \sum_{x} \delta^{x, l})$$
获得在一个mini_batch内的权重和偏置的改变。
-
遍历完所有的mini_batch,得到一次迭代后w和b的改变。
-
将test_data输入到刚刚训练好的网络中,得到准确率。
-
继续下一次迭代。
4.反向传播算法
对于一个单独的元祖输入(x,y),其中x是一个包含了输入图片的784维的numpy矩阵,y是一个10维的numpy矩阵,表示该数字的期待输出,反向传播算法的具体做法如下:
- 第一层的激活值a^1^即为输入x。
- 根据公式,使用网络原本的w和b,算出每一层的中间值z和激活值a。
- 计算输出层误差:$\delta^{x, L}=\nabla_{a} C_{x} \odot \sigma^{\prime}\left(z^{x, L}\right)$,其中$\nabla_{a} C_{x}=a^{L}-y$
- 反向传播,计算其他层的误差:$\delta^{l}=\left(\left(w^{l+1}\right)^{T} \delta^{l+1}\right) \odot \sigma^{\prime}\left(z^{l}\right)$
- 得到代价函数的梯度下降公式:$\frac{\partial C}{\partial w_{j k}^{l}}=a_{k}^{l-1} \delta_{j}^{l}$,$\frac{\partial C}{\partial b_{j }^{l}}=\delta_{j}^{l}$