Вопрос-Ответ

Unable to allocate array with shape and data type

Невозможно выделить массив с формой и типом данных

Я столкнулся с проблемой выделения огромных массивов в numpy в Ubuntu 18, но не столкнулся с такой же проблемой в macOS.

Я пытаюсь выделить память для numpy-массива с формой (156816, 36, 53806) с помощью

np.zeros((156816, 36, 53806), dtype='uint8')

и пока я получаю сообщение об ошибке в ОС Ubuntu

>>> import numpy as np
>>> np.zeros((156816, 36, 53806), dtype='uint8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
numpy.core._exceptions.MemoryError: Unable to allocate array with shape (156816, 36, 53806) and data type uint8

Я не получаю это на macOS:

>>> import numpy as np 
>>> np.zeros((156816, 36, 53806), dtype='uint8')
array([[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]],

[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]],

[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]],

...,

[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]],

[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]],

[[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]]], dtype=uint8)

Я где-то читал, что np.zeros на самом деле не следует выделять всю память, необходимую для массива, а только для ненулевых элементов. Несмотря на то, что на компьютере Ubuntu установлено 64 ГБ памяти, в то время как на моем MacBook Pro - только 16 ГБ.

Версии:

Ubuntu
os -> ubuntu mate 18
python -> 3.6.8
numpy -> 1.17.0

mac
os -> 10.14.6
python -> 3.6.4
numpy -> 1.17.0

PS: также сбой в Google Colab

Переведено автоматически
Ответ 1

Вероятно, это связано с режимом избыточной обработки в вашей системе.

В режиме по умолчанию, 0,


Эвристическая обработка избыточных обязательств. Очевидные избыточные обязательства адресного пространства отклоняются. Используется для типичной системы. Это гарантирует сбой при серьезном необузданном распределении, позволяя избыточным обязательствам уменьшить использование подкачки. В этом режиме root может выделять немного больше памяти. Это значение по умолчанию.


Точная используемая эвристика здесь недостаточно хорошо объяснена, но подробнее это обсуждается в Linux через commit evuristic и на этой странице .

Вы можете проверить свой текущий режим избыточной привязки, выполнив

$ cat /proc/sys/vm/overcommit_memory
0

В этом случае вы выделяете

>>> 156816 * 36 * 53806 / 1024.0**3
282.8939827680588

~ 282 ГБ, и ядро, очевидно, говорит, что я никак не смогу выделить для этого столько физических страниц, и оно отказывается от выделения.

Если (от имени root) вы запускаете:

$ echo 1 > /proc/sys/vm/overcommit_memory

Это включит режим "всегда перегружать", и вы обнаружите, что система действительно позволит вам выполнять выделение независимо от того, насколько оно велико (по крайней мере, в пределах 64-битной адресации памяти).

Я сам тестировал это на компьютере с 32 ГБ оперативной памяти. В режиме overcommit 0 я также получил MemoryError, но после замены его обратно на 1 он работает:

>>> import numpy as np
>>> a = np.zeros((156816, 36, 53806), dtype='uint8')
>>> a.nbytes
303755101056

Затем вы можете продолжить запись в любое место в массиве, и система будет выделять физические страницы только при явной записи на эту страницу. Таким образом, вы можете использовать это с осторожностью для разреженных массивов.

Ответ 2

У меня была такая же проблема в Window, и я наткнулся на это решение. Итак, если кто-то столкнется с этой проблемой в Windows, решением для меня было увеличить размер файла подкачки, поскольку для меня это тоже была проблема с избыточным объемом памяти.

