一、实验要求
用 python 的 numpy 模块实现全连接神经网络。网络结构为一个输入层、一个隐藏层、一个输出层。隐藏层的激活函数为 Relu 函数,输出层的激活函数为 softmax 函数,损失函数为交叉熵。
二、实验目的
- 学会构建一个简单的全连接神经网络模型
- 学习使用Python的NumPy模块进行神经网络的搭建和训练
- 增加对前馈神经网络,参数学习,激活函数的了解
- 学会对模型进行优化、改进,比如:学习率调整、正则化等操作
三、实验过程
1.搭建神经网络
首先,在虚拟环境进行环境配置,创建虚拟环境,并进入,安装tensorflow和numpy模块。
用Python完成神经网络模型的构建,包括两个隐藏层和一个输出层,并且使用了矩阵乘法、ReLU激活函数、Softmax函数和交叉熵函数等操作。部分代码讲解:
对图像数据进行预处理
定义myModel类,是一个简单的神经网络模型,模型包含两个隐藏层和一个输出层,使用了矩阵乘法、ReLU激活函数、Softmax函数和交叉熵函数等操作。类的构造函数 __init__() 初始化了模型的权重 W1 和 W2,这些权重是随机生成的矩阵,以及用于执行矩阵乘法、ReLU、Softmax和交叉熵操作的实例对象。forward() 方法用于执行模型的前向传播操作。该方法首先将输入数据 x 转换为二维矩阵,并在末尾添加偏置项。然后,通过矩阵乘法、ReLU激活函数、矩阵乘法和Softmax函数的顺序,计算模型的输出结果 h2_soft,即预测的概率分布。最后,计算并存储交叉熵损失值 loss。backward() 方法用于执行模型的反向传播操作。接收标签 labels 作为输入,并按照与前向传播相反的顺序,调用各个操作的反向传播方法,计算并存储各个层的梯度值。
使用小批量数据执行一次前向传播和反向传播。使用梯度下降更新权重。
使用测试数据计算损失和准确性。
循环训练模型,每个epoch都对训练数据进行多次迭代。并且打印每个batch的损失和准确性。最后,在测试集上评估模型的性能。
2.对模型进行优化、改进
运行初始代码
序号 | 学习率 | 神经元个数 | 训练轮数 |
1 | 1e-5 | 100 | 50 |
再次运行
发现运行相同的代码,但是每次实验结果并不相同,经过查相关资料,发现是因为没有设置固定的随机种子,每次初始的条件不一致。于是考虑设置随机数种子,一方面是为了在得到比较好的结果时可以复现这个结果,另一方面,每次随机的初始权重一样,有利于实验的比较和改进。
设置完随机种子后再次训练发现同一情况下准确率相同
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 100 | 50 | 9.5599 | 0.5951 |
深度学习的优化过程是一个反复迭代的过程,需要不断地调整超参数和算法以达到最优的效果。
选择先调整学习率:
学习率是控制每次参数更新的步长大小的超参数。学习率越大, 输出误差对参数的影响就越大, 参数更新的就越快, 但同时受到异常数据的影响也就越大, 很容易发散.合适的学习率能够使目标函数在合适的时间内收敛到局部最小值
学习率 | 训练轮数 | Test loss | accuracy |
1e-4 | 50 | nan | 0.098 |
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-6 | 100 | 50 | 20.3428 | 0.2211 |
综合比较之后,学习率为1e-5时的准确率最高,故选定学习率为1e-5.
接下来选择调整神经元个数
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 100 | 50 | 9.5599 | 0.5951 |
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 150 | 50 | 5.7203 | 0.7636 |
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 200 | 50 | 6.5324 | 0.7355 |
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 250 | 50 | 7.7025 | 0.6984 |
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 300 | 50 | 8.2460 | 0.6831 |
综合比较,最终神经元个数选为150
接下来调整训练轮次
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 150 | 100 | 4.9358 | 0.7974 |
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 150 | 150 | 3.5525 | 0.839 |
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 150 | 200 | 2.2190 | 0.8938 |
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 150 | 250 | 2.0297 | 0.9006 |
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 150 | 300 | 1.8736 | 0.9069 |
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 150 | 500 | 1.6171 | 0.9129 |
最终,选定训练轮数为500
此时,准确率并不是很理想,考虑将神经网络层数加1,但结果并不理想
通过搜查相关资料,可以采用小批量训练的方法,进而提高准确率.具体方法为:将训练数据划分为小批量,而不是整个数据集一次性输入,可以提高内存和计算效率,并提高训练的稳定性。这使得模型能够更好地处理大规模数据集,并加快模型的训练速度。
但使用小批量训练后
训练出现过拟合现象,该方法也不可取
四、实验结果
最终采取以下的参数进行实验,是本次实验得出的最好的模型
学习率 | 神经元个数 | 训练轮数 |
1e-5 | 150 | 500 |
去掉随机数种子的约束,进行三次实验,取三次实验准确率进行求取平均值
最终结果为:
学习率 | 神经元个数 | 训练轮数 | Test loss | accuracy |
1e-5 | 150 | 500 | 1.3570 | 0.9233 |