diff --git a/doc/fluid/user_guides/howto/prepare_data/reader.md b/doc/fluid/user_guides/howto/prepare_data/reader.md index aa50e4d26166536eaf8044d527debd8ad46060f6..fab10bdd4473d3f1cb0cbc9dcddd60ff863e3412 100644 --- a/doc/fluid/user_guides/howto/prepare_data/reader.md +++ b/doc/fluid/user_guides/howto/prepare_data/reader.md @@ -21,7 +21,7 @@ and also provide a function which can convert a reader to a batch reader, freque iterable = data_reader() ``` -The item produced from the iterable should be a **single** entry of data and **not** a mini batch. The entry of data could be a single item or a tuple of items. Item should be of one of the [supported types](http://www.paddlepaddle.org/doc/ui/data_provider/pydataprovider2.html?highlight=dense_vector#input-types) (e.g., numpy 1d array of float32, int, list of int etc.) +The item produced from the iterable should be a **single** entry of data and **not** a mini batch. The entry of data could be a single item or a tuple of items. Item should be of one of the supported types (e.g., numpy 1d array of float32, int, list of int etc.) An example implementation for single item data reader creator is as follows: @@ -164,7 +164,7 @@ reader = paddle.reader.shuffle(paddle.dataset.mnist.train(), 512) ### Why does a reader return only a single entry, and not a mini batch? -Returning a single entry makes reusing existing data readers much easier (for example, if an existing reader returns 3 entries instead if a single entry, the training code will be more complicated because it need to handle cases like a batch size 2). +Returning a single entry makes reusing existing data readers much easier (for example, if an existing reader returns 3 entries instead of a single entry, the training code will be more complicated because it needs to handle cases like a batch size 2). We provide a function: `paddle.batch` to turn (a single entry) reader into a batch reader. diff --git a/doc/fluid/user_guides/howto/prepare_data/reader_cn.md b/doc/fluid/user_guides/howto/prepare_data/reader_cn.md new file mode 100644 index 0000000000000000000000000000000000000000..f4e3178a85d4f7c3944c0d3c204a35ad3d1bb010 --- /dev/null +++ b/doc/fluid/user_guides/howto/prepare_data/reader_cn.md @@ -0,0 +1,203 @@ +```eval_rst +.. _user_guide_reader: +``` + +# Python Reader +在模型训练和预测阶段,PaddlePaddle程序需要读取训练或预测数据。为了帮助用户编写数据读取的代码,我们提供了如下接口: + +- *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`的任意对象)的任意不带参数的函数: + +``` +iterable = data_reader() +``` + +Iterable对象应产生单项或tuple形式的数据,而不是一个mini batch的数据。产生的数据项应在[支持的类型](./feeding_data.html#fluid) 中,例如float32,int类型的numpy一维矩阵,int类型的列表等。 + +以下是实现单项数据reader creator的示例: + +```python +def reader_creator_random_image(width, height): + def reader(): + while True: + yield numpy.random.uniform(-1, 1, size=width*height) + return reader +``` + +以下是实现多项数据reader creator的示例: + +```python +def reader_creator_random_image_and_label(width, height, label): + def reader(): + while True: + yield numpy.random.uniform(-1, 1, size=width*height), label + return reader +``` + +## Batch Reader 接口 +*Batch reader*可以是返回iterable对象(即可以用于`for x in iterable`的任意对象)的任意不带参数的函数。Iterable的输出应为一个batch(list)的数据项。list中的每个数据项均为一个tuple元组。 + +这里是一些有效输出: + +```python +# 三个数据项组成一个mini batch。每个数据项有三列,每列数据项为1。 +[(1, 1, 1), +(2, 2, 2), +(3, 3, 3)] + +# 三个数据项组成一个mini batch。每个数据项是一个列表(单列)。 +[([1,1,1],), +([2,2,2],), +([3,3,3],)] +``` + +请注意列表里的每个项必须为tuple,下面是一个无效输出: +```python + # 错误, [1,1,1]需在一个tuple内: ([1,1,1],). + # 否则产生歧义,[1,1,1]是否表示数据[1, 1, 1]整体作为单一列。 + # 或者数据的三列,每一列为1。 +[[1,1,1], +[2,2,2], +[3,3,3]] +``` + +很容易将reader转换成batch reader: + +```python +mnist_train = paddle.dataset.mnist.train() +mnist_train_batch_reader = paddle.batch(mnist_train, 128) +``` + +也可以直接创建一个自定义batch reader: + +```python +def custom_batch_reader(): + while True: + batch = [] + for i in xrange(128): + batch.append((numpy.random.uniform(-1, 1, 28*28),)) # note that it's a tuple being appended. + yield batch + +mnist_random_image_batch_reader = custom_batch_reader +``` + +## 使用 +以下是我们如何用PaddlePaddle的reader: + +batch reader是从数据项到数据层(data layer)的映射,batch_size和总pass数通过以下方式传给`paddle.train`: + +```python +# 创建两个数据层: +image_layer = paddle.layer.data("image", ...) +label_layer = paddle.layer.data("label", ...) + +# ... +batch_reader = paddle.batch(paddle.dataset.mnist.train(), 128) +paddle.train(batch_reader, {"image":0, "label":1}, 128, 10, ...) +``` + +## Data Reader装饰器 +*Data reader decorator*接收一个或多个reader对象作为参数,返回一个新的reader对象。它类似于[python decorator](https://wiki.python.org/moin/PythonDecorators) ,但在语法上不需要写`@`。 + +我们对data reader接口有严格限制(无参数并返回单个数据项),data reader可灵活地搭配data reader decorators使用。以下是一些示例: + +### 预取回数据(缓存数据) +由于读数据需要一些时间,而没有数据无法进行训练,因此一般而言数据预读取会是一个很好的方法。 + +用`paddle.reader.buffered`预读取数据: + +```python +buffered_reader = paddle.reader.buffered(paddle.dataset.mnist.train(), 100) +``` + +`buffered_reader`将尝试缓存(预读取)`100`个数据项。 + +### 组成多个Data Reader +例如,如果我们想用实际图像源(也就是复用mnist数据集),和随机图像源作为[Generative Adversarial Networks](https://arxiv.org/abs/1406.2661)的输入。 + +我们可以参照如下: + +```python +def reader_creator_random_image(width, height): + def reader(): + while True: + yield numpy.random.uniform(-1, 1, size=width*height) + return reader + +def reader_creator_bool(t): + def reader: + while True: + yield t + return reader + +true_reader = reader_creator_bool(True) +false_reader = reader_creator_bool(False) + +reader = paddle.reader.compose(paddle.dataset.mnist.train(), data_reader_creator_random_image(20, 20), true_reader, false_reader) +# 跳过1因为paddle.dataset.mnist.train()为每个数据项生成两个项。 +# 并且这里我们暂时不考虑第二项。 +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`个数据项,并在读取一个数据项前进行随机排序。 + +示例: +```python +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 raeder,在训练过程中给出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? +```python +def image_reader_creator(image_path, label_path, n): + def reader(): + f = open(image_path) + l = open(label_path) + images = numpy.fromfile( + f, 'ubyte', count=n * 28 * 28).reshape((n, 28 * 28)).astype('float32') + images = images / 255.0 * 2.0 - 1.0 + labels = numpy.fromfile(l, 'ubyte', count=n).astype("int") + for i in xrange(n): + yield images[i, :], labels[i] # a single entry of data is created each time + f.close() + l.close() + return reader + +# images_reader_creator创建一个reader +reader = image_reader_creator("/path/to/image_file", "/path/to/label_file", 1024) +paddle.train(paddle.batch(reader, 128), {"image":0, "label":1}, ...) +``` + +### `paddle.train`实现原理 +实现`paddle.train`的示例如下: + +```python +def train(batch_reader, mapping, batch_size, total_pass): + for pass_idx in range(total_pass): + for mini_batch in batch_reader(): # this loop will never end in online learning. + do_forward_backward(mini_batch, mapping) +```