0%

神经网络:手写数字识别

  • 本篇博文介绍了利用numpy库,搭建一个简单的神经网络实现手写数字识别问题

  • 使用的数据库是大名鼎鼎的MINST,这个库的图片以256级灰度图存储,分辨率为28*28,如下图

  • image-20210805183315982

  • 训练集由$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,}$
  • 预测值:计算时,将所有的像素值按顺序输入到输入层,并将输出层中值最大的神经元的序号作为预测输出
  • image-20210806065421186

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值和正确率图👇
  • image-20210807184834697

  • 这一曲线和同样的结构使用pyTorch的训练速度、准确率大致相同,都能在30轮时达到$93\%$的准确率,最终达到$95\%$左右准确率(我自己编写的代码甚至比pyTorch还要高上0.5%嘿嘿嘿 \( ̄▽ ̄)/)

8. 其他