手写数字识别---基于Adam优化算法的神经网络

手写数字识别—基于Adam优化算法的神经网络

@Victorzl

1、实验目的与要求

(1)掌握神经网络的基本结构与原理。

(2)熟悉MNIST数据集的使用方法。

(3)理解并运用Adam优化算法进行神经网络的训练。

(4)掌握Dropout技术在神经网络中的应用。

(5)学习如何评估神经网络模型的性能。

2.实验内容

(1)构建一个包含784个输入节点,200个隐藏节点和10个输出节点的神经网络。

(2)使用Adam优化算法进行模型训练。

(3)在训练过程中应用Dropout技术以防止过拟合。

(4)在测试集上评估模型的准确率,并输出相应的准确率和训练过程中的损失变化图

3.代码实现

这里我分别用了两种方法实现手写数字识别:
(1)基于Adam优化算法融合Dropout技术和AdaGrad
原理:
  • 初始化权重:同样使用正态分布随机初始化网络的权重。
  • 前向传播:计算输入数据经过隐藏层和输出层的输出,同时使用Dropout技术在训练过程中随机丢弃一定比例的神经元。
  • 计算误差:同样通过比较网络输出和实际标签,计算出误差。
  • 计算梯度:利用误差反向传播算法,计算出每个权重的梯度。
  • 更新权重:结合了Adam算法和AdaGrad算法,根据梯度更新每个权重,并根据历史梯度的平方根调整学习率。
实现过程:
  • 初始化网络参数:输入节点数、隐藏层节点数、输出节点数、学习率等,并设置Dropout率。
  • 读取训练数据,并将其归一化处理。
  • 使用训练数据进行网络的训练:包括前向传播、计算误差、计算梯度和更新权重等步骤。此外,还在前向传播过程中使用Dropout技术。
  • 读取测试数据,并使用训练好的网络进行预测。
  • 计算模型的准确率并输出。
代码实现:
#引入库
import numpy
import scipy.special
import matplotlib.pyplot as plt
import random
# 设置支持中文的字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
class neuralNetwork:
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate, dropout_rate=0.2):
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        self.lr = learningrate
        self.dropout_rate = dropout_rate
        # 初始化权重
        self.wih = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))
        self.who = numpy.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))
        # 初始化动量参数
        self.beta1 = 0.9
        self.beta2 = 0.999
        self.epsilon = 1e-8
        self.m_wih = numpy.zeros(self.wih.shape)
        self.m_who = numpy.zeros(self.who.shape)
        self.v_wih = numpy.zeros(self.wih.shape)
        self.v_who = numpy.zeros(self.who.shape)
        self.beta1_t = self.beta1
        self.beta2_t = self.beta2
        # Dropout 随机丢弃一些神经元
        self.dropout_mask = None
        # 激活函数
        self.activation_function = lambda x: scipy.special.expit(x)
    def train(self, inputs_list, targets_list):
        inputs = numpy.array(inputs_list, ndmin=2).T
        targets = numpy.array(targets_list, ndmin=2).T
        # 前向传播
        hidden_inputs = numpy.dot(self.wih, inputs)
        hidden_outputs = self.activation_function(hidden_inputs) 
        # Dropout 随机丢弃一些神经元
        self.dropout_mask = numpy.random.binomial(1, 1 - self.dropout_rate, size=hidden_outputs.shape)
        hidden_outputs *= self.dropout_mask        
        final_inputs = numpy.dot(self.who, hidden_outputs)
        final_outputs = self.activation_function(final_inputs)      
        # 计算误差
        output_errors = targets - final_outputs
        hidden_errors = numpy.dot(self.who.T, output_errors)     
        # 计算梯度
        who_grad = numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs))
        wih_grad = numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs))       
        # 更新动量参数
        self.m_wih = self.beta1 * self.m_wih + (1 - self.beta1) * wih_grad
        self.m_who = self.beta1 * self.m_who + (1 - self.beta1) * who_grad
        self.v_wih = self.beta2 * self.v_wih + (1 - self.beta2) * (wih_grad ** 2)
        self.v_who = self.beta2 * self.v_who + (1 - self.beta2) * (who_grad ** 2)
        # 纠正偏差
        self.beta1_t *= self.beta1
        self.beta2_t *= self.beta2
        m_wih_hat = self.m_wih / (1 - self.beta1_t)
        m_who_hat = self.m_who / (1 - self.beta1_t)
        v_wih_hat = self.v_wih / (1 - self.beta2_t)
        v_who_hat = self.v_who / (1 - self.beta2_t)        
        # Adam 更新权重
        self.wih += self.lr * m_wih_hat / (numpy.sqrt(v_wih_hat) + self.epsilon)
        self.who += self.lr * m_who_hat / (numpy.sqrt(v_who_hat) + self.epsilon)
    def query(self, inputs_list):
        inputs = numpy.array(inputs_list, ndmin=2).T
        hidden_inputs = numpy.dot(self.wih, inputs)
        hidden_outputs = self.activation_function(hidden_inputs)
        final_inputs = numpy.dot(self.who, hidden_outputs)
        final_outputs = self.activation_function(final_inputs)
        return final_outputs
