README.md 8.1 KB
Newer Older
1
# Python Data Reader Design Doc
2

3
During the training and testing phases, PaddlePaddle programs need to read data. To help the users write code that performs reading input data, we define the following:
H
Helin Wang 已提交
4

5 6 7 8
- A *reader*: A function that reads data (from file, network, random number generator, etc) and yields the data items.
- A *reader creator*: A function that returns a reader function.
- A *reader decorator*: A function, which takes in one or more readers, and returns a reader.
- A *batch reader*: A function that reads data (from *reader*, file, network, random number generator, etc) and yields a batch of data items.
H
Helin Wang 已提交
9

10
and also provide a function which can convert a reader to a batch reader, frequently used reader creators and reader decorators.
11

12
## Data Reader Interface
13

14
*Data reader* doesn't have to be a function that reads and yields data items. It can just be any function without any parameters that creates an iterable (anything can be used in `for x in iterable`) as follows:
15 16

```
17
iterable = data_reader()
18 19
```

20
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.)
21

22
An example implementation for single item data reader creator is as follows:
23

H
Helin Wang 已提交
24
```python
H
Helin Wang 已提交
25
def reader_creator_random_image(width, height):
Y
Yu Yang 已提交
26 27 28 29
    def reader():
        while True:
            yield numpy.random.uniform(-1, 1, size=width*height)
    return reader
H
Helin Wang 已提交
30 31
```

32
An example implementation for multiple item data reader creator is as follows:
H
Helin Wang 已提交
33
```python
Y
Yu Yang 已提交
34 35 36 37 38
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
39
```
H
Helin Wang 已提交
40

41 42
## Batch Reader Interface

43 44 45
*Batch reader* can be any function without any parameters that creates an iterable (anything can be used in `for x in iterable`). The output of the iterable should be a batch (list) of data items. Each item inside the list should be a tuple.

Here are some valid outputs:
46 47 48 49 50 51 52 53 54 55

```python
# a mini batch of three data items. Each data item consist three columns of data, each of which is 1.
[(1, 1, 1),
(2, 2, 2),
(3, 3, 3)]

# a mini batch of three data items, each data item is a list (single column).
[([1,1,1],),
([2,2,2],),
P
Peng Li 已提交
56
([3,3,3],)]
57 58 59 60 61
```

Please note that each item inside the list must be a tuple, below is an invalid output:
```python
 # wrong, [1,1,1] needs to be inside a tuple: ([1,1,1],).
62 63
 # Otherwise it is ambiguous whether [1,1,1] means a single column of data [1, 1, 1],
 # or three columns of data, each of which is 1.
64 65 66 67 68
[[1,1,1],
[2,2,2],
[3,3,3]]
```

69 70
It is easy to convert from a reader to a batch reader:

71 72 73 74 75
```python
mnist_train = paddle.dataset.mnist.train()
mnist_train_batch_reader = paddle.batch(mnist_train, 128)
```

76 77
It is also straight forward to create a custom batch reader:

78 79
```python
def custom_batch_reader():
Y
Yu Yang 已提交
80 81 82 83 84
    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
85 86 87 88

mnist_random_image_batch_reader = custom_batch_reader
```

89 90
## Usage

91 92
Following is how we can use the reader with PaddlePaddle:
The batch reader, a mapping from item(s) to data layer, the batch size and the number of total passes will be passed into `paddle.train` as follows:
93 94 95 96 97 98 99

```python
# two data layer is created:
image_layer = paddle.layer.data("image", ...)
label_layer = paddle.layer.data("label", ...)

# ...
100 101
batch_reader = paddle.batch(paddle.dataset.mnist.train(), 128)
paddle.train(batch_reader, {"image":0, "label":1}, 128, 10, ...)
102 103
```

104
## Data Reader Decorator
H
Helin Wang 已提交
105

