2016-10-06 11 views
3

1.7 Gigabyteのデータセットを正規化しようとしています。私は14Gig of RAMを持っていて、私は非常に速く私の限界に突き当たった。このスクリプトのメモリ制限を回避するにはどうすればよいですか?

これは、トレーニングデータのmean/stdを計算するときに発生します。トレーニングデータは、RAM(13.8Gig)にロードされたときにメモリの大半を占めるため、平均が計算されますが、stdの計算中に次の行に到達すると、平均値がクラッシュします。

はスクリプトに従う:

import caffe 
import leveldb 
import numpy as np 
from caffe.proto import caffe_pb2 
import cv2 
import sys 
import time 

direct = 'examples/svhn/' 
db_train = leveldb.LevelDB(direct+'svhn_train_leveldb') 
db_test = leveldb.LevelDB(direct+'svhn_test_leveldb') 
datum = caffe_pb2.Datum() 

#using the whole dataset for training which is 604,388 
size_train = 604388 #normal training set is 73257 
size_test = 26032 
data_train = np.zeros((size_train, 3, 32, 32)) 
label_train = np.zeros(size_train, dtype=int) 

print 'Reading training data...' 
i = -1 
for key, value in db_train.RangeIter(): 
    i = i + 1 
    if i % 1000 == 0: 
     print i 
    if i == size_train: 
     break 
    datum.ParseFromString(value) 
    label = datum.label 
    data = caffe.io.datum_to_array(datum) 
    data_train[i] = data 
    label_train[i] = label 

print 'Computing statistics...' 
print 'calculating mean...' 
mean = np.mean(data_train, axis=(0,2,3)) 
print 'calculating std...' 
std = np.std(data_train, axis=(0,2,3)) 

#np.savetxt('mean_svhn.txt', mean) 
#np.savetxt('std_svhn.txt', std) 

print 'Normalizing training' 
for i in range(3): 
     print i 
     data_train[:, i, :, :] = data_train[:, i, :, :] - mean[i] 
     data_train[:, i, :, :] = data_train[:, i, :, :]/std[i] 


print 'Outputting training data' 
leveldb_file = direct + 'svhn_train_leveldb_normalized' 
batch_size = size_train 

# create the leveldb file 
db = leveldb.LevelDB(leveldb_file) 
batch = leveldb.WriteBatch() 
datum = caffe_pb2.Datum() 

for i in range(size_train): 
    if i % 1000 == 0: 
     print i 

    # save in datum 
    datum = caffe.io.array_to_datum(data_train[i], label_train[i]) 
    keystr = '{:0>5d}'.format(i) 
    batch.Put(keystr, datum.SerializeToString()) 

    # write batch 
    if(i + 1) % batch_size == 0: 
     db.Write(batch, sync=True) 
     batch = leveldb.WriteBatch() 
     print (i + 1) 

# write last batch 
if (i+1) % batch_size != 0: 
    db.Write(batch, sync=True) 
    print 'last batch' 
    print (i + 1) 
#explicitly freeing memory to avoid hitting the limit! 
#del data_train 
#del label_train 

print 'Reading test data...' 
data_test = np.zeros((size_test, 3, 32, 32)) 
label_test = np.zeros(size_test, dtype=int) 
i = -1 
for key, value in db_test.RangeIter(): 
    i = i + 1 
    if i % 1000 == 0: 
     print i 
    if i ==size_test: 
     break 
    datum.ParseFromString(value) 
    label = datum.label 
    data = caffe.io.datum_to_array(datum) 
    data_test[i] = data 
    label_test[i] = label 

print 'Normalizing test' 
for i in range(3): 
     print i 
     data_test[:, i, :, :] = data_test[:, i, :, :] - mean[i] 
     data_test[:, i, :, :] = data_test[:, i, :, :]/std[i] 

#Zero Padding 
#print 'Padding...' 
#npad = ((0,0), (0,0), (4,4), (4,4)) 
#data_train = np.pad(data_train, pad_width=npad, mode='constant', constant_values=0) 
#data_test = np.pad(data_test, pad_width=npad, mode='constant', constant_values=0) 

print 'Outputting test data' 
leveldb_file = direct + 'svhn_test_leveldb_normalized' 
batch_size = size_test 