Windows 8


  1. На клавиатуре нажмите WindowsKey + X, затем выберите System во всплывающем меню

  2. Коснитесь или щелкните Дополнительные системные настройки. Вас могут попросить ввести пароль администратора или подтвердить ваш выбор

  3. На вкладке Дополнительно в разделе Производительность коснитесь или щелкните Настройки.

  4. Коснитесь или щелкните вкладку Дополнительно, а затем в разделе Виртуальная память коснитесь или щелкните Изменить

  5. Снимите флажок Автоматически управлять размером файла подкачки для всех дисков.

  6. В разделе Диск [Метка тома] коснитесь диска, содержащего файл подкачки, который вы хотите изменить

  7. Коснитесь или щелкните Пользовательский размер, введите новый размер в мегабайтах в поле начальный размер (МБ) или Максимальный размер (МБ), коснитесь или щелкните Установить, а затем коснитесь или нажмите OK

  8. Перезагрузите систему

Windows 10


  1. Нажмите клавишу Windows

  2. Введите SystemPropertiesAdvanced

  3. Нажмите Запуск от имени администратора

  4. В разделе Производительность нажмите Настройки

  5. Выберите вкладку Дополнительно

  6. Выберите Изменить...

  7. Снимите флажок Автоматически управлять размером файла подкачки для всех дисков

  8. Затем выберите пользовательский размер и заполните соответствующий размер

  9. Нажмите Set, затем нажмите OK, затем выйдите из диалогового окна виртуальной памяти, параметров производительности и системных свойств.

  10. Перезагрузите систему

Примечание: У меня в системе не хватило памяти на ~ 282 ГБ в этом примере, но для моего конкретного случая это сработало.

Редактировать

Из здесь предложены рекомендации по размеру файла подкачки:


Существует формула для вычисления правильного размера файла подкачки. Начальный размер равен полутора (1,5) кратному объему общей системной памяти. Максимальный размер равен трем (3) кратному исходному размеру. Итак, допустим, у вас есть 4 ГБ (1 ГБ = 1,024 МБ x 4 = 4,096 МБ) памяти. Начальный размер будет 1,5 x 4096 = 6,144 МБ, а максимальный размер будет 3 x 6,144 = 18,432 МБ.


Некоторые вещи, которые следует иметь в виду отсюда:


Однако при этом не учитываются другие важные факторы и системные настройки, которые могут быть уникальными для вашего компьютера. Опять же, позвольте Windows выбирать, что использовать, вместо того, чтобы полагаться на какую-то произвольную формулу, которая работала на другом компьютере.


Также:


Увеличение размера файла подкачки может помочь предотвратить нестабильность и сбои в Windows. Однако время чтения / записи с жесткого диска намного медленнее, чем было бы, если бы данные находились в памяти вашего компьютера. Больший размер файла подкачки добавит дополнительной нагрузки на ваш жесткий диск, в результате чего все остальное будет работать медленнее. Размер файла подкачки следует увеличивать только при возникновении ошибок нехватки памяти и только в качестве временного исправления. Лучшим решением является добавление большего объема памяти на компьютер.


Ответ 3

Я тоже сталкивался с этой проблемой в Windows. Решением для меня было переключиться с 32-разрядной на 64-разрядную версию Python. Действительно, 32-разрядное программное обеспечение, такое как 32-разрядный процессор, может использовать максимум 4 ГБ оперативной памяти (2 ^ 32). Итак, если у вас более 4 ГБ оперативной памяти, 32-разрядная версия не сможет воспользоваться этим преимуществом.

С 64-разрядной версией Python (обозначенной x86-64 на странице загрузки) проблема исчезает.

Вы можете проверить, какая у вас версия, введя интерпретатор. У меня теперь 64-разрядная версия, и у меня есть: Python 3.7.5rc1 (tags/v3.7.5rc1:4082f600a5, Oct 1 2019, 20:28:14) [MSC v.1916 64 bit (AMD64)], где [MSC v.1916 64 bit (AMD64)] означает "64-разрядный Python".

Исходники :

Ответ 4

В моем случае добавление атрибута dtype изменило dtype массива на меньший тип (с float64 на uint8), уменьшив размер массива настолько, чтобы не вызывать MemoryError в Windows (64-разрядная версия).

От

mask = np.zeros(edges.shape)

Для

mask = np.zeros(edges.shape,dtype='uint8')
python numpy