मेमोरी में एक अस्थायी मैट्रिक्स बनाए बिना मैट्रिक्स को 'कॉपी' कैसे करें जिससे मेमोरी अतिप्रवाह हो?


9

एक मैट्रिक्स को बहुत बड़ी आवंटित मेमोरी में असाइन करके, मैटलैब किसी भी तरह से इसे 'कॉपी' करते समय डुप्लिकेट कर देगा, और यदि मैट्रिक्स को कॉपी किया जाना काफी बड़ा है, तो मेमोरी ओवरफ्लो होगी। यह नमूना कोड है:

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

ओवरहेड slice_matrixके main_matबिना बस 'स्मैश' करने का कोई तरीका ? अग्रिम में धन्यवाद।

संपादित करें:

ओवरफ्लो तब हुआ जब main_matपहले से आवंटित है। यदि (छोटे आकार) के main_matसाथ आरंभ किया जाता है main_mat=zeros(500,500,1);, तो अतिप्रवाह नहीं होगा, लेकिन यह धीमा हो जाएगा क्योंकि मैट्रिक्स इसमें सौंपे जाने से पहले आवंटन नहीं किया जाता है। यह kवृद्धि की सीमा के रूप में प्रदर्शन को काफी कम कर देगा ।


1
अपने छोरों के रूप में: अनुकूलन उद्देश्यों के लिए बाहरी लूप को एक लूप पर सेट करने की सिफारिश की जाती हैparfor । इसके अतिरिक्त, parforआपके डेटा को प्रत्येक अलग-अलग कार्यकर्ता में कॉपी करता है, इस प्रकार 4 श्रमिकों का मानना ​​है कि यह आपके डेटा को रैम में चार बार डुप्लिकेट करता है।
एड्रियन

1
आपका क्या संकेत है कि मतलाब वास्तव में स्मृति की नकल कर रहा है? क्या आप memoryफ़ंक्शन का उपयोग कर रहे हैं ? कार्य-प्रबंधक? एक स्मृति त्रुटि Matlab से? यह किस लाइन के कोड में हो रहा है?
एलियाहु आरोन

जैसा कि आप देख सकते हैं कि जहां मैंने कोड पर टिप्पणी की थी, main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)वह जगह है जहां मेमोरी ओवरफ्लो समस्या होती है। यह सत्यापित है कि जब मैंने main_matपहले से आवंटित किया था , तो यह अतिप्रवाह होगा, अगर मैं नहीं करता, तो यह नहीं होगा। मतलूब 'स्मृति त्रुटि से बाहर' लौटेगा।
ग्रेगोर इसैक

क्या आपका 500x500x2000 मैट्रिक्स मेमोरी में फिट होता है? यह ~ 4 जीबी है। Stackoverflow.com/q/51987892/7328782 देखें कि मेमोरी एरर के कारण सरणी में लिखते समय ही कैसे हो सकता है।
संकट लुएंगो

अपनी समस्या को बेहतर ढंग से समझने के लिए, क्या आप h=h+slice_matrix(end)पहले से main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix;(और 0 के साथ ज को इनिशियलाइज़) कर सकते हैं? मुझे संदेह है कि यह नई जोड़ी गई लाइन पहले से ही आपकी मेमोरी समस्याओं का कारण बनेगी।
डैनियल

जवाबों:


4

मुख्य मुद्दा यह है कि संख्या शून्य से अधिक स्थान लेती है। main_mat=zeros(500,500,2000);जब main_mat = rand(500,500,2000);आप GPU या parfor का उपयोग करते हैं, तो बहुत कम रैम लेता है, (वास्तव में, parfor आप अधिक रैम का उपयोग करेंगे)। तो यह स्मृति की अप्राकृतिक सूजन नहीं है। डैनियल के नीचे दिए गए लिंक के बाद, ऐसा लगता है कि शून्य का असाइनमेंट केवल मेमोरी को इंगित करता है, और भौतिक मेमोरी केवल तभी भरी जाती है जब आप "संख्या" के लिए मैट्रिक्स का उपयोग करते हैं। यह ऑपरेटिंग सिस्टम द्वारा प्रबंधित किया जाता है। और यह विंडोज, मैक और लिनक्स के लिए अपेक्षित है, या तो आप इसे Matlab या अन्य भाषाओं जैसे C के साथ करते हैं।


अभी मैं MATLAB को नहीं समझता। एक बार जब मैं zerosपूरे वर्चुअल मेमोरी के साथ कमांड टाइप करता हूं , तो वास्तव में आवंटित किया जाता है, लेकिन कोई भी मेमोरी का उपयोग नहीं किया जाता है। whosदोनों मैट्रीस के लिए समान आकार दिखाता है, जबकि मेरा ओएस एक अलग मेमोरी खपत दिखाता है। मैंने अपनी टिप्पणी हटा दी क्योंकि आपका उत्तर निश्चित रूप से गलत नहीं है।
डैनियल

