未验证 提交 a342aa1f 编写于 作者: K Kaipeng Deng 提交者: GitHub

Add dataloader doc (#2606)

* add paddle.io. test=develop

* fix indent. test=develop
上级 f4ae9411
......@@ -2,6 +2,64 @@
BatchSampler
-------------------------------
:doc_source: paddle.fluid.dataloader.BatchSampler
.. py:class:: paddle.io.BatchSampler(dataset=None, sampler=None, shuffle=Fasle, batch_size=1, drop_last=False)
批采样器的基础实现,用于 ``paddle.io.DataLoader`` 中迭代式获取mini-batch的样本下标数组,数组长度与 ``batch_size`` 一致。
所有用于 ``paddle.io.DataLoader`` 中的批采样器都必须是 ``paddle.io.BatchSampler`` 的子类并实现以下方法:
``__iter__``: 迭代式返回批样本下标数组。
``__len__``: 每epoch中mini-batch数。
参数:
- **dataset** (Dataset) - 此参数必须是 ``paddle.io.Dataset`` 或 ``paddle.io.IterableDataset`` 的一个子类实例或实现了 ``__len__`` 的Python对象,用于生成样本下标。默认值为None。
- **sampler** (Sampler) - 此参数必须是 ``paddle.io.Sampler`` 的子类实例,用于迭代式获取样本下标。``dataset`` 和 ``sampler`` 参数只能设置一个。默认值为None。
- **shuffle** (bool) - 是否需要在生成样本下标时打乱顺序。默认值为False。
- **batch_size** (int) - 每mini-batch中包含的样本数。默认值为1。
- **drop_last** (bool) - 是否需要丢弃最后无法凑整一个mini-batch的样本。默认值为False。
见 ``paddle.io.DataLoader`` 。
返回:返回样本下标数组的迭代器。
返回类型: BatchSampler
**代码示例**
.. code-block:: python
from paddle.io import RandomSampler, BatchSampler, Dataset
# init with dataset
class RandomDataset(Dataset):
def __init__(self, num_samples):
self.num_samples = num_samples
def __getitem__(self, idx):
image = np.random.random([784]).astype('float32')
label = np.random.randint(0, 9, (1, )).astype('int64')
return image, label
def __len__(self):
return self.num_samples
bs = BatchSampler(dataset=RandomDataset(100),
shuffle=False,
batch_size=16,
drop_last=False)
for batch_indices in bs:
print(batch_indices)
# init with sampler
sampler = RandomSampler(RandomDataset(100))
bs = BatchSampler(sampler=sampler,
shuffle=True,
batch_size=8,
drop_last=True)
for batch_indices in bs:
print(batch_indices)
......@@ -3,10 +3,139 @@
DataLoader
-------------------------------
.. py:class:: paddle.fluid.io.DataLoader
.. py:class:: paddle.fluid.io.DataLoader(dataset, feed_list=None, places=None, return_list=False, batch_sampler=None, batch_size=1, shuffle=False, drop_last=False, collate_fn=None, num_workers=0, use_buffer_reader=True, use_shared_memory=False, timeout=0, worker_init_fn=None)
DataLoader返回一个迭代器,该迭代器根据 ``batch_sampler`` 给定的顺序迭代一次给定的 ``dataset``
DataLoader支持单进程和多进程的数据加载方式,当 ``num_workers`` 大于0时,将使用多进程方式异步加载数据。
DataLoader当前仅支持 ``map-style`` 的数据集(可通过下标索引样本), ``map-style`` 的数据集请参考 ``paddle.io.Dataset`` 。
``batch_sampler`` 请参考 ``fluid.io.BatchSampler``
参数:
- **dataset** (Dataset) - DataLoader从此参数给定数据集中加载数据,此参数必须是 ``paddle.io.Dataset`` 或 ``paddle.io.IterableDataset`` 的一个子类实例。
- **feed_list** (list(Tensor)|tuple(Tensor)) - feed变量列表,由 ``fluid.layers.data()`` 创建。当 ``return_list`` 为False时,此参数必须设置。默认值为None。
- **places** (list(Place)|tuple(Place)) - 数据需要放置到的Place列表。在静态图和动态图模式中,此参数均必须设置。在动态图模式中,此参数列表长度必须是1。默认值为None。
- **return_list** (bool) - 每个设备上的数据是否以list形式返回。若return_list = False,每个设备上的返回数据均是str -> Tensor的映射表,其中映射表的key是每个输入变量的名称。若return_list = True,则每个设备上的返回数据均是list(Tensor)。在动态图模式下,此参数必须为True。默认值为False。
- **batch_sampler** (BatchSampler) - ``fluid.io.BatchSampler`` 或其子类的实例,DataLoader通过 ``batch_sampler`` 产生的mini-batch索引列表来 ``dataset`` 中索引样本并组成mini-batch。默认值为None。
- **batch_size** (int) - 每mini-batch中样本个数,为 ``batch_sampler`` 的替代参数,若 ``batch_sampler`` 未设置,会根据 ``batch_size`` ``shuffle`` ``drop_last`` 创建一个 ``fluid.io.BatchSampler`` 。默认值为1。
- **shuffle** (bool) - 生成mini-batch索引列表时是否对索引打乱顺序,为 ``batch_sampler`` 的替代参数,若 ``batch_sampler`` 未设置,会根据 ``batch_size`` ``shuffle`` ``drop_last`` 创建一个 ``fluid.io.BatchSampler`` 。默认值为False。
- **drop_last** (bool) - 是否丢弃因数据集样本数不能被 ``batch_size`` 整除而产生的最后一个不完整的mini-batch,为 ``batch_sampler`` 的替代参数,若 ``batch_sampler`` 未设置,会根据 ``batch_size`` ``shuffle`` ``drop_last`` 创建一个 ``fluid.io.BatchSampler`` 。默认值为False。
- **collate_fn** (callable) - 通过此参数指定如果将样本列表组合为mini-batch数据,当 ``collate_fn`` 为None时,默认为将样本个字段在第0维上堆叠(同 ``np.stack(..., axis=0)`` )为mini-batch的数据。默认值为None。
- **num_workers** (int) - 用于加载数据的子进程个数,若为0即为不开启子进程,在主进程中进行数据加载。默认值为0。
- **use_buffer_reader** (bool) - 是否使用缓存读取器 。若 ``use_buffer_reader`` 为True,DataLoader会异步地预读取下一个mini-batch的数据,可加速数据读取过程,但同时会占用少量的CPU/GPU存储,即一个batch输入数据的存储空间。默认值为True。
- **use_shared_memory** (bool) - 是否使用共享内存来提升子进程将数据放入进程间队列的速度,该参数尽在多进程模式下有效(即 ``num_workers > 0`` ),请确认机器上有足够的共享内存空间(如Linux系统下 ``/dev/shm/`` 目录空间大小)再设置此参数。默认为False。
- **timeout** (int) - 从子进程输出队列获取mini-batch数据的超时时间。默认值为0。
- **worker_init_fn** (callable) - 子进程初始化函数,此函数会被子进程初始化时被调用,并传递 ``worker id`` 作为参数。默认值为None。
返回:迭代 ``dataset`` 数据的迭代器
返回类型: DataLoader
**代码示例**
.. code-block:: python
import numpy as np
import paddle.fluid as fluid
from paddle.io import Dataset, BatchSampler, DataLoader
BATCH_NUM = 20
BATCH_SIZE = 16
EPOCH_NUM = 4
IMAGE_SIZE = 784
CLASS_NUM = 10
USE_GPU = True # whether use GPU to run model
# define a random dataset
class RandomDataset(Dataset):
def __init__(self, num_samples):
self.num_samples = num_samples
def __getitem__(self, idx):
image = np.random.random([IMAGE_SIZE]).astype('float32')
label = np.random.randint(0, CLASS_NUM - 1, (1, )).astype('int64')
return image, label
def __len__(self):
return self.num_samples
# get places
places = fluid.cuda_places() if USE_GPU else fluid.cpu_places()
# -------------------- static graph ---------------------
def simple_net(image, label):
fc_tmp = fluid.layers.fc(image, size=CLASS_NUM, act='softmax')
cross_entropy = fluid.layers.softmax_with_cross_entropy(image, label)
loss = fluid.layers.reduce_mean(cross_entropy)
sgd = fluid.optimizer.SGD(learning_rate=1e-3)
sgd.minimize(loss)
return loss
image = fluid.data(name='image', shape=[None, IMAGE_SIZE], dtype='float32')
label = fluid.data(name='label', shape=[None, 1], dtype='int64')
loss = simple_net(image, label)
exe = fluid.Executor(places[0])
exe.run(fluid.default_startup_program())
prog = fluid.CompiledProgram(fluid.default_main_program()).with_data_parallel(loss_name=loss.name)
dataset = RandomDataset(BATCH_NUM * BATCH_SIZE)
loader = DataLoader(dataset,
feed_list=[image, label],
places=places,
batch_size=BATCH_SIZE,
shuffle=True,
drop_last=True,
num_workers=2)
for e in range(EPOCH_NUM):
for i, data in enumerate(loader()):
l = exe.run(prog, feed=data, fetch_list=[loss], return_numpy=True)
print("Epoch {} batch {}: loss = {}".format(e, i, l[0][0]))
# -------------------------------------------------------
# -------------------- dynamic graph --------------------
class SimpleNet(fluid.dygraph.Layer):
def __init__(self):
super(SimpleNet, self).__init__()
self.fc = fluid.dygraph.nn.Linear(IMAGE_SIZE, CLASS_NUM, act='softmax')
def forward(self, image, label=None):
return self.fc(image)
with fluid.dygraph.guard(places[0]):
simple_net = SimpleNet()
opt = fluid.optimizer.SGD(learning_rate=1e-3,
parameter_list=simple_net.parameters())
loader = DataLoader(dataset,
places=places[0],
batch_size=BATCH_SIZE,
shuffle=True,
drop_last=True,
num_workers=2)
for e in range(EPOCH_NUM):
for i, (image, label) in enumerate(loader()):
out = simple_net(image)
loss = fluid.layers.cross_entropy(out, label)
avg_loss = fluid.layers.reduce_mean(loss)
avg_loss.backward()
opt.minimize(avg_loss)
simple_net.clear_gradients()
print("Epoch {} batch {}: loss = {}".format(e, i, np.mean(loss.numpy())))
# -------------------------------------------------------
.. py:method:: from_generator(feed_list=None, capacity=None, use_double_buffer=True, iterable=True, return_list=False, use_multiprocess=False, drop_last=True)
......
.. _cn_api_io_Dataset:
.. _cn_api_io_cn_Dataset:
Dataset
-------------------------------
.. py:class:: paddle.io.Dataset()
.. py:class:: paddle.io.Dataset
概述Dataset的方法和行为的抽象类。
映射式(map-style)数据集需要继承这个基类,映射式数据集为可以通过一个键值索引并获取指定样本的数据集,所有映射式数据集须实现以下方法:
``__getitem__``: 根据给定索引获取数据集中指定样本,在 ``paddle.io.DataLoader`` 中需要使用此函数通过下标获取样本。
``__len__``: 返回数据集样本个数, ``paddle.io.BatchSampler`` 中需要样本个数生成下标序列。
见 ``paddle.io.DataLoader`` 。
**代码示例**
.. code-block:: python
import numpy as np
from paddle.io import Dataset
# define a random dataset
class RandomDataset(Dataset):
def __init__(self, num_samples):
self.num_samples = num_samples
def __getitem__(self, idx):
image = np.random.random([784]).astype('float32')
label = np.random.randint(0, 9, (1, )).astype('int64')
return image, label
def __len__(self):
return self.num_samples
dataset = RandomDataset(10)
for i in range(len(dataset)):
print(dataset[i])
待补充
.. _cn_api_io_IterableDataset:
.. _cn_api_io_cn_IterableDataset:
IterableDataset
-------------------------------
.. py:class:: paddle.io.IterableDataset()
.. py:class:: paddle.io.IterableDataset
待补充
概述迭代式数据集的方法和行为的抽象类。
参数
:::::::::
迭代式(iterable style)数据集需要继承这个基类,迭代式数据集为只能依次迭代式获取样本的数据集,类似Python中的迭代器,所有迭代式数据集须实现以下方法:
``__iter__``: 依次返回数据赝本。
.. note::
迭代式数据集不需要实现 ``__getitem__`` 和 ``__len__``,也不可以调用迭代式数据集的这两个方法。
代码示例
:::::::::
见 ``paddle.io.DataLoader`` 。
**代码示例**
.. code-block:: python
import numpy as np
from paddle.io import Dataset
# define a random dataset
class RandomDataset(Dataset):
def __init__(self, num_samples):
self.num_samples = num_samples
def __iter__(self):
for i in range(self.num_samples):
image = np.random.random([784]).astype('float32')
label = np.random.randint(0, 9, (1, )).astype('int64')
yield image, label
dataset = RandomDataset(10)
for img, lbl in dataset:
print(img, lbl)
当 ``paddle.io.DataLoader`` 中 ``num_workers > 0`` 时,每个子进程都会遍历全量的数据集返回全量样本,所以数据集会重复 ``num_workers``
次,如果需要数据集样本不会重复返回,可通过如下两种方法避免样本重复,两种方法中都需要通过 ``paddle.io.get_worker_info`` 获取各子进程的信息。
1. 通过 ``__iter__`` 函数划分各子进程的数据
**代码示例1**
.. code-block:: python
import math
import numpy as np
import paddle.fluid as fluid
from paddle.io import IterableDataset, DataLoader, get_worker_info
class SplitedIterableDataset(IterableDataset):
def __init__(self, start, end):
self.start = start
self.end = end
def __iter__(self):
worker_info = get_worker_info()
if worker_info is None:
iter_start = self.start
iter_end = self.end
else:
per_worker = int(
math.ceil((self.end - self.start) / float(
worker_info.num_workers)))
worker_id = worker_info.id
iter_start = self.start + worker_id * per_worker
iter_end = min(iter_start + per_worker, self.end)
for i in range(iter_start, iter_end):
yield np.array([i])
place = fluid.CPUPlace()
with fluid.dygraph.guard(place):
dataset = SplitedIterableDataset(start=2, end=9)
dataloader = DataLoader(
dataset,
places=place,
num_workers=2,
batch_size=1,
drop_last=True)
print(list(dataloader))
# outputs: [2, 5, 3, 6, 4, 7]
2. 通过各子进程初始化函数 ``worker_inif_fn`` 划分子进程数据
**代码示例2**
.. code-block:: python
import math
import numpy as np
import paddle.fluid as fluid
from paddle.io import IterableDataset, DataLoader, get_worker_info
class RangeIterableDataset(IterableDataset):
def __init__(self, start, end):
self.start = start
self.end = end
def __iter__(self):
for i in range(self.start, self.end):
yield np.array([i])
place = fluid.CPUPlace()
with fluid.dygraph.guard(place):
dataset = RangeIterableDataset(start=2, end=9)
def worker_init_fn(worker_id):
worker_info = get_worker_info()
dataset = worker_info.dataset
start = dataset.start
end = dataset.end
num_per_worker = int(
math.ceil((end - start) / float(worker_info.num_workers)))
worker_id = worker_info.id
dataset.start = start + worker_id * num_per_worker
dataset.end = min(dataset.start + num_per_worker, end)
dataloader = DataLoader(
dataset,
places=place,
num_workers=2,
batch_size=1,
drop_last=True,
worker_init_fn=worker_init_fn)
print(list(dataloader))
# outputs: [2, 5, 3, 6, 4, 7]
.. _cn_api_io_cn_RandomSampler:
RandomSampler
-------------------------------
.. py:class:: paddle.io.RandomSampler(data_source=None, replacement=False, num_samples=None, generator=None)
顺序迭代 ``data_source`` 返回样本下标,即一次返回 ``0, 1, 2, ..., len(data_source) - 1``
参数:
- **data_source** (Dataset) - 此参数必须是 ``paddle.io.Dataset`` 或 ``paddle.io.IterableDataset`` 的一个子类实例或实现了 ``__len__`` 的Python对象,用于生成样本下标。默认值为None。
- **replacement** (bool) - 如果为 ``False`` 则会采样整个数据集,如果为 ``True`` 则会按 ``num_samples`` 指定的样本数采集。默认值为 ``False`` 。
- **num_samples** (int) - 如果 ``replacement`` 设置为 ``True`` 则按此参数采集对应的样本数。默认值为None。
- **generator** (Generator) - 指定采样 ``data_source`` 的采样器。默认值为None。
返回: 返回随机采样下标的采样器
返回类型: RandomSampler
**代码示例**
.. code-block:: python
from paddle.io import Dataset, RandomSampler
class RandomDataset(Dataset):
def __init__(self, num_samples):
self.num_samples = num_samples
def __getitem__(self, idx):
image = np.random.random([784]).astype('float32')
label = np.random.randint(0, 9, (1, )).astype('int64')
return image, label
def __len__(self):
return self.num_samples
sampler = RandomSampler(data_souce=RandomDataset(100))
for index in sampler:
print(index)
.. _cn_api_io_cn_Sampler:
Sampler
-------------------------------
.. py:class:: paddle.io.Sampler(data_source=None)
概括数据集采样器行为和方法的基类。
所有数据集采样器必须继承这个基类,并实现以下方法:
``__iter__``: 迭代返回数据样本下标
``__len__``: ``data_source`` 中的样本数
参数:
- **data_source** (Dataset) - 此参数必须是 ``paddle.io.Dataset`` 或 ``paddle.io.IterableDataset`` 的一个子类实例或实现了 ``__len__`` 的Python对象,用于生成样本下标。默认值为None。
可见 ``paddle.io.BatchSampler`` 和 ``paddle.io.DataLoader``
返回:返回样本下标的迭代器。
返回类型: Sampler
**代码示例**
.. code-block:: python
from paddle.io import Dataset, Sampler
class RandomDataset(Dataset):
def __init__(self, num_samples):
self.num_samples = num_samples
def __getitem__(self, idx):
image = np.random.random([784]).astype('float32')
label = np.random.randint(0, 9, (1, )).astype('int64')
return image, label
def __len__(self):
return self.num_samples
class MySampler(Sampler):
def __init__(self, data_source):
self.data_source = data_source
def __iter__(self):
return iter(range(len(self.data_source)))
def __len__(self):
return len(self.data_source)
sampler = MySampler(data_source=RandomDataset(100))
for index in sampler:
print(index)
.. _cn_api_io_cn_SequenceSampler:
SequenceSampler
-------------------------------
.. py:class:: paddle.io.SequenceSampler(data_source=None)
顺序迭代 ``data_source`` 返回样本下标,即一次返回 ``0, 1, 2, ..., len(data_source) - 1``
参数:
- **data_source** (Dataset) - 此参数必须是 ``paddle.io.Dataset`` 或 ``paddle.io.IterableDataset`` 的一个子类实例或实现了 ``__len__`` 的Python对象,用于生成样本下标。默认值为None。
返回:返回样本下标的迭代器。
返回类型: SequenceSampler
**代码示例**
.. code-block:: python
from paddle.io import Dataset, SequenceSampler
class RandomDataset(Dataset):
def __init__(self, num_samples):
self.num_samples = num_samples
def __getitem__(self, idx):
image = np.random.random([784]).astype('float32')
label = np.random.randint(0, 9, (1, )).astype('int64')
return image, label
def __len__(self):
return self.num_samples
sampler = SequenceSampler(data_source=RandomDataset(100))
for index in sampler:
print(index)
.. _cn_api_io_cn_get_worker_info:
get_worker_info
-------------------------------
.. py:class:: paddle.io.get_worker_info
获取 ``paddle.io.DataLoader`` 子进程信息的函数,用于 ``paddle.io.IterableDataset`` 中划分子进程数据。子进程信息包含以下字段:
``num_workers``: 子进程数。
``id``: 子进程逻辑序号,从0到 ``num_workers - 1``
``dataset``: 各子进程中数据集实例。
示例代码见 ``paddle.io.IterableDataset``
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册