手写数字识别--神经网络实验

实验源码自取:

 我自己搞的代码,预测精度才94%

神经网络实验报告源码.zip - 蓝奏云

 老师给的实验源码答案和资料,预测精度高达99%

深度学习实验报告.zip - 蓝奏云

上深度学习的课程,老师布置了一个经典的实验报告,我做了好久才搞懂,所以把实验报告放到CSDN保存,自己忘了方便查阅,也为其他人提供借鉴

由于本人是小白,刚入门炼丹,有写地方搞不懂,实验报告有错误的在所难免,请及时指出错误的地方

前馈神经网络的设计

一、实验目标及要求

1.掌握python编程

2.掌握神经网络原理

3. 掌握numpy库的基本使用方法

4. 掌握pytorch的基本使用

前馈神经网络是学习神经网络的基础。本实验针对MNIST手写数字识别数据集,设计实现一个基本的前馈神经网络模型,要求如下:

1. 在PyCharm平台上,分别基于numpy库和PyTorch实现两个版本的模型。

2. 网络包含一个输入层、一个输出层,以及k个隐藏层(1≤k≤3 )。

3. 每个版本的项目文件夹里面有一个文件夹以及三个文件,文件夹名为data,存放MNIST数据集,三个文件为: main.py、network.py、 data_loader.py。main为主文件,通过运行main启动手写数字识别程序;network.py存放神经网络类定义及相关函数;data_loader.py存放负责读入数据的相关方法。

4. 原训练集重新划分为训练集(5万样本)、验证集(1万样本),原测试集(1万样本)作为测试集。

5. 模型中使用交叉熵代价函数和L2正则化项。

6. 在每一个epoch(假设为第i个epoch)中,用训练数据训练网络后,首先用验证集数据进行评估,假设验证集的历史最佳准确率为p ,本次epoch得到的准确率为pi ,如果pi>p ,则用测试集评估模型性能,并把p更新为pi ;否则不评估并且p不更新 ,进行第i+1个epoch的训练。

7. 假设学习率固定为0.01,通过实验,评估不同的隐藏层个数k,以及隐藏层神经元个数m对模型性能的影响,找到你认为最好的k和m。

二、实验过程(含错误调试)

1.基于numpy库的模型

打开并统计数据集,发现训练集有50000个,验证集有10000个,测试集有10000个

对训练集输入的28x28图像矩阵转成784x1的列形状,把目标转成长度为10的列向量

对测试集和验证集输入的28x28图像矩阵转成784x1的列形状,目标保持不变

把数据传进模型,进行训练和测试

根据实验要求,定义Network类,实现初始化网络、前向传播、反向传播,更新参数,验证模型,测试模型,继续迭代,寻找最优参数。

