Step 2. 创建DataLoader并设置自定义Reader¶
在命令式编程模式(动态图)下,我们推荐使用DataLoader进行数据载入,DataLoader默认使用线程进行异步加速,使用也更加简便直观。
创建DataLoader
命令式编程模式(动态图)下,创建DataLoader对象的方式为:
import paddle.fluid as fluid
data_loader = fluid.io.DataLoader.from_generator(capacity=10)
其中,
capacity为DataLoader对象的缓存区大小,单位为batch数量。
该值根据实际需求设定即可,一般对于单卡训练的场景,设置5到20即可满足需求,特别是对于一个Batch数据较大的情况,不宜设置过大,可能会消耗过多内存资源,反而降低效率。
如果模型消耗训练或预测数据较慢的话,缓存队列设置过大也没有收益,但对于模型训练速度非常快,数据载入是训练速度瓶颈的情况,适当扩大队列能够提高训练速度。
对于其他参数,我们推荐使用默认设置,无需再额外配置,具体可参见官方文档 DataLoader
设置DataLoader对象的数据源
上文中讲到,DataLoader支持配置三种不同的自定义Reader,配置这三种Reader的方法分别为: set_sample_generator() , set_sample_list_generator 和 set_batch_generator() 。
这三个方法均接收Python生成器 generator 作为参数,其区别在于:
set_sample_generator() 要求 generator 返回的数据格式为(image_1, label_1),其中image1和label_1为单个样本的Numpy Array类型数据。
set_sample_list_generator() 要求 generator 返回的数据格式为[(image_1, label_1), (image_2, label_2), ..., (image_n, label_n)],其中image_i和label_i均为每个样本的Numpy Array类型数据,n为batch size。
set_batch_generator() 要求 generator 返回的数据的数据格式为([BATCH_SIZE, image], [BATCH_SIZE, label]),其中[BATCH_SIZE, image]和[BATCH_SIZE, label]为batch级的Numpy Array或Tensor类型数据。
此处我们构建三个不同的示例生成器,对应上述三个接口:
import numpy as np
BATCH_NUM = 10
BATCH_SIZE = 16
MNIST_IMAGE_SIZE = 784
MNIST_LABLE_SIZE = 1
# 伪数据生成函数,服务于下述三种不同的生成器
def get_random_images_and_labels(image_shape, label_shape):
image = np.random.random(size=image_shape).astype('float32')
label = np.random.random(size=label_shape).astype('int64')
return image, label
# 每次生成一个Sample,使用set_sample_generator配置数据源
def sample_generator_creator():
def __reader__():
for _ in range(BATCH_NUM * BATCH_SIZE):
image, label = get_random_images_and_labels([MNIST_IMAGE_SIZE], [MNIST_LABLE_SIZE])
yield image, label
return __reader__
# 每次生成一个Sample List,使用set_sample_list_generator配置数据源
def sample_list_generator_creator():
def __reader__():
for _ in range(BATCH_NUM):
sample_list = []
for _ in range(BATCH_SIZE):
image, label = get_random_images_and_labels([MNIST_IMAGE_SIZE], [MNIST_LABLE_SIZE])
sample_list.append([image, label])
yield sample_list
return __reader__
# 每次生成一个Batch,使用set_batch_generator配置数据源
def batch_generator_creator():
def __reader__():
for _ in range(BATCH_NUM):
batch_image, batch_label = get_random_images_and_labels([BATCH_SIZE, MNIST_LABLE_SIZE], [BATCH_SIZE, MNIST_LABLE_SIZE])
yield batch_image, batch_label
return __reader__
然后,可以根据需求为DataLoader配置不同的数据源,此处完整的创建DataLoader及相应配置为:
import paddle.fluid as fluid
BATCH_SIZE = 16
place = fluid.CPUPlace() # 或者 fluid.CUDAPlace(0)
fluid.enable_imperative(place)
# 使用sample数据生成器作为DataLoader的数据源
data_loader1 = fluid.io.DataLoader.from_generator(capacity=10)
data_loader1.set_sample_generator(sample_generator_creator(), batch_size=BATCH_SIZE, places=place)
# 使用sample list数据生成器作为DataLoader的数据源
data_loader2 = fluid.io.DataLoader.from_generator(capacity=10)
data_loader2.set_sample_list_generator(sample_list_generator_creator(), places=place)
# 使用batch数据生成器作为DataLoader的数据源
data_loader3 = fluid.io.DataLoader.from_generator(capacity=10)
data_loader3.set_batch_generator(batch_generator_creator(), places=place)
此处有两点值得注意:
DataLoader的使用需要在命令式编程模式(动态图)下,即提前通过 fluid.enable_imperative() 进入命令式编程模式(动态图)。
命令式编程模式(动态图)下DataLoader配置数据源,需要在 set_XXX_generator 时执行place,一般为当前执行的place。(该点后续可能会优化,在这里默认使用动态图当前place,而无需用户指定)