机器学习编程:从编码到深度学习
上QQ阅读APP看书,第一时间看更新

6.2.2 处理数据

互联网上充斥着读取MNIST数据的程序库和代码片段。但我们是开发者,所以就自己写一个吧!我将在本节中向你展示加载这些图像和标签的小型程序库中的代码,并将它们重新组合成我们刚才描述的矩阵X和Y。

1.加载图像

下面的代码将MNIST中的图像样本加载到两个矩阵中,一个用于存储训练样本数据,另一个用于存储测试样本数据:

让我们快速浏览一下这段代码。load_images()从MNIST的二进制文件解压缩和解码图像。这个函数特定于MNIST样本库的二进制格式,所以你不需要真正了解它的细节。如果你感兴趣,只要知道struct.unpack()函数是根据模式字符串从二进制文件中读取数据就可以了。在本例中,模式是'>IIII',意思是“4个无符号整数,先从最重要的字节编码”。代码的注释应该可以帮助你理解这个函数的其余部分。

load_images()函数返回一个矩阵,在训练样本的情况下是(60000,784),在测试样本的情况下是(10000,784)。然后它可以将这些矩阵传递给第二个函数prepend_bias(),从而为它们提供额外的1列,其中充满了表示偏置的1。

代码中的最后几行将训练图像样本和测试图像样本存储到两个常量中。其基本思想是:这个程序库的用户不需要调用load_images()函数和prepend_bias()函数。相反,它可以导入库(使用导入mnist),然后引用这些常量(使用mnist.X_train和mnist.X_test)。

这就是图像样本加载部分的所有代码了,下面来处理标签。

2.加载标签

下面的代码加载并准备MNIST样本数据的标签:

load_labels()函数将MNIST中样本数据的标签加载到NumPy数组中,然后将该数组塑造为一个单列矩阵。同样,你不需要理解这段代码的具体细节,因为你不太可能经常加载MNIST数据标签。但是如果你感兴趣,可以阅读注释。(提示:reshape(-1,1)函数的含义是:“将这些数据排列成一个矩阵,该矩阵包含一列和你需要的任意数量的行数。”)使用函数load_labels()得到的返回数据是一个形状为(60000,1)的矩阵,还是形状为(10000,1)的矩阵,取决于我们加载的数据是训练样本的标签还是测试样本的标签。

从函数load_labels()中返回的矩阵包含了0~9的标签值。我们可以将该矩阵传递给函数encode_fives(),将这些标签值转换为二进制的形式。我们通常不会长期使用函数encode_fives(),所以没有对它进行参数化,只是通过硬编码的方式实现对数字5的编码。

函数encode_fives()中的一行代码是典型的NumPy代码,非常简洁,甚至有点晦涩难懂。(Y==5)表示:“创建一个数组,其中Y包含5时为真,Y不包含5时为假。”然后,该数组被转换为一个整数数组,所有为真的值变成了1,所有为假的值变成了0。最终的结果是一个与矩阵Y具有形状相同的新矩阵,其中在矩阵Y中为5的元素位置上,新矩阵的元素取1,新矩阵其他位置上的元素取0。

在这些函数之后,代码中的最后几行定义了两个常量。我们可以分别使用它们访问训练样本的标签和测试样本的标签。

这样,我们的MNIST库就完成了。我们将它保存为一个文件(mnist.py),并使用它来充实我们的机器学习程序。