深度学习入门3——手写数字识别

本实例使用的数据集是MNIST手写数字图像集。其由0到9的数字图像构成的。训练图像有6万张, 测试图像有1万张,这些图像可以用于学习和推理。图像数据为28像素 × 28像素的灰度图像(单通道),各个像素的取值在0到255之间。每个图像数据都相应地标有“7”“2”“1”等标签。接下来进行具体的手写数字识别的python代码实现。

1.MNIST数据集

import sys, os
import numpy as np
from PIL import Image
sys.path.append(os.pardir) # 将父目录的路径添加到sys.path中。这可能是因为你希望在当前脚本或程序中导入父目录中的模块,而默认情况下Python不会在父目录中查找模块。
from dataset.mnist import load_mnist #load_mnist函数以“(训练图像 ,训练标签 ),(测试图像,测试标签 )”的形式返回读入的MNIST数据。

# 第一次调用会花费几分钟 ……
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True,
normalize=False) # flatten=True: 表示是否将图像展平为一维数组。如果为True,每个图像将从28x28的矩阵变为长度为784的一维数组。normalize=False: 表示是否对图像进行归一化处理。如果为True,图像的像素值将被缩放到0到1之间。“one_hot_label=False”第3个参数one_hot_label设置是否将标签保存为one-hot表示(one-hot representation)。one-hot表示是仅正确解标签为1,其余皆为0的数组,如[0,0,1,0,0,0,0,0,0,0]这样。当one_hot_label为False时,只是像7、2这样简单保存正确解标签;当one_hot_label为True时,标签则保存为one-hot表示。未设定则默认将标签以非独热编码(non-one-hot-label)的形式返回。

# 输出各个数据的形状,利用上一节3层神经网络的实现进行理解输入数据各个维度的要求。
print(x_train.shape) # (60000, 784)
print(t_train.shape) # (60000,)
print(x_test.shape) # (10000, 784)
print(t_test.shape) # (10000,)

def img_show(img):
 pil_img = Image.fromarray(np.uint8(img))
 pil_img.show()
    
img = x_train[0]
label = t_train[0]
print(label) # 5
print(img.shape) # (784,)
img = img.reshape(28, 28) # 把图像的形状变成原来的尺寸
print(img.shape) # (28, 28)
img_show(img)
#要注意的是,flatten=True时读入的图像是以一列(一维)NumPy数组的形式保存的。因此,显示图像时,需要把它变为原来的28像素 × 28像素的形状。可以通过reshape()方法的参数指定期望的形状,更改NumPy数组的形状。此外,还需要把保存为NumPy数组的图像数据转换为PIL用的数据对象,这个转换处理由Image.fromarray()来完成。

2 神经网络的推理处理

该神经网络输入层有784个神经元,输出层有10个神经元。此外,这个神经网络有2个隐藏层,第1个隐藏层有 50个神经元,第2个隐藏层有100个神经元。下面我们先定义get_data()、init_network()、predict()这3个函数

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: #init_network()会读入保存在pickle文件sample_weight.pkl(报错时可以使用该文件绝对路径)中的学习到的权重参数。这个文件中以字典变量的形式保存了权重和偏置参数。在推理阶段,我们直接加载这些已经学习到的参数。
    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


x, t = get_data()
network = init_network()

batch_size = 100 # 批数量
accuracy_cnt = 0

for i in range(0, len(x), batch_size):
    x_batch = x[i:i+batch_size]
    y_batch = predict(network, x_batch)
    p = np.argmax(y_batch, axis=1)
    accuracy_cnt += np.sum(p == t[i:i+batch_size])

print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
#首先获得MNIST数据集,生成网络。接着,用for语句逐一取出保存在x中的图像数据,用predict()函数进行分类。predict()函数以NumPy数组的形式输出各个标签对应的概率。比如输出[0.1, 0.3, 0.2, ..., 0.04]的数组,该数组表示“0”的概率为0.1,“1”的概率为0.3,等等。然后,我们取出这个概率列表中的最大值的索引(第几个元素的概率最高),作为预测结果。可以用np.argmax(x)函数取出数组中的最大值的索引,np.argmax(x)将获取被赋给参数x的数组中的最大值元素的索引。最后,比较神经网络所预测的答案和正确解标签,将回答正确的概率作为识别精度。
3.批处理

以上实现了手写数字识别的神经网络实现,现在我们来看一下从输入到输出数据和权重参数矩阵形状之间的对应关系。可以通过调用.shape()函数获得其形状。

x, _ = get_data()
network = init_network()
W1, W2, W3 = network['W1'], network['W2'], network['W3']
 print(x.shape())  #(10000, 784)
 print(x[0].shape())  #(784,)
print(W1.shape ())  #(784, 50)
print(W2.shape ())  #(50, 100)
print(W3.shape ())  #(100, 10)

上述单张图片数据x是一个784维的向量,且上面的计算流程符合矩阵乘法的要求。现在我们来考虑用predict函数一次性打包处理100张图片,此时x的形状变为100x784,输出为100x10。我们把这种处理方式称为__批处理__,批处理对计算机的运算大有利处,可以大幅缩短每张图像的处理时间。

接下来我们进行基于批处理的代码实现:

x,t = get_data()
network = init_network()

batch_size = 100 #批处理的规模
accuracy_cnt = 0

for i in range(0,len(x), batch_size):
    x_batch = x[i:i+batch_size] #索引范围是从i到i+batch_size
    y_batch = predict(network, x_batch) #得到预测结果y_batch
    p = np.argmax(y_batch,axis=1)#每个样本的预测结果取最大值的索引,得到预测的类别.axis=1为指定从第二个维度找最大值的索引,这里指的是从10个中选一个最大的。
    accuracy_cnt += np.sum(p==t[i:i+batch_size])#将预测结果与真实标签t进行比较,对比正确的样本数进行累加.p==t[i:i+batch_size]会生成一个布尔数组,np.sum() 计算为 True 的元素个数,即正确预测的样本数。最后这个数量被累加到 accuracy_cnt 中。
    
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值