import random
import numpy as np# https://zhuanlan.zhihu.com/p/148102828class Network(object):def __init__(self, sizes):self.num_layers = len(sizes)self.sizes = sizesself.biases = [np.random.randn(y, 1) for y in sizes[1:]]  # randn,随机正态分布self.weights = [np.random.randn(y, x) for x, y in zip(sizes[:-1], sizes[1:])]self.lmbda = 0.1  # L2正则化参数def feedforward(self, a):for b, w in zip(self.biases, self.weights):a = sigmoid(np.dot(w, a) + b)return a# 重复训练epochs次,训练集mini_batch_size个一包,学习率步长def SGD(self, training_data, epochs, mini_batch_size, eta, val_data,test_data=None):n_test = len(test_data)n = len(training_data)n_val = len(val_data)best_accuracy = 0for j in range(epochs):  # 重复训练的次数random.shuffle(training_data)  # 随机打乱训练集顺序mini_batches = [training_data[k:k + mini_batch_size]  # 切分成每批10个一组for k in range(0, n, mini_batch_size)]for mini_batch in mini_batches:self.update_mini_batch(mini_batch, eta)  # TODO# 一次训练完毕val_accuracy = self.evaluate(val_data) / n_val  # 进行验证# if j==1:#     print(f"参数m={m}训练第二次时,验证集精度{val_accuracy * 100}% ")if val_accuracy > best_accuracy:best_accuracy = val_accuracytest_num = self.evaluate(test_data) # 进行测试print(f"迭代次数: {j + 1},验证集精度{best_accuracy * 100}% ,测试集预测准确率: {(test_num / n_test) * 100}%")else:print(f'迭代次数:{j + 1},验证精度比前面那个小了,不进行测试')# return val_accuracydef update_mini_batch(self, mini_batch, eta):m = len(mini_batch)x_matrix = np.zeros((784, m))y_matrix = np.zeros((10, m))for i in range(m):  # 初始化矩阵为输入的10个x,一次计算x_matrix[:, i] = mini_batch[i][0].flatten()  # 将多维数组转换为一维数组y_matrix[:, i] = mini_batch[i][1].flatten()self.backprop_matrix(x_matrix, y_matrix, m, eta)def backprop_matrix(self, x, y, m, eta):# 生成梯度矩阵,初始为全零nabla_b = [np.zeros(b.shape) for b in self.biases]nabla_w = [np.zeros(w.shape) for w in self.weights]# 前向传播activation = xactivations = [x]  # 各层的激活值矩阵zs = []  # 各层的带权输入矩阵for w, b in zip(self.weights, self.biases):z = np.dot(w, activation) + bactivation = sigmoid(z)zs.append(z)activations.append(activation)# 后向传播# 计算输出层误差, # 加上L2正则化delta = (self.cross_entropy_cost_derivative(activations[-1], y) +self.L2_regularization(self.weights[-1], m)) * sigmoid_prime(zs[-1])# 计算输出层的偏置、权重梯度nabla_b[-1] = np.array([np.mean(delta, axis=1)]).transpose()nabla_w[-1] = (np.dot(delta, activations[-2].transpose()) / m)# 反向传播误差,并计算梯度for l in range(2, self.num_layers):z = zs[-l]sp = sigmoid_prime(z)delta = np.dot(self.weights[-l + 1].transpose(), delta) * spnabla_b[-l] = np.array([np.mean(delta, axis=1)]).transpose()nabla_w[-l] = np.dot(delta, activations[-l - 1].transpose()) / mfor l in range(1, self.num_layers):self.biases[-l] = self.biases[-l] - eta * nabla_b[-l]self.weights[-l] = self.weights[-l] - eta * nabla_w[-l]def evaluate(self, test_data):test_results = [(np.argmax(self.feedforward(x)), y)  # argmax()找到数组中最大值的索引for (x, y) in test_data]return sum(int(x == y) for (x, y) in test_results)def L2_regularization(self, weights, m):return (self.lmbda / (m * 2)) * np.sum(np.square(weights))def cross_entropy_cost_derivative(self, a, y):# a是预测值矩阵,y是真实值矩阵epsilon = 1e-7a = a + epsilon  # 防止除0错误dc = -y / a  # 交叉熵代价函数的导数return dcdef sigmoid(z):if np.all(z >= 0):  # 对sigmoid函数优化,避免出现极大的数据溢出return 1.0 / (1.0 + np.exp(-z))else:return np.exp(z) / (1 + np.exp(z))# 求导sigmoid函数
def sigmoid_prime(z):return sigmoid(z) * (1 - sigmoid(z))# def cross_entropy_cost(a, y):
#     # a是预测值矩阵,y是真实值矩阵
#     n = a.shape[1]  # 样本数量
#     return -np.sum(y * np.log(a)) / n  # 交叉熵代价函数
#
#
# def relu(z):
#     return np.maximum(0, z)
#
#
# def relu_prime(z):
#     # return np.array(x > 0, dtype=x.dtype)
#     return (z > 0).astype(int)  # relu函数的导数# # 交叉熵代价函数和L2正则化项  -(self.lmbda / m) * self.weights[-1]  # 加入L2正则化项
#
# def cost_function(output_activations, y):
#     return np.sum(np.nan_to_num(-y * np.log(output_activations) - (1 - y) * np.log(1 - output_activations)))
# def L2_regularization(self, lmbda, weights):
#     return lmbda * np.sum(np.square(weights)) / 2.0
#
# def cost_function_with_regularization(output_activations, y, weights, lmbda):
#     return cost_function(output_activations, y) + L2_regularization(lmbda, weights)

