Dizi şekli ve veri türü ile ayrılamıyor


105

MacOS'ta aynı sorunla karşılaşmazken Ubuntu 18'de numpy'de büyük diziler tahsis etmekte bir sorunla karşı karşıyayım.

Bir şekle (156816, 36, 53806) sahip uyuşmuş bir dizi için bellek ayırmaya çalışıyorum

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

ve Ubuntu işletim sisteminde bir hata alırken

>>> 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'ta anlamıyorum:

>>> 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.zerosDizi için gereken tüm belleği gerçekten ayırmaması gereken bir yerde okudum , sadece sıfır olmayan öğeler için. Ubuntu makinemde 64 gb bellek olmasına rağmen, MacBook Pro'mda yalnızca 16 gb var.

sürümler:

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

Not: Google Colab'da da başarısız oldu


1
Bellekte çalışan başka işlemler var mı?
BlueRine S

hayır, denedim topve free -m60 gb mem ücretsiz ve daha fazlasını iten komutları
Martin Brisiak

hmmm. tuhaf. Bu o kadar hafızayı almamalı. Macos'ta ne kadar hafıza kaplıyordu?
BlueRine S

1
Pek olası değil, ancak Ubuntu'da 32 bitlik bir Python yorumlayıcısı çalıştırmıyorsunuz değil mi?
jdehesa

1
np.zerosbir sparsematris oluşturmaz . Sıfırların doldurulmasında bir gecikme olabilir. Ancak stackoverflow.com/q/27464039'a
hpaulj

Yanıtlar:


107

Bunun nedeni muhtemelen sisteminizin aşırı taahhüt işleme modudur.

Varsayılan modda 0,

Sezgisel aşırı taahhüt yönetimi. Adres alanının bariz şekilde aşırı yüklenmeleri reddedildi. Tipik bir sistem için kullanılır. Takas kullanımını azaltmak için aşırı yüklemeye izin verirken ciddi bir vahşi tahsisin başarısız olmasını sağlar. Bu modda root'un biraz daha fazla bellek ayırmasına izin verilir. Bu varsayılandır.

Kullanılan kesin buluşsal yöntem burada iyi bir şekilde açıklanmamıştır, ancak bu, Linux'ta daha çok commit sezgiselliğine göre ve bu sayfada tartışılmaktadır .

Mevcut aşırı taahhüt modunuzu çalıştırarak kontrol edebilirsiniz.

$ cat /proc/sys/vm/overcommit_memory
0

Bu durumda tahsis ediyorsunuz

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

~ 282 GB, ve çekirdek gayet açık bir şekilde bu kadar fiziksel sayfayı buna aktarmamın hiçbir yolu olmadığını söylüyor ve bu tahsisatı reddediyor.

Eğer (kök olarak) çalıştırırsanız:

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

Bu, "her zaman aşırı yükleme" modunu etkinleştirir ve gerçekten sistemin, ne kadar büyük olursa olsun (en azından 64 bit bellek adresleme dahilinde) ayırma yapmanıza izin verdiğini göreceksiniz.

Bunu 32 GB RAM'e sahip bir makinede kendim test ettim. Overcommit modu ile 0ayrıca bir tane aldım MemoryError, ancak tekrar değiştirdikten sonra 1çalışıyor:

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

Ardından devam edebilir ve dizi içindeki herhangi bir konuma yazabilirsiniz ve sistem yalnızca o sayfaya açıkça yazdığınızda fiziksel sayfaları tahsis eder. Yani bunu seyrek diziler için dikkatli bir şekilde kullanabilirsiniz.


2
Bu, özellikle Linux çekirdeğinin bir özelliğidir, bu nedenle, muhtemelen benzer bir şey olsa da, MacOS'ta zorunlu olarak doğrudan bir eşdeğeri yoktur. Çekirdek ayarlarını çevirmenin Mac'lerde o kadar kolay olduğunu sanmıyorum.
Iguananaut

