Подтвердить что ты не робот

Методы работы с большими массивами Numpy?

Иногда вам приходится выполнять много промежуточных операций на одном или нескольких больших массивах Numpy. Это может привести к MemoryError s. В моих исследованиях до сих пор, U обнаружили, что травление (Pickle, CPickle, Pytables и т.д.) И gc.collect() - это способы смягчения этого. Мне было интересно, есть ли какие-либо другие методы, которые опытные программисты используют при работе с большими объемами данных (за исключением удаления избыточности в вашей стратегии/коде, конечно).

Кроме того, если я уверен, что нет ничего свободного. С некоторыми из этих методов, каковы компромиссы (то есть скорость, надежность и т.д.)?

4b9b3361

Ответ 1

Я чувствую вашу боль... Иногда вы в конечном итоге сохраняете несколько раз размер вашего массива в значениях, которые вы позже сбросите. При обработке одного элемента в массиве за раз это не имеет значения, но может убить вас при векторизации.

Я использую пример из работы для иллюстрации. Недавно я закодировал алгоритм, описанный здесь, используя numpy. Это алгоритм цветовой карты, который принимает изображение RGB и преобразует его в изображение CMYK. Процесс, который повторяется для каждого пикселя, выглядит следующим образом:

  • Используйте самые важные 4 бита каждого значения RGB, как индексы в трехмерную таблицу поиска. Это определяет значения CMYK для 8 вершин куба внутри LUT.
  • Используйте наименее значимые 4 бита каждого значения RGB для интерполяции внутри этого куба на основе значений вершин с предыдущего шага. Самый эффективный способ сделать это требует вычисления 16 массивов uint8s размером обрабатываемого изображения. Для 24-битного изображения RGB, которое эквивалентно необходимости хранения в x6 раза, чем изображение для его обработки.

Несколько вещей, которые вы можете сделать, чтобы справиться с этим:

1. Разделите и победите

Возможно, вы не можете обработать массив 1000x1000 за один проход. Но если вы можете сделать это с помощью python для цикла, повторяющего более 10 массивов размером 100x1000, он все равно будет бить на очень отдаленном итераторе python более 1 000 000 элементов! Это будет медленнее, да, но не так много.

2. Кэширование дорогостоящих вычислений

Это относится непосредственно к моему примеру интерполяции выше, и его сложнее встретить, хотя стоит держать его открытым. Поскольку я интерполирую на трехмерном кубе с 4 битами в каждом измерении, возможны только 16x16x16 возможных результатов, которые могут быть сохранены в 16 массивах 16x16x16 байт. Таким образом, я могу прекомпилировать их и хранить их с использованием 64 Кбайт памяти, а также искать значения один за другим для всего изображения, а не повторять одни и те же операции для каждого пикселя при огромной стоимости памяти. Это уже окупается для изображений размером до 64x64 пикселей и в основном позволяет обрабатывать изображения с x6 раз большим количеством пикселей без разделения массива.

3. Используйте dtypes мудро

Если ваши промежуточные значения могут вписываться в один uint8, не используйте массив int32 s! Это может превратиться в кошмар загадочных ошибок из-за молчаливого переполнения, но если вы будете осторожны, это может обеспечить большую экономию ресурсов.

Ответ 2

Первый наиболее важный трюк: выделить несколько больших массивов и использовать и перерабатывать их части, вместо того, чтобы приводить в жизнь и отбрасывать/мусор, собирать много временных массивов. Звучит немного старомодно, но с осторожным программированием ускорение может быть впечатляющим. (Вам лучше контролировать выравнивание и локальность данных, поэтому числовой код можно сделать более эффективным.)

Второе: используйте numpy.memmap и надеемся, что кэширование доступа к ресурсам на ОС достаточно эффективно.

В-третьих: как указано @Jaime, работайте с блочными подматрицами, если вся матрица имеет большой размер.

EDIT:

Избегайте ненужного понимания списка, как указано в ответе в SE.

Ответ 3

Если это возможно, используйте numexpr. Для числовых вычислений, таких как a**2 + b**2 + 2*a*b (для a и b являются массивами), он

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

  • использует все ядра вашего двухъядерного или четырехъядерного процессора,

  • является расширением numpy, а не альтернативой.

Для массивов среднего и большого размера, это быстрее, чем только numpy.

Взгляните на приведенную выше веб-страницу, есть примеры, которые помогут вам понять, является ли numexpr для вас.

Ответ 4

Библиотека dask.array предоставляет интерфейс numpy, который использует блокированные алгоритмы для обработки массивов большего размера, чем массивы с несколькими ядрами.

Вы также можете посмотреть Spartan, Distarray и Biggus.