在交叉熵代价函数求导后加上L2正则化,先衰减偏置,再衰减权重,防止过拟合

# 后向传播
# 计算输出层误差, # 加上L2正则化
delta = (self.cross_entropy_cost_derivative(activations[-1], y) + self.L2_regularization(self.weights[-1], m)) * sigmoid_prime(zs[-1])
# 计算输出层的偏置、权重梯度
nabla_b[-1] = np.array([np.mean(delta, axis=1)]).transpose()
nabla_w[-1] = (np.dot(delta, activations[-2].transpose()) / m)

在大范围的改变学习率时,运行报错,

RuntimeWarning: overflow encountered in exp return 1.0 / (1 + np.exp(-x))

参照网上的做法,对sigmoid函数的x做判断,if np.all(x>=0): #对sigmoid函数优化,避免出现极大的数据溢出

        return 1.0 / (1 + np.exp(-x))

    else:

        return np.exp(x)/(1+np.exp(x))

写交叉熵代价函数的导数时出现除0错误,于是对a加上很小的数

def cross_entropy_cost_derivative(self, a, y):# a是预测值矩阵,y是真实值矩阵epsilon = 1e-7a = a + epsilon  # 防止除0错误dc = -y / a  # 交叉熵代价函数的导数return dc

2.基于PyTorch模型

打开并统计数据集,发现训练集有50000个,验证集有10000个,测试集有10000个

对数据集的图像矩阵转成浮点型的张量,对目标转成长整型的张量

把图像张量和目标张量一一对应放到 TensorDataset()函数转成数据对象,然后调用DataLoader()函数分批打包数据,生成迭代器对象

把数据传进模型,进行训练和测试

定义Net类,继承Model类,实现初始化网络、定义网络每一层的对象放入列表,前向传播、把输入传进每一层对象、最后一层调用log_softmax()函数进行归一化; 输入训练数据进行前向传播,把结果放进交叉熵损失函数、后向传播计算梯度,更新参数,验证模型,测试模型,继续迭代,寻找最优参数

处理数据集的时候把图像和目标都转成浮点张量torch.Tensor(),然后报错,网上找原因,需要把目标转成 长整型的张量,因为使用交叉熵损失函数进行训练时,需要将标签转换为整数编码。y=LongTensor(y),以便进行后续的计算,而模型中并没有使用y=LongTensor(y)函数,则需要提前将目标转成长整型张量

train_images, train_labels = torch.tensor(tr_d[0], dtype=torch.float32), torch.tensor(tr_d[1], dtype=torch.long)

在处理数据集的时候,直接把张量放到DataLoader()里,然后报错了,查了书本后发现DataLoader()要传入dataset对象,需要把张量对应传入TensorDataset()函数生成dataset对象

train_dataset = TensorDataset(train_images, train_labels)

  • 三、对实验中参数和结果的分析

1.基于numpy库的模型

当使用默认参数:sizes=[784,30,10] ,epochs=30,mini_batch_size=10,

Lmbda=0.1 ,eta=1.3

测试最高精度是94.3%

运行时间79s

根据实验要求,分析不同隐藏层个数k和隐藏层神经元个数m对模型性能的影响:

由于我的电脑不太行,训练不同隐藏层个数k和隐藏层神经元个数m对模型性能的影响的时候需要很多时间,因此只训练2次出结果,结果可能会有偶然性。

当epochs=2,mini_batch_size=10,

Lmbda=0.1 ,eta=0.01,当只用一层隐藏层时,测试不同的神经元m对模型精度的影响,代码和结果如下

