Bellek taşmasına neden olan geçici bir matris oluşturmadan matris nasıl kopyalanır?


9

Çok daha büyük bir ayrılmış belleğe bir matris atayarak, matlab 'kopyalarken' bir şekilde çoğaltır ve kopyalanacak matris yeterince büyükse, bellek taşması olur. Bu örnek koddur:

main_mat=zeros(500,500,2000);
n=500;
slice_matrix=zeros(500,500,n);
for k=1:4
    parfor i=1:n
        slice_matrix(:,:,i)=gather(gpuArray(rand(500,500)));
    end
    main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix; %This is where the memory will likely overflow
end

Tepegöz olmadan slice_matrixüzerine sadece 'parçalamak' için herhangi bir yolu var main_matmı? Şimdiden teşekkürler.

DÜZENLE:

Taşma main_matönceden tahsis edildiğinde meydana geldi . Eğer main_matile başlatıldı main_mat=zeros(500,500,1);(küçük boyutu), taşma meydana gelmez, ancak matris içine tahsis önce ayırma yapılmazsa gibi yavaşlatılmamış olur. Bu, menzil karttıkça performansı önemli ölçüde azaltacaktır .


1
Döngülerinizle ilgili olarak: optimizasyon amacıyla dış döngüyü bir döngüye ayarlamanız önerilirparfor . Ek olarak, parforverilerinizi her bir çalışana kopyalar, böylece 4 çalışanın verilerinizi RAM'de dört kez çoğalttığını varsayar.
Adriaan

1
Matlab'ın aslında belleği çoğalttığına dair belirtiniz nedir? memoryİşlevi kullanıyor musunuz ? Görev yöneticisi? Matlab'dan bir bellek hatası mı? Hangi kod satırında oluyor?
Eliahu Aaron

Gördüğünüz gibi nereye kod yorumladı main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1), nerede bellek taşması sorunu oluşur. main_matÖnceden tahsis ettiğimde doğrulandı , taşacak, eğer yapmazsam etmeyecek. Matlab 'bellek yetersiz hatası' döndürür.
Gregor Isack

500x500x2000 matrisiniz belleğe sığıyor mu? ~ 4 Gb. Bkz stackoverflow.com/q/51987892/7328782 diziye yazarken bellek hatası dışında sadece olabilirdi niçin.
Cris Luengo

Sorununuzu daha iyi anlamak için, önüne bir ekleyebilir (ve h ile 0 h=h+slice_matrix(end)değerini main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix;başlatabilir misiniz?) Bu yeni eklenen satırın zaten bellek sorunlarınıza neden olacağından şüpheleniyorum.
Daniel

Yanıtlar:


4

Asıl mesele, sayıların sıfırlardan daha fazla yer kaplamasıdır. GPU veya parfor kullanırsanız olsun, çok fazla main_mat=zeros(500,500,2000);RAM alırken main_mat = rand(500,500,2000);(aslında, parfor daha fazla RAM kullanmanıza neden olur). Yani bu hafızanın doğal olmayan bir şişmesi değil. Daniel'in aşağıdaki bağlantısından sonra, sıfırların atanması yalnızca belleğe işaretçiler oluşturuyor ve fiziksel belleğin yalnızca "sayılar" için matrisi kullandığınızda doldurulduğu görülüyor. Bu işletim sistemi tarafından yönetilir. Ve Windows, Mac ve Linux için ya Matlab ile ya da C gibi diğer dillerle yapmanız bekleniyor.


Şu an MATLAB'ı anlamıyorum. Komutları zerostüm sanal belleğe yazdığımda aslında tahsis edilir, ancak bellek kullanılmaz. whosher iki matris için aynı boyutu gösterirken işletim sistemim farklı bir bellek tüketimi gösteriyor. Yorumumu sildim çünkü cevabınız kesinlikle yanlış değil.
Daniel

3
Bunu açıklayan bir şey buldum: stackoverflow.com/questions/51987892/…
Daniel

