reader_cn.md 7.2 KB
Newer Older
C
chentianyu03 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
# 数据预处理工具

在模型训练和预测阶段,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`的任意对象)的任意不带参数的函数:

```
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(), 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 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?
```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)
```