# 当隐藏层k=1时
accuracy_list=[]
for m in range(10,784):net = Network([784,m, 10])accuracy=net.SGD(training_data, 2, 10, 0.01, validation_data,m,test_data=test_data)accuracy_list.append(accuracy)x = range(10, 784)
max_acc=max(accuracy_list)
max_index = accuracy_list.index(max_acc)
print(f"当神经元m={10+max_index} 时,验证精度最大值为:{max_acc}")
plt.plot(x, accuracy_list)
plt.xlabel('m')
plt.ylabel('val_accuracy')
plt.show()

当运行到m=297 时,就卡住了,因此只讨论10到297个神经元的结果:

当只用一层隐藏层,神经元个数为138时,验证集精度最高,为77.92%

当用两层隐藏层时,测试不同的神经元m对模型精度的影响,由于组合次数太多,不可能每个神经元都训练,因此固定第一个隐藏层为138,神经元个数逐层递减进行训练,代码和结果如下

......

当有两层隐藏层,[784,138,m,10],神经元个数为124时,验证集精度最高,为77.38%

当用三层隐藏层时,测试不同的神经元m对模型精度的影响,由于组合次数太多,不可能每个神经元都训练,因此固定第一个隐藏层为138,神经元个数逐层递减进行训练,代码和结果如下

........

当有三层隐藏层,[784,138,124,m,10],神经元个数为118时,验证集精度最高,为76.18%

根据以上结果,当学习率固定为0.01时,我认为模型最好的k是1 ,m是138,精度77.92%,因为增加层数后验证集精度并没有多大提升,反而浪费了时间, 有点奇怪,也可能是模型有点问题

            

学习率固定为0.01,可能学习率小,步长小,迭代30次精度才77%左右,当学习率为默认的1.3时,精度才快速到94%

2.基于PyTorch模型

当使用默认参数:layers=[784,30,10] ,epochs=30,mini_batch_size=10,

,lr=0.01weight_decay=0.0001时

测试最高精度是93.17%

运行时间171s

根据实验要求,分析不同隐藏层个数k和隐藏层神经元个数m对模型性能的影响:

由于我的电脑不太行,训练不同隐藏层个数k和隐藏层神经元个数m对模型性能的影响的时候需要很多时间,因此只训练2次出结果,结果可能会有偶然性。

当epochs=2,mini_batch_size=10,

lr=0.01,weight_decay=0.0001时,当只用一层隐藏层时,测试不同的神经元m对模型精度的影响,代码和结果如下

# 当隐藏层k=1时
accuracy_list=[]
for m in range(10,298):net = Net([784,m, 10])accuracy=train_and_test_net(net,training_data,validation_data,test_data,2,0.01,0.0001,m)accuracy_list.append(accuracy)x = range(10,298)
max_acc=max(accuracy_list)
max_index = accuracy_list.index(max_acc)
print(f"当神经元m={10+max_index} 时,验证精度最大值为:{max_acc}")
plt.plot(x, accuracy_list)
plt.xlabel('m')
plt.ylabel('val_accuracy')
plt.show()

结果:当只用一层隐藏层,神经元个数为247时,验证集精度最高,为93.51%

当用两层隐藏层时,测试不同的神经元m对模型精度的影响,由于组合次数太多,不可能每个神经元都训练,因此固定第一个隐藏层为138,神经元个数逐层递减进行训练,代码和结果如下

......

结果: 当有两层隐藏层,[784,247,m,10],神经元个数为19时,验证集精度最高,为93.34%

当用三层隐藏层时,测试不同的神经元m对模型精度的影响,由于组合次数太多,不可能每个神经元都训练,因此固定第一个隐藏层为138,神经元个数逐层递减进行训练,代码和结果如下

.......

结果:当有三层隐藏层,[784,247,19,m,10],神经元个数为14时,验证集精度最高,为83.91%

根据以上结果,当学习率固定为0.01时,我认为模型最好的k是1 ,m是247,精度93.51%,因为增加层数后验证集精度并没有多大提升,反而浪费了时间和内存

            