106
The *Data reader decorator* takes in a single reader or multiple data readers and returns a new data reader. It is similar to a [python decorator](https://wiki.python.org/moin/PythonDecorators), but it does not use `@` in the syntax.
H
Helin Wang 已提交
107

108
Since we have a strict interface for data readers (no parameters and return a single data item), a data reader can be used in a flexible way using data reader decorators. Following are a few examples:
H
Helin Wang 已提交
109 110 111

### Prefetch Data

112
Since reading data may take some time and training can not proceed without data, it is generally a good idea to prefetch the data.
H
Helin Wang 已提交
113 114 115 116

Use `paddle.reader.buffered` to prefetch data:

```python
117
buffered_reader = paddle.reader.buffered(paddle.dataset.mnist.train(), 100)
H
Helin Wang 已提交
118 119
```

120
`buffered_reader` will try to buffer (prefetch) `100` data entries.
H
Helin Wang 已提交
121

122
### Compose Multiple Data Readers
H
Helin Wang 已提交
123

124
For example, if we want to use a source of real images (say reusing mnist dataset), and a source of random images as input for [Generative Adversarial Networks](https://arxiv.org/abs/1406.2661).
H
Helin Wang 已提交
125

126
We can do the following :
H
Helin Wang 已提交
127 128

```python
H
Helin Wang 已提交
129
def reader_creator_random_image(width, height):
Y
Yu Yang 已提交
130 131 132 133
    def reader():
        while True:
            yield numpy.random.uniform(-1, 1, size=width*height)
    return reader
H
Helin Wang 已提交
134

H
Helin Wang 已提交
135
def reader_creator_bool(t):
Y
Yu Yang 已提交
136 137 138 139
    def reader:
        while True:
            yield t
    return reader
H
Helin Wang 已提交
140

H
Helin Wang 已提交
141 142
true_reader = reader_creator_bool(True)
false_reader = reader_creator_bool(False)
H
Helin Wang 已提交
143

144 145
reader = paddle.reader.compose(paddle.dataset.mnist.train(), data_reader_creator_random_image(20, 20), true_reader, false_reader)
# Skipped 1 because paddle.dataset.mnist.train() produces two items per data entry.
146
# And we don't care about the second item at this time.
147
paddle.train(paddle.batch(reader, 128), {"true_image":0, "fake_image": 2, "true_label": 3, "false_label": 4}, ...)
H
Helin Wang 已提交
148 149 150 151
```

### Shuffle

152
Given the shuffle buffer size `n`, `paddle.reader.shuffle` returns a data reader that buffers `n` data entries and shuffles them before a data entry is read.
H
Helin Wang 已提交
153 154 155

Example:
```python
156
reader = paddle.reader.shuffle(paddle.dataset.mnist.train(), 512)
157 158 159 160
```

## Q & A

161
### Why does a reader return only a single entry, and not a mini batch?
162

163
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).
164

165
We provide a function: `paddle.batch` to turn (a single entry) reader into a batch reader.
166

167
### Why do we need a batch reader, isn't is sufficient to give the reader and batch_size as arguments during training ?
168

169
In most of the cases, it would be sufficient to give the reader and batch_size as arguments to the train method. However sometimes the user wants to customize the order of data entries inside a mini batch, or even change the batch size dynamically. For these cases using a batch reader is very efficient and helpful.
170

171
### Why use a dictionary instead of a list to provide mapping?
H
Helin Wang 已提交
172

173
Using a dictionary (`{"image":0, "label":1}`) instead of a list (`["image", "label"]`) gives the advantage that the user can easily reuse the items (e.g., using `{"image_a":0, "image_b":0, "label":1}`) or even skip an item (e.g., using `{"image_a":0, "label":2}`).
H
Helin Wang 已提交
174

175
### How to create a custom data reader creator ?
176 177

```python
178
def image_reader_creator(image_path, label_path, n):
Y
Yu Yang 已提交
179 180 181 182 183 184 185 186 187 188 189 190
    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
191

192 193
# images_reader_creator creates a reader
reader = image_reader_creator("/path/to/image_file", "/path/to/label_file", 1024)
194
paddle.train(paddle.batch(reader, 128), {"image":0, "label":1}, ...)
195 196 197 198
```

### How is `paddle.train` implemented

199
An example implementation of paddle.train is:
200 201

```python
202
def train(batch_reader, mapping, batch_size, total_pass):
Y
Yu Yang 已提交
203 204 205
    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)
206
```