# 定义神经网络参数
input_nodes = 784
hidden_nodes = 200
output_nodes = 10
learning_rate = 0.001
dropout_rate = 0.2
# 创建神经网络实例
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate, dropout_rate)
# 读取训练数据
data_file = open("mnist_train.csv", 'r')
data_list = data_file.readlines()
data_file.close()
# 训练神经网络
for record in data_list:
    all_values = record.split(',')
    inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
    targets = numpy.zeros(output_nodes) + 0.01
    targets[int(all_values[0])] = 0.99
    n.train(inputs, targets)
# 读取测试数据并测试模型
test_data_file = open("mnist_test.csv", 'r')
test_data_list = test_data_file.readlines()
test_data_file.close()
# 计算模型准确率
scorecard = []
for test_record in test_data_list:
    all_values = test_record.split(',')
    true_label = int(all_values[0])
    inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
    outputs = n.query(inputs)
    predicted_label = numpy.argmax(outputs)
    
    if predicted_label == true_label:
        scorecard.append(1)
    else:
        scorecard.append(0)
# 绘制准确率随训练次数的变化图
epochs = range(1, len(scorecard) + 1)
plt.plot(epochs, numpy.cumsum(scorecard) / epochs * 100, marker='o', markersize=5, color='blue')
plt.title("模型准确率随训练次数变化")
plt.xlabel("训练次数")
plt.ylabel("准确率 (%)")
plt.grid(True)
plt.show()
# 计算并输出最终准确率
accuracy = sum(scorecard) / len(scorecard)
print(f"准确率: {accuracy * 100}%")
# 随机选择一个测试样本并绘制图形
random_index = random.randint(0, len(test_data_list) - 1)
test_record = test_data_list[random_index]
all_values = test_record.split(',')
true_label = int(all_values[0])
inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
# 用模型预测
outputs = n.query(inputs)
predicted_label = numpy.argmax(outputs)
# 输出预测类别
print(f"真实标签: {true_label}")
print(f"预测标签: {predicted_label}")
# 绘制测试样本图像
image_array = numpy.asfarray(all_values[1:]).reshape((28, 28))
plt.imshow(image_array, cmap='Greys', interpolation='None')
plt.title(f"真实标签: {true_label} 预测标签: {predicted_label}")
plt.show()
(2)基于AdaGrad算法实现手写数字识别
原理:
  • 初始化权重:使用正态分布随机初始化网络的权重。
  • 前向传播:通过输入数据和当前的权重,计算出隐藏层和输出层的输出。
  • 计算误差:比较网络的输出和实际标签,计算出误差。
  • 计算梯度:利用误差反向传播算法,计算出每个权重的梯度。
  • 更新权重:使用AdaGrad算法根据梯度更新每个权重,并根据历史梯度的平方根调整学习率。
实现过程:
  • 初始化网络参数:输入节点数、隐藏层节点数、输出节点数、学习率等。
  • 读取训练数据,并将其归一化处理。
  • 使用训练数据进行网络的训练:包括前向传播、计算误差、计算梯度和更新权重等步骤。
  • 读取测试数据,并使用训练好的网络进行预测。
  • 计算模型的准确率并输出。
