AI入门:神经网络实战----全连接神经网络

MNIST数据集介绍MNIST数据集是0~9等十个数字的手写数字数据集,它有50000张训练图片,10000张测试图片。每一张图片都是28 * 28像素的灰度图。这些图片都被预处理成一维的数组: 28 * 28 = 784,每一个像素都是0~255之间的一个整数表示,每张图片都有对应的数字。这些图片和对应的数字分别被称之为x和label。这种有x和label一一对应关系的数据集称之为one-hot。编写针对MNIST数据集的神经网络相当于编写C、Python等语言中的Hello World程序,是基础的
摘要由CSDN通过智能技术生成

MNIST数据集介绍
MNIST数据集是0~9等十个数字的手写数字数据集,它有50000张训练图片,10000张测试图片。每一张图片都是28 * 28像素的灰度图。这些图片都被预处理成一维的数组: 28 * 28 = 784,每一个像素都是0~255之间的一个整数表示,每张图片都有对应的数字。这些图片和对应的数字分别被称之为x和label。这种有x和label一一对应关系的数据集称之为one-hot。
编写针对MNIST数据集的神经网络相当于编写C、Python等语言中的Hello World程序,是基础的基础,所以我们要好好掌握它。
数据集的读取
MNIST数据集是程序化的内容,大家的写法基本都一样,没有什么需要理解和记忆的。需要注意的是在读取的时候已经进行数据的归一化处理了,这个归一化处理很重要。
这里得到的train_loader和test_loader是生成器,它们把数据读取出来之后,经过一些预处理,然后保存在变量中,每次问它们要,生成器就会给出一批数据,直到所有数据都被读取完。

在这里插入图片描述
简单的神经网络的构建1:全连接神经网络
本节使用两种方式构建神经网络,这里采用用户手动控制w和b参数的方式。
在之前我们提起过:上一层网络中的神经元的数据是通过一个简单的一元一次方程处理之后,再经过激活函数,然后就传给下一层神经网络的神经元。使用的一元一次方程就是:y = x * w + b。
当然,这只是对于一个神经元的处理。事实上,我们的网络层中往往含有很多个神经元。这时,我们就需要使用二维的张量。
对于MNIST数据集的输入,每张图片都是28 * 28 = 784维度的,我们希望第一层的输出是256维的,所以我们需要这样定义第一层的w1和b1。其中w1和b1都是需要迭代优化的,所以它们都需要写上requires_grad=True (默认值是False)。

在这里插入图片描述

有了第一层之后,剩下几层就简单了,依样画葫芦就可了。从256 -> 256 -> 10输出。最后的10的意思是一共有十种可能。至此,我们需要的参数都已经定义好了,且已经完成初始化工作。

在这里插入图片描述

下面是利用这些参数构建神经网络。我们的预测工作 (前向传播) 就在forward(x)函数中完成。其中x表示输入的数据。这里一次性输入64张图片,每张图片的维度都是784,所以x的size是64行,784列的矩阵,以后简写成 (64, 784)。

x是 (64, 784) 的矩阵,w1是 (784, 256) 的矩阵,用线性代数中的矩阵乘法进行运算,得到(64, 256) 的结果,这个结果正好与b1相加,得到 (64, 256) 的结果。激活函数不影响x的形状,所以第一层的输出就是(64, 256) 的矩阵。以此类推,第二层得到的是(64, 256) 的矩阵;第三层得到的是(64, 10) 的矩阵。
这里有三点需要注意:
① 矩阵运算的时候,矩阵的维度一定要衔接好,否则是无法计算的。另外矩阵的尺寸最好是2^n,这样的尺寸的矩阵在计算时速度更快。
② 最后一层是不需要激活的,所以没有必要再用relu()
③ 对于多分类的输出,需要softmax(),但这个操作已经被PyTorch自动执行了,所以我们没必要添加softmax()。如果添加,反而会导致结果不收敛。

在这里插入图片描述

在构建完网络模型之后,我们还需要指定梯度下降时用的算法、学习率、使用的损失函数等。
在这里,我们使用SGD算法 (随机梯度下降),[w1,b1,w2,b2,w3,b3]指的是要优化的参数列表,lr是学习率,也就是我们之前说的步长。步长不要太大,一般选取0.01~0.1即可,步子迈得太大会不稳的,如果有必要,甚至可以每过一轮就减少一点学习率。这里使用的损失函数是交叉熵损失函数。

在这里插入图片描述

至此,我们就完成了神经网络的搭建。这个神经网络中的参数都是我们手动指定的。这种方式一般只用来构建很小的神经网络。为了更快,更方便的搭建神经网络,我们更常用第二种方式。
简单的神经网络的构建2:全连接神经网络
用类的方式构建神经网络需要继承PyTorch提供的nn.Module类,并在__init__()中调用父类的构造函数。
用这种方式时,需要优化的参数都隐藏在layer1 ~ layer3中。需要注意的是,需要优化的层前面都要用self指定,且都要放在__init__()中。forward()函数只负责预测 (前向传播)。

在这里插入图片描述

与方式1最大的区别就是方式2需要实例化一个对象model,model.parameters()可以自动获得需要优化的参数,也就是隐藏在layer1 ~ layer3中的参数。

在这里插入图片描述

这种类的方法的好处是模型搭建更加简单,参数收集更容易,且比较完整。所以我们最常用第二种方式。下面我们就使用这个模型进行训练和预测。
神经网络的训练和结果
这一段我们就对模型进行训练。epochs是要训练的次数,我们假设移动需要训练5轮,也就是每一张测试图片都将被读取5次。
我们从train_loader中读取每一个批次的index,以及数据和标签。我们的数据的尺寸是(64, 1, 28, 28),其中64是每一个批次读取的图片数量,1是图片的通道数 (灰度图的通道数是1,彩色图的通道数为3),剩余两个28是宽和高。这个数据我们需要将其转化成(64, 784)就需要使用reshape(batch_size, 784),也可以写成reshape(-1, 784)。写成-1时,PyTorch将自动计算batch_size。数据变形之后就可以用于model.forward()了,并得到预测值(logits)。用criterion(logits, target)计算预测值与真实值之间的差距 (loss)。
在得到损失值loss之后就可以进行反向传播求导了,但前提是要把所有参数的梯度清零。求导结束之后进行一次优化,也就是进行类似 w = w - lr * w.grad这样的操作。这样就完成了一轮训练。我们可以每个100个批次显示一下训练结果。这里有用的主要是loss.item(),显示的是损失值变化。理想的损失值是不规则的慢慢下降的一个过程。

在这里插入图片描述

在训练完一个epoch之后,我们需要对当前的神经网络进行一次测试。测试需要知道的是损失值和准确率。
测试过程与训练过程一样,也是一次预测的过程。区别是需要统计criterion函数计算得到的损失值,以及把正确结果统计出来。值得注意的是logits.data.max(1)不要换成logits.data.argmax(1)。因为两个函数一个得到的是最大值,另一个得到的是最大值的index。不过因为这里的值与index正好相等,所以这两个函数在这个例子中的运行结果是一样的。

在这里插入图片描述

最终,经过5轮训练之后,我们的模型在测试集的准确

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值