数据集简介:
MINST数据集是由Yann提供的手写数字数据库文件。这个数据集主要包含了60000张的训练图像和10000张的测试图像,数据库的里的图像都是28*28大小的灰度图像,每个像素的是一个八位字节(0~255)。
数据集内容:
主要是下面的四个文件:
Training set images: train-images-idx3-ubyte.gz (9.9 MB, 解压后 47 MB, 包含 60,000 个样本)
Training set labels: train-labels-idx1-ubyte.gz (29 KB, 解压后 60 KB, 包含 60,000 个标签)
Test set images: t10k-images-idx3-ubyte.gz (1.6 MB, 解压后 7.8 MB, 包含 10,000 个样本)
Test set labels: t10k-labels-idx1-ubyte.gz (5KB, 解压后 10 KB, 包含 10,000 个标签)
任务:
利用前馈神经网络,实现手写数字集的分类识别。
import numpy as np
import scipy.special
import matplotlib.pyplot as plt
import os
import struct
# 定义前馈全连接神经网络模型
class NetworkNP:
# 网络初始化
def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
"""
:param inputnodes: 网络输入节点数
:param hiddennodes: 隐藏层 节点数
:param outputnodes: 输出层 节点数
:param learningrate: 学习率
:param weit_simple:
"""
# 网络层定义,以及初始化
self.inodes = inputnodes
self.hnodes = hiddennodes
self.onodes = outputnodes
self.lr = learningrate
# 权重初始、偏置初始化
self.w_ih = (np.random.rand(self.hnodes, self.inodes) - 0.5)
self.w_ho = (np.random.rand(self.onodes, self.hnodes) - 0.5)
# 激活函数定义Sigmoid
self.activaltion_function = lambda x: scipy.special.expit(x)
# 交叉熵损失函数 输入即为网络的输出结果 Y正确的类别 返回交叉熵损失值
def cross_entropy(self, out, Y):
# nan_to_num函数:使用0代替数组中的inf和nan值
loss = np.sum(np.nan_to_num(-Y*np.log(out)-(1-Y)*np.log(1-out)))
return loss
# 多分类softmax 返回预测的概率
def softmax(self, x):
max_per_row = np.max(x)
exp_scores = np.exp(x - max_per_row)
probs = exp_scores / np.sum(exp_scores)
return probs
# 模型训练函数
def train(self, inputs_list, targets_list):
"""
训练函数
:param inputs_list: 输入数据
:param targets_list: 输出返回数据
"""
## 前向传播过程
inputs = np.array(inputs_list, ndmin=2).T
targets = np.array(targets_list, ndmin=2).T
hidden_inputs = np.matmul(self.w_ih, inputs)
hidden_outputs = self.activaltion_function(hidden_inputs)
final_inputs = np.dot(self.w_ho, hidden_outputs)
final_outputs = self.softmax(final_inputs)
output_errors = targets - final_outputs
hidden_errors = np.dot(self.w_ho.T, output_errors)
# 反向传播更新参数
self.w_ho += self.lr * np.dot((output_errors * final_outputs * (1.0 - final_outputs)),
np.transpose(hidden_outputs))
self.w_ih += self.lr * np.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), np.transpose(inputs))
return self.cross_entropy(final_outputs, targets)
# 训练之后的模型
def query(self, inputs_list):
inputs = np.array(inputs_list, ndmin=2).T
hidden_inputs = np.dot(self.w_ih, inputs)
hidden_outputs = self.activaltion_function(hidden_inputs)
final_inputs = np.dot(self.w_ho, hidden_outputs)
final_outputs = self.activaltion_function(final_inputs)
return final_outputs
# 读取MNIST数据集函数,提前下载好数据集
def load_mnist(path, kind='train'):
"""Load MNIST data from `path`"""
labels_path = os.path.join(path,
'%s-labels.idx1-ubyte'
% kind)
images_path = os.path.join(path,
'%s-images.idx3-ubyte'
% kind)
with open(labels_path, 'rb') as lbpath:
magic, n = struct.unpack('>II',
lbpath.read(8))
labels = np.fromfile(lbpath,
dtype=np.uint8)
with open(images_path, 'rb') as imgpath:
magic, num, rows, cols = struct.unpack('>IIII',
imgpath.read(16))
images = np.fromfile(imgpath,
dtype=np.uint8).reshape(len(labels), 784)
# 返回MNIST图像序列,以及label
return images, labels
# 1 定义网络参数
input_nodes = 784 # 图像大小为28*28
hidden_nodes = 200 # 隐藏层,200个节点
output_nodes = 10 # 输出层,10个节点分别表示0-9 10个数字
learning_rate = 0.2 # 学习率
# 2 调用神经网络
n = NetworkNP(input_nodes, hidden_nodes, output_nodes, learning_rate)
# 3 读取数据,训练集、测试集
X_train, Y_train = load_mnist(".\\MNIST\\", "train")
X_test, Y_test = load_mnist(".\\MNIST\\", "t10k")
print("训练数据维度为:", X_train.shape, Y_train.shape)
print("测试数据维度为:", X_test.shape, Y_test.shape)
# 4 一部分数据集可视化
fig, ax = plt.subplots(
nrows = 2,
ncols = 5,
sharex = True,
sharey = True, )
ax = ax.flatten()
for i in range(10):
img = X_train[Y_train == i][0].reshape(28, 28)
ax[i].imshow(img, cmap='Greys', interpolation='nearest')
ax[0].set_xticks([]) #去掉坐标轴
ax[0].set_yticks([])
plt.tight_layout() # 布局调整为合适大小
plt.show()
# 5 设置迭代轮数,进行训练
epochs = 1
for e in range(epochs):
cnt = 0
err = 0.0
cnt_true = 0
for record in zip(X_train, Y_train):
correct_label = int(record[1])
inputs = (np.array(record[0]).astype(np.float) / 255.0 * 0.99) + 0.01 # 数据初始化, 把图像归一化到0-1
outputs = n.query(inputs) # 经过当模型训练之后的预测结果
label = np.argmax(outputs) # 当前图像被预测的数字值
if (label == correct_label): #统计正确预测的图像个数
cnt_true += 1
targets = np.zeros(output_nodes) + 0.01 # One-hot编码
targets[int(record[1])] = 0.99
error = n.train(inputs, targets) # 一次训练损失
err += error # 当前轮次总损失,以1000个训练样本为一轮
cnt += 1 # 当前训练样本数
if cnt % 1000 == 0:
print("[Epoch %d/%d] 训练准确度为 %.6f"%(cnt, X_train.shape[0], cnt_true/1000))
err = 0 # 上轮误差归零
cnt_true = 0 #上轮正确分类样本数清零
print("Epoch %d 完成训练"%(e+1))
# 6 计算测试集上神经网络准确率
cnt = 0
for record in zip(X_test, Y_test):
correct_label = int(record[1])
inputs = (np.array(record[0]) / 255.0 * 0.99) + 0.01
outputs = n.query(inputs)
label = np.argmax(outputs)
if (label == correct_label):
cnt += 1
print("测试集 准确率为:= ", cnt / float(len(Y_test)))