Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
FluidDoc
提交
1a92bbad
F
FluidDoc
项目概览
PaddlePaddle
/
FluidDoc
通知
5
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
23
列表
看板
标记
里程碑
合并请求
111
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
F
FluidDoc
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
23
Issue
23
列表
看板
标记
里程碑
合并请求
111
合并请求
111
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
1a92bbad
编写于
6月 12, 2019
作者:
Z
Zeng Jinle
提交者:
GitHub
6月 12, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
polish data reader API for release/1.5 (#891)
上级
f01477b1
变更
2
显示空白变更内容
内联
并排
Showing
2 changed file
with
181 addition
and
133 deletion
+181
-133
doc/fluid/user_guides/howto/prepare_data/index_cn.rst
doc/fluid/user_guides/howto/prepare_data/index_cn.rst
+45
-22
doc/fluid/user_guides/howto/prepare_data/use_py_reader.rst
doc/fluid/user_guides/howto/prepare_data/use_py_reader.rst
+136
-111
未找到文件。
doc/fluid/user_guides/howto/prepare_data/index_cn.rst
浏览文件 @
1a92bbad
...
...
@@ -4,7 +4,7 @@
准备数据
########
使用PaddlePaddle Fluid准备数据分为
两
个步骤:
使用PaddlePaddle Fluid准备数据分为
三
个步骤:
Step1: 自定义Reader生成训练/预测数据
###################################
...
...
@@ -16,32 +16,55 @@ Batch级的Reader每次返回一个Batch的数据,Sample级的Reader每次返
如果您的数据是Sample级的数据,我们提供了一个可以数据预处理和组建batch的工具::code:`Python Reader` 。
Step2:
将数据送入网络进行训练/预测
Step2:
在网络配置中定义数据层变量
###################################
用户需使用 :code:`fluid.layers.data` 在网络中定义数据层变量。定义数据层变量时需指明数据层的名称name、数据类型dtype和维度shape。例如:
Fluid提供两种方式,分别是同步Feed方式或异步py_reader接口方式,具体介绍如下:
.. code-block:: python
import paddle.fluid as fluid
image = fluid.layers.data(name='image', dtype='float32', shape=[28, 28])
label = fluid.layers.data(name='label', dtype='int64', shape=[1])
需要注意的是,此处的shape是单个样本的维度,PaddlePaddle Fluid会在shape第0维位置添加-1,表示batch_size的维度,即此例中image.shape为[-1, 28, 28],
label.shape为[-1, 1]。
若用户不希望框架在第0维位置添加-1,则可通过append_batch_size=False参数控制,即:
.. code-block:: python
import paddle.fluid as fluid
image = fluid.layers.data(name='image', dtype='float32', shape=[28, 28], append_batch_size=False)
label = fluid.layers.data(name='label', dtype='int64', shape=[1], append_batch_size=False)
此时,image.shape为[28, 28],label.shape为[1]。
Step3: 将数据送入网络进行训练/预测
###################################
Fluid提供两种方式,分别是异步PyReader接口方式或同步Feed方式,具体介绍如下:
- 异步PyReader接口方式
用户需要先使用 :code:`fluid.io.PyReader` 定义PyReader对象,然后通过PyReader对象的decorate方法设置数据源。
使用PyReader接口时,数据传入与模型训练/预测过程是异步进行的,效率较高,推荐使用。
- 同步Feed方式
用户需使用 :code:`fluid.layers.data`
配置数据输入层,并在 :code:`fluid.Executor` 或 :code:`fluid.ParallelExecutor`
用户自行构造输入数据,并在 :code:`fluid.Executor` 或 :code:`fluid.ParallelExecutor`
中使用 :code:`executor.run(feed=...)` 传入训练数据。数据准备和模型训练/预测的过程是同步进行的,
效率较低。
- 异步py_reader接口方式
用户需要先使用 :code:`fluid.layers.py_reader` 配置数据输入层,然后使用
:code:`py_reader` 的 :code:`decorate_paddle_reader` 或 :code:`decorate_tensor_provider`
方法配置数据源,再通过 :code:`fluid.layers.read_file` 读取数据。数据传入与模型训练/预测过程是异步进行的,
效率较高。
这两种准备数据方法的比较如下:
======== ================================= =====================================
对比项 同步Feed方式 异步
py_r
eader接口方式
对比项 同步Feed方式 异步
PyR
eader接口方式
======== ================================= =====================================
API接口 :code:`executor.run(feed=...)`
:code:`fluid.layers.py_r
eader`
API接口 :code:`executor.run(feed=...)`
:code:`fluid.io.PyR
eader`
数据格式 Numpy Array或LoDTensor Numpy Array或LoDTensor
数据增强 Python端使用其他库完成 Python端使用其他库完成
速度 慢 快
...
...
@@ -51,7 +74,7 @@ API接口 :code:`executor.run(feed=...)` :code:`fluid.layers.py_reader
Reader数据类型对使用方式的影响
###############################
根据Reader数据类型的不同,上述
Step1和Step2
的具体操作将有所不同,具体介绍如下:
根据Reader数据类型的不同,上述
步骤
的具体操作将有所不同,具体介绍如下:
读取Sample级Reader数据
+++++++++++++++++++++
...
...
@@ -71,12 +94,12 @@ Step1. 组建数据
Step2. 送入数据
=================================
若使用同步Feed方式送入数据,请使用DataFeeder接口将Reader数据转换为LoDTensor格式后送入网络,具体请参见 :ref:`cn_api_fluid_DataFeeder`
若使用异步py_reader接口方式送入数据,请调用 :code:`decorate_paddle_reader` 接口完成,具体请参见:
若使用异步PyReader接口方式送入数据,请调用 :code:`decorate_sample_generator` 或 :code:`decorate_sample_list_generator` 接口完成,具体请参见:
- :ref:`user_guides_use_py_reader`
若使用同步Feed方式送入数据,请使用DataFeeder接口将Reader数据转换为LoDTensor格式后送入网络,具体请参见 :ref:`cn_api_fluid_DataFeeder`
读取Batch级Reader数据
+++++++++++++++++++++++
...
...
@@ -88,19 +111,19 @@ Step1. 组建数据
Step2. 送入数据
=================================
若使用
同步Feed方式送入数据,具体
请参见:
若使用
异步PyReader接口方式送入数据,请调用PyReader的 :code:`decorate_batch_generator` 接口完成,具体方式
请参见:
.. toctree::
:maxdepth: 1
feeding_data
.rst
use_py_reader
.rst
若使用
异步py_reader接口方式送入数据,请调用py_reader的 :code:`decorate_tensor_provider` 接口完成,具体方式
请参见:
若使用
同步Feed方式送入数据,具体
请参见:
.. toctree::
:maxdepth: 1
use_py_reader
.rst
feeding_data
.rst
...
...
doc/fluid/user_guides/howto/prepare_data/use_py_reader.rst
浏览文件 @
1a92bbad
...
...
@@ -15,33 +15,22 @@
import paddle.fluid as fluid
py_reader = fluid.layers.py_reader(capacity=64,
shapes=[(-1,784), (-1,1)],
dtypes=['float32', 'int64'],
name='py_reader',
use_double_buffer=True)
image = fluid.layers.data(name='image', dtype='float32', shape=[784])
label = fluid.layers.data(name='label', dtype='int64', shape=[1])
其中,capacity为PyReader对象的缓存区大小;shapes为batch各参量(如图像分类任务中的image和label)的尺寸;dtypes为batch各参量的数据类型;name为PyReader对象的名称;use_double_buffer默认为True,表示使用 :code:`double_buffer_reader` ,建议开启,可提升数据读取速度。
ITERABLE = True
需要注意的是:如果您要创建多个不同PyReader对象(例如训练和预测阶段需创建两个不同的PyReader),则需要必须给不同的PyReader对象指定不同的name。这是因为PaddlePaddle采用不同的变量名区分不同的变量,而且 `Program.clone()` (参见 :ref:`cn_api_fluid_Program_clone` )不能实现PyReader对象的复制。
py_reader = fluid.io.PyReader(feed_list=[image, label], capacity=64, use_double_buffer=True, iterable=ITERABLE)
.. code-block:: python
import paddle.fluid as fluid
train_py_reader = fluid.layers.py_reader(capacity=64,
shapes=[(-1,784), (-1,1)],
dtypes=['float32', 'int64'],
name='train',
use_double_buffer=True)
其中,
test_py_reader = fluid.layers.py_reader(capacity=64,
shapes=[(-1,3,224,224), (-1,1)],
dtypes=['float32', 'int64'],
name='test',
use_double_buffer=True)
- feed_list为需要输入的数据层变量列表;
- capacity为PyReader对象的缓存区大小;
- use_double_buffer默认为True,表示使用 :code:`double_buffer_reader` 。建议开启,可提升数据读取速度;
- iterable默认为True,表示该PyReader对象是可For-Range迭代的。当iterable=True时,PyReader与Program解耦,定义PyReader对象不会改变Program;当iterable=False时,PyReader会在Program中插入数据读取相关的op。
在使用PyReader时,如果需要共享训练阶段和测试阶段的模型参数,您可以通过 :code:`fluid.unique_name.guard()` 的方式来实现。
需要注意的是:`Program.clone()` (参见 :ref:`cn_api_fluid_Program_clone` )不能实现PyReader对象的复制。如果您要创建多个不同PyReader对象(例如训练和预测阶段需创建两个不同的PyReader),则需重定义两个PyReader对象。
若需要共享训练阶段和测试阶段的模型参数,您可以通过 :code:`fluid.unique_name.guard()` 的方式来实现。
注:Paddle采用变量名区分不同变量,且变量名是根据 :code:`unique_name` 模块中的计数器自动生成的,每生成一个变量名计数值加1。 :code:`fluid.unique_name.guard()` 的作用是重置 :code:`unique_name` 模块中的计数器,保证多次调用 :code:`fluid.unique_name.guard()` 配置网络时对应变量的变量名相同,从而实现参数共享。
下面是一个使用PyReader配置训练阶段和测试阶段网络的例子:
...
...
@@ -52,19 +41,11 @@
import paddle.fluid as fluid
import paddle.dataset.mnist as mnist
def network(is_train):
# Create py_reader object and give different names
# when is_train = True and is_train = False
reader = fluid.layers.py_reader(
capacity=10,
shapes=((-1, 784), (-1, 1)),
dtypes=('float32', 'int64'),
name="train_reader" if is_train else "test_reader",
use_double_buffer=True)
# Use read_file() method to read out the data from py_reader
img, label = fluid.layers.read_file(reader)
...
def network():
image = fluid.layers.data(name='image', dtype='float32', shape=[784])
label = fluid.layers.data(name='label', dtype='int64', shape=[1])
reader = fluid.io.PyReader(feed_list=[image, label], capacity=64)
# Here, we omitted the definition of loss of the model
return loss , reader
...
...
@@ -75,7 +56,7 @@
with fluid.program_guard(train_prog, train_startup):
# Use fluid.unique_name.guard() to share parameters with test network
with fluid.unique_name.guard():
train_loss, train_reader = network(
True
)
train_loss, train_reader = network()
adam = fluid.optimizer.Adam(learning_rate=0.01)
adam.minimize(train_loss)
...
...
@@ -85,66 +66,99 @@
with fluid.program_guard(test_prog, test_startup):
# Use fluid.unique_name.guard() to share parameters with train network
with fluid.unique_name.guard():
test_loss, test_reader = network(
False
)
test_loss, test_reader = network()
设置PyReader对象的数据源
################################
PyReader对象通过 :code:`decorate_paddle_reader()` 或 :code:`decorate_tensor_provider()` 方法设置其数据源。 :code:`decorate_paddle_reader()` 和 :code:`decorate_tensor_provider()` 均接收Python生成器 :code:`generator` 作为参数, :code:`generator` 内部每次通过yield的方式生成一个batch的数据。
PyReader对象通过 :code:`decorate_sample_generator()` , :code:`decorate_sample_list_generator` 和 :code:`decorate_batch_generator()` 方法设置其数据源。
这三个方法均接收Python生成器 :code:`generator` 作为参数,其区别在于:
- :code:`decorate_sample_generator()` 要求 :code:`generator` 返回的数据格式为[img_1, label_1],其中img_1和label_1为单个样本的Numpy Array类型数据。
:code:`decorate_paddle_reader()` 和 :code:`decorate_tensor_provider()` 方法的区别在于:
- :code:`decorate_sample_list_generator()` 要求 :code:`generator` 返回的数据格式为[(img_1, label_1), (img_2, label_2), ..., (img_n, label_n)],其中img_i和label_i均为每个样本的Numpy Array类型数据,n为batch size。
- :code:`decorate_
paddle_reader()` 要求 :code:`generator` 返回的数据格式为[(img_1, label_1), (img_2, label_2), ..., (img_n, label_n)],其中img_i和label_i均为每个样本的Numpy Array类型数据,n为batch size。而 :code:`decorate_tensor_provide
r()` 要求 :code:`generator` 返回的数据的数据格式为[batched_imgs, batched_labels],其中batched_imgs和batched_labels为batch级的Numpy Array或LoDTensor类型数据。
- :code:`decorate_
batch_generato
r()` 要求 :code:`generator` 返回的数据的数据格式为[batched_imgs, batched_labels],其中batched_imgs和batched_labels为batch级的Numpy Array或LoDTensor类型数据。
- :code:`decorate_tensor_provider()` 要求 :code:`generator` 返回的数据类型、尺寸必须与配置py_reader时指定的dtypes、shapes参数相同,而 :code:`decorate_paddle_reader()` 不要求数据类型和尺寸的严格一致,其内部会完成数据类型和尺寸的转换。
当PyReader的iterable=True(默认)时,必须给这三个方法传 :code:`places` 参数,
指定将读取的数据转换为CPU Tensor还是GPU Tensor。当PyReader的iterable=False时,不需传places参数。
具体方式为:
例如,假设我们有两个reader,其中fake_sample_reader每次返回一个sample的数据,fake_batch_reader每次返回一个batch的数据。
.. code-block:: python
import paddle.batch
import paddle.fluid as fluid
import numpy as np
BATCH_SIZE = 32
# sample级reader
def fake_sample_reader():
for _ in range(100):
sample_image = np.random.random(size=(784, )).astype('float32')
sample_label = np.random.random_integers(size=(1, ), low=0, high=9).astype('int64')
yield sample_image, sample_label
# batch级reader
def fake_batch_reader():
batch_size = 32
for _ in range(100):
batch_image = np.random.random(size=(batch_size, 784)).astype('float32')
batch_label = np.random.random_integers(size=(batch_size, 1), low=0, high=9).astype('int64')
yield batch_image, batch_label
# Case 1: Use decorate_paddle_reader() method to set the data source of py_reader
# The generator yields Numpy-typed batched data
def fake_random_numpy_reader():
image = np.random.random(size=(784, ))
label = np.random.random_integers(size=(1, ), low=0, high=9)
yield image, label
image1 = fluid.layers.data(name='image1', dtype='float32', shape=[784])
label1 = fluid.layers.data(name='label1', dtype='int64', shape=[1])
py_reader1 = fluid.layers.py_reader(
capacity=10,
shapes=((-1, 784), (-1, 1)),
dtypes=('float32', 'int64'),
name='py_reader1',
use_double_buffer=True)
image2 = fluid.layers.data(name='image2', dtype='float32', shape=[784])
label2 = fluid.layers.data(name='label2', dtype='int64', shape=[1])
py_reader1.decorate_paddle_reader(paddle.batch(fake_random_numpy_reader, batch_size=BATCH_SIZE))
image3 = fluid.layers.data(name='image3', dtype='float32', shape=[784])
label3 = fluid.layers.data(name='label3', dtype='int64', shape=[1])
对应的PyReader设置如下:
# Case 2: Use decorate_tensor_provider() method to set the data source of py_reader
# The generator yields Tensor-typed batched data
def fake_random_tensor_provider():
image = np.random.random(size=(BATCH_SIZE, 784)).astype('float32')
label = np.random.random_integers(size=(BATCH_SIZE, 1), low=0, high=9).astype('int64')
yield image_tensor, label_tensor
.. code-block:: python
py_reader2 = fluid.layers.py_reader(
capacity=10,
shapes=((-1, 784), (-1, 1)),
dtypes=('float32', 'int64'),
name='py_reader2',
use_double_buffer=True)
import paddle
import paddle.fluid as fluid
py_reader2.decorate_tensor_provider(fake_random_tensor_provider)
USE_CUDA = True
USE_DATA_PARALLEL = True
if ITERABLE:
# 若PyReader可迭代,则必须设置places参数
if USE_DATA_PARALLEL:
# 若进行多GPU卡训练,则取所有的CUDAPlace
# 若进行多CPU核训练,则取多个CPUPlace,本例中取了8个CPUPlace
places = fluid.cuda_places() if USE_CUDA else fluid.cpu_places(8)
else:
# 若进行单GPU卡训练,则取单个CUDAPlace,本例中0代表0号GPU卡
# 若进行单CPU核训练,则取单个CPUPlace,本例中1代表1个CPUPlace
places = fluid.cuda_places(0) if USE_CUDA else fluid.cpu_places(1)
else:
# 若PyReader不可迭代,则不需要设置places参数
places = None
# 使用sample级的reader作为PyReader的数据源
py_reader1 = fluid.io.PyReader(feed_list=[image1, label1], capacity=10, iterable=ITERABLE)
py_reader1.decorate_sample_generator(fake_sample_reader, batch_size=32, places=places)
# 使用sample级的reader + paddle.batch设置PyReader的数据源
py_reader2 = fluid.io.PyReader(feed_list=[image2, label2], capacity=10, iterable=ITERABLE)
sample_list_reader = paddle.batch(fake_sample_reader, batch_size=32)
sample_list_reader = paddle.reader.shuffle(sample_list_reader) # 还可以进行适当的shuffle
py_reader2.decorate_sample_list_generator(sample_list_reader, places=places)
# 使用batch级的reader作为PyReader的数据源
py_reader3 = fluid.io.PyReader(feed_list=[image3, label3], capacity=10, iterable=ITERABLE)
py_reader3.decorate_batch_generator(fake_batch_reader, places=places)
使用PyReader进行模型训练和测试
################################
使用PyReader进行模型训练和测试的例程如下:
使用PyReader进行模型训练和测试的例程如下。
- 第一步,我们需组建训练网络和预测网络,并定义相应的PyReader对象,设置好PyReader对象的数据源。
.. code-block:: python
...
...
@@ -153,46 +167,45 @@ PyReader对象通过 :code:`decorate_paddle_reader()` 或 :code:`decorate_tensor
import paddle.dataset.mnist as mnist
import six
def network(is_train):
# Create py_reader object and give different names
# when is_train = True and is_train = False
reader = fluid.layers.py_reader(
capacity=10,
shapes=((-1, 784), (-1, 1)),
dtypes=('float32', 'int64'),
name="train_reader" if is_train else "test_reader",
use_double_buffer=True)
img, label = fluid.layers.read_file(reader)
...
ITERABLE = True
def network():
# 创建数据层对象
image = fluid.layers.data(name='image', dtype='float32', shape=[784])
label = fluid.layers.data(name='label', dtype='int64', shape=[1])
# 创建PyReader对象
reader = fluid.io.PyReader(feed_list=[image, label], capacity=64, iterable=ITERABLE)
# Here, we omitted the definition of loss of the model
return loss , reader
#
Create main program and startup program for training
#
创建训练的main_program和startup_program
train_prog = fluid.Program()
train_startup = fluid.Program()
#
Define train network
#
定义训练网络
with fluid.program_guard(train_prog, train_startup):
#
Use
fluid.unique_name.guard() to share parameters with test network
# fluid.unique_name.guard() to share parameters with test network
with fluid.unique_name.guard():
train_loss, train_reader = network(
True
)
train_loss, train_reader = network()
adam = fluid.optimizer.Adam(learning_rate=0.01)
adam.minimize(train_loss)
#
Create main program and startup program for testing
#
创建预测的main_program和startup_program
test_prog = fluid.Program()
test_startup = fluid.Program()
#
Define test network
#
定义预测网络
with fluid.program_guard(test_prog, test_startup):
# Use fluid.unique_name.guard() to share parameters with train network
with fluid.unique_name.guard():
test_loss, test_reader = network(
False
)
test_loss, test_reader = network()
place = fluid.CUDAPlace(0)
exe = fluid.Executor(place)
#
Run startup program
#
运行startup_program进行初始化
exe.run(train_startup)
exe.run(test_startup)
...
...
@@ -200,33 +213,45 @@ PyReader对象通过 :code:`decorate_paddle_reader()` 或 :code:`decorate_tensor
train_prog = fluid.CompiledProgram(train_prog).with_data_parallel(loss_name=train_loss.name)
test_prog = fluid.CompiledProgram(test_prog).with_data_parallel(share_vars_from=train_prog)
# Set the data source of py_reader using decorate_paddle_reader() method
train_reader.decorate_paddle_reader(
paddle.reader.shuffle(paddle.batch(mnist.train(), 512), buf_size=8192))
# 设置PyReader的数据源
places = fluid.cuda_places() if ITERABLE else None
train_reader.decorate_sample_list_generator(
paddle.reader.shuffle(paddle.batch(mnist.train(), 512), buf_size=1024), places=places)
test_reader.decorate_sample_list_generator(paddle.batch(mnist.test(), 512), places=places)
- 第二步:根据PyReader对象是否iterable,选用不同的方式运行网络。
若iterable=True,则PyReader对象是一个Python的生成器,可直接for-range迭代。for-range返回的结果通过exe.run的feed参数传入执行器。
.. code-block:: python
test_reader.decorate_paddle_reader(paddle.batch(mnist.test(), 512))
def run_iterable(program, exe, loss, py_reader):
for data in py_reader():
loss_value = exe.run(program=program, feed=data, fetch_list=[loss])
print('loss is {}'.format(loss_value))
for epoch_id in six.moves.range(10):
train_reader.start()
try:
while True:
loss = exe.run(program=train_prog, fetch_list=[train_loss])
print 'train_loss', loss
except fluid.core.EOFException:
print 'End of epoch', epoch_id
train_reader.reset()
run_iterable(train_prog, exe, loss, train_reader)
run_iterable(test_prog, exe, loss, test_reader)
若iterable=False,则需在每个epoch开始前,调用 :code:`start()` 方法启动PyReader对象;并在每个epoch结束时,exe.run会抛出 :code:`fluid.core.EOFException` 异常,在捕获异常后调用 :code:`reset()` 方法重置PyReader对象的状态,
以便启动下一轮的epoch。iterable=False时无需给exe.run传入feed参数。具体方式为:
test_reader.start()
.. code-block:: python
def run_non_iterable(program, exe, loss, py_reader):
py_reader.start()
try:
while True:
loss
= exe.run(program=test_prog, fetch_list=[test_
loss])
print
'test loss', loss
loss
_value = exe.run(program=program, fetch_list=[
loss])
print
('loss is {}'.format(loss_value))
except fluid.core.EOFException:
print
'End of testing'
test
_reader.reset()
print
('End of epoch')
py
_reader.reset()
具体步骤为:
1. 在每个epoch开始前,调用 :code:`start()` 方法启动PyReader对象;
for epoch_id in six.moves.range(10):
run_non_iterable(train_prog, exe, loss, train_reader)
run_non_iterable(test_prog, exe, loss, test_reader)
2. 在每个epoch结束时, :code:`read_file` 抛出 :code:`fluid.core.EOFException` 异常,在捕获异常后调用 :code:`reset()` 方法重置PyReader对象的状态,以便启动下一轮的epoch。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录