Mükemmel cevap! Teşekkürler.
JLev

@Gregor: Sanırım bunu onaylamak, onesbunun yerine denemek zeros, bu, belleğin ilgili işlevi çağırırken gerçekten ayrıldığından emin olur.
Daniel

Her şeyi doğru anladığımda, sonuç şu: Geçici bir kopya yok. main_matSıfır dışı değerler atandığı için bellek yetersiz özel durumları ortaya çıkıyor . Daha önce sadece sanal bellek (adres alanı) atanmıştı, bu artık fiziksel belleğe atanmıştı.
Daniel

1

Kaldırma parforişlemi büyük olasılıkla sorununuzu çözecektir.

parfororada yararlı değil. MATLAB'lar parforpaylaşılan bellek paralelliğini kullanmaz (yani yeni iş parçacıkları başlatmaz), daha çok dağıtılmış bellek paralelliğini kullanır (yeni işlemler başlatır). İşi bir küme veya çalışan düğümler üzerinde dağıtmak için tasarlanmıştır. Ayrıca, işleri birden fazla çekirdek üzerinde dağıtmak için bir düğüm (veya tek bir masaüstü bilgisayar) içinde de çalışmasına rağmen, bir düğüm içinde paralellik yapmanın en uygun yolu değildir.

Bu, başlatılan işlemlerin her birinin parforkendi kopyasına sahip olması gerektiği anlamına gelir slice_matrix, bu da programınız tarafından kullanılan büyük miktarda belleğin nedenidir.

Hakkında ve ne zaman kullanılacağı hakkında daha fazla bilgi için MATLAB belgelerindeki " Ne Zaman Kullanılacağına Karar Verin" kısmınaparfor bakın parfor.


1
Kaldırmak parfor tek yol mu? İşlem, bu şekilde tasarladığımda en iyi şekilde çalışır, çünkü içerideki her şey parforCPU ve GPU yoğun olduğundan, performansı önemli ölçüde geliştirdi.
Gregor Isack

@GregorIsack: Örnek kodunuzla gittim, aslında içinde çok fazla iş yaptığınızı bilmiyordum parfor. Eğer öyleyse, evet, muhtemelen faydalıdır. - Belki slice_matrixbir değil gpuarrayödevde kopyalanamaz edilmeyecektir.
Cris Luengo

Hmmm bile slice_matrixbir değil gpuArray, hala alma taşma belirti. Bu sorunun açılmasına izin vereceğim, bakalım başka bir çözüm var mı? Yine de cevap için teşekkürler!
Gregor Isack

0

Kodunuzun sadece örnek bir kod olduğunu ve rand()MVE'nizde bir geleneği temsil ettiğini varsayıyorum . Matlab'da bellek kullanımı için birkaç ipucu ve püf noktası var.

MathWorks eğitim el kitaplarından bir pasaj vardır:

Parametreleri bir fonksiyona geçirirken olduğu gibi MATLAB'da bir değişkeni diğerine atarken, MATLAB şeffaf olarak bu değişkene bir referans oluşturur. MATLAB, başvuruyu keser ve yalnızca kod değerlerden birini veya daha fazlasını değiştirdiğinde bu değişkenin bir kopyasını oluşturur. Olarak bilinen bu davranış, kopya üzerinde yazma veya tembel-kopyalama , kod, değiştirmektedir bir değerler kadar büyük veri setlerini kopyalama maliyet ertelemektedir. Bu nedenle, kod hiçbir değişiklik yapmazsa, değişkenleri kopyalamak için fazladan bellek alanına ve yürütme süresine gerek yoktur.

