2016-10-06 2 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) или написать собственную версию среднего значения, которая последовательно читает один (или несколько) datapoint (s) в файле и вычисляет 'mean' /' std'. Среднее значение представляет собой сумму всех данных, деленных на длину (псевдокод: 'sum_i x_i/N'), поэтому вам не нужен весь набор данных в памяти для вычисления среднего значения. То же самое для стандартного отклонения, вам не нужен весь набор данных в памяти, просто вычислите среднее значение и вычислите 'sqrt (sum_i (x_i - x_mean) ** 2/(N-1))'. –

ответ

1

Почему бы не вычислить статистику по подмножеству исходных данных? Например, здесь мы вычисляем среднее и зЬй для всего 100 пунктов:

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, то весьма маловероятно, что вам нужны все данные, чтобы получить точную оценку среднего и станд.

Кроме того, вы могли бы уйти с меньшим количеством бит в вашем типе данных? Я не уверен, что тип данных caffe.io.datum_to_array возвращается, но вы можете сделать:

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

для обеспечения данных в формате float32. (Если данные в настоящее время float64, то это спасет вас на половину пространства).

+0

Спасибо, к сожалению, его float64, поскольку caffe не поддерживает float32, я должен использовать значение по умолчанию. , и поскольку мне нужно сохранить нормализованный набор тренировок, мне все равно нужно загрузить его в плунжер. – Breeze

+0

ОК, это позор для float32. Однако для нормализации моя задача - вычислить статистику только с помощью подмножества. Затем вы можете нормализовать весь набор данных, используя эти статистические данные. Это экономит ваш барабан во время вычисления 'mean' и' std', который, по моему мнению, там, где ваш скрипт терпит неудачу. –

+0

Спасибо, я попробую;) – Breeze

0

Преступник, которые вызывают стольких вопросов и постоянные сбои из-за нехватки памяти, был обусловлен размером партии является размером всего комплекта обучения:

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

Это, видимо, не были причина, ничего бы получить совершенное и сохраненный на диске до тех пор, пока весь набор данных не будет прочитан и не загружен в одну огромную транзакцию, это также случай, когда использование np.float32, предложенное @BillCheatham, не работает должным образом.

решение memorymap не работает для меня по какой-то причине, и я использовал решение, упомянутое выше.

ps: Позже я полностью изменил на float32, исправил batch_size и пробежал все это вместе, вот как я могу сказать, что мое прежнее решение (разделите и добавьте фракции вместе) работает и дает точное число до 2 десятичных знака.

Смежные вопросы