我一直认为作为二进制格式,TFRecord将比人类可读的csv消耗更少的空间。但是当我试图比较它们时,我发现事实并非如此。
例如,我在这里创建一个带有num_rows X 10
标签的num_rows
矩阵,并将其另存为csv。我通过将其保存到TFRecors来做同样的事情:
import pandas as pd
import tensorflow as tf
from random import randint
num_rows = 1000000
df = pd.DataFrame([[randint(0,300) for r in xrange(10)] + [randint(0, 1)] for i in xrange(num_rows)])
df.to_csv("data/test.csv", index=False, header=False)
writer = tf.python_io.TFRecordWriter('data/test.bin')
for _, row in df.iterrows():
arr = list(row)
features, label = arr[:-1], arr[-1]
example = tf.train.Example(features=tf.train.Features(feature={
'features' : tf.train.Feature(int64_list=tf.train.Int64List(value=features)),
'label': tf.train.Feature(int64_list=tf.train.Int64List(value=[label])),
}))
writer.write(example.SerializeToString())
writer.close()
创建二进制文件不仅比csv(2秒VS 1分50秒)花费更多时间,而且它还使用了近2倍的空间(38Mb VS 67.7Mb)。
我能正确地做到吗?如何使输出文件更小(看到TFRecordCompressionType),但还有什么我可以做的吗?更大尺寸的原因是什么?
Vijay关于int64 的评论是有道理的,但仍然没有回答所有问题。 Int64消耗8个字节,因为我在csv中存储数据,整数的字符串表示应该是8的长度。所以如果我这样做df = pd.DataFrame([[randint(1000000,99999999) for r in xrange(10)] for i in xrange(num_rows)])
我仍然会得到一个稍大的大小。现在它是90.9Mb VS 89.1Mb。除此之外,csv为每个整数之间的每个逗号存储1个字节。
答案 0 :(得分:1)
您的文件较大的事实是由于TFRecords对每一行的开销,特别是每次都存储标签名称的事实。
在您的示例中,如果您增加功能的数量(从10到1000),您会发现您的tfrecord文件实际上大约是csv的一半大小。
此外,整数存储在64位上的事实最终无关紧要,因为序列化使用" varint"编码取决于整数的值,而不是其初始编码。以上面的示例为例,而不是0到300之间的随机值,使用常量值300:您将看到文件大小增加。
请注意,用于编码的字节数不完全是整数本身的字节数。因此值255仍然需要两个字节,但值127将占用一个字节。有趣的是,负值会带来巨大的损失:无论如何都要存储10个字节。
值和存储要求之间的对应关系可以在protobuf的函数_SignedVarintSize
中找到。
答案 1 :(得分:0)
这可能是因为你生成的数字在0~300范围内,所以它们只需要3个字节来存储一个数字,但是当它们作为int64存储在tfrecords中时,它至少需要8个字节(不太确定)存储一个号码。如果你生成的数字在0~2 ^ 64-1范围内,我认为tfrecords文件会比csv文件小得多。