Yapılacak ilk şey , kodunuzun (bellek) verimliliğini kontrol etmek olacaktır. Mükemmel programcıların kodu bile (biraz) beyin gücü ile daha da optimize edilebilir. Bellek verimliliği ile ilgili birkaç ipucu

  • matlab nativ vektörleştirme faydalanmak, örneğin sum(X,2), mean(X,2),std(X,[],2)
  • matlab'ın matrisleri genişletmek zorunda olmadığından emin olun ( örtülü genişletme son zamanlarda değiştirildi). Kullanmak daha verimli olabilirbsxfun
  • Kullanım in-yer-operasyonlar, örneğin x = 2*x+3ziyadex = 2*x+3
  • ...

Bellek kullanımıyla ilgili optimumun, hesaplama süresini azaltmak isteyip istemediğinizle aynı olmadığını unutmayın. Bu nedenle, işçi sayısını azaltmayı veya parfor-loop'u kullanmaktan kaçınmayı düşünebilirsiniz. ( parforPaylaşılan belleği kullanamayacağınız için, Paralel Araç Kutusu kullanılarak yazma üzerine kopyalama özelliği yoktur .

Belleğinize daha yakından bakmak istiyorsanız, Matlab tarafından nelerin kullanılabilir olduğunu ve neler kullanılabileceğini kontrol edin feature('memstats'). Ne sizin için ilginç olduğunu Sanal Bellek olduğunu

Tüm MATLAB işlemiyle ilişkili toplam ve kullanılabilir bellek. İşlemci mimarisi ve işletim sistemi ile sınırlıdır. veya bu komutu kullanın [user,sys] = memory.

Hızlı yan düğüm : Matlab matrisleri tutarlı bir şekilde bellekte saklar. Büyük matrisler için büyük bir boş RAM bloğuna sahip olmanız gerekir. Değişkenleri ayırmak istemenizin nedeni de budur, çünkü değişkenleri dinamik olarak değiştirmek, Matlab'ı mevcut noktayı her aştığında tüm matrisi RAM'de daha büyük bir noktaya kopyalamaya zorlar.

Gerçekten bellek sorunlarınız varsa, daha düşük seviyeli dillerde gerektiği gibi veri türleri sanatına girmek isteyebilirsiniz. Örneğin, bellek kullanımınızı doğrudan en baştan tek duyarlık kullanarak main_mat=zeros(500,500,2000,'single');- btw kullanarak yarıya düşürebilirsiniz , bu aynı zamanda rand(...,'single')ve daha yerel işlevlerle de çalışır - daha karmaşık matlab işlevlerinden birkaçı, çift tip giriş gerektirir; tekrar upcast.


0

Doğru anlıyorsam asıl sorununuz parforbellek paylaşmaya izin vermiyor. Her çalışanı neredeyse ayrı bir matlab örneği olarak düşünün.

Temelde bildiğim tek bir çözüm var (hiç denemedim), Fileexchange'te 'paylaşılan matris': https://ch.mathworks.com/matlabcentral/fileexchange/28572-sharedmatrix

Daha fazla çözüm: diğerlerinin önerdiği gibi: parfor'u kaldırmak kesinlikle bir çözümdür, daha fazla koç elde edin, uzun diziler kullanın (koç dolu olduğunda sabit diskleri kullanan, burada okuyun ), işlemleri daha küçük parçalar halinde bölün, son fakat en az değil, başka bir alternatif düşünün Matlab.


0

Aşağıdaki kodu kullanabilirsiniz. Aslında slice_matrix'e ihtiyacınız yok

main_mat=zeros(500,500,2000);
n=500;
slice_matrix=zeros(500,500,n);
for k=1:4
   parfor i=1:n
       main_mat(:,:,1+(k-1)*n + i - 1) = gather(gpuArray(rand(500,500)));
   end
   %% now you don't need this main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix; %This is where the memory will likely overflow
end

Bunu bir çözüm döngüsünün içinde yapamazsınız
Gregor Isack

Bunu denedin mi?
mayank1513

Bunu parfoor döngüsünün dışına taşımamın bir nedeni var. Aynı kodu denemedim, ama indeksleme nedeniyle işe yaramayacağını biliyordum.
Gregor Isack
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.