四、两个模型的对比

基于numpy库的模型:

当使用默认参数:sizes=[784,30,10] ,epochs=30,mini_batch_size=10,

Lmbda=0.1 ,eta=1.3时

迭代30次后测试集最高精度是94.3%

运行时间79s

基于PyTorch模型

当使用默认参数:layers=[784,30,10] ,epochs=30,mini_batch_size=10,

,lr=0.01,weight_decay=0.0001时

测试最高精度是93.17%

运行时间171s

由此可见基于numpy库训练的模型比基于PyTorch的模型好,测试精度高,用的时间也少

基于numpy库的模型比较偏向底层,实现难,代码复杂,但运行速度快;基于PyTorch模型实现方式比较简单,代码比较简洁,但底层比较复杂,运行速度慢

训练神经网络模型首选PyTorch框架

五、总结

学会了很多,收获了很多,普通电脑只能训练小模型,以后遇到中模型肯定要用各大云平台的算力进行训练。

........................

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/131183.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

libpcap之数据分流

当前系统都是多核系统,为了充分利用多核优势,数据包可以在底层就进行分流,可以通过多线程/多进程对同一个接口的数据进行并行的处理。 一、实验 一个server/client程序一个简单的抓包程序,抓取server/client之间的通信数据 1.1 …

【蓝桥杯 第十四届省赛Java B组】真题训练(A - C)正在更新

目录 A、阶乘求和 - BigInteger B、幸运数字 - 字符串 进制转换 暴力大法 C、数组分割 - A、阶乘求和 - BigInteger 思路: 当时比赛时,拿计算器算的,然后辛辛苦苦也没对 看到这个数肯定很大,而且只求后9位,阶乘越…

【计算机网络】应用层

应用层协议原理 客户-服务器体系结构: 特点:客户之间不能直接通信;服务器具有周知的,固定的地址,该地址称为IP地址。 配备大量主机的数据中心常被用于创建强大的虚拟服务器;P2P体系结构: 特点&…

K8S知识点(二)

(1)K8S概念 K8S是通过控制pod来控制容器进而控制程序的 service是沟通Pod和外键的桥梁,可以实现负载均衡的效果,加权负载的效果 (2)环境搭建-环境规划 (3)环境搭建-主机安装 使用…

时序分解 | Matlab实现PSO-VMD粒子群算法优化变分模态分解时间序列信号分解

时序分解 | Matlab实现PSO-VMD粒子群算法优化变分模态分解时间序列信号分解 目录 时序分解 | Matlab实现PSO-VMD粒子群算法优化变分模态分解时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 PSO-VMD粒子群算法PSO优化VMD变分模态分解 可直接运行 分解效果…

2023-11-04 LeetCode每日一题(数组中两个数的最大异或值)

2023-11-04每日一题 一、题目编号 421. 数组中两个数的最大异或值二、题目链接 点击跳转到题目位置 三、题目描述 给你一个整数数组 nums &#xff0c;返回 nums[i] XOR nums[j] 的最大运算结果&#xff0c;其中 0 ≤ i ≤ j < n 。 示例 1&#xff1a; 示例 2&…

[动态规划] (六) 路径问题 LeetCode 63.不同路径II

[动态规划] (六) 路径问题: LeetCode 63.不同路径II 文章目录 [动态规划] (六) 路径问题: LeetCode 63.不同路径II题目解析解题思路状态表示状态转移方程初始化和填表返回值 代码实现总结 63. 不同路径 II 题目解析 (1) 机器人从左上角移动到右下角 (2) 机器人只能向右或者向…

【漏洞复现】Nginx_0.7.65_空字节漏洞

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞扫描3、漏洞验证 1.1、漏洞描述 1.2、漏洞等级 1.3、影响版本 0.7.65 1.4、漏洞复现 1、基础环…

JavaSpringbootMySQL高校实训管理平台01557-计算机毕业设计项目选题推荐(附源码)

