发布时间:2022-11-28 10:00
实验3 基于神经网络的模式识别实验
一、实验目的:
理解BP神经网络和卷积神经网络的结构和原理,掌握反向传播学习算法对神经元的训练过程,了解反向传播公式。通过构建BP神经网络和卷积神经网络模式识别实例,熟悉前馈神经网络的原理、结构和工作过程。
二、实验原理
BP学习算法是通过反向学习过程使误差最小,其算法过程从输出节点开始,反向地向第一隐含层(即最接近输入层的隐含层)传播由总误差引起的权值修正。BP网络不仅含有输入节点和输出节点,而且含有一层或多层隐(层)节点。输入信号先向前传递到隐节点,经过作用后,再把隐节点的输出信息传递到输出节点,最后给出输出结果。
卷积神经网络的人工神经元可以响应一部分覆盖范围内的周围单元。卷积神经网络由三部分构成:第一部分是输入层,第二部分由n个卷积层和池化层的组合组成,第三部分由一个全连接的多层感知机分类器构成。这一结构使得卷积神经网络能够利用输入数据的二维结构。卷积神经网络会自动的对于一张图片学习出最好的卷积核以及这些卷积核的组合方式,然后来进行判断。
三、实验条件:
自主安装64位的python 3.6以上,以及TensorFlow2.0以上、numpy、matplotlib、pylab等第三方库,新建一个文件夹datasets (C:\Users\A\.keras\datasets),把mnist.npz放入datasets文件夹里。
四、实验内容:
1.分析Mnist数据集,选择55000个训练样本、5000个验证样本、10000个测试样本,设置批量大小为100。
2.设计一个含有2个隐层的BP网络结构模型,输出层采用sofmax回归后的交叉熵损失函数,设置学习率、训练步数、批数等参数,给出训练和测试结果,分别填入下表1。(注:下表 1中 ?和空白区域都需要补充完整)
表1 BP网络的参数及训练、测试结果
参数 |
隐层数 |
隐层激活函数 |
隐层神经元数 |
学习算法 |
训练结果(训练损失值、验证正确率) |
测试正确率 |
批量大小:100 学习率:0.01 训练次数:10 输入神经元数:512 输出神经元数:10 输出激活函数:sofmax回归后的交叉熵 |
2 |
Relu |
第1个隐层: 神经元数为:512 参数量为:401920 第2个隐层: 神经元数为:512 参数量为:261656 |
随机梯度下降+动量法:optimizers.SGD(lr=0.01) |
loss: 0.4541553258895874 Acc: 0.9074 |
Test Acc: 0.8866 |
Adagrad算法: optimizers.Adagrad(lr=0.01) |
loss: 0.0027855050284415483 Acc: 0.984 |
Test Acc: 0.9819 |
||||
Adam算法:optimizer=optimizers.Adam(lr=0.01) |
Loss: 0.17099925875663757 ACC=0.972 |
TEST ACC=0.9636 |
3.对于含有4个(含有512个神经元)隐层的BP网络结构模型,隐层激活函数采用relu,学习算法采用Adam算法,设计并比较不同模型的正确率,把训练和测试结果填入下表2。(注:下表2中?和空白区域都需要补充完整)
表2 含4个隐层的BP网络训练、测试结果
不同模型 |
训练结果(训练损失值、验证正确率) |
测试正确率 |
使用指数衰减学习率: 初始学习率=0.01 衰减系数=0.96 衰减步数=1000 |
loss: 0.0005220939638093114 Acc: 0.9766 |
Test Acc: 0.9776 |
只使用正则化,学习率固定: 学习率=0.01 正则化系数=0.001 |
loss: 0.17735381424427032 Acc: 0.971 |
Test Acc: 0.9676 |
使用指数衰减学习率和正则化: 正则化系数=0.001 初始学习率=0.01 衰减系数=0.96 衰减步数=1000 |
loss: 0.02895130217075348 Acc: 0.9806 |
Test Acc: 0.9793 |
只使用Dropout,学习率固定: 学习率=0.01 Dropout断开率=0.5 |
loss: 0.1732 Acc: 0.967 |
Test Acc: 0.958 |
4. 对Mnist数据集,选择55000个训练样本、5000个验证样本、10000个测试样本,设置批量大小为100。然后构建一个卷积神经网络模型,把卷积神经网络的结构模型参数填入表3,隐层激活函数采用relu,选择学习算法,设置参数,把不同模型的训练和测试结果填入下表4。(注:表3中,名称填输入层、卷积层、池化层、全连接层、输出层;表4中的BP神经网络采用含有4个隐层(每层含有512个神经元,激活函数采用relu)的网络结构模型)
表3 卷积神经网络的结构模型参数
名称 |
神经元个数 |
过滤器尺寸 |
卷积核个数 |
步长 |
激活函数 |
填充数 |
输出特征图大小 |
|
第1层 |
卷积层1 |
6*26*26 |
3*3 |
6 |
1 |
Relu |
0 |
26*26 |
第2层 |
池化层1 |
- |
2*2 |
6 |
2 |
Relu |
0 |
13*13 |
第3层 |
卷积层2 |
16*11*11 |
3*3 |
16 |
1 |
Relu |
0 |
11*11 |
第4层 |
池化层2 |
- |
2*2 |
16 |
2 |
Relu |
0 |
5*5 |
第5层 |
全连接层1 |
120 |
- |
- |
- |
Relu |
0 |
- |
第6层 |
全连接层2 |
84 |
- |
- |
- |
Relu |
0 |
- |
第7层 |
全连接层3 |
10 |
- |
- |
- |
Relu |
0 |
- |
表4卷积神经网络和BP神经网络的训练、测试结果
学习算法及参数设置 |
不同模型 |
训练结果(训练损失值、验证正确率) |
测试正确率 |
学习率为0.01 学习算法为 Adam |
使用正则化的卷积神经网络 (正则化系数=0.001) |
loss: 0.10340672731399536 Acc: 0.9824 |
Test Acc: 0.9799 |
使用正则化的BP神经网络 (正则化系数=0.001) |
loss: 0.17735381424427032 Acc: 0.971 |
Test Acc: 0.9676 |
五、实验报告要求:
1. 按照实验内容,给出相应结果。
2.分析比较不同学习算法对BP网络的训练结果、测试结果等的影响。
①随机梯度下降的算法是训练速度最快的,同时也是准确率最低的,训练结果和测试结果的准确率都不是很高。代价函数也最大,为0.4541553258895874,比其他两种算法都高很多,说明其模型拟合的不好。因为它是盲目搜索,是随机抽取的一个样本,信息少,容易跑偏。
②Adagrad算法性能是三种里面最好的,无论是训练效果还是测试效果都是准确率最高的,代价函数的值也是远远小于其他两种算法,可以从结果看Adagrad算法并没有发生严重的过拟合现象。
③Adam算法优化,也可以提高训练结果和测试结果的准确度,但没有Adagrad算法准确度高。
3. 分析比较使用指数衰减学习率、正则化和Drop层等不同模型对于训练结果、测试结果等的影响。
①使用指数衰减学习率提高了训练结果和测试结果的准确度,但提升的程度不明显,但是代价函数小了很多。
②使用正则化后,可以比较好的解决过拟合的问题,这边的loss值比不使用时大了一点,但是从准确度上来说模型拟合的性能并没有提高多少。
③使用droout层,也是和使用正则化一样的效果,它对于神经网络单元按照一定的概率将其暂时从网络中丢弃,从而提升训练效果,但是在本实验中不太明显,本实验是只在第3层加dropout层,如下:
network = Sequential([layers.Dense(512, activation='relu'),
layers.Dense(512, activation='relu'),
layers.Dense(512, activation='relu'),
layers.Dropout(0.5),
layers.Dense(512, activation='relu'),
layers.Dense(10, activation='softmax')])
④使用指数衰减学习率和正则化结合的方法比只使用指数衰减学习率的loss值高,说明一定程度上减小了过拟合的效应,但是loss比值使用正则化的loss值高,提升了模型性能,训练结果和测试结果的准确度都提升了。
4. 总结BP网络和卷积神经网络在模式识别方面的异同点。
不同点:
①BP网络和卷积神经网络的计算方法不同:
BP神经网络是一种按照误差逆向传播算法训练的多层前馈神经网络
卷积神经网络则包含卷积计算且具有深度结构的前馈神经网络。
②卷积网络使用共享权值来减少网络各层之间的连接
③BP的网络结构:包括输入层,隐层和输出层。
卷积网络结构:输入层,卷积层,池化层,全连接层,输出层。
④BP采用全连接,卷积网络采用局部感知
相同点:
①BP神经网络和卷积神经网络都属于前馈神经网络,
②输入层都是输入图像,输出层都是多分类的结果。
③网络的中间层数、各层的神经元个数都可以根据具体情况任意设定,并且随着结构的差异其性能也有所不同。
④都采用了前向传播计算输出值,反向传播调整权重和偏置。
5. 实验心得。
①掌握了卷积层中输入大小和输出大小之间的计算关系:
输入:rxc,卷积核:axb,步长stride:s=1 输出:长=(r-a)/s+1 ,宽 =(c-b) )/s +1
②掌握了训练参数的计算
③掌握了BP和卷积网络的搭建和和优化算法的使用及训练和预测
代码(例:4层指数衰减):
import tensorflow as tf
from tensorflow.keras import datasets, layers, optimizers, Sequential
import matplotlib.pyplot as plt
import numpy as np
import pylab
def preprocess(x, y):
x = tf.cast(x, dtype=tf.float32) / 255.
y = tf.cast(y, dtype=tf.int32)
return x,y
(x, y), (x_test, y_test) = datasets.mnist.load_data()#下载或读取数据集
print('datasets:', x.shape, y.shape, x.min(), x.max())#打印
训练:
imgs = x_test[0:5]#选取第0到5的图片
labs = y_test[0:5]
#print(labs)
plot_imgs = np.hstack(imgs)#将五张图片拼接成一行
plt.imshow(plot_imgs, cmap='gray')#选择gray灰度图
#pylab.show()#显示测试图片
x_train,x_val=tf.split(x,num_or_size_splits=[55000,5000])
y_train,y_val=tf.split(y,num_or_size_splits=[55000,5000])
batchsz = 100#设置批量大小
db = tf.data.Dataset.from_tensor_slices((x_train,y_train))
db = db.map(preprocess).shuffle(55000).batch(batchsz).repeat(10)
db_test = tf.data.Dataset.from_tensor_slices((x_test,y_test))
db_test = db_test.map(preprocess).batch(batchsz)
ds_val = tf.data.Dataset.from_tensor_slices((x_val, y_val))
ds_val = ds_val.map(preprocess).batch(batchsz)
#构建网络模型
network = Sequential([layers.Dense(512, activation='relu'),
layers.Dense(512, activation='relu'),
layers.Dense(512, activation='relu'),
layers.Dense(512, activation='relu'),
layers.Dense(10, activation='softmax')])
network.build(input_shape=(batchsz, 28*28))#批量大小
network.summary() #打印网络参数
# 设置优化器
exponential_decay=tf.keras.optimizers.schedules.ExponentialDecay(
initial_learning_rate=0.01,decay_steps=1000,decay_rate=0.96)
optimizer=tf.keras.optimizers.Adam(exponential_decay)
#optimizer = optimizers.Adam(lr=0.01) # 固定学习率的Adam学习算法,大块=快,会振荡
#optimizer = = optimizers.SGD(0.01, decay=1e-2)# 固定学习率的SGD学习算法
#分批进行训练
for echo in range(10):
for step, (x,y) in enumerate(db):#从训练集读取一批样本数据
with tf.GradientTape() as tape:#构建梯度训练环境
# [b, 28, 28] => [b, 784]
x = tf.reshape(x, (-1, 28*28))
# [b, 784] => [b, 10]
out = network(x,training=True)
# [b] => [b, 10]
y_onehot = tf.one_hot(y, depth=10)
# [b]
#计算交叉熵损失函数
loss = tf.reduce_mean(tf.losses.categorical_crossentropy(y_onehot, out, from_logits=False))
grads = tape.gradient(loss, network.trainable_variables)#计算梯度
optimizer.apply_gradients(zip(grads, network.trainable_variables))#更新训练参数
if step % 100 == 0:
print('echo=',echo,' step=',step, 'loss:', float(loss))#打印训练的损失函数
# 模型评价
if step % 500 == 0:
total, total_correct = 0., 0
for i, (x, y) in enumerate(ds_val):
# [b, 28, 28] => [b, 784]
x = tf.reshape(x, (-1, 28*28))
# [b, 784] => [b, 10]
out = network(x)#神经网络模型输出
# [b, 10] => [b]
pred = tf.argmax(out, axis=1)
pred = tf.cast(pred, dtype=tf.int32)
# bool type
correct = tf.equal(pred, y)
# bool tensor => int tensor => numpy
total_correct += tf.reduce_sum(tf.cast(correct, dtype=tf.int32)).numpy()
total += x.shape[0]
print(' step=',step, 'Evaluate Acc:', total_correct/total)#打印模型验证正确率
print("train is over")
#测试模型
total, total_correct = 0., 0
for i, (x, y) in enumerate(db_test):#读取一批测试数据
# [b, 28, 28] => [b, 784]
x = tf.reshape(x, (-1, 28*28))
# [b, 784] => [b, 10]
out = network(x)#神经网络模型输出
# [b, 10] => [b]
pred = tf.argmax(out, axis=1)
pred = tf.cast(pred, dtype=tf.int32)
# bool type
correct = tf.equal(pred, y)
# bool tensor => int tensor => numpy
btestacc=tf.reduce_sum(tf.cast(correct, dtype=tf.int32)).numpy()
total_correct += btestacc
total += x.shape[0]
#print('第',i,'批','test acc=',btestacc/x.shape[0])
#print(y)
#print(pred)
print('Test Acc:', total_correct/total)
训练结果: