• 数据预处理工具
    • Data Reader 接口
    • Batch Reader 接口
    • 使用
    • Data Reader装饰器
      • 预取回数据(缓存数据)
      • 组成多个Data Reader
      • 随机排序
    • Q & A
      • 为什么一个reader只返回单项而不是mini batch?
      • 为什么需要一个batch reader,在训练过程中给出reader和batch_size参数这样不足够吗?
      • 为什么用字典而不是列表进行映射?
      • 如何创建一个自定义data reader?

    数据预处理工具

    在模型训练和预测阶段,PaddlePaddle程序需要读取训练或预测数据。为了帮助您编写数据读取的代码,我们提供了如下接口:

    • reader: 样本级的reader,用于读取数据的函数,数据可来自于文件、网络、随机数生成器等,函数每次返回一个样本数据项。
    • reader creator: 接受一个或多个reader作为参数、返回一个新reader的函数。
    • reader decorator: 一个函数,接受一个或多个reader,并返回一个reader。
    • batch reader: 用于读取数据的函数,数据可来自于文件、网络、随机数生成器等,函数每次返回一个batch大小的数据项。此外,还提供了将reader转换为batch reader的函数,会频繁用到reader creator和reader decorator。

    Data Reader 接口

    Data reader不一定要求为读取和遍历数据项的函数。它可以是返回iterable对象(即可以用于for x in iterable的任意对象)的任意不带参数的函数:

    1. iterable = data_reader()

    Iterable对象应产生单项或tuple形式的数据,而不是一个mini batch的数据。产生的数据项应在支持的类型 中,例如float32,int类型的numpy一维矩阵,int类型的列表等。

    以下是实现单项数据reader creator的示例:

    1. def reader_creator_random_image(width, height):
    2. def reader():
    3. while True:
    4. yield numpy.random.uniform(-1, 1, size=width*height)
    5. return reader

    以下是实现多项数据reader creator的示例:

    1. def reader_creator_random_image_and_label(width, height, label):
    2. def reader():
    3. while True:
    4. yield numpy.random.uniform(-1, 1, size=width*height), label
    5. return reader

    Batch Reader 接口

    Batch reader可以是返回iterable对象(即可以用于for x in iterable的任意对象)的任意不带参数的函数。Iterable的输出应为一个batch(list)的数据项。list中的每个数据项均为一个tuple元组。

    这里是一些有效输出:

    1. # 三个数据项组成一个mini batch。每个数据项有三列,每列数据项为1。
    2. [(1, 1, 1),
    3. (2, 2, 2),
    4. (3, 3, 3)]
    5.  
    6. # 三个数据项组成一个mini batch。每个数据项是一个列表(单列)。
    7. [([1,1,1],),
    8. ([2,2,2],),
    9. ([3,3,3],)]

    请注意列表里的每个项必须为tuple,下面是一个无效输出:

    1. # 错误, [1,1,1]需在一个tuple内: ([1,1,1],).
    2. # 否则产生歧义,[1,1,1]是否表示数据[1, 1, 1]整体作为单一列。
    3. # 或者数据的三列,每一列为1。
    4. [[1,1,1],
    5. [2,2,2],
    6. [3,3,3]]

    很容易将reader转换成batch reader:

    1. mnist_train = paddle.dataset.mnist.train()
    2. mnist_train_batch_reader = paddle.batch(mnist_train, 128)

    也可以直接创建一个自定义batch reader:

    1. def custom_batch_reader():
    2. while True:
    3. batch = []
    4. for i in xrange(128):
    5. batch.append((numpy.random.uniform(-1, 1, 28*28),)) # note that it's a tuple being appended.
    6. yield batch
    7.  
    8. mnist_random_image_batch_reader = custom_batch_reader

    使用

    以下是我们如何用PaddlePaddle的reader:

    batch reader是从数据项到数据层(data layer)的映射,batch_size和总pass数通过以下方式传给paddle.train

    1. # 创建两个数据层:
    2. image_layer = paddle.layer.data("image", ...)
    3. label_layer = paddle.layer.data("label", ...)
    4.  
    5. # ...
    6. batch_reader = paddle.batch(paddle.dataset.mnist.train(), 128)
    7. paddle.train(batch_reader, {"image":0, "label":1}, 128, 10, ...)

    Data Reader装饰器

    Data reader decorator接收一个或多个reader对象作为参数,返回一个新的reader对象。它类似于python decorator ,但在语法上不需要写@

    我们对data reader接口有严格限制(无参数并返回单个数据项),data reader可灵活地搭配data reader decorators使用。以下是一些示例:

    预取回数据(缓存数据)

    由于读数据需要一些时间,而没有数据无法进行训练,因此一般而言数据预读取会是一个很好的方法。

    paddle.reader.buffered预读取数据:

    1. buffered_reader = paddle.reader.buffered(paddle.dataset.mnist.train(), 100)

    buffered_reader将尝试缓存(预读取)100个数据项。

    组成多个Data Reader

    例如,如果我们想用实际图像源(也就是复用mnist数据集),和随机图像源作为Generative Adversarial Networks的输入。

    我们可以参照如下:

    1. def reader_creator_random_image(width, height):
    2. def reader():
    3. while True:
    4. yield numpy.random.uniform(-1, 1, size=width*height)
    5. return reader
    6.  
    7. def reader_creator_bool(t):
    8. def reader():
    9. while True:
    10. yield t
    11. return reader
    12.  
    13. true_reader = reader_creator_bool(True)
    14. false_reader = reader_creator_bool(False)
    15.  
    16. reader = paddle.reader.compose(paddle.dataset.mnist.train(), reader_creator_random_image(20, 20), true_reader, false_reader)
    17. # 跳过1因为paddle.dataset.mnist.train()为每个数据项生成两个项。
    18. # 并且这里我们暂时不考虑第二项。
    19. paddle.train(paddle.batch(reader, 128), {"true_image":0, "fake_image": 2, "true_label": 3, "false_label": 4}, ...)

    随机排序

    给定大小为n的随机排序缓存, paddle.reader.shuffle返回一个data reader ,缓存n个数据项,并在读取一个数据项前进行随机排序。

    示例:

    1. reader = paddle.reader.shuffle(paddle.dataset.mnist.train(), 512)

    Q & A

    为什么一个reader只返回单项而不是mini batch?

    返回单项,可以更容易地复用已有的data reader,例如如果一个已有的reader返回3项而不是一个单项,这样训练代码会更复杂,因为需要处理像batch_size为2这样的例子。

    我们提供一个函数来将一个单项reader转换成一个batch reader。

    为什么需要一个batch reader,在训练过程中给出reader和batch_size参数这样不足够吗?

    在大多数情况下,在训练方法中给出reader和batch_size参数是足够的。但有时用户想自定义mini batch里数据项的顺序,或者动态改变batch_size。在这些情况下用batch reader会非常高效有用。

    为什么用字典而不是列表进行映射?

    使用字典({"image":0, "label":1})而不是列表["image", "label"])有利于用户易于复用数据项,例如使用{"image_a":0, "image_b":0, "label":1},或者甚至跳过数据项,例如使用{"image_a":0, "label":2}

    如何创建一个自定义data reader?

    1. def image_reader_creator(image_path, label_path, n):
    2. def reader():
    3. f = open(image_path)
    4. l = open(label_path)
    5. images = numpy.fromfile(
    6. f, 'ubyte', count=n * 28 * 28).reshape((n, 28 * 28)).astype('float32')
    7. images = images / 255.0 * 2.0 - 1.0
    8. labels = numpy.fromfile(l, 'ubyte', count=n).astype("int")
    9. for i in xrange(n):
    10. yield images[i, :], labels[i] # a single entry of data is created each time
    11. f.close()
    12. l.close()
    13. return reader
    14.  
    15. # images_reader_creator创建一个reader
    16. reader = image_reader_creator("/path/to/image_file", "/path/to/label_file", 1024)