1
@Iguananaut "özenli" uyarısının tam anlamı nedir? yani. GTX 1080 GPU'lu bir Ubuntu 18 sunucusunda bununla ilgili yanlış giden bir şeyin en kötü senaryosu nedir?
mLstudent33

1
@ mLstudent33 Birincisi, bunun kendi belleği olan GPU'nuzla ilgisi yoktur. Demek istediğim, hafızanızı yine de doldurabilirsiniz - hafızadaki bir sayfaya her yazdığınızda, bu sayfanın (tipik olarak 4k bayt) fiziksel belleğe ayrılması gerekir. Yani en kötü senaryo hafızanızın bitmesidir.
Iguananaut

1
Bu değişiklik hemen geçerli mi yoksa kabuğumuzu veya makineyi yeniden başlatmamız mı gerekiyor?
dumbledad

2
Anında etkili olur, ancak ek önlemler alınmadan yeniden başlatmanın ötesine geçmez. /proc/sysDağıtımınızdaki ayarların en iyi şekilde nasıl sürdürüleceğine dair diğer soruları araştırın .
Iguananaut

45

Aynı sorunu Windows'ta da yaşadım ve bu çözüme rastladım. Bu nedenle, Windows'ta birisi bu soruna rastlarsa benim için çözüm disk belleği dosyası boyutunu artırmaktı , çünkü bu benim için de bir Bellek aşırı taahhüdü sorunuydu.

Windows 8

  1. Klavyede WindowsKey + X'e basın, ardından açılır menüde Sistem'i tıklayın
  2. Gelişmiş sistem ayarları'na dokunun veya tıklayın. Bir yönetici şifresi girmeniz veya seçiminizi onaylamanız istenebilir
  3. Gelişmiş sekmesinde, Performans'ın altında Ayarlar'a dokunun veya tıklayın.
  4. Gelişmiş sekmesine dokunun veya tıklayın ve ardından Sanal bellek altında Değiştir'e dokunun veya tıklayın.
  5. Tüm sürücüler için disk belleği dosyası boyutunu otomatik yönet onay kutusunun işaretini kaldırın.
  6. Sürücü [Birim Etiketi] altında, değiştirmek istediğiniz disk belleği dosyasını içeren sürücüye dokunun veya tıklayın
  7. Özel boyut'a dokunun veya tıklayın, ilk boyut (MB) veya Maksimum boyut (MB) kutusuna megabayt cinsinden yeni bir boyut girin, Ayarla'ya dokunun veya tıklayın ve ardından Tamam'a dokunun veya tıklayın
  8. Sisteminizi yeniden başlatın

Windows 10

  1. Windows tuşuna basın
  2. Type SystemPropertiesAdvanced
  3. Yönetici olarak çalıştır'ı tıklayın.
  4. Ayarlar'ı tıklayın
  5. Gelişmiş sekmesini seçin
  6. Değiştir'i seçin ...
  7. Tüm sürücüler için disk belleği dosyası boyutunu otomatik olarak yönetme seçeneğinin işaretini kaldırın.
  8. Ardından Özel boyut'u seçin ve uygun boyutu doldurun
  9. Ayarla'ya ve ardından Tamam'a basın, ardından Sanal Bellek, Performans Seçenekleri ve Sistem Özellikleri İletişim Kutusundan çıkın
  10. Sisteminizi yeniden başlatın

Not: Bu örnekte ~ 282GB için sistemimde yeterli belleğe sahip değildim ama benim özel durumum için bu işe yaradı.

DÜZENLE

Gönderen burada sayfa dosya boyutu için öneriler önerdi:

Doğru disk belleği dosyası boyutunu hesaplamak için bir formül var. Başlangıç ​​boyutu bir buçuk (1,5) x toplam sistem belleği miktarıdır. Maksimum boyut, üç (3) x başlangıç ​​boyutudur. Diyelim ki 4 GB (1 GB = 1.024 MB x 4 = 4.096 MB) belleğiniz var. Başlangıç ​​boyutu 1,5 x 4,096 = 6,144 MB ve maksimum boyut 3 x 6,144 = 18,432 MB olacaktır.