# create the leveldb file 
db = leveldb.LevelDB(leveldb_file) 
batch = leveldb.WriteBatch() 
datum = caffe_pb2.Datum() 

for i in range(size_test): 
    # save in datum 
    datum = caffe.io.array_to_datum(data_test[i], label_test[i]) 
    keystr = '{:0>5d}'.format(i) 
    batch.Put(keystr, datum.SerializeToString()) 

    # write batch 
    if(i + 1) % batch_size == 0: 
     db.Write(batch, sync=True) 
     batch = leveldb.WriteBatch() 
     print (i + 1) 

# write last batch 
if (i+1) % batch_size != 0: 
    db.Write(batch, sync=True) 
    print 'last batch' 
    print (i + 1) 

は、どのように私は、スクリプトを実行するために得ることができるように、それはより少ないメモリを消費することができますか?

+0

正規化しようとするデータが大きくなるほど、プログラムを実行するためにメモリが不足する可能性が高くなります。トレーニングセットを減らすことができない場合は、データサイズを – Shaydoth

+0

以下にしてください。これは不可能です。私はセット全体を正規化する必要があります。 – Breeze

+0

データをメモリマップ(http://docs.scipy.org/doc/numpy/reference/generated/numpy.memmap.html)として読むことができます。または、独自のバージョンの平均を書き込んで、連続して1つ(または複数)datapoint(s)を読み込み、 'mean' /' std'を計算します。平均はすべてのデータを長さで割ったもの(擬似コード: 'sum_i x_i/N')だけなので、平均値を計算するためにメモリ内のデータセット全体を必要としません。標準偏差と同じですが、データセット全体をメモリに格納する必要はなく、平均を計算してsqrt(sum_i(x_i - x_mean)** 2 /(N-1))を計算するだけです。 –

答えて

1

なぜ元のデータのサブセットの統計情報を計算しないのですか?たとえば、ここに私達はちょうど100ポイントの平均とstdを計算:

sample_size = 100 
data_train = np.random.rand(1000, 20, 10, 10) 

# Take subset of training data 
idxs = np.random.choice(data_train.shape[0], sample_size) 
data_train_subset = data_train[idxs] 

# Compute stats 
mean = np.mean(data_train_subset, axis=(0,2,3)) 
std = np.std(data_train_subset, axis=(0,2,3)) 

あなたのデータが1.7GBであれば、あなたがすべてのデータが平均値とstdの正確な推定を取得する必要があるということはほとんどありません。

さらに、データ型のビット数を減らすことができますか?私は、どのようなデータ型caffe.io.datum_to_arrayリターンをわからないんだけど、あなたは何ができる:

data = caffe.io.datum_to_array(datum).astype(np.float32) 

データがfloat32形式であることを確認します。 (データが現在float64の場合、スペースの半分を節約できます)。

+0

残念ながら、私はデフォルトを使用しなければならないので、残念ながらそのfloat64、caffe doesntはfloat32をサポートしています。 私は正規化されたトレーニングセットを保存する必要があるので、私はそれをRAMにロードする必要があります。 – Breeze

+0

これはfloat32については残念です。しかし、正規化では、私の指摘はサブセットを使って統計を計算することだけです。次に、これらの統計を使用してデータセット全体を正規化することができます。これにより、 'mean'と' std'の計算中にRAMが節約されます。これはあなたのスクリプトが失敗している場所だと思います。 –

+0

ありがとう、私は試してみましょう;) – Breeze

0

メモリ不足のためそれほど問題と一定のクラッシュを引き起こす犯人は、全体のトレーニングセットのサイズであるバッチサイズによるものであった:

print 'Outputting test data' 
leveldb_file = direct + 'svhn_test_leveldb_normalized' 
batch_size = size_test 

これは明らかに原因だった、何もコミットを取得しないだろうし、データセット全体が読み込まれて1つの巨大トランザクションにロードされるまでディスクに保存されましたが、これは@BillCheathamによって提案されたnp.float32を使用しても正しく動作しなかった場合にも当てはまります。

何らかの理由でmemorymapの解決策がうまくいかず、上記の解決方法を使用しました。

ps:後で、私は完全にfloat32に変更し、batch_sizeを修正して、すべてをまとめて実行しました。私の以前のソリューション(分数を分けて追加する方法)がどのように機能するのか、 2小数点以下

関連する問題