Неможливо виділити масив із формою та типом даних


105

Я стикаюся з проблемою виділення величезних масивів у 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
Чи працюють в пам'яті інші процеси?
BlueRine S

ні, я пробував topі free -m, ті команди, куди всували 60 Гб вільної пам'яті та більше
Мартін Брисяк

хммм. дивний. Це не повинно забирати стільки пам'яті. Скільки пам'яті він зайняв на Macos?
BlueRine S

1
Навряд чи, але у вас випадково не працює 32-розрядний інтерпретатор Python в Ubuntu, чи не так?
jdehesa

1
np.zerosне створює sparseматрицю. Можливо затримка заповнення нулів. Але побачити stackoverflow.com/q/27464039
hpaulj

Відповіді:


107

Можливо, це пов’язано з режимом обробки надмірних зобов’язань вашої системи .

У режимі за замовчуванням 0,

Евристична обробка надміру. Очевидні надмірності адресного простору відмовляються. Використовується для типової системи. Це гарантує серйозний збій розподілу, дозволяючи надміру зменшити використання свопу. root може виділяти трохи більше пам'яті в цьому режимі. Це за замовчуванням.

Точна використана евристика тут недостатньо пояснена, але це обговорюється більше в Linux, а не на евристиці комітів та на цій сторінці .

Ви можете перевірити поточний режим надмірної комісії, запустивши

$ 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 ГБ оперативної пам'яті. У режимі надмірної комісії 0я також отримав a MemoryError, але після його повернення до 1нього працює:

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

Потім ви можете продовжувати писати в будь-яке місце в масиві, і система буде виділяти фізичні сторінки лише тоді, коли ви явно пишете на цю сторінку. Тож ви можете обережно використовувати це для розріджених масивів.


2
Це конкретно особливість ядра Linux, тому на MacOS немає необхідного прямого еквівалента, хоча можливо щось подібне. Я не думаю, що Mac так просто перевертати налаштування ядра.
Ігуанановт

1
@Iguananaut, яке саме значення має попередження "з обережністю"? тобто Який найгірший сценарій, коли з цим щось піде не так на сервері Ubuntu 18 з графічним процесором GTX 1080?
mLstudent33

1
@ mLstudent33 По-перше, це не має нічого спільного з вашим графічним процесором, який має власну пам’ять. Все, що я маю на увазі, це те, що ви все ще можете заповнити свою пам’ять - кожен раз, коли ви пишете на якусь сторінку в пам’яті, ця сторінка (як правило, 4 кбайти) повинна бути виділена у фізичну пам’ять. Тож найгірший сценарій - у вас закінчується пам’ять.
Ігуанановт

1
Чи ця зміна набирає чинності негайно, чи нам потрібно перезапустити нашу оболонку або саму машину?
dumbledad

2
Він набирає негайної сили, але після перезавантаження не буде тривати без додаткових заходів. Шукайте інші запитання про те, як найкраще зберігати /proc/sysналаштування у вашому розповсюдженні.
Ігуананоут

45

У мене була така сама проблема на Window's і я натрапив на це рішення. Отже, якщо хтось стикається з цією проблемою у Windows, рішенням для мене було збільшення розміру файлу сторінки , оскільки це для мене теж було проблемою перевитрати пам’яті.

Windows 8

  1. На клавіатурі натисніть клавішу WindowsKey + X, а потім у спадному меню натисніть Система
  2. Торкніться або клацніть Додаткові налаштування системи. Можливо, вас попросять ввести пароль адміністратора або підтвердити свій вибір
  3. На вкладці Додатково в розділі Продуктивність торкніться або клацніть Налаштування.
  4. Торкніться або клацніть вкладку Додатково, а потім у розділі Віртуальна пам’ять торкніться або натисніть Змінити
  5. Зніміть прапорець Автоматично керувати розміром файлу підкачки для всіх дисків.
  6. У розділі Диск [Мітка гучності] торкніться або клацніть диск, який містить файл підкачки, який потрібно змінити
  7. Торкніться або клацніть Нестандартний розмір, введіть новий розмір у мегабайтах у полі початковий розмір (МБ) або Максимальний розмір (МБ), торкніться або клацніть Встановити, а потім торкніться або натисніть OK
  8. Перезавантажте систему