Burada akılda tutulması gereken bazı noktalar :

Ancak bu, bilgisayarınıza özgü olabilecek diğer önemli faktörleri ve sistem ayarlarını dikkate almaz. Yine, Windows'un farklı bir bilgisayarda çalışan bazı rastgele formüle güvenmek yerine neyi kullanacağını seçmesine izin verin.

Ayrıca:

Sayfa dosyası boyutunu artırmak, Windows'ta kararsızlıkların ve çökmenin önlenmesine yardımcı olabilir. Bununla birlikte, bir sabit sürücü okuma / yazma süreleri, veriler bilgisayarınızın belleğinde olsaydı olacağından çok daha yavaştır. Daha büyük bir sayfa dosyasına sahip olmak, sabit sürücünüz için fazladan iş ekleyerek diğer her şeyin daha yavaş çalışmasına neden olur. Sayfa dosyası boyutu yalnızca yetersiz bellek hatalarıyla karşılaşıldığında ve yalnızca geçici bir düzeltme olarak artırılmalıdır. Daha iyi bir çözüm, bilgisayara daha fazla bellek eklemektir.


Şu anda hangi özel boyut (başlangıç ​​boyutu + maksimum boyut) ayarlarına sahipsiniz? Kendime ne kadar
ayıracağımdan

1
@Azizbro Şimdi varsayılana geri döndüm, ancak bellek yetersiz hatası ortadan kalkana kadar değerleri ayarladım.
2019, 04

23

Windows'ta da bu problemle karşılaştım. Benim için çözüm , Python'un 32 bit sürümünden 64 bit sürümüne geçmekti . Aslında, 32 bitlik bir CPU gibi 32 bitlik bir yazılım maksimum 4 GB RAM (2 ^ 32) adresleyebilir. Dolayısıyla, 4 GB'den fazla RAM'iniz varsa, 32 bitlik bir sürüm bundan yararlanamaz.

Python'un 64 bit sürümüyle ( indirme sayfasında x86-64 olarak etiketlenen ) sorun ortadan kalktı.

Tercümana girerek hangi sürüme sahip olduğunuzu kontrol edebilirsiniz. 64-bit sürümle, şimdi var:, Python 3.7.5rc1 (tags/v3.7.5rc1:4082f600a5, Oct 1 2019, 20:28:14) [MSC v.1916 64 bit (AMD64)]burada [MSC v.1916 64 bit (AMD64)] "64-bit Python" anlamına gelir.

Not : Bu yazının yazıldığı tarih itibariyle (Mayıs 2020), matplotlibpython39'da mevcut değil , bu yüzden python37, 64 bit yüklemenizi tavsiye ediyorum.

Kaynaklar:


teşekkür ederim. Son kararlı 64 bit Python sürümü (3.8.3) ile matplotlib'i de yükleyebilirim.
Federico Tomasi

1
Tercümana nasıl girebilirim?
Shayan

Benim sorunumu da çözdüm. Pycharm'ı kullanma. Kaldırılan 32 bit sürümü, 64 bit olanı yeniden yüklendi, proje yorumlayıcısını yeni 64 bit python ile değiştirdi.
Jason Goal

3

Benim durumumda, dizinin dtype değişkenini daha küçük bir türe (float64'ten uint8'e) değiştiren bir dtype özniteliği eklemek, Windows'ta MemoryError'ı (64 bit) atmayacak kadar azalan dizi boyutunu düşürdü.

itibaren

mask = np.zeros(edges.shape)

-e

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


1

veri türünü daha az bellek kullanan bir başkasıyla değiştirin. Benim için veri türünü numpy.uint8 olarak değiştiriyorum:

data['label'] = data['label'].astype(np.uint8)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.