我正在从事一个以图像作为输入的深度学习项目。由于其他一些要求,我无法随时从文件夹中加载图像,需要事先加载。
我很难将所有图像加载到 numpy 数组中,因为它们很多。也就是说,由于列表的长度,我经常用完 Google Colab 上的 25 GB RAM。我知道列表非常占用空间,而 numpy 数组则不是。但是,将图像直接加载到 numpy 数组中是很痛苦的。所以,我想出了一种解决方法,我一次只将 1000 张图像加载到列表中,将其转换为 numpy 数组并附加它。这一切似乎都运行得非常好,直到大约第九次交互时,RAM 使用量从大约 3GB 跃升至 25GB,一切都崩溃了。
我正在使用以下代码:
# Get images
def get_images(folder):
imgsl = []
i = 0
for filename in os.listdir(folder):
imgsl.append(img_to_array(load_img(folder + filename)))
i += 1
if i == 19:
imgs = np.array(imgsl, dtype=float)
imgsl = []
if i%1000 == 0:
i = 20
imgst = np.array(imgsl, dtype=float)
imgsl = []
imgs = np.append(imgs, imgst, axis = 0)
print('Thousand images processed!')
print('len: imgls: ', len(imgsl))
print('imgs shape: ', imgs.shape)
#imgs = np.array(imgs, dtype=float)
imgst = np.array(imgsl, dtype=float)
imgsl = []
imgs = np.append(imgs, imgst, axis = 0)
return imgs
并获得预期的结果,直到它崩溃:
Thousand images processed!
len: imgls: 0
imgs shape: (1000, 224, 224, 3)
Thousand images processed!
len: imgls: 0
imgs shape: (1980, 224, 224, 3)
Thousand images processed!
len: imgls: 0
imgs shape: (2960, 224, 224, 3)
Thousand images processed!
len: imgls: 0
imgs shape: (3940, 224, 224, 3)
Thousand images processed!
len: imgls: 0
imgs shape: (4920, 224, 224, 3)
Thousand images processed!
len: imgls: 0
imgs shape: (5900, 224, 224, 3)
Thousand images processed!
len: imgls: 0
imgs shape: (6880, 224, 224, 3)
Thousand images processed!
len: imgls: 0
imgs shape: (7860, 224, 224, 3)
Thousand images processed!
len: imgls: 0
imgs shape: (8840, 224, 224, 3)
Thousand images processed!
len: imgls: 0
imgs shape: (9820, 224, 224, 3)
知道发生了什么事吗?或修复它的建议?谢谢!
回答1
我很难将所有图像加载到 numpy 数组中,因为它们很多
这样做通常是不合理的,并且会导致像您看到的那样占用大量内存。
我知道列表非常占用空间,而 numpy 数组不是。
如果列表包含 Numpy 数组,则不成立。在 64 位平台上,列表的开销是每个项目对内存中 CPython 对象的 8 字节引用和每个列表的小标题(<100 字节)。假设你的图像很大,这个开销可以忽略不计。然而,使用 list of list to store N images 会非常昂贵(因为每个 integer/float value 将存储在一个单独的 CPython 对象中,除了引用之外还要占用几十个字节)。
将图像直接加载到 numpy 数组中是很痛苦的。
这取决于用于加载它们的库。 OpenCV 等一些库直接为您提供 Numpy 数组(顺便说一句,这非常方便)。
我想出了一种解决方法,我一次只将 1000 张图像加载到列表中
不错的决定,尽管它仍然需要很大的空间(小批量肯定更合理)。
这一切似乎都运行得非常好,直到大约第九次交互时,RAM 使用量从大约 3GB 跃升至 25GB,一切都崩溃了。
一个问题是您使用 np.append
每次都会创建一个新数组。每个数组都是根据前一个数组构建的,因此您实际上至少需要其中的 2 个。这也可能导致内存碎片,从而导致更高的内存占用。您应该将项目附加到列表中,然后连接数组(例如,使用 np.concatenate
或替代函数,如 np.vstack
/ np.hstack
)。
另一个问题是 np.array(imgsl, dtype=float)
,这肯定是最大的一个。实际上,图像通常使用每个组件 1 个字节进行编码(例如,每个像素 3 或 4 个字节)。 float
类型表示数组项是 64 位浮点数。因此,生成的数组每个组件占用 8 个字节,这是不合理的(在空间和时间效率方面)。一个小的改进是使用 32 位浮点数 (np.float32
)。您可以尝试 np.float16
类型以进一步减少内存占用。不过,它比基于 uint8
/int8
的数组多占用 2 倍的空间,更不用说这两个数组应该同时存储在内存中以进行转换。更好的方法是预先分配输出数组并在循环中动态填充它。