python - 从列表构建长 np.array 的另一种方法 - Google Colab RAM 崩溃

我正在从事一个以图像作为输入的深度学习项目。由于其他一些要求,我无法随时从文件夹中加载图像,需要事先加载。

我很难将所有图像加载到 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 倍的空间,更不用说这两个数组应该同时存储在内存中以进行转换。更好的方法是预先分配输出数组并在循环中动态填充它。

相似文章

php - 挣扎于数组 php 中的索引

从rapidapi获取json数据并尝试将其放入canvasjs图表中。我相信为什么我的图表不打印的问题是因为我创建的数组没有正确的索引。我的数组在所需的每个元素上都有索引0,它的索引为0-13。<!...

随机推荐

最新文章