2017-06-28 16 views
1

私はいつもバイナリ形式であると考えていました。TFRecordは人間が読めるCSVよりも少ない領域を消費します。しかし、私はそれらを比較しようとしたとき、私はそれが当てはまらないことを見た。私のTFRecordファイルがcsvよりもずっと大きいのはなぜですか?

たとえば、ここではnum_rowsラベルのnum_rows X 10行列を作成し、それを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)、他に何ができますか?はるかに大きなサイズの理由は何ですか?


int64型に関するビジェイさんのコメントには意味がありますが、それでもすべてを答えていません。私はcsvにデータを格納しているので、Int64は8バイトを消費します。整数の文字列表現は長さが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バイトを格納します。

+1

これは、実際にint32になっているときに、tfrecordsに書き込むときにint64で機能を保存するためですか? –

+0

この種のことは意味がありますが、FloatListに変更するとファイルサイズは92Mbに増加します。浮動小数点数でfloat64を意味する場合、それは同じままでなければなりません。そうでなければ、2倍に減少します。同様の状況(より大きなサイズ)は文字列のためのものです。 –

答えて

0

これは、生成された数値が0〜300の範囲であるために発生する可能性があります。したがって、数値を格納するのに3バイトが必要ですが、tfrecordsにint64として格納されている場合、 )を押して数字を保存します。生成された数値が0〜2^64-1の範囲にある場合、tfrecordsファイルはcsvファイルよりもはるかに小さくなると思います。

+0

このような意味がありますが、FloatListに変更するとファイルサイズは92Mbに増加します。浮動小数点数でfloat64を意味する場合、それは同じままでなければなりません。そうでなければ、2倍に減少します。同様の状況(より大きなサイズ)は文字列のためのものです。私は10000000から99999999までの数字を生成する必要があります。これは、csvがデータ​​を文字列として格納するため、8桁の文字列でなければならないためです。 –

+0

私はいくつかの実験を今行った、私は生成された値の範囲を変更した、csvファイルとtfrecordsファイルサイズの両方が成長している、csvファイルはより速く成長する。だから私はprotobufが文字列にシリアル化されたときにいくつかの圧縮を行うだろうと思う。 –

1

ファイルが大きいという事実は、TFRecordsが各行に対して持っているオーバーヘッド、特にラベル名が毎回格納されていることが原因です。

例では、機能の数を10から1000に増やすと、tfrecordファイルが実際にcsvの約半分のサイズになっていることがわかります。

整数が64ビットに格納されているという事実も、結局のところ無関係です。なぜなら、シリアル化では、最初のエンコーディングではなく整数の値に依存する "varint"エンコーディングが使用されるからです。上記の例を参考にして、0から300までのランダムな値の代わりに300の定数を使用してください。ファイルサイズが増加することがわかります。

エンコードに使用されるバイト数は、整数自体のバイト数とまったく同じではないことに注意してください。 255の値はまだ2バイト必要ですが、127の値は1バイトをとります。興味深いことに、負の値には大きなペナルティが伴います。

値と格納要件の対応は、protobufの関数_SignedVarintSizeにあります。

+0

ラベルを削除または削除する方法はありますか(「フィーチャー」から「f」へ、「ラベル」から「l」への明白な変更を除いて)基本的に、ファイルのサイズを減らす方法はありますか? –

+0

TFRコードがシリアル化される方法を見ると、これは現時点で提案されているオプションではないと思います。 – user1735003

関連する問題