paddle video_tag paddle.fluid.io.xmap_readers
#源码第1层
infer_reader = get_reader(args.model_name.upper(), 'infer', infer_config)
#源码第2层
def get_reader(name, mode, cfg):
reader_model = reader_zoo.get(name, mode, cfg)
return reader_model.create_reader()
#源码第3层
def create_reader(self):
assert os.path.exists(self.filelist), \
'{} not exist, please check the data list'.format(self.filelist)
# self.ffail=open(self.filefail,'w',encoding='utf-8')
_reader = self._reader_creator(self.filelist, self.mode, seg_num=self.seg_num, seglen = self.seglen, \
short_size = self.short_size, target_size = self.target_size, \
img_mean = self.img_mean, img_std = self.img_std, \
shuffle = (self.mode == 'train'), \
num_threads = self.num_reader_threads, \
buf_size = self.buf_size, format = self.format)
def _batch_reader():
batch_out = []
for imgs, label in _reader():
if imgs is None:
continue
batch_out.append((imgs, label))
if len(batch_out) == self.batch_size:
yield batch_out
batch_out = []
return _batch_reader
#源码第4层
def _reader_creator(self,
# ffail,
file_list,
mode,
seg_num,
seglen,
short_size,
target_size,
img_mean,
img_std,
shuffle=False,
num_threads=1,
buf_size=1024,
format='frames'):
………………………………此处省略decode_mp4、decode_frames函数,功能就是解析MP4
def reader_():
with open(file_list) as flist:
lines = [line.strip() for line in flist]
if shuffle:
random.shuffle(lines)
for line in lines:
file_path = line.strip()
yield [file_path]
if format == 'frames':
decode_func = decode_frames
elif format == 'video':
decode_func = decode_mp4
else:
raise ("Not implemented format {}".format(format))
mapper = functools.partial(
decode_func,
mode=mode,
seg_num=seg_num,
seglen=seglen,
short_size=short_size,
target_size=target_size,
img_mean=img_mean,
img_std=img_std)
return fluid.io.xmap_readers(
mapper, reader_, num_threads, buf_size, order=True)
- step1
我们先看第二部分的最后一行代码,fluid.io.xmap_readers(
mapper, reader_, num_threads, buf_size, order=True)
官网给出的解释
2、step2
既然提到了装饰器,我们就磕一下这个点,lazy_sum是装饰器下一个很经典的例子。
# alist = [1,2,3,...,100]
def lazy_sum():
return reduce(lambda x,y:x+y,alist)
我们定义了一个函数lazy_sum,作用是对alist中的所有元素求和后返回。但由于某种原因,我并不想马上返回计算结果,而是在之后的某个地方,通过显示调用输出结果。于是我用一个wrapper函数对其进行包装:
def wrapper():
alist = [1,2,3,...,100]
def lazy_sum():
return reduce(lambda x,y:x+y,alist)
return lazy_sum
lazy_sum = wrapper() #wrapper()返回的是lazy_sum函数对象
if __name__ =="__main__":
lazy_sum() #返回5050,计算结果
这是一个典型的lazy Evaluation的例子。我们知道,一般情况下,局部变量在函数返回时,就会被垃圾回收器回收,而不能再被使用。但是这里alist却没有,它随着lazy_sum函数对象的返回被一并返回了(这个说法不准确,实际时包含在lazy_sum的执行环境中,通过__globals__),从而延长了生命周期。
- step3
所以源码第1层, get_reader最终返回的是一个_batch_reader函数,以及由=由self._reader_creator创建的_reader,通过infer_reader()完成对函数的调用,得到一个生成器(因为_batch_reader函数中有yield关键字,可以看上一篇博文中对yield关键字的解释)。
最终paddle video_tag中使用下面的语句完成对生成器的遍历。
for infer_iter, data in enumerate(infer_reader()):
…………此处完成对生成器的遍历