Советы по обработке большого количества изображений в python

Я пытаюсь обработать два огромных файла, содержащих около 40000-50000 изображений в python. Но всякий раз, когда я пытаюсь преобразовать свои наборы данных в массив numpy, я получаю ошибку памяти. У меня только около 8 ГБ оперативной памяти, что не очень много, но, поскольку мне не хватает опыта в python, мне интересно, есть ли способ решить эту проблему, используя некоторую библиотеку python, о которой я не знаю, или, может быть, оптимизировать мой код? Я хотел бы услышать ваше мнение по этому вопросу.

Мой код обработки изображений:

from sklearn.cluster import MiniBatchKMeans
import numpy as np
import glob
import os
from PIL import Image
from sklearn.decomposition import PCA

image_dir1 = "C:/Users/Ai/Desktop/KAGA FOLDER/C/train"
image_dir2 = "C:/Users/Ai/Desktop/KAGA FOLDER/C/test1"
Standard_size = (300,200)
pca = PCA(n_components = 10)
file_open = lambda x,y: glob.glob(os.path.join(x,y))


def matrix_image(image):
    "opens image and converts it to a m*n matrix" 
    image = Image.open(image)
    print("changing size from %s to %s" % (str(image.size), str(Standard_size)))
    image = image.resize(Standard_size)
    image = list(image.getdata())
    image = map(list,image)
    image = np.array(image)
    return image
def flatten_image(image):  
    """
    takes in a n*m numpy array and flattens it to 
    an array of the size (1,m*n)
    """
    s = image.shape[0] * image.shape[1]
    image_wide = image.reshape(1,s)
    return image_wide[0]

if __name__ == "__main__":
    train_images = file_open(image_dir1,"*.jpg")
    test_images = file_open(image_dir2,"*.jpg")
    train_set = []
    test_set = []

    "Loop over all images in files and modify them"
    train_set = [flatten_image(matrix_image(image))for image in train_images]
    test_set = [flatten_image(matrix_image(image))for image in test_images]
    train_set = np.array(train_set) #This is where the Memory Error occurs
    test_set = np.array(test_set)

Небольшое редактирование: я использую 64-разрядный питон

Ответ 1

Предполагая целое число в 4 байта для каждого пикселя, вы пытаетесь хранить около 11,2 ГБ данных в (4 * 300 * 200 * 50000/(1024) ** 3). Половина этого для целых 2 байтов.

У вас есть несколько вариантов:

  • Уменьшите количество или размер изображений, которые вы пытаетесь сохранить в памяти.
  • Используйте файл или базу данных для хранения данных вместо памяти (может быть слишком медленным для некоторых приложений)
  • Используйте более эффективную память...

Вместо копирования из списка в numpy, который временно будет использовать вдвое больше объема памяти, как вы здесь:

test_set = [flatten_image(matrix_image(image))for image in test_images]
test_set = np.array(test_set)

Сделайте это:

n = len(test_images)
test_set = numpy.zeros((n,300*200),dtype=int)
for i in range(n):
    test_set[i] = flatten_image(matrix_image(test_images[i]))

Ответ 2

Поскольку ваши файлы JPEG и у вас есть изображения размером 300x200, для 24-битного цветного изображения вы просматриваете примерно 1,4 МБ на файл и, по крайней мере, всего 40,2 ГБ в целом:

In [4]: import humanize # `pip install humanize` if you need it

In [5]: humanize.naturalsize(300*200*24, binary=True)
Out[5]: '1.4 MiB'

In [6]: humanize.naturalsize(300*200*24*30000, binary=True)
Out[6]: '40.2 GiB'

Если у вас есть оттенки серого, у вас, вероятно, есть 8-битные изображения, которые звонят в 13,4 ГБ:

In [7]: humanize.naturalsize(300*200*8, binary=True)
Out[7]: '468.8 KiB'

In [8]: humanize.naturalsize(300*200*8*30000, binary=True)
Out[8]: '13.4 GiB'

Это только для одной копии. В зависимости от операций это может стать намного больше.

Перейти больше

Вы всегда можете арендовать некоторое время на сервере с большим объемом памяти.

Глядя на них по объему ОЗУ - это не единственный способ подумать о том, какие серверы лучше всего подходят для вашей рабочей нагрузки. Существуют и другие различия между поставщиками, включая IOPS, количество ядер, тип процессора и т.д.

Тест после тренировки

После обучения модели вам не нужен полный набор данных для обучения. Удалите, что вы можете потерять из памяти. Здесь, на земле Python, это означает, что не следует ссылаться на данные. Странный зверь, да.

Скорее всего, это настройка ваших данных обучения и создание вашей модели в рамках функции, которая возвращает только то, что вам нужно.

Уменьшение объема памяти

Представьте себе на мгновение, что вы можете сохранить все это в памяти. Одним из улучшений, которые вы можете сделать здесь, является конвертировать непосредственно из PIL-изображения в массив numpy. Существующие массивы не копируются, а вид исходных данных. Однако, похоже, что вам нужно flatten также в ваше векторное пространство.

image = Image.open(image)
print("changing size from %s to %s" % (str(image.size), str(Standard_size)))
image = image.resize(Standard_size)
np_image = np.asarray(image).flatten()

EDIT: На самом деле это помогает поддерживать ваш код, но не помогает производительности. Вы выполняете эту операцию для каждого изображения в функции по отдельности. Сборщик мусора будет бросать старые вещи. Двигайтесь дальше, ничего не видно здесь.