我将一些图像数据复制到了Google Cloud上的一个实例(8个vCPU,64GB内存,Tesla K80 GPU),在将原始数据转换为特征并更改输出数据结构时遇到了内存问题。最终我想在Keras/Tensorflow神经网络中使用这些派生特征。
过程
将数据复制到存储桶后,我运行了一个build_features.py函数,将原始数据转换为神经网络处理的数据。在这个流程中,我首先将每张原始图像放入一个列表x中(这个列表存储派生特征)。
由于我处理的是大量图像(数万张类型为float32,尺寸为250x500x3的图像),列表x变得非常大。x的每个元素都是一个存储图像形状为250x500x3的numpy数组。
问题1 – 随着列表x增大,内存减少
我拍了两张截图,显示了随着x的增长,可用内存减少(见下图)。我最终能够完成这一步骤,但只剩下几GB的内存,所以我肯定想解决这个问题(将来我想处理更大的数据集)。如何构建特征以避免受x大小的限制?
问题2 – 将x转换为numpy数组时内存错误
实例实际失败的步骤如下:
x = np.array(x)
失败信息是:
Traceback (most recent call last): File "build_features.py", line 149, in <module> build_features(pipeline='9_11_2017_fan_3_lights') File "build_features.py", line 122, in build_features x = np.array(x)MemoryError
如何调整这一步骤以避免内存不足?
回答:
你的代码中每张图像有两个副本 – 一个在列表中,一个在数组中:
images = []for i in range(many): images[i] = load_img(i) # 这里是第一张图像x = np.array(images) # 将它们全部合并成第二个副本
直接将图像加载到数组中
x = np.zeros((many, 250, 500, 3))for i in range(many): x[i] = load_img(i)
这意味着你一次只持有一个图像的副本。
如果你事先不知道图像的大小或数据类型,或者不想硬编码,你可以使用:
x0 = load_img(0)x = np.zeros((many,) + x0.shape, x0.dtype)for i in range(1, many): x[i] = load_img(i)
尽管如此,你现在走的是一条艰难的路。如果你没有足够的空间在内存中存储数据集的两倍,你也没有空间计算y = x + 1
。
你可能需要考虑使用np.float16
来换取更多的存储空间,但这会牺牲精度。