目 录 摘要 1 绪论 1.1 研究背景 1.2 研究意义 1.3论文结构与章节安排 2 高校实训管理平台系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系…

Oracle安全基线检查

一、账户安全 1、禁止SYSDBA用户远程连接 用户具备数据库超级管理员(SYSDBA)权限的用户远程管理登录SYSDBA用户只能本地登录,不能远程。REMOTE_LOGIN_PASSWORDFILE函数的Value值为NONE。这意味着禁止共享口令文件,只能通过操作系统认证登录Oracle数据库。 1)检查REMOTE…

【python 深拷贝与浅拷贝】

python 深拷贝与浅拷贝 问题&#xff1a; 在用影刀编写流程的时候发现&#xff0c;明明只修改人名为“小张”对应的字典里面的值&#xff0c;但是所有的人名对应的值都被修改了。 原因&#xff1a; 第14行&#xff0c;设置键值对&#xff0c;值对应的变量“初始打卡类型字…

伪随机序列——m序列及MATLAB仿真

文章目录 前言一、m 序列1、m 序列的产生2、m 序列的性质①、均衡性②、游程分布③、移位相加特性④、自相关函数⑤、功率谱密度⑥、伪噪声特性 二、M 序列1、m 序列的产生2、m 序列的性质 三、MATLAB 中 m 序列1、m 序列生成函数的 MATLAB 代码2、MATLAB 仿真 前言 在通信系统…

CVE-2023-34040 Kafka 反序列化RCE

漏洞描述 Spring Kafka 是 Spring Framework 生态系统中的一个模块&#xff0c;用于简化在 Spring 应用程序中集成 Apache Kafka 的过程&#xff0c;记录 (record) 指 Kafka 消息中的一条记录。 受影响版本中默认未对记录配置 ErrorHandlingDeserializer&#xff0c;当用户将容…

二叉树第i层结点个数

//二叉树第i层结点个数 int LevelNodeCount(BiTree T, int i) {if (T NULL || i < 1)return 0;if (i 1) return 1;return LevelNodeCount(T->lchild, i - 1) LevelNodeCount(T->rchild, i - 1); } int GetDepthOfBiTree(BiTree T) {if (T NULL)return 0;return Ge…

【HTML】播放器如何自动播放【已解决】

自动播放器策略 先了解浏览器的自动播放器策略 始终允许静音自动播放在以下情况&#xff0c;带声音的自动播放才会被允许 2.1 用户已经与当前域进行交互 2.2 在桌面上&#xff0c;用户的媒体参与指数阈值(MEI)已被越过&#xff0c;这意味着用户以前播放带有声音的视频。 2.3 …

发现一款PDF转换成翻页电子书的网站

​随着科技的发展&#xff0c;电子书越来越受到人们的喜爱。而PDF格式的文件也越来越多地被人们使用。那么&#xff0c;如何将PDF文件转换成翻页电子书呢&#xff1f;今天就为大家推荐一款好用的PDF转翻页电子书网站。 一、网站介绍 这款网站是一款非常实用的在线转换工具&…

【漏洞复现】Apache_Shiro_1.2.4_反序列化漏洞(CVE-2016-4437)

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞分析3、漏洞验证 说明内容漏洞编号CVE-2016-4437漏洞名称Apache_Shiro_1.2.4_反序列化漏洞漏洞评级…

selenium自动化测试入门 —— cookie 处理

driver.get_cookies() # 获得cookie 信息 driver.get_cookies(name) # 获得对应name的cookie信息 add_cookie(cookie_dict) # 向cookie 添加会话信息 delete_cookie(name) # 删除特定(部分)的cookie delete_all_cookies() # 删除所有cookie 示例&#xff1a; from sel…

基于深度学习的视频多目标跟踪实现 计算机竞赛

文章目录 1 前言2 先上成果3 多目标跟踪的两种方法3.1 方法13.2 方法2 4 Tracking By Detecting的跟踪过程4.1 存在的问题4.2 基于轨迹预测的跟踪方式 5 训练代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的视频多目标跟踪实现 …