Как я могу читать данные из большого набора данных .h5 партиями, предварительно обрабатывать их с помощью ImageDataGenerator и model.fit, и все это без нехватки памяти? - PullRequest
0 голосов
/ 16 июня 2020

Сводка: Недостаточно памяти при попытке обработать большой набор данных с помощью TF / Keras. Я знаю, что пакетная обработка является основным компонентом решения ... просто не понимаю, как это реализовать.

Вопрос: Как я могу считывать данные из чрезвычайно большого набора данных .h5 партиями, стандартизировать / удалить среднее значение, а затем разделить данные без нехватки памяти?

Контекст: Создание рабочего процесса для исследования неконтролируемой глубокой встроенной кластеризации (DE C ) естественных сейсмических c сигналов. Эта проблема конкретно связана с предварительной обработкой данных, то есть подготовкой данных для обучения / проверки автокодировщика / декодера.

Данные: ~ 6e6 спектрограмм сейсмических сигналов c обнаружения из массива. Размеры: (m, n, o) = (6e6, 66, 301) = (samples, freq_bins, time_bins). Данные хранятся в файле .h5 в одном наборе данных. Файл .h5 занимает на диске ~ 1 ТБ.

Аппаратное обеспечение: Dual Intel Xeon E5-2683 v4 2,1 ГГц, кэш 40 МБ, 16 ядер, 2 GPU Titan, 528 ГБ RAM

Текущая процедура предварительной обработки: 1. Соберите массив numpy, X, состоящий из M спектрограмм, выбрав M случайных индексов, отсортированных в порядке возрастания, и итеративно нарезав набор данных .h5. (Кроме того: самый быстрый подход здесь заключался в том, чтобы сохранить набор данных .h5 с фрагментами, оптимизированными для последующего чтения, а затем использовать простой "for" l oop для доступа к данным. Необычное индексирование и read_direct заняли значительно больше времени, чтобы пройти набор данных.) 2. Обрежьте ненужные данные из X (значения частотных и временных интервалов, а также последние 46 временных интервалов данных) и добавьте 4-ю ось, «p», как «интервал амплитуды». Окончательная форма: (m, n, o, p) = (M, 64,256,1). 3. Удалите среднее и стандартизируйте данные. 4. Разделите X на наборы для обучения / проверки.

# Define sample size:
M = int(1e6)
# Load spectrograms into X:
with h5py.File(train_dataname, 'r') as f:
    DataSpec = '/30sec/Spectrogram'
    dset = f[DataSpec]
    m, n, o = dset.shape
    index = sorted(np.random.choice(m, size=M, replace=False))
    X = np.empty([M, n, o])
    for i in range(M):
        X[i,:,:] = dset[index[i],:,:]

# Remove the frequency and time vectors from the data, trim time bins to len=256:
X = X[:,1:-1,1:256]

# Add amplitude dimension:
X = X[..., np.newaxis]
m, n, o, p = X.shape

# Remove mean & standardize data:
datagen = tf.keras.preprocessing.image.ImageDataGenerator(
    samplewise_center=True,
    samplewise_std_normalization=True)
datagen.fit(X)
X = datagen.standardize(X)

# Split data into training/validation:
X_train, X_val = train_test_split(X, test_size=0.2, shuffle=True, random_state=812)

# Free up memory:
del X

Проблема в деталях: Когда M ~ 1e6, X занимает примерно 30% ОЗУ (общий объем ОЗУ составляет 528 ГБ). Выполнение приведенного выше кода приводит к ошибке памяти, указанной ниже. Неудивительно, что у меня заканчивается память, учитывая, что операция копирует весь массив ...

---------------------------------------------------------------------------
MemoryError                               Traceback (most recent call last)
<ipython-input-10-fb00ad200706> in <module>
----> 1 datagen.fit(X)

~/Anaconda/anaconda3/envs/AEC-DEC/lib/python3.6/site-packages/keras_preprocessing/image/image_data_generator.py in fit(self, x, augment, rounds, seed)
    943             np.random.seed(seed)
    944 
--> 945         x = np.copy(x)
    946         if augment:
    947             ax = np.zeros(

~/Anaconda/anaconda3/envs/AEC-DEC/lib/python3.6/site-packages/numpy/lib/function_base.py in copy(a, order)
    790 
    791     """
--> 792     return array(a, order=order, copy=True)
    793 
    794 # Basic operations

MemoryError:

Что я пытаюсь сделать (и мне нужна ваша помощь!): Я знаю, что мое решение связано с пакетной обработкой, но я не уверен, как его реализовать, а также как связать его с эффективным способом чтения .h5 без необходимости считывать спектрограммы M в массив, а затем выполнять пакетный процесс. Я определил подход model.fit_generator, который теперь кажется устаревшим в пользу model.fit; и я читал об утилите hdf5matrix. Задано в вопросе: как я могу считывать данные из очень большого набора данных .h5 партиями, стандартизировать / удалить среднее значение, а затем разделить данные, и все это без нехватки памяти?

Сколько времени я потратил на то, чтобы понять это, я не понимаю, как собрать все части вместе, поэтому я ищу какое-нибудь продуманное руководство, которое подтолкнет меня в правильном направлении. Заранее благодарим за помощь!

1 Ответ

0 голосов
/ 17 июня 2020

Вы должны избегать процессов, которые удваивают объем памяти, равный X. (Я знаю, это констатирует очевидное). Это БОЛЬШОЙ массив, и вы удваиваете необходимую память с помощью X = X[:,1:-1,1:256] (и, возможно, с помощью X = X[..., np.newaxis]).
Их ключ состоит в том, чтобы выделить X в окончательном желаемом размере / форме (чтобы избежать копий). Затем измените свой logi c, чтобы загрузить данные из dset (f['/30sec/Spectrogram']) в промежуточный массив (ds_arr ниже), измените при необходимости, затем загрузите в X.

Я положил вместе альтернативная процедура. Это может быть не самым эффективным с точки зрения вычислений, но позволяет избежать копий X.

# Define sample size:
M = int(1e6)
# Load spectrograms into X:
with h5py.File(train_dataname, 'r') as f:
    DataSpec = '/30sec/Spectrogram'
    dset = f[DataSpec]
    m, n, o = dset.shape        
    index = sorted(np.random.choice(m, size=M, replace=False))

# new code:     
    X = np.empty([M, n-1, o-46, 1])
    for i in range(M):
        ds_arr=dset[index[i],1:,1:256]   
        ds_arr=ds_arr[..., np.newaxis]
        X[i,:,:,:] = ds_arr

# Remove mean & standardize data:

Тщательно проверьте мои нотации нарезки. Я не совсем уверен, какое значение вы хотите удалить из второго индекса (первое или последнее значение?). Я получил ошибку трансляции, когда использовал ds_arr=dset[index[i],1:-1,1:256]. Сообщение об ошибке:

ValueError: could not broadcast input array from shape (63,255,1) into shape (64,255,1) 
...