Windows 10

  1. Натисніть клавішу Windows
  2. Введіть SystemPropertiesAdvanced
  3. Клацніть Запустити від імені адміністратора
  4. Клацніть Налаштування
  5. Виберіть вкладку Додатково
  6. Виберіть Змінити ...
  7. Зніміть прапорець біля пункту Автоматичне керування розміром файлу підкачки для всіх дисків
  8. Потім виберіть Нестандартний розмір та заповніть відповідний розмір
  9. Натисніть Встановити, потім натисніть OK, а потім вийдіть із віртуальної пам'яті, параметрів продуктивності та діалогового вікна властивостей системи
  10. Перезавантажте систему

Примітка: У моїй системі не вистачало пам’яті на ~ 282 Гб у цьому прикладі, але для мого конкретного випадку це спрацювало.

РЕДАГУВАТИ

З тут запропонованих рекомендацій за розміром файлу підкачки:

Існує формула для розрахунку правильного розміру файлу сторінки. Початковий розмір - півтора (1,5) х обсягу загальної системної пам'яті. Максимальний розмір - три (3) x початковий розмір. Тож припустимо, у вас є 4 ГБ (1 ГБ = 1024 МБ x 4 = 4096 МБ) пам’яті. Початковий розмір складе 1,5 х 4 096 = 6 144 МБ, а максимальний розмір - 3 х 6 144 = 18 432 МБ.

Деякі речі, про які слід пам’ятати звідси :

Однак це не враховує інших важливих факторів та системних налаштувань, які можуть бути унікальними для вашого комп'ютера. Знову ж таки, нехай Windows вибирає, що використовувати, а не покладатися на якусь довільну формулу, яка працювала на іншому комп’ютері.

Також:

Збільшення розміру файлу сторінки може допомогти запобігти нестабільності та збоям у роботі Windows. Однак час читання / запису на жорсткому диску набагато повільніший, ніж те, що було б, якби дані були в пам'яті комп'ютера. Маючи більший файл сторінки, це додасть додаткової роботи на вашому жорсткому диску, в результаті чого все інше працюватиме повільніше. Розмір файлу сторінки слід збільшувати лише при виявленні помилок, що не входять до пам'яті, і лише як тимчасове виправлення. Краще рішення - додати більше пам’яті до комп’ютера.


які налаштування нестандартного розміру (початковий розмір + максимальний розмір) у вас зараз? Не знаю, скільки виділити собі
Азізбро

1
@Azizbro Я повернувся до типового за замовчуванням, але просто регулював значення, доки помилка нестачі пам'яті не зникла.
повторити до

23

Я зіткнувся з цією проблемою і в 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".

Примітка : станом на час написання статті (травень 2020 р.)Matplotlib недоступний на python39, тому я рекомендую встановити python37, 64 біти.

Джерела:


Дякую. З останньою стабільною 64-розрядною версією Python (3.8.3) я також можу встановити matplotlib.
Федеріко Томасі

1
Як ввести перекладача?
Шаян

Вирішив і мою проблему. Використання Pycharm. Видалена 32-розрядна версія, переінстальована 64-розрядна, змінено інтерпретатор проекту на новий 64-розрядний пітон.
Джейсон Гол

3

У моєму випадку додавання атрибута dtype змінило тип dray масиву на менший тип (з float64 на uint8), зменшивши розмір масиву настільки, щоб не викликати MemoryError у Windows (64 біт).

від

mask = np.zeros(edges.shape)

до

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


1

змінити тип даних на інший, який використовує менше пам'яті. Для мене я зміню тип даних на numpy.uint8:

data['label'] = data['label'].astype(np.uint8)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.