代码实现:
#引入库
import numpy
import scipy.special
import matplotlib.pyplot as plt
from matplotlib import font_manager
import random
# 设置支持中文的字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False    # 解决负号'-'显示为方块的问题
# 读取训练数据
data_file = open("mnist_train.csv", 'r')
data_list = data_file.readlines()
data_file.close()
class neuralNetwork:
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate, dropout_rate=0.2):
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        self.lr = learningrate
        self.dropout_rate = dropout_rate      
        # 初始化权重
        self.wih = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))
        self.who = numpy.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))     
        # AdaGrad 累积梯度
        self.accumulate_wih = numpy.zeros(self.wih.shape)
        self.accumulate_who = numpy.zeros(self.who.shape)        
        # 激活函数
        self.activation_function = lambda x: scipy.special.expit(x)
    def train(self, inputs_list, targets_list):
        inputs = numpy.array(inputs_list, ndmin=2).T
        targets = numpy.array(targets_list, ndmin=2).T        
        # 前向传播
        hidden_inputs = numpy.dot(self.wih, inputs)
        hidden_outputs = self.activation_function(hidden_inputs)      
        # Dropout 随机丢弃一些神经元
        dropout_mask = numpy.random.binomial(1, 1 - self.dropout_rate, size=hidden_outputs.shape)
        hidden_outputs *= dropout_mask        
        final_inputs = numpy.dot(self.who, hidden_outputs)
        final_outputs = self.activation_function(final_inputs)        
        # 计算误差
        output_errors = targets - final_outputs
        hidden_errors = numpy.dot(self.who.T, output_errors)       
        # 计算梯度
        who_grad = numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs))
        wih_grad = numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs))
        # 更新累积梯度
        self.accumulate_who += who_grad**2
        self.accumulate_wih += wih_grad**2       
        # AdaGrad 更新权重
        self.who += self.lr * who_grad / (numpy.sqrt(self.accumulate_who) + 1e-7)
        self.wih += self.lr * wih_grad / (numpy.sqrt(self.accumulate_wih) + 1e-7)

    def query(self, inputs_list):
        inputs = numpy.array(inputs_list, ndmin=2).T
        hidden_inputs = numpy.dot(self.wih, inputs)
        hidden_outputs = self.activation_function(hidden_inputs)
        final_inputs = numpy.dot(self.who, hidden_outputs)
        final_outputs = self.activation_function(final_inputs)
        return final_outputs
# 定义神经网络参数
input_nodes = 784
hidden_nodes = 200
output_nodes = 10
learning_rate = 0.1
dropout_rate = 0.2
# 创建神经网络实例
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate, dropout_rate)
# 训练神经网络
for record in data_list:
    all_values = record.split(',')
    inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
    targets = numpy.zeros(output_nodes) + 0.01
    targets[int(all_values[0])] = 0.99
    n.train(inputs, targets)
# 读取测试数据并测试模型
test_data_file = open("mnist_test.csv", 'r')
test_data_list = test_data_file.readlines()
test_data_file.close()
# 利用训练出来的模型计算训练准确率
scorecard = []
for test_record in test_data_list:
    all_values = test_record.split(',')
    true_label = int(all_values[0])
    inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
    outputs = n.query(inputs)
    predicted_label = numpy.argmax(outputs)
    
    if (predicted_label == true_label):
        scorecard.append(1)
    else:
        scorecard.append(0)
# 定义训练轮数
epochs = range(1, len(scorecard) + 1)
# 绘制准确率随训练次数的变化图
plt.plot(epochs, numpy.cumsum(scorecard) / epochs * 100, marker='o', markersize=5, color='blue')
plt.title("模型准确率随训练次数变化", fontproperties='SimHei')
plt.xlabel("训练次数")
plt.ylabel("准确率 (%)")
plt.grid(True)
plt.show()
# 计算并输出最终准确率
scorecard_array = numpy.asarray(scorecard)
accuracy = scorecard_array.sum() / scorecard_array.size
print(f"准确率: {accuracy * 100}%")
# 随机选择一个测试样本并绘制图形
random_index = random.randint(0, len(test_data_list) - 1)
test_record = test_data_list[random_index]
all_values = test_record.split(',')
true_label = int(all_values[0])
inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
# 用模型预测
outputs = n.query(inputs)
predicted_label = numpy.argmax(outputs)
# 输出预测类别
print(f"真实标签: {true_label}")
print(f"预测标签: {predicted_label}")
# 绘制测试样本图像
image_array = numpy.asfarray(all_values[1:]).reshape((28, 28))
plt.imshow(image_array, cmap='Greys', interpolation='None')
plt.title(f"真实标签: {true_label} 预测标签: {predicted_label}",fontproperties='SimHei')
plt.show()

实现结果分析

结果:
(1)基于Adam优化算法融合Dropout技术和AdaGrad
a.模型准确率随测试集识别次数变化:

在这里插入图片描述

b.模型识别准确率:

在这里插入图片描述

c.随机抽取测试集某一个数字进行预测识别结果:

在这里插入图片描述

(2)基于AdaGrad算法实现手写数字识别
a.模型准确率随测试集识别次数变化:

在这里插入图片描述

b.模型识别准确率:

在这里插入图片描述

c.随机抽取测试集某一个数字进行预测识别结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Victor ZL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值