从飞桨paddle课程学习Python的yield函数语法

在“百度架构师手把手带你零基础实践深度学习”课程中,第一周课程的实践作业中,要求写一个cifar-10数据集的数据读取器。这是这门课程第一个作业,也是我现在到课程结束,感觉最能0距离体验paddle程序架构的一个作业。
何出此言呢?后面的作业,虽然程序越来越复杂,但以笔者机器学习0基础上手的前提,在短短的三周学习时间内,其实只能大致把握其思路与流程,并没有深入钻研每个算法的实现和设计思路的机会。
但这个数据读取器大大满足了我“钻研算法实现”的愿望,要是没有群里助教的指点险些没做出来。下面分享一下我的学习过程:

首先,作业要求写一个读写器,实现读入和乱序。

读入一般有两种思路,第一种是采用本地数据集,调用方法是:

for counter in range(本地数据个数),(其中counter代表循环计数器,下同),

由于本地数据个数已知,不管是做乱序还是读入,都可以采用这种最简单可靠的全部遍历方法。

另一种方法是在飞桨里看到的,构造一个读取器,类型reader_creator(),函数返回一个reader()函数。这个函数的特点有点类似于链表,只能顺序读取,不能直接全局定位到特定的第N个元素。
缺点是不能任意定位读取
优点是可以节约空间,你可以用多少数据读多少数据,不用一口气全部读完才开始后续工作。
cifa-10数据集在paddle网络上有配置,如果采用该种方法就可以不下载数据的情况下完成读取任务。

reader()函数的基本用法是

for counter in enumerate(reader())

每执行一次for循环相当于对reader()函数使用一次next(reader()),让读取器reader()去调用获得一个新的值以后,再进行循环内的操作。
但前提是reader()函数必须是一个带有yield的函数,类型为generator(生成器)。
这样的迭代循环方式颠覆了我对“for”函数的理解,在使用yield结构后,函数居然可以用“for”进行迭代调用,而且可以用于enumerate()(枚举函数),即函数为“可数的”,“枚举变量”。

正当我惊讶于这个神奇的结构时,我对新想法的实验程序报错了:
在这里插入图片描述

我的完美计划是:
trainset是paddle提供的数据读取器,类型是reader_creator()
任务是打包成patch、把数据乱序,生成新的读取器。
那么很自然的想到先打乱,再分批次,是比较合理的设计。

1, paddle.reader.shuffle(reader=trainset(),buf_size=1000)

shuffle是一个修饰reader_creator的函数,返回一个读取器reader(),作用是读取buf_size数量数据元素后打乱。

2, train_creator=paddle.batch(paddle.reader.shuffle(),batch_size)

把打乱以后的数据再分批次就好了
但这样做是不行的。

以batch函数为例,读取器修饰函数(源代码:https://github.com/PaddlePaddle/Paddle/blob/release/1.8/python/paddle/reader/decorator.py#L102),之所以可以对reader_creator()进行处理后返回reader()函数,是因为其源代码定义如下:

def batch(reader, batch_size, drop_last=False):
    def batch_reader():
    ……
    return batch_reader

按照官网的api说明:“该接口是一个reader的装饰器。返回的reader将输入reader的数据打包成指定的batch_size大小的批处理数据(batched data)。”
返回:batched reader
返回类型:generator
而batch函数调用的是reader_creator类型。paddle的api中并没有明确给出reader_creator的定义.
但《【深度学习系列】关于PaddlePaddle的一些避“坑”技巧》一文中,给出了一段样例程序:

def reader_creator(data,label):
    def reader():
    for i in xrange(len(data)):
        yield data[i,:],int(label[i])
    return reader

对比可知,batch函数,shuffle函数,也属于reader_creator类型。其能够处理并返回一个reader()类型函数的理由就在于,它在函数定义时,嵌套定义了一个函数"def reader():"
因此我的代码:

train_creator=paddle.batch(    paddle.reader.shuffle()    ,batch_size)

不能运行的原理就在于,shuffle输出的函数是reader()类型,没有进行嵌套定义成reader_creator类型,因此不能被batch函数调用。

当时作业采取的方案是绕过了这个问题,现在看看对这个答案并不十分满意。将输出的shuffle用reader_creator()格式包装一下,就可以被batch进行调用,这样才是当时本来设计的思路的满意答案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值