Python 使用tf.data.TFRecordDataset时,无法解释的RAM使用情况和潜在内存泄漏

Python 使用tf.data.TFRecordDataset时,无法解释的RAM使用情况和潜在内存泄漏,python,tensorflow,tensorflow2.0,tensorflow2.x,Python,Tensorflow,Tensorflow2.0,Tensorflow2.x,背景 我们对TensorFlow比较陌生。我们正在研究一个涉及视频数据集的DL问题。由于涉及的数据量很大,我们决定对视频进行预处理,并将帧作为JPEG格式存储在TFRecord文件中。然后,我们计划使用tf.data.TFRecordDataset将数据提供给我们的模型 这些视频已经被处理成段,每段由16帧组成,以一个连续的张量。每一帧是一幅128*128 RGB图像,编码为jpeg。每个序列化段与一些元数据一起存储为tf记录中的序列化tf.train.Example TensorFlow版本:

背景

我们对TensorFlow比较陌生。我们正在研究一个涉及视频数据集的DL问题。由于涉及的数据量很大,我们决定对视频进行预处理,并将帧作为JPEG格式存储在TFRecord文件中。然后,我们计划使用
tf.data.TFRecordDataset
将数据提供给我们的模型

这些视频已经被处理成段,每段由16帧组成,以一个连续的张量。每一帧是一幅128*128 RGB图像,编码为jpeg。每个序列化段与一些元数据一起存储为tf记录中的序列化
tf.train.Example

TensorFlow版本:2.1

代码

下面是我们用来从TFRecords创建
tf.data.TFRecordDataset
的代码。您可以忽略
num
file
字段

导入操作系统
输入数学
导入tensorflow作为tf
#此处将进行相应的更改
#如果tf2_preprocessing.py中的功能描述
#改变
功能描述={
“段”:tf.io.FixedLenFeature([],tf.string),
“文件”:tf.io.FixedLenFeature([],tf.string),
“num”:tf.io.FixedLenFeature([],tf.int64)
}
def build_数据集(目录路径,批处理大小=16,文件缓冲区=500*1024*1024,
洗牌(缓冲区=1024,标签=1):
''基于目录路径中的所有tf记录返回tf.data.Dataset
Args:
dir\u path:指向包含TFR记录的目录的路径
批次大小:数据集每个元素的批次ie培训示例的大小
文件缓冲区:对于TF记录,大小以字节为单位
洗牌缓冲区:#洗牌时缓冲区的示例
标签:示例的目标标签
'''
#文件的全局模式
file_pattern=os.path.join(dir_path,'*.tfrecord')
#存储无序文件名
file\u ds=tf.data.Dataset.list\u文件(文件模式)
#并行读取多个文件
ds=tf.data.TFRecordDataset(文件,
num_parallel_reads=tf.data.experimental.AUTOTUNE,
缓冲区大小=文件缓冲区)
#从洗牌缓冲区中随机抽取示例
ds=ds.shuffle(缓冲区大小=1024,
重新洗牌(每次迭代=真)
#批处理示例
#现在删除剩余部分,在解析时遇到麻烦-添加标签
ds=ds.batch(批大小,丢弃剩余=True)
#将记录解析为正确的类型
ds=ds.map(lambda x:_my_解析器(x,标签,批量大小),
num_parallel_calls=tf.data.experimental.AUTOTUNE)
ds=ds.预取(tf.数据.实验.自动调谐)
返回ds
定义我的解析器(示例、标签、批次大小):
''解析一批序列化的tf.train.Example
Args:
示例:批量序列化的tf.train.示例
返回:
元组(段、标签)
其中段是形状张量(#在#批中,#帧,h,w,#通道)
'''
#ex将是连续张量的张量
ex=tf.io.parse_示例(示例,功能=功能描述)
ex['segment']=tf.map\u fn(λx:\u parse\u segment(x),
ex['segment'],dtype=tf.uint8)
#暂时忽略文件名和段数
#返回元组(tensor1,tensor2)
#tensor1是一批段,tensor2是相应的标签
退货(例如['segment',tf.填充((批次大小,1),标签))
定义解析段(段):
''解析段并将其作为张量返回
段是许多编码JPEG的序列化张量
'''
#现在是编码JPEG的张量
parsed=tf.io.parse_张量(段,输出类型=tf.string)
#现在是形状的张量(#帧,h,w,#通道)
已解析=tf.map\u fn(lambda y:tf.io.decode\u jpeg(y),已解析,数据类型=tf.uint8)
返回解析
问题

在训练时,我们的模型因为内存不足而崩溃了。我们通过运行一些测试并使用
--include children
标志分析内存来进行调查

所有这些测试都是通过使用以下代码在数据集上多次迭代来运行的(仅限CPU):

count=0
目录路径='some/path'
ds=构建数据集(目录路径、文件缓冲区=某些值)
对于范围(100)内的itr:
打印(itr)
对于ds中的itx:
计数+=1
我们正在处理的TF记录子集的总大小约为3GB 我们希望使用TF2.1,但也可以使用TF2.2进行测试

根据,文件缓冲区以字节为单位

试用版1:文件缓冲区=500*1024*1024,TF2.1

试用版2:文件缓冲区=500*1024*1024,TF2.2 这个看起来好多了。

试用版3文件缓冲区=1024*1024,TF2.1 我们手头没有这张图,但RAM的最大容量约为4.5GB

试用版4文件缓冲区=1024*1024,TF2.1,但预取设置为10

我认为这里存在内存泄漏,因为我们可以看到内存使用随着时间的推移逐渐增加。

下面的所有试验只运行了50次迭代,而不是100次

试用版5文件缓冲区=500*1024*1024,TF2.1,预取=2,所有其他自动调谐值均设置为16。

试用版6文件缓冲区=1024*1024,其余同上

问题

  • file_buffer值如何影响内存使用,比较Trail 1和Trail 3,file_buffer减少了500倍,但内存使用只减少了一半。文件缓冲区值是否以字节为单位
  • 试验6的参数似乎很有希望,但尝试用同样的参数训练模型失败了,因为它再次耗尽了内存
  • TF2.1中是否存在缺陷,为什么试用版1和试用版2之间存在巨大差异
  • 我们应该继续使用自动调谐还是恢复为常量值
  • 我很乐意用不同的参数运行更多的测试。 提前谢谢