今天开始接触MNIST数据集之外的另一个数据集CIFAR-10
。使用数据集,就需要导入它,tensorflow 是如何以最大效率导入数据的呢?本节将介绍之。
CIFAR-10 数据集
CIFAR-10 数据集一共包含了 10 个类别的 RGB 彩色图片,每张图片尺寸都是 32x32 像素的,包含 50000 张训练图片和 10000 张测试图片。
10 个类别是:飞机,汽车,鸟,猫,鹿,狗,蛙,马,船
与我们前面介绍的 MNIST 数据集相比,CIFAR-10 有一些不同的点:
- CIFAR-10 数据集是 3 通道的 RGB 彩色图片,而 MNIST 数据集则是 1 通道的灰度图片、
- CIFAR-10 图片的尺寸是 32x32,略大于 MNIST 的 28x28。
- CIFAR-10 数据集取自自然世界真实存在的物体,存在噪声,即使是同种物体的比例特征差异也远大于 MNIST,因此识别相对 MNIST 困难的多。事实上,经测试,我们第二节采用的线性 softmax 模型在 CIFAR-10 数据集中表现非常差。
常规导入数据方法的效率问题
将数据由外部导入内部,计算机才能够计算。对于 CPU 来说,需要将数据导入内存,对于 GPU 来说,需要将数据导入显存。假设,硬盘(外部)中有一个图片数据集 1.jpg, 2.jpg, 3.jpg, ...。将图片集导入内存,通常有两种做法:
- 一次性将所有图片全部读入内存
- 根据需要读取,需要多少,导入多少到内存
第一种方法适合小数据集,因为目前计算机的内存非常有限。第二种方法,则效率比较低。因为 IO 的读写速度比较慢,与读写内存的速度差了好几个数量级。
必须先读入数据才能计算,假设读入用时 0.1 秒,计算用时 0.9 秒,CPU 每秒都有 10% 的时间是空闲的,这大大降低了计算的效率。
对于比较大的数据集,以上两种导入数据的方法都有局限性,因此需要设计一套数据导入方法。一个比较好用的方法就是,将读入数据和计算放在两个线程里,一个线程不断把数据读入内存的队列中,另一个线程则负责计算,需要数据时直接从队列中取即可。
tensroflow 是如何导入数据的
为了方便管理,tensorflow 在内存队列前又添加了文件名队列
。为什么要增加这一个队列呢?我们知道,机器学习中一个比较重要的概念就是 epoch,对于一个数据集而言,运行一个 epoch 就是将数据集所有数据全部计算一遍。
如上图,tensroflow 把数据集中的数据读入文件名队列
,假设要训练 1 个 epoch,那么将数据集排列一次到文件名队列
,计算时,直接取数据到内存中即可,无需再关心 epoch 次数。如果训练 3 个 epoch,则只需将数据集排列 3 次即可。
1. tf.train.string_input_producer 方法
tensorflow 提供了 tf.train.string_input_producer
方法,只需要传入一个文件名 list,tensorflow 会自动转换成一个文件名队列
。此外它还有两个重要参数,一个是num_epochs
,就是上面讨论的 epoch 次数;另一个是shuffle
,若设置为 False,则读入的数据和传入的文件名 list 是同一顺序,若设置为 True,则读入的数据的顺序会被打乱。
2. tf.train.start_queue_runners 方法
tf.train.string_input_producer 只是描述了一个文件名队列,它只是告诉 tensorflow 应该怎么做,还没有让它开始这么做。实际上,若仅仅调用了该方法,整个队列还是空的。tf.train.start_queue_runners
方法,就是告诉 tensorflow “开干了”的,调用它之后,tensorflow 才开始填充队列,系统的计算才可以往下推进。
本节就介绍到此,下一节将利用 tensorflow 提供的数据导入方法读取 CIFAR-10 数据集,并且将其转换为 jpg 图片保存下来。
[…] […]