深度学习入门—手写文字识别机

小鸡
阅读883 喜欢3 算法 更新2019-5-20

和求解机器学习问题的步骤(分成学习和推理两个阶段进行)一样, 使用神经网络解决问题时,也需要首先使用训练数据(学习数据)进 行权重参数的学习;进行推理时,使用刚才学习到的参数,对输入 数据进行分类。

mnist数据集

MNIST数据集是由0到9的数字图像构成的。训练图像有6万张, 测试图像有1万张,这些图像可以用于学习和推理。MNIST数据集的一般使用方法是,先用训练图像进行学习,再用学习到的模型度量能在多大程度上对测试图像进行正确的分类。


MNIST的图像数据是28像素 × 28像素的灰度图像(1通道),各个像素 的取值在0到255之间。每个图像数据都相应地标有“7”“2”“1”等标签。

下面代码简单地读出数据集

# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 为了导入父目录的文件而进行的设定
import numpy as np
from dataset.mnist import load_mnist
# 第一次调用会花费几分钟 ……
# (训练图像 ,训练标签 ),(测试图像,测试标签 )
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True,
normalize=False)
# 输出各个数据的形状
print(x_train.shape) # (60000, 784)
print(t_train.shape) # (60000,)
print(x_test.shape) # (10000, 784)
print(t_test.shape) # (10000,)

load_mnist函数以“(训练图像 ,训练标签 ),(测试图像,测试标签 )”的 形式返回读入的MNIST数据。此外,还可以像load_mnist(normalize=True, flatten=True, one_hot_label=False) 这 样,设 置 3 个 参 数。第 1 个参数 normalize设置是否将输入图像正规化为0.0~1.0的值。

如果将该参数设置为False,则输入图像的像素会保持原来的0~255。第2个参数flatten设置是否展开输入图像(变成一维数组)。如果将该参数设置为False,则输入图 像为1 × 28 × 28的三维数组;若设置为True,则输入图像会保存为由784个 元素构成的一维数组。第3个参数one_hot_label设置是否将标签保存为onehot表示(one-hotrepresentation)


normalize : 将图像的像素值正规化为0.0~1.0

one_hot_label:one_hot_labelTrue的情况下,标签作为one-hot数组返回

one-hot数组是指[0,0,1,0,0,0,0,0,0,0]这样的数组

flatten : 是否将图像展开为一维数组Returns


导入数据集完成后,开始实现神经网络地推理处理。可以看出,每个图像有784个像素点,将每个图像作为一个输入点,也就是作为一个输入层地神经元,那么输入层的神经元一共有784个(只讨论一张图片),而输出层的为十个数字,分别表示该图片是0~9的概率,此外该神经网络还有两个中间层(隐藏层)第一个隐藏层有50个神经元,第二个隐藏层有100个神经元。其实这50和100可以设置成其他值。

下面定义三个函数
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", &aposrb&apos) as f:
network = pickle.load(f)
return network

def predict(network, x):
W1, W2, W3 = network[&aposW1&apos], network[&aposW2&apos], network[&aposW3&apos]
b1, b2, b3 = network[&aposb1&apos], network[&aposb2&apos], network[&aposb3&apos]
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
  • get_data函数通过load_mnist读取数据集并返回测试数据集。
  • Init_network函数读取pkl文件并将其反序列化,这个文件中以字典变量的形式保存了权重和偏置参数
  • predic函数对输入进行分类

正规化/预处理

load_mnist函数的参数normalize设置成了True。将normalize设置成True后,函数内部会进行转换,将图像的各个像 素值除以255,使得数据的值在0.0~1.0的范围内。像这样把数据限定到某 个范围内的处理称为正规化normalization)。

此外,对神经网络的输入数据进行某种既定的转换称为预处理pre-processing)。这里,作为对输入图像的 一种预处理,我们进行了正规化。

补充:序列化

pickle提供了一个简单的持久化功能。可以将对象以文件的形式存放在磁盘上。pickle模块只能在python中使用,python中几乎所有的数据类型(列表,字典,集合,类等)都可以用pickle来序列化,pickle.dump(obj, file[, protocol])序列化对象,并将结果数据流写入到文件对象中。

参数protocol是序列化模式,默认值为0,表示以文本的形式序列化。protocol的值还可以是1或2,表示以二进制的形式序列化。
pickle.load(file)

反序列化对象。将文件中的数据解析为一个Python对象。


现在利用这三个函数进行神经网络的推演

x, t = get_data()
network = init_network()
accuracy_cnt = 0
for i in range(len(x)):
y = predict(network, x[i])
p= np.argmax(y) # 获取概率最高的元素的索引
if p == t[i]:
accuracy_cnt += 1

首先获得MNIST数据集,生成网络。接着,用for语句逐一取出保存 在x中的图像数据,用predict()函数进行分类。predict()函数以NumPy数 组的形式输出各个标签对应的概率。比如输出[0.1, 0.3, 0.2, ..., 0.04]的 数组,该数组表示“0”的概率为0.1,“1”的概率为0.3
用np.argmax(x)函数取出数组中的最大值的索引
比较神经网络所预 测的答案和正确解标签,将回答正确的概率作为识别精度。

输出结果Accuracy:0.9352

批处理

上面的代码中,每次for循环处理处理一张图片的数据,单张图片的神经网络推处理过程如下


输入一个由784个元素构成的一维数组,输出有10个元素的一维数组,这只是输入一张图片的处理流程,如果考虑多张图片打包输入,比如用predict()函数一次性打包处理100张图片,这时可以把x的形状改为100X784,神经网络推理过程如下


输入数据的形状为 100 × 784,输出数据的形状为 100 × 10。这表示输入的100张图像的结果被一次性输出了。比如x[0]y[0]中保存了第0张图像及其推理结果,x[1]y[1]中保存了第1张图像及 其推理结果。

这种打包式的输入数据称为批(batch)。

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)))

首先是range()函数。range()函数若 指定为range(start, end),则会生成一个由startend-1之间的整数构成的 列表。若像range(start, end, step)这样指定3个整数,则生成的列表中的 下一个元素会增加step指定的值

本章所学的内容

  • 神经网络中的激活函数使用平滑变化sigmoid函数或ReLU函数
  • 通过巧妙地使用NumPy多维数组,可以高效地实现神经网络。
  • 机器学习的问题大体上可以分为回归问题分类问题
  • 关于输出层的激活函数,回归问题中一般用恒等函数,分类问题中 一般用softmax函数。
  • 分类问题中,输出层的神经元的数量设置为要分类的类别数
  • 输入数据的集合称为批。通过以批为单位进行推理处理,能够实现 高速的运算。

神经网络和上一章的感知机在信号的按层传递这一点上是相同的,但是,向下一个神经元发送信号时, 改变信号的激活函数有很大差异。神经网络中使用的是平滑变化的sigmoid 函数,而感知机中使用的是信号急剧变化的阶跃函数。这个差异对于神经网 络的学习非常重要


:本文为斋藤康毅的《深度学习入门:基于Python的理论与实现》片段摘抄与学习笔记