MNIST手写数字识别概述及实践

本文详细介绍了MNIST手写数字识别项目,包括数据集构成、预处理方法、卷积神经网络结构、模型训练与优化过程,以及如何通过调整学习率和多次训练提高模型性能。
摘要由CSDN通过智能技术生成

       MNIST手写数字识别是机器学习领域中的一个经典问题,它涉及到了图像处理和模式识别的多个关键步骤。以下是对其原理的详细解释:

       首先,我们需要了解MNIST数据集的基本构成。MNIST包含了一系列手写数字的图像,每个图像都是28x28像素的灰度图,表示一个手写数字(0-9)。每张图像都对应一个标签,即该图像所表示的数字的真实值。

       数据集下载链接(CSDN):点击此处跳转

原理步骤

  1. 数据预处理
    • 灰度化:由于MNIST图像本身就是灰度图,这一步骤通常已经由数据集提供者完成。
    • 归一化:将图像的像素值缩放到一个统一的范围(如0-1),以便模型更好地处理。
    • 去除噪声:可能通过滤波等技术来减少图像中的噪声,提高图像质量。
  2. 特征提取
    • 在传统方法中,人们可能会手动设计特征提取器,从图像中提取出如边缘、角点等特征。
    • 但在深度学习中,尤其是使用卷积神经网络(CNN)时,特征提取是自动进行的。CNN通过一系列的卷积层、池化层等结构,自动从原始图像中学习到有用的特征表示。
  3. 模型训练
    • 使用预处理后的数据和对应的标签来训练模型。
    • 在深度学习中,这通常意味着定义一个网络结构(如CNN),然后使用反向传播算法和梯度下降优化器来更新网络的权重。
    • 训练的目标是使模型能够准确地将输入图像映射到其对应的数字标签。
  4. 模型评估和优化
    • 使用测试集来评估模型的性能,通常使用准确率作为评估指标。
    • 如果模型性能不佳,可以通过调整网络结构、优化器参数、学习率等方式进行优化。
    • 还可以使用数据增强技术(如旋转、平移、缩放等)来增加训练数据的多样性,进一步提高模型性能。
  5. 预测和应用
    • 训练好的模型可以用于预测新的、未知的手写数字图像。
    • 通过将输入图像输入到模型中,模型会输出一个预测的数字标签。
    • 这种技术可以应用于各种实际场景,如邮政编码识别、表单自动填写等。

卷积神经网络(CNN)结构

CNN在MNIST手写数字识别中起到了关键作用。以下是CNN的基本结构:

  • 输入层:接收28x28像素的灰度图像作为输入。
  • 卷积层:通过卷积操作提取图像中的局部特征。
  • 激活函数:如ReLU,用于增加模型的非线性。
  • 池化层:通过下采样操作减少特征图的尺寸,同时保留重要信息。
  • 全连接层:用于将学习到的特征映射到最终的输出标签。
  • 输出层:通常使用softmax函数输出每个类别的概率分布。

总结

MNIST手写数字识别是一个典型的监督学习任务,通过深度学习技术(尤其是卷积神经网络),我们可以自动从原始图像中学习到有用的特征表示,并训练出一个能够准确识别手写数字的模型。这一技术不仅在手写数字识别领域有着广泛的应用,也为其他图像识别和分类任务提供了有力的支持。

代码

# coding = utf-8
# 导入需要的库
import numpy
import scipy.special
import scipy
import matplotlib.pyplot


# 搭建神经网络框架
class neuralNetwork:
    # 初始化神经网络
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
        # 设置输入层、隐藏层、输出层的节点数
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        
        # 链接权重矩阵,(输入→隐藏)、(隐藏→输出)权重
        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.lr = learningrate
        
        # 创建激活函数
        self.activation_function = lambda x: scipy.special.expit(x)
        
        pass
    
    # 训练神经网络
    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)
        
        # 将信号计算到输出层
        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)
        
        # 更新隐藏层和输出层间的权重
        self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs))
        # 更新输入层和隐藏层间的权重
        self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs))
        
        pass
    
    # 查询神经网络
    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 = 100
output_nodes = 10
learning_rate = 0.3

# 使用神经网络
n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

# 加载训练集到列表
training_data_file = open("./mnist_train.csv", "r")
training_data_list = training_data_file.readlines()
training_data_file.close()

# 训练网络
# 遍历训练集中的所有记录
for record in training_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)
    pass

# 加载测试集到列表
test_data_file = open("./mnist_test.csv", "r")
test_data_list = test_data_file.readlines()
test_data_file.close()

# 测试网络
# 设置计分板
scoreboard = []

# 遍历测试集中的所有记录
for record in test_data_list:
    # 分割记录
    all_values = record.split(',')
    # 选择正确答案
    correct_label = int(all_values[0])
    print(f"正确的标签: {correct_label}")
    # 缩放和转换输入数据
    inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
    # 查询网络
    outputs = n.query(inputs)
    # 最高值索引对应的标签
    label = numpy.argmax(outputs)
    print(f"网络的答案: {label}")
    # 添加结果到计分板
    if label == correct_label:
        # 两者匹配,计分1
        scoreboard.append(1)
    else:
        # 两者不匹配,计分0
        scoreboard.append(0)
        pass
    pass

# 查看计分板
print(scoreboard)

# 查看网络的测试成绩
scoreboard_array = numpy.asarray(scoreboard)
score = scoreboard_array.sum() / scoreboard_array.size
print(f"该神经网络的测试准确率: {score}")

问题

当我们要求网络的准确率最好在95%以上时,我们可以适度调整学习率(learning rate),根据多次调整运行可以得出,学习率在0.1~0.3之间效果较好;另外我们还可以多次训练网络来提高其准确率,下面附上多次训练网络的代码:

# 重新训练多次网络
epochs = 5

for e in range(epochs):
    # 遍历训练集中的所有记录
    for record in training_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)
        pass
    pass

# 重新测试网络
scoreboard.clear()

# 遍历测试集中的所有记录
for record in test_data_list:
    # 分割记录
    all_values = record.split(',')
    # 选择正确答案
    correct_label = int(all_values[0])
    print(f"正确的标签: {correct_label}")
    # 缩放和转换输入数据
    inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
    # 查询网络
    outputs = n.query(inputs)
    # 最高值索引对应的标签
    label = numpy.argmax(outputs)
    print(f"网络的答案: {label}")
    # 添加结果到计分板
    if label == correct_label:
        # 两者匹配,计分1
        scoreboard.append(1)
    else:
        # 两者不匹配,计分0
        scoreboard.append(0)
        pass
    pass

# 查看网络的测试成绩
scoreboard_array = numpy.asarray(scoreboard)
score = scoreboard_array.sum() / scoreboard_array.size
print(f"该神经网络的测试准确率: {score}")

# 展示一个测试集数据
all_values = test_data_list[0].split(',')
print(all_values[0])

# 展示一张测试集图片
img_array = numpy.asfarray(all_values[1:]).reshape((28, 28))
matplotlib.pyplot.imshow(img_array, cmap='Greys', interpolation='None')

# 展示该数据对应每个输出节点输出的结果
n.query((numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01)

此次将训练轮数设为5轮,经过训练可以发现准确率提高了,如果还想要进一步提升准确率可以再对网络进行微调,希望可以对你有所帮助,感谢!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值