如何批量读取大型 .h5 数据集的数据,使用 ImageDataGenerator 和 model.fit 进行预处理,而不 运行 内存不足?

How do I read data from large .h5 dataset in batches, preprocess with ImageDataGenerator & model.fit, all without running out of memory?

摘要: 运行 尝试使用 TF/Keras 处理大型数据集时内存不足。我知道批处理是解决方案的主要组成部分...只是不明白如何实施。

问题:如何从一个非常大的.h5数据集中批量读入数据,standardize/remove均值,然后拆分数据,全部不用运行ning内存不足?

上下文: 构建一个工作流来研究自然发生的地震信号的无监督深度嵌入聚类 (DEC)。这个问题特别是在数据的预处理中,即为 training/validating 和 autoencoder/decoder.

准备数据

数据: ~6e6 阵列地震检测的频谱图。 维度:(m,n,o) = (6e6, 66, 301) = (samples, freq_bins, time_bins).
数据存储在一个数据集下的 .h5 文件中。
.h5 文件占用约 1 TB 的磁盘空间。

硬件: 双 Intel Xeon E5-2683 v4 2.1 GHz,40MB 缓存,16 核,2 Titan GPU,528GB RAM

当前预处理程序:
1. Assemble 一个 numpy 数组 X,由 M 个频谱图组成,选择 M 个随机索引,按升序排序,并迭代切片 .h5 数据集。 (另外:这里最快的方法是保存 .h5 数据集,其中包含为以后读取而优化的块,然后使用简单的 "for" 循环来访问数据。花哨的索引和 "read_direct" 花费了更长的时间遍历数据集。)
2. Trim 来自 X 的不必要数据(频率和时间仓值,以及数据的最后 46 个时间仓)并添加第 4 个轴,"p",作为 "amplitude bin." 最终形状:(m, n,o,p) = (M,64,256,1).
3. 去除均值并对数据进行标准化。
4. 将 X 分成 training/validation 组。

# 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% 的 RAM(总 RAM 为 528GB)。 运行 上面的代码产生下面的内存错误。考虑到操作是复制整个数组,我 运行 内存不足也就不足为奇了...

---------------------------------------------------------------------------
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 数据集中批量读取数据,standardize/remove 平均值,然后拆分数据,所有这些都没有 运行ning内存?

虽然我花了很多时间试图解决这个问题,但我不清楚如何将所有部分组合在一起,这就是为什么我正在寻找一些经过深思熟虑的指导来推动我做出正确的决定方向。预先感谢您的帮助!

您必须避免使 X 的内存占用量翻倍的进程。 (我知道,这是显而易见的)。这是一个大数组,使用 X = X[:,1:-1,1:256](可能使用 X = X[..., np.newaxis])需要双倍的内存。
他们的关键是在最终需要的 size/shape 中分配 X (以避免复制)。然后修改你的逻辑,将数据从dsetf['/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)