赞
踩
MNIST手写数字识别是机器学习领域中的一个经典问题,它涉及到了图像处理和模式识别的多个关键步骤。以下是对其原理的详细解释:
首先,我们需要了解MNIST数据集的基本构成。MNIST包含了一系列手写数字的图像,每个图像都是28x28像素的灰度图,表示一个手写数字(0-9)。每张图像都对应一个标签,即该图像所表示的数字的真实值。
数据集下载链接(CSDN):点击此处跳转
CNN在MNIST手写数字识别中起到了关键作用。以下是CNN的基本结构:
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轮,经过训练可以发现准确率提高了,如果还想要进一步提升准确率可以再对网络进行微调,希望可以对你有所帮助,感谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。