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

H
Helin Wang 已提交
3 4 5 6 7 8 9
At training and testing time, PaddlePaddle programs need to read data. To ease the users' work to write data reading code, we define that

- A *reader* is a function that reads data (from file, network, random number generator, etc) and yields data items.
- A *reader creator* is a function that returns a reader function.
- A *reader* decorator is a function, which accepts one or more readers, and returns a reader.

and provide frequently used reader creators and reader decorators.
10

11
## Data Reader Interface
12

H
Helin Wang 已提交
13
Indeed, *data reader* doesn't have to be a function that reads and yields data items. It can be any function with no parameter that creates a iterable (anything can be used in `for x in iterable`):
14 15

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

H
Helin Wang 已提交
19
Element produced from the iterable should be a **single** entry of data, **not** a mini batch. That entry of data could be a single item, or a tuple of items. Item should be of [supported type](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)
20

H
Helin Wang 已提交
21
An example implementation for single item data reader creator:
22

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

H
Helin Wang 已提交
31
An example implementation for multiple item data reader creator:
H
Helin Wang 已提交
32
```python
H
Helin Wang 已提交
33 34 35 36 37
def reader_creator_random_imageand_label(widht, height, label):
	def reader():
		while True:
			yield numpy.random.uniform(-1, 1, size=width*height), label
	return reader
38
```
H
Helin Wang 已提交
39

40 41
## Usage

42
data reader, mapping from item(s) read to data layer, batch size and number of total pass will be passed into `paddle.train`:
43 44 45 46 47 48 49 50 51 52 53

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

# ...

paddle.train(paddle.dataset.mnist, {"image":0, "label":1}, 128, 10, ...)
```

54
## Data Reader Decorator
H
Helin Wang 已提交
55

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

58
Since we have a strict interface for data readers (no parameter, return a single data item). Data reader can be used flexiable via data reader decorators. Following are a few examples:
H
Helin Wang 已提交
59 60 61 62 63 64 65 66

### Prefetch Data

Since reading data may take time and training can not proceed without data. It is generally a good idea to prefetch data.

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

```python
67
buffered_reader = paddle.reader.buffered(paddle.dataset.mnist, 100)
H
Helin Wang 已提交
68 69
```

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

72
### Compose Multiple Data Readers
H
Helin Wang 已提交
73

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

We can do:

```python
H
Helin Wang 已提交
79 80 81 82 83
def reader_creator_random_image(width, height):
	def reader():
		while True:
			yield numpy.random.uniform(-1, 1, size=width*height)
	return reader
H
Helin Wang 已提交
84

H
Helin Wang 已提交
85
def reader_creator_bool(t):
86
	def reader:
87 88
		while True:
			yield t
89
	return reader
H
Helin Wang 已提交
90

H
Helin Wang 已提交
91 92
true_reader = reader_creator_bool(True)
false_reader = reader_creator_bool(False)
H
Helin Wang 已提交
93

H
Helin Wang 已提交
94
reader = paddle.reader.compose(paddle.dataset.mnist, data_reader_creator_random_image(20, 20), true_reader, false_reader)
95 96
# Skipped 1 because paddle.dataset.mnist produces two items per data entry.
# And we don't care second item at this time.
97
paddle.train(reader, {"true_image":0, "fake_image": 2, "true_label": 3, "false_label": 4}, ...)
H
Helin Wang 已提交
98 99 100 101
```

### Shuffle

102
Given shuffle buffer size `n`, `paddle.reader.shuffle` will return a data reader that buffers `n` data entries and shuffle them before a data entry is read.
H
Helin Wang 已提交
103 104 105

Example:
```python
106
reader = paddle.reader.shuffle(paddle.dataset.mnist, 512)
107 108 109 110 111 112
```

## Q & A

### Why return only a single entry, but not a mini batch?

113
If a mini batch is returned, data reader need to take care of batch size. But batch size is a concept for training, it makes more sense for user to specify batch size as a parameter for `train`.
114

115
Practically, always return a single entry make reusing existing data readers much easier (e.g., if existing reader return not a single entry but 3 entries, training code will be more complex because it need to handle cases like batch size 2).
116

H
Helin Wang 已提交
117 118 119 120
### Why use a dictionary but not a list to provide mapping?

We decided to use dictionary (`{"image":0, "label":1}`) instead of list (`["image", "label"]`) is because that user can easily resue item (e.g., using `{"image_a":0, "image_b":0, "label":1}`) or skip item (e.g., using `{"image_a":0, "label":2}`).

H
Helin Wang 已提交
121
### How to create custom data reader creator
122 123

```python
124
def image_reader_creator(image_path, label_path, n):
125
	def reader():
126 127 128 129 130 131 132 133 134 135
		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()
136
	return reader
137

138 139 140
# images_reader_creator creates a reader
reader = image_reader_creator("/path/to/image_file", "/path/to/label_file", 1024)
paddle.train(reader, {"image":0, "label":1}, ...)
141 142 143 144 145 146 147
```

### How is `paddle.train` implemented

An example implementation of paddle.train could be:

```python
H
Helin Wang 已提交
148
def make_minibatch(reader, minibatch_size):
149
	def ret():
150
		r = reader()
151 152 153 154 155
		buf = [r.next() for x in xrange(minibatch_size)]
		while len(buf) > 0:
			yield buf
			buf = [r.next() for x in xrange(minibatch_size)]
	return ret
156

157
def train(reader, mapping, batch_size, total_pass):
158
	for pass_idx in range(total_pass):
H
Helin Wang 已提交
159
		for mini_batch in make_minibatch(reader): # this loop will never end in online learning.
160 161
			do_forward_backward(mini_batch, mapping)
```