神经网络:手写数字识别

欢迎访问个人博客网站获取更多文章:

https://beityluo.space

  • 本篇博文介绍了利用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值和正确率

上一篇:使用nn.Sequential()对象和nn.ModuleList建立模型


下一篇:机器学习中常用的激活函数