3
मुझे यह समझाते हुए कुछ मिला: stackoverflow.com/questions/51987892/…
डैनियल

बहुत बढ़िया जवाब! धन्यवाद।
JLev

@Gregor: मुझे लगता है कि इसकी पुष्टि करने के लिए, onesइसके बजाय इसके साथ प्रयास करें, यह zerosसुनिश्चित करता है कि मेमोरी वास्तव में संबंधित फ़ंक्शन को कॉल करने के समय आवंटित की गई है।
डैनियल

जब मैं सब कुछ सही समझता हूं, तो निष्कर्ष यह है: कोई अस्थायी प्रति नहीं है। मेमोरी अपवादों से बाहर निकलता है क्योंकि main_matनॉनजेरो वैल्यूज़ को असाइन किया जाता है। पहले केवल वर्चुअल मेमोरी (पता स्थान) को असाइन किया गया था, यह अब भौतिक मेमोरी को सौंपा गया है।
डैनियल

1

हटाने parforसे आपकी समस्या ठीक हो जाएगी।

parforवहाँ उपयोगी नहीं है। MATLAB parforसाझा मेमोरी समानतावाद का उपयोग नहीं करता है (यानी यह नए थ्रेड शुरू नहीं करता है) बल्कि वितरित मेमोरी समानतावाद (यह नई प्रक्रियाएं शुरू करता है)। यह एक सेट या कार्यकर्ता नोड्स पर काम वितरित करने के लिए डिज़ाइन किया गया है। और हालांकि यह एक से अधिक नोड्स पर काम वितरित करने के लिए एक नोड (या एक डेस्कटॉप कंप्यूटर) के भीतर भी काम करता है, यह एक नोड के भीतर समानता करने का एक इष्टतम तरीका नहीं है।

इसका मतलब यह है कि प्रत्येक प्रक्रिया की शुरुआत की parforअपनी प्रति होनी चाहिए slice_matrix, जो आपके प्रोग्राम द्वारा उपयोग की जाने वाली बड़ी मात्रा में मेमोरी का कारण हो।

MATLAB प्रलेखन में "निर्णय लें कि कब उपयोग करना है parfor" देखें parforऔर इसका उपयोग कब करें।


1
क्या हटाना parfor ही एकमात्र रास्ता है ? प्रसंस्करण सबसे अच्छा काम करता है जब मैंने इसे इस तरह से डिज़ाइन किया था, क्योंकि अंदर सब कुछ parforसीपीयू और जीपीयू गहन है, इस प्रकार इसने प्रदर्शन में काफी सुधार किया।
ग्रेगोर इसैक

@GregorIsack: मैं आपके उदाहरण कोड के साथ गया था, आपको नहीं पता था कि आपने वास्तव में बहुत काम किया था parfor। यदि हां, तो हां, यह उपयोगी है। - शायद अगर slice_matrixयह नहीं है तो gpuarrayइसे असाइनमेंट में कॉपी नहीं किया जाएगा।
क्राइस लुआंगो

हममम भले ही slice_matrixएक नहीं है gpuArray, मैं अभी भी अतिप्रवाह लक्षण प्राप्त कर रहा हूं। मैं इस प्रश्न को खोलने देता हूँ, चलो देखते हैं कि कोई वैकल्पिक समाधान है या नहीं। जवाब के लिए धन्यवाद!
ग्रेगोर इसैक

0

मुझे लगता है कि आपका कोड सिर्फ एक नमूना कोड है और यह rand()आपके MVE में एक कस्टम का प्रतिनिधित्व करता है। तो मैटलैब में मेमोरी के उपयोग के लिए कुछ संकेत और ट्रिक हैं।

मैथवर्क्स प्रशिक्षण पुस्तिकाओं से एक स्निपेट है:

MATLAB में दूसरे चर को असाइन करते समय, जैसा कि किसी फ़ंक्शन में पैरामीटर पास करते समय होता है, MATLAB पारदर्शी रूप से उस चर का संदर्भ बनाता है। MATLAB संदर्भ को तोड़ता है, और उस चर की एक प्रति बनाता है, केवल जब कोड एक या एक से अधिक मानों को संशोधित करता है। कॉपी-ऑन-राइट , या आलसी- कॉपीिंग के रूप में जाना जाने वाला यह व्यवहार, बड़े डेटा सेटों की प्रतिलिपि बनाने की लागत को तब तक रोकता है जब तक कि कोड एक मान को संशोधित नहीं करता है। इसलिए, यदि कोड कोई संशोधन नहीं करता है, तो चर की प्रतिलिपि बनाने के लिए अतिरिक्त मेमोरी स्पेस और निष्पादन समय की आवश्यकता नहीं है।

अपने कोड की दक्षता (मेमोरी) दक्षता की जांच करने के लिए पहली बात यह होगी। यहां तक ​​कि उत्कृष्ट प्रोग्रामर के कोड को (थोड़ी) दिमागी शक्ति के साथ अनुकूलित किया जा सकता है। मेमोरी दक्षता के बारे में कुछ संकेत यहाँ दिए गए हैं

  • matlab के nativ vectorization का मेकअप उपयोग करते हैं, उदाहरण के लिए sum(X,2), mean(X,2),std(X,[],2)
  • यह सुनिश्चित कर लें कि matlab को matrices का विस्तार नहीं करना है ( हाल ही में अंतर्निहित विस्तार को बदल दिया गया था)। यह उपयोग करने के लिए अधिक कुशल हो सकता हैbsxfun
  • इन-प्लेस-ऑपरेशंस का उपयोग करें, जैसे कि x = 2*x+3इसके बजायx = 2*x+3
  • ...

ध्यान रखें कि मेमोरी उपयोग के संबंध में इष्टतम समान नहीं है यदि आप गणना समय को कम करना चाहते हैं। इसलिए, आप श्रमिकों की संख्या कम करने या parfor-लूप का उपयोग करने से बचना चाहते हैं । (जैसा कि parforसाझा मेमोरी का उपयोग नहीं किया जा सकता है, समानांतर टूलबॉक्स का उपयोग करने के साथ कोई कॉपी-ऑन-राइट फीचर नहीं है।

यदि आप अपनी याददाश्त पर करीब से नज़र डालना चाहते हैं , तो क्या उपलब्ध है और इसका इस्तेमाल मतलाब द्वारा किया जा सकता है, इसकी जाँच करें feature('memstats')। आपके लिए जो दिलचस्प है वह वर्चुअल मेमोरी है

संपूर्ण MATLAB प्रक्रिया से जुड़ी कुल और उपलब्ध मेमोरी। यह प्रोसेसर आर्किटेक्चर और ऑपरेटिंग सिस्टम द्वारा सीमित है। या इस कमांड का उपयोग करें [user,sys] = memory

क्विक साइड नोड : मैटलैब मैट्रिसेस को लगातार मेमोरी में स्टोर करता है। बड़े मैट्रिसेस के लिए आपके पास फ्री रैम का एक बड़ा ब्लॉक होना चाहिए। यही कारण है कि आप चर को आवंटित करना चाहते हैं, क्योंकि उन्हें बदलने से डायनामिक रूप से मटलैब को पूरी मैट्रिक्स को रैम में कॉपी करने के लिए मजबूर किया जाता है, हर बार जब यह वर्तमान स्पॉट को बढ़ा देता है।

यदि आपके पास वास्तव में स्मृति समस्याएं हैं , तो आप केवल डेटा प्रकारों की कला में खुदाई करना चाहते हैं - जैसा कि निचले स्तर की भाषाओं में आवश्यक है। उदाहरण के लिए, आप शुरू से ही सीधे एकल परिशुद्धता का उपयोग करके अपनी मेमोरी के उपयोग में कटौती कर सकते हैं main_mat=zeros(500,500,2000,'single');- btw, यह भी rand(...,'single')और अधिक मूल कार्यों के साथ काम करता है - हालांकि अधिक परिष्कृत matlab कार्यों में से कुछ को टाइप डबल के इनपुट की आवश्यकता होती है, जिसे आप कर सकते हैं फिर से बढ़ा।


0

अगर मैं सही ढंग से समझता हूं कि आपका मुख्य मुद्दा parforस्मृति को साझा करने की अनुमति नहीं है। लगभग हर एक अलग-अलग matlab उदाहरण के रूप में प्रत्येक parfor कार्यकर्ता के बारे में सोचो।

इसके लिए मूल रूप से केवल एक वर्कअराउंड है जो मुझे पता है (कि मैंने कभी कोशिश नहीं की है), जो कि फाइलएक्सचेंज पर 'साझा मैट्रिक्स' है: https://ch.mathworks.com/matlabcentral/fileexchange/28572-s माईक्रोडिक्स

अधिक समाधान: जैसा कि दूसरों ने सुझाव दिया है: पैरार्फ को हटा दें निश्चित रूप से एक समाधान है, अधिक राम प्राप्त करें, लंबा सरणियों का उपयोग करें (जो हार्ड का उपयोग करते हैं जब राम पूरा चलता है, यहां पढ़ें ), छोटे टुकड़ों में संचालन को विभाजित करें, अंतिम लेकिन कम से कम, एक वैकल्पिक विकल्प के अलावा पर विचार करें Matlab।


0

आप निम्न कोड का उपयोग कर सकते हैं। आपको वास्तव में slice_matrix की आवश्यकता नहीं है

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

आप एक पैरा लूप के अंदर ऐसा नहीं कर सकते
ग्रेगर इस्साक

क्या आपने कोशिश की?
मयंक 1513

वहाँ एक कारण है कि मैं कि parfoor पाश से बाहर चले गए। मैंने ठीक उसी कोड की कोशिश नहीं की, लेकिन मुझे पता था कि यह अनुक्रमण के कारण काम नहीं करेगा।
ग्रेगोर इसैक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.