欢迎访问个人博客网站获取更多文章:
-
本篇博文介绍了利用
numpy
库,搭建一个简单的神经网络实现手写数字识别问题 -
使用的数据库是大名鼎鼎的
MINST
,这个库的图片以256级灰度图存储,分辨率为28*28
,如下图 -
!
-
训练集由\(60000\)张图片组成,测试集由\(10000\)张图片组成
-
一组数据由一张图片、一个标签组成,标签的值为0,1,,,9
1. 神经网络结构介绍
- 借鉴\(3blue1brown\)的结构,输入层为\(28\times28=784\)个神经元,中间层为两层\(16\)个神经元的隐藏层,输出层为\(10\)个神经元。这一结构并不是必要的,比如将\(16\)改成\(20\),或者改成一层\(20\)一层\(16\)都是可以的。只要保证参数足够多、深度足够深就能够实现预测。
- 期望值:如果数字为\(5\),则期望输出层输出\(\{0,0,0,0,0,1,0,0,0,0,\}\)
- 预测值:计算时,将所有的像素值按顺序输入到输入层,并将输出层中值最大的神经元的序号作为预测输出
2. 激活函数选择:
- 最后一层选择\(Sigmoid\)函数作为激活函数,前两层选择\(Relu\)函数作为激活函数。
- 其实可以都用\(Sigmoid\)或者都用\(Relu\),但是训练速度和准确性会稍微差一些。因为\(Sigmoid\)是非线性函数,能够为神经网络带来更多非线性特征,但是容易出现梯度消失的问题,前向反向传播计算速度也慢,训练较慢;\(Relu\)接近于线性函数,虽然容易降低神经网络的准确度,却不容易出现梯度消失问题,训练速度较快。
3.参数初始化
-
各个全连接层的\(w\)和\(b\)不能简单采取标准正态分布进行初始化,这会导致梯度消失问题。需要再根据该层的输出维度数\(n^{(l-1)}\)进行调整。
-
具体的,根据该层的激活函数不同:
-
\(Relu\):将标准正态分布得到的随机值再乘以\(\frac{2}{n^{(l-1)}}\)
-
\(Sigmoid\):将标准正态分布得到的随机值再乘以\(\frac{1}{n^{(l-1)}}\)
-
\(Tanh\):将标准正态分布得到的随机值再乘以\(\frac{1}{n^{(l-1)}}\)
-
-
此部分理论见吴恩达深度学习https://www.bilibili.com/video/BV1FT4y1E74V?p=57
4. 损失函数选择:
- 这一模型较为简单,其实选啥都行。
- 我这里选的是\(均方损失函数\)也就是\(MSE\),公式为\((\hat{y}-y)^2\)
5. 梯度下降优化算法
- 实际不需要优化也可以有不错的效果,使用最简单的随机梯度下降即可
6. batch_size选择
- 最开始将
batch_size
设置为\(100\),但是这样训练速度较慢,通过不断实验,发现设置为\(20\)的效果最好 - 另外,在训练每一轮时,可以将所有样本重新随机排列,保证训练的随机性,这一行为也叫做洗牌shuffle。但经过实验,是否洗牌的影响不是很大
7. 训练效果
-
前150轮的测试集Loss值和正确率图