手写数字识别实验是机器学习中最常见的一个示例,可以有很多种办法实现,最基础的其实就是利用knn算法,根据数字图片对应矩阵与经过训练的数字进行距离计算,最后这个距离最短,那么就认为它是哪个数字。
这里直接通过神经网络的办法来进行手写数字识别实验。不借助其他框架,编写网络,然后进行测试。这个代码其实网上有很多,并不是原创。
这里有必要说明一下手写数字的数据集,这里采用的是mnist_dataset/mnist_train.csv数据集,数据地址: https://www.kaggle.com/datasets/oddrationale/mnist-in-csv。下载之后是一个压缩包,里面包含mnist_train.csv,mnist_test.csv。
我们可以看看mnist_train.csv的部分数据:
上图中,①处表示 第一行内容 其实是标题,我们在数据处理的时候需要过滤这一行。② 表示的是label内容,也就是真实数字,它由0-9组成,也就是10个分类。③ 处表示的28 * 28矩阵,这个数字由784个数字组成。
实验过程,先使用mnist_train.csv数据训练网络,然后利用我们自己手写的数字进行测试。这里没有使用mnist_test.csv进行测试,主要是它本身就是人家进行测试的数据,我们这里自己测试。
我自己准备的数字图片如下所示:
这些图片都是根据这里测试数据mnist_train.csv数据格式的要求进行绘制的28*28像素的图片,这个图片很小,但是可以借助windows系统paint绘图工具,选择28*28像素画布,然后进行放大,最后可以在编辑区域画出这些数字。
下面给出代码:
import os
import numpy as np
import scipy.special
import imageio
image_path = 'number_images'
# 加载图片
def load_img_number(root_dir):
files = os.listdir(root_dir)
file_list = []
for file in files:
file_path = os.path.join(root_dir, file)
file_list.append(file_path)
return file_list
class neuralnetwork:
def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
# 输入层
self.inodes = inputnodes
# 隐藏层
self.hnodes = hiddennodes
# 输出层
self.onodes = outputnodes
# 学习率
self.lr = learningrate
# 输入层-隐藏层权重
self.wih = (np.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes)))
# 隐藏层-输出层权重
self.who = (np.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes)))
# 激活函数
self.activation_function = lambda x: scipy.special.expit(x)
def train(self, inputs_list, targets_list):
inputs = np.array(inputs_list, ndmin=2).T
targets = np.array(targets_list, ndmin=2).T
hidden_inputs = np.dot(self.wih, inputs)
hidden_outputs = self.activation_function(hidden_inputs)
final_inputs = np.dot(self.who, hidden_outputs)
final_outputs = self.activation_function(final_inputs)
output_errors = targets - final_outputs
hidden_errors = np.dot(self.who.T, output_errors)
self.who += self.lr * np.dot((output_errors * final_outputs * (1.0 - final_outputs)),
np.transpose(hidden_outputs))
self.wih += self.lr * np.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), np.transpose(inputs))
def query(self, inputs_list):
inputs = np.array(inputs_list, ndmin=2).T
hidden_inputs = np.dot(self.wih, inputs)
hidden_outputs = self.activation_function(hidden_inputs)
final_inputs = np.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.2
# 构建模型
model = neuralnetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)
# 准备训练数据
training_data_file = open('mnist/mnist_train.csv', 'r')
training_data_list = training_data_file.readlines()
# 去掉第一行标题
training_data_list = training_data_list[1:]
training_data_file.close()
# 训练
for record in training_data_list:
all_values = record.split(',')
inputs = (np.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
targets = np.zeros(output_nodes) + 0.01
targets[int(all_values[0])] = 0.99
model.train(inputs, targets)
pass
img_list = load_img_number(image_path)
for i in range(len(img_list)):
img_name = img_list[i]
img_arr = imageio.v2.imread(img_name, mode='L')
img_data = 255.0 - img_arr.reshape(784)
inputs = (img_data / 255.0 * 0.99) + 0.01
outputs = model.query(inputs)
label = np.argmax(outputs)
print(f'{img_name} 识别结果是 {label}')
运行代码,打印结果:
1、识别率很感人,其实很多都识别错误。
2、多次运行,结果也不一样。
3、识别不正确的基本会认为6或者8。不知道怎么会有这种奇怪的结果。
最后,给出本示例的代码和资源:https://gitee.com/buejee/aitutorial