微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 Tensorflow/Keras 和内存问题训练神经网络,输入作为矩阵的滑动窗口

如何解决使用 Tensorflow/Keras 和内存问题训练神经网络,输入作为矩阵的滑动窗口

我有一个数据集,它是一个形状为 (100 000,2 000) 的大矩阵。

我想用这个大矩阵的形状 (16,2000) 的所有可能的滑动窗口/子矩阵来训练我的 Tensorflow 神经网络。

enter image description here

我使用:

from skimage.util.shape import view_as_windows

A.shape  # (100000,2000)  ie 100k x 2k matrix
X = view_as_windows(A,(16,2000)).reshape((-1,16,2000,1))
X.shape   # (99985,1)
...
model.fit(X,Y,batch_size=4,epochs=8)

不幸的是,这会导致内存问题:

W tensorflow/core/framework/allocator.cc:122] ...的分配超过系统内存的 10%。

这是正常的,因为 X 有 ~ 100k * 16 * 2k 个系数,即超过 30 亿个系数!

但实际上,在内存中加载 X 是一种内存浪费,因为它高度冗余:它是由 A 上形状为 (16,2000) 的滑动窗口组成的.

问题:如何训练输入为宽度为 16 的所有滑动窗口超过 100k x 2k 矩阵的神经网络,而不浪费内存?

skimage.util.view_as_windows 的文档确实指出它的内存成本很高:

当涉及到内存使用时,应该非常小心滚动视图。实际上,尽管“视图”与其基本数组具有相同的内存占用,但在计算中使用此“视图”时出现的实际数组通常比原始数组大(很多),尤其是对于二维数组及以上。

例如,让我们考虑一个大小为 (100,100,100) 的 float64 的 3 维数组。 [...] 滚动视图的假设大小(例如,如果要重塑视图)将是 8*(100-3+1)3*33,大约 203 MB !随着输入数组的维度变大,缩放变得更糟。


编辑:timeseries_dataset_from_array 正是我正在寻找的,只是它仅适用于一维序列:

import tensorflow
import tensorflow.keras.preprocessing
x = list(range(100))
x2 = tensorflow.keras.preprocessing.timeseries_dataset_from_array(x,None,10,sequence_stride=1,sampling_rate=1,batch_size=128,shuffle=False,seed=None,start_index=None,end_index=None)
for b in x2:
    print(b)

它不适用于二维数组:

x = np.array(range(90)).reshape(6,15)
print(x)
x2 = tensorflow.keras.preprocessing.timeseries_dataset_from_array(x,(6,3),end_index=None)
# does not work

解决方法

您可以使用生成器动态生成示例,而不是将它们存储在内存中。

您可以编写自定义 generator 或由 keras 提供的生成器,例如 timeseries_dataset_from_array (docs),它们也可以在 sequence_stride 等选项的帮助下生成窗口。>

对于自定义生成器,您可以执行类似的操作

def generator_custom(df3):
    for idex,row in df3.iterrows():
            #some preprocessing
            yield X,y

然后您可以使用 tf.data 将 128/64/32 的批次作为

tf.data.Dataset.from_generator(lambda: generator_custom(df_train))
train_dataset = train_dataset.batch(128,drop_remainder=True)

回复你关于二维的评论

只是一个例子(例如我将 100000,2000 缩放到 1000.200,可以随意更改它们)

import numpy as np
x = np.array(range(200000)).reshape(1000,200)
x2 = tensorflow.keras.preprocessing.timeseries_dataset_from_array(x,None,16,sequence_stride=1,sampling_rate=1,batch_size=128)

这给了你类似的东西

形状(128、16、200)

形状(128、16、200)

你想要哪个(16*2000),对吧? (记住我们有 200 个只是为了显示目的)

,

如果使用 Tensorflow,您可以使用 Tensorflow 数据集并在数据上映射预处理函数,如下所示:

import tensorflow as tf

A.shape # (100000,2000)

def get_window(starting_idx):
    """Extract a window from A of shape (16,2000) as a tf.Tensor"""
    return tf.convert_to_tensor(A[starting_idx : starting_idx + 16])

# Make dataset for actual data
data_ds = tf.data.Dataset.range(A.shape[0] - 16)
data_ds = data_ds.map(get_window)

# Make dataset for labels
label_ds = tf.data.Dataset.from_tensor_slices(Y)

# Zip them into one dataset
ds = tf.data.Dataset.zip((data_ds,label_ds))

# Pre-batch the dataset
ds = ds.batch(4)

# Sanity check for batch size
for batch,label in ds:
    print(batch.shape)    # (4,2000,1)
    break

# Now call .fit() without batch size
model.fit(ds,epochs=8)

定义用于提取每个窗口并将其映射到现有数据集的函数应该可以解决您的内存问题,因为它应该允许仅在需要时形成窗口。

这通常是使用 Tensorflow 时处理数据的最佳方式之一,您可以通过这种方式处理大量数据。

有关详细信息,请参阅 tf.data.Datasettensorflow.org/guide/data

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。