小言_互联网的博客

深度学习入门学习07--MNIST手写数字识别(详细版)

406人阅读  评论(0)

1、下载mnist数据集,将4个文件放到PyCharm工程目录下,与.py文件同一个目录下

2、4个文件包含训练集数据、训练集标签、测试集数据、测试集标签。

    训练集和测试集数据是图片,28*28像素的小图片,内容是手写的数字,0~9

    训练集有60000张图片,测试集10000张,标签是纪录了训练集、测试集图片中对应的数字

    比如:训练集的第1000个数据是一张手写数字内容为5的图片,那训练集标签的第1000个数据就是数字5,以此类推

3、以下是代码解析

# coding: utf-8
import os.path
import gzip
import pickle
import os
import numpy as np
from PIL import Image

dataset_dir = os.path.dirname(os.path.abspath(__file__))#当前目录的绝对路径
save_file = dataset_dir + "/mnist.pkl"#将4个文件处理后保存成一个文件的文件名

train_num = 60000#训练集的图片数量
test_num = 10000#测试集的图片数量
img_dim = (1, 28, 28)#一张图片的尺寸28*28像素的
img_size = 784#将一张二维的图片转成一维的数组(一张图片横切成28份然后横着排列)

 

def _load_label(file_name):#将label转成numpy数组
    file_path = dataset_dir + "/" + file_name
    print("将 " + file_name + " 转换成NumPy数组")
    with gzip.open(file_path, 'rb') as f:
        labels = np.frombuffer(f.read(), np.uint8, offset=8)
    return labels

 

def _load_img(file_name):#将图片转成numpy数组
    file_path = dataset_dir + "/" + file_name
    print("将 " + file_name + " 转换成NumPy数组")
    with gzip.open(file_path, 'rb') as f:
        data = np.frombuffer(f.read(), np.uint8, offset=16)
    data = data.reshape(-1, img_size)#转成一维的
    return data

 

def init_mnist():#将mnist的4个文件转成NumPy数组,保存到字典(键值对)
    dataset = {}#
    dataset['train_img'] = _load_img('train-images-idx3-ubyte.gz')
    dataset['train_label'] = _load_label('train-labels-idx1-ubyte.gz')
    dataset['test_img'] = _load_img('t10k-images-idx3-ubyte.gz')
    dataset['test_label'] = _load_label('t10k-labels-idx1-ubyte.gz')

    with open(save_file, 'wb') as f:
        pickle.dump(dataset, f, -1)  # 将python对象保存为文件 这里将NumPy数组保存为mnist.pkl

 

#将标签保存为onehot表示, one-hot表示是仅正确解标签为1,其余皆为0的数组,如[0,0,1,0,0,0,0,0,0,0]

def _change_one_hot_label(X):
    #X传入的标签,是一维数组 60000*1 / 10000*1
    T = np.zeros((X.size, 10))#一个空数组 60000*10 / 10000*10的二维数组
    for idx, row in enumerate(T): #enumerate()给这个空数组序列化 idx是序号 row是二维数组的一列
        #print(idx) 0~60000 / 0~10000
        #row是一列[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
        #X[idx]遍历

        row[X[idx]] = 1#X[idx]是标签的值:0~9 。例如X[idx] = 5,则[0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
    return T

 

#1、是否归一化
#2、是否将图像展开为一维数组
#3、是否将标签保存为onehot表示, one-hot表示是仅正确解标签为1,其余皆为0的数组,如[0,0,1,0,0,0,0,0,0,0]

def load_mnist(normalize = True, flatten = True, one_hot_label = False):
    if not os.path.exists(save_file):#打开保存为numpy数组的mnist数据集文件
        init_mnist()

    with open(save_file, 'rb') as f:
        dataset = pickle.load(f)#载入数据集

    if normalize:
        for key in ('train_img', 'test_img'):#字典中的训练图片和测试图片
            dataset[key] = dataset[key].astype(np.float32)
            dataset[key] /= 255.0

    if one_hot_label:
        dataset['train_label'] = _change_one_hot_label(dataset['train_label'])
        dataset['test_label'] = _change_one_hot_label(dataset['test_label'])

    if not flatten:
        for key in ('train_img', 'test_img'):
            dataset[key] = dataset[key].reshape(-1, 1, 28, 28)#传入的是一维的图片数据,转成二维图片

    return (dataset['train_img'], dataset['train_label']), (dataset['test_img'], dataset['test_label'])

 

def img_show(img):#打开图片
    pil_img = Image.fromarray(np.uint8(img))
    pil_img.show()

 

#以下函数是识别用的

 

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

 

#输出层的激活函数,将输入内容转成概率

def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a - c)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

 

def get_data():#获取测试数据
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
    return x_test, t_test #只返回测试集

 

def init_network():#初始化网络,从文件中中读取参数
    with open("sample_weight.pkl", 'rb') as f:
        network = pickle.load(f)
    return network

 

#这里之前的博客有详细过程

def predict(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']
    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = softmax(a3)
    return y

 

if __name__ == '__main__':
    init_mnist()#初始化数据
    (x_train, t_train), (x_test, t_test) = load_mnist(flatten=True, normalize=False,one_hot_label = True)#载入数据
    #输出各个数据的形状
    print(x_train.shape)  # (60000, 784)
    print(t_train.shape)  # (60000,)
    print(x_test.shape)  # (10000, 784)
    print(t_test.shape)  # (10000,)

    img = x_train[0]# 训练集的第一张图片
    label = t_train[0]# 训练集的第一张图片的label
    print(label) # 5 训练集第一张图片显示的内容是手写数字5
    print(img.shape) # (784,) 一维长度为784的数组 上面 load_mnist的flatten=True,将图片展开成一维的所以这里是784*1的数组
    img = img.reshape(28, 28) # 转成28*28的二维数组
    print(img.shape) # (28, 28)
    img_show(img)#打开图片

 

#以下是手写数字识别过程

    x, t = get_data()#载入数据集(测试集 10000张图片)x图片数据(一维) t测试集标签
    network = init_network()#载入权重参数文件用文件中的参数设置神经网络的参数
    accuracy_cnt = 0
    batch_size = 1000  # 批数量,一次传入1000张图片
    range_arr = range(0, len(x), batch_size)#[0,1000,2000,3000....,10000]

    print(len(range_arr))#10
    for i in range_arr:
        x_batch = x[i:i + batch_size]#每次取1000张测试集的图片
        y_batch = predict(network, x_batch)#1000张测试图片的预测结果 每个结果是10*1的数组,其中内容是概率值
        p = np.argmax(y_batch, axis = 1)#取出每张图片最大概率值对应的索引

    print("p的长度:", len(p)) #p的长度:1000
        a = (p == t[i:i + batch_size])#这里是索引值(0~9)就是预测得到的数值(仅限本程序),比如第100张图片的最大概率的索引是3,则预测结果是0~9这10个数字中的3,再与测试集的label比较,得到bool数组a = [True True False True ...](这里每次处理1000张图片,t[i:i + batch_size]取1000张图片的label与预计结果比较)
        num = np.sum(a)#bool转int 得到结果是a中true的个数,也就是预测结果与label比较起来正确的个数
        accuracy_cnt += num
print("正确率:" + str(float(accuracy_cnt) / len(x)))#正确率:0.9352


转载:https://blog.csdn.net/kenfan1647/article/details/102055694
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场