Matlab में, bsxfun का उपयोग कब किया जाता है?


135

मेरा प्रश्न: मैंने देखा है कि SO पर Matlab प्रश्नों के बहुत सारे अच्छे उत्तर अक्सर फ़ंक्शन का उपयोग करते हैं bsxfun। क्यों?

प्रेरणा: के लिए Matlab प्रलेखन में bsxfun, निम्नलिखित उदाहरण प्रदान किया गया है:

A = magic(5);
A = bsxfun(@minus, A, mean(A))

बेशक हम एक ही ऑपरेशन का उपयोग कर सकते हैं:

A = A - (ones(size(A, 1), 1) * mean(A));

और वास्तव में एक साधारण गति परीक्षण दर्शाता है कि दूसरी विधि लगभग 20% तेज है। तो पहली विधि का उपयोग क्यों करें? मैं अनुमान लगा रहा हूं कि कुछ परिस्थितियां हैं जहां bsxfun"मैनुअल" दृष्टिकोण की तुलना में बहुत तेजी से उपयोग किया जाएगा। मैं वास्तव में इस तरह की स्थिति का एक उदाहरण और एक स्पष्टीकरण देखने में रुचि रखता हूं कि यह क्यों तेज है।

इसके अलावा, इस प्रश्न के लिए एक अंतिम तत्व, फिर से मैटलैब प्रलेखन के लिए bsxfun: "C = bsxfun (मज़ा, ए, बी) सिंगलटन द्वारा फ़ंक्शन ए और बी के सरणियों के लिए फ़ंक्शन हैंडल मज़ा द्वारा निर्दिष्ट तत्व-बाय-तत्व बाइनरी ऑपरेशन लागू होता है। विस्तार सक्षम है। " वाक्यांश "सिंगलटन विस्तार के साथ सक्षम" का क्या अर्थ है?


4
ध्यान दें कि आपको पढ़ने की गति आपके द्वारा किए जाने वाले परीक्षण पर निर्भर करती है। यदि आप Matlab को पुनरारंभ करने के बाद उपरोक्त कोड चलाते हैं और बस tic...tocलाइनों के चारों ओर डालते हैं, तो कोड की गति मेमोरी में फ़ंक्शन पढ़ने के लिए निर्भर करेगी।
जोनास

@ जोनास हां, मैंने timeitआपको लिंक के फंक्शन / एंजेनर / डैन प्रदान करने के बारे में पढ़ा है ।
कॉलिन टी बोवर्स

जवाबों:


152

मेरे द्वारा उपयोग किए जाने के तीन कारण हैं bsxfun( प्रलेखन , ब्लॉग लिंक )

  1. bsxfunसे तेज है repmat(नीचे देखें)
  2. bsxfun कम टाइपिंग की आवश्यकता है
  3. उपयोग करना bsxfun, उपयोग करना , accumarrayमुझे माटलाब की मेरी समझ के बारे में अच्छा लगता है।

bsxfunउनके "सिंगलटन आयाम" के साथ इनपुट सरणियों को दोहराएगा, अर्थात आयाम जिनके साथ सरणी का आकार 1 है, ताकि वे अन्य सरणी के संबंधित आयाम के आकार से मेल खाते हों। इसे ही "सिंगलटन एक्सप्लोरेशन" कहा जाता है। एक तरफ के रूप में, सिंगलटन आयाम वे हैं जिन्हें यदि आप कहते हैं तो गिरा दिया जाएगा squeeze

यह संभव है कि बहुत छोटी समस्याओं के लिए, repmatदृष्टिकोण तेज हो - लेकिन उस सरणी आकार में, दोनों ऑपरेशन इतने तेज़ हैं कि यह संभवतः समग्र प्रदर्शन के मामले में कोई फर्क नहीं पड़ेगा। दो महत्वपूर्ण कारण bsxfunतेजी से होते हैं: (1) गणना संकलित कोड में होती है, जिसका अर्थ है कि सरणी की वास्तविक प्रतिकृति कभी नहीं होती है, और (2) bsxfunमल्टीथ्रेडेड मैटलैब फ़ंक्शन में से एक है।

मैंने अपने तेजी से लैपटॉप पर R2012b के बीच repmatऔर bsxfunसाथ में एक गति की तुलना की है ।

यहां छवि विवरण दर्ज करें

मेरे लिए, bsxfunकी तुलना में लगभग 3 गुना तेज है repmat। यदि सरणियाँ बड़ी हो जाती हैं तो अंतर अधिक स्पष्ट हो जाता है

यहां छवि विवरण दर्ज करें

रन-टाइम में कूदता है repmat1Mb के एक सरणी आकार के आसपास, जो मेरे प्रोसेसर कैश के आकार के साथ कुछ कर सकता है - bsxfunएक छलांग के रूप में खराब नहीं होता है, क्योंकि इसे केवल आउटपुट सरणी को आवंटित करने की आवश्यकता होती है।

नीचे आपको वह कोड मिल रहा है जिसका मैंने समय के लिए उपयोग किया था:

n = 300;
k=1; %# k=100 for the second graph
a = ones(10,1);
rr = zeros(n,1);
bb=zeros(n,1);
ntt=100;
tt=zeros(ntt,1);
for i=1:n;
   r = rand(1,i*k);
   for it=1:ntt;
      tic,
      x=bsxfun(@plus,a,r);
      tt(it)=toc;
   end;
   bb(i)=median(tt);
   for it=1:ntt;
      tic,
      y=repmat(a,1,i*k)+repmat(r,10,1);
      tt(it)=toc;
   end;
   rr(i)=median(tt);
end

एक उत्कृष्ट प्रतिक्रिया के लिए धन्यवाद +1। मैंने इसे उत्तर के रूप में चिह्नित किया है क्योंकि यह सबसे व्यापक चर्चा है और (इस बिंदु पर) सबसे अधिक वोट प्राप्त हुए हैं।
कॉलिन टी बोवर्स

40

मेरे मामले में, मैं उपयोग करता हूं bsxfunक्योंकि यह मुझे कॉलम या पंक्ति के मुद्दों के बारे में सोचने से बचता है।

अपना उदाहरण लिखने के लिए:

A = A - (ones(size(A, 1), 1) * mean(A));

मुझे कई समस्याओं को हल करना है:

1) size(A,1)याsize(A,2)

2) ones(sizes(A,1),1)याones(1,sizes(A,1))

३) ones(size(A, 1), 1) * mean(A)याmean(A)*ones(size(A, 1), 1)

4) mean(A)याmean(A,2)

जब मैं उपयोग करता हूं bsxfun, तो मुझे अंतिम हल करना होगा:

a) mean(A)याmean(A,2)

आप सोच सकते हैं कि यह आलसी या कुछ और है, लेकिन जब मैं उपयोग करता bsxfunहूं, तो मेरे पास कीड़े कम होते हैं और मैं तेजी से कार्यक्रम करता हूं ।

इसके अलावा, यह छोटा है, जो टाइपिंग गति और पठनीयता में सुधार करता है


1
प्रतिक्रिया ओली के लिए धन्यवाद। +1 जैसा कि मुझे लगता है कि इस उत्तर ने एंगेनर और जोनास की प्रतिक्रियाओं के अलावा कुछ योगदान दिया। मुझे विशेष रूप से पसंद है कि आपने वैचारिक समस्याओं की संख्या को निर्धारित किया है जिन्हें किसी दिए गए लाइन कोड में हल करने की आवश्यकता है।
कॉलिन टी बोवर्स

16

बहुत दिलचस्प सवाल! मैंने हाल ही में इस प्रश्न का उत्तर देते समय वास्तव में ऐसी स्थिति पर ठोकर खाई है । निम्न कोड पर विचार करें जो वेक्टर के माध्यम से आकार 3 की स्लाइडिंग विंडो के सूचकांकों की गणना करता है a:

a = rand(1e7,1);

tic;
idx = bsxfun(@plus, [0:2]', 1:numel(a)-2);
toc

% equivalent code from im2col function in MATLAB
tic;
idx0 = repmat([0:2]', 1, numel(a)-2);
idx1 = repmat(1:numel(a)-2, 3, 1);
idx2 = idx0+idx1;
toc;

isequal(idx, idx2)

Elapsed time is 0.297987 seconds.
Elapsed time is 0.501047 seconds.

ans =

 1

इस मामले bsxfunमें लगभग दोगुना तेज है! यह उपयोगी और तेज़ है क्योंकि यह मैट्रिसेस के लिए मेमोरी के स्पष्ट आवंटन से बचता हैidx0 और idx1उन्हें मेमोरी में सहेजता है, और फिर उन्हें जोड़ने के लिए उन्हें फिर से पढ़ता है। चूंकि मेमोरी बैंडविड्थ एक मूल्यवान संपत्ति है और अक्सर आज के आर्किटेक्चर पर अड़चन है, इसलिए आप प्रदर्शन में सुधार करने के लिए इसे बुद्धिमानी से उपयोग करना चाहते हैं और अपने कोड की मेमोरी आवश्यकताओं को कम करते हैं।

bsxfunआपको बस ऐसा करने की अनुमति देता है: वैक्टर को दोहराते हुए प्राप्त किए गए दो मैट्रिक्स पर स्पष्ट रूप से संचालित करने के बजाय, दो वैक्टर के सभी जोड़े के लिए एक मनमाना ऑपरेटर को लागू करने के आधार पर एक मैट्रिक्स बनाएं। यह सिंगलटन विस्तार है । आप इसे BLAS के बाहरी उत्पाद के रूप में भी सोच सकते हैं :

v1=[0:2]';
v2 = 1:numel(a)-2;
tic;
vout = v1*v2;
toc
Elapsed time is 0.309763 seconds.

मैट्रिक्स प्राप्त करने के लिए आप दो वैक्टरों को गुणा करते हैं। बस यह कि बाहरी उत्पाद केवल गुणा करता है, और bsxfunमनमाने ऑपरेटरों को लागू कर सकता है। एक साइड नोट के रूप में, यह देखना बहुत दिलचस्प है कि bsxfunBLAS बाहरी उत्पाद जितना तेज़ है। और BLAS को आमतौर पर प्रदर्शन देने के लिए माना जाता है ।

डैन की टिप्पणी के लिए धन्यवाद संपादित करें , यहाँ लोरेन द्वारा एक बढ़िया लेख है जो बिल्कुल चर्चा करता है।


7
यह लेख प्रासंगिक हो सकता है: blogs.mathworks.com/loren/2008/08/04/…
Dan

@ एक महान संदर्भ के लिए धन्यवाद।
अंगदान

एक महान प्रतिक्रिया angainor के लिए धन्यवाद। bsxfunएक अच्छा उदाहरण के साथ स्पष्ट रूप से मुख्य लाभ के लिए पहली बार होने के लिए +1 ।
कॉलिन टी बोवर्स

13

R2016b के रूप में, Matlab विभिन्न प्रकार के ऑपरेटरों के लिए Implicit Expansion का समर्थन करता है , इसलिए ज्यादातर मामलों में इसका उपयोग करना आवश्यक नहीं है bsxfun:

पहले, यह कार्यक्षमता फ़ंक्शन के माध्यम से उपलब्ध थी bsxfun। अब यह अनुशंसा की जाती है कि आप bsxfunउन कार्यों और ऑपरेटरों को प्रत्यक्ष कॉल के अधिकांश उपयोगों को प्रतिस्थापित करें जो निहित विस्तार का समर्थन करते हैं । उपयोग की तुलना में bsxfun, निहित विस्तार प्रदान करता है तेज गति , बेहतर स्मृति के उपयोग , और कोड के बेहतर पठनीयता

वहाँ एक है विस्तृत चर्चा की अंतर्निहित विस्तार और लोरेन के ब्लॉग पर उसके प्रदर्शन। MathWorks से स्टीव एडिन्स को उद्धृत करने के लिए :

R2016b में, निहित विस्तारbsxfun ज्यादातर मामलों में तेजी या तेजी से काम करता है । निहित विस्तार के लिए सबसे अच्छा प्रदर्शन लाभ छोटे मैट्रिक्स और सरणी आकारों के साथ हैं। बड़े मैट्रिक्स आकारों के लिए, निहित विस्तार लगभग उसी गति से होता है जैसा कि होता है bsxfun


8

चीजें हमेशा 3 सामान्य तरीकों के अनुरूप नहीं होती हैं:, repmatअनुक्रमण द्वारा विस्तार और bsxfun। यह और अधिक दिलचस्प हो जाता है जब आप वेक्टर आकार को और भी अधिक बढ़ाते हैं। प्लॉट देखें:

तुलना

bsxfunवास्तव में कुछ बिंदु पर अन्य दो की तुलना में थोड़ा धीमा हो जाता है, लेकिन मुझे आश्चर्य होता है कि क्या आप वेक्टर आकार को और भी अधिक बढ़ाते हैं (> 13E6 आउटपुट एलिमेंट्स), bsxfun अचानक 3x के द्वारा फिर से तेज हो जाता है। उनकी गति चरणों में कूदती प्रतीत होती है और क्रम हमेशा सुसंगत नहीं होता है। मेरा अनुमान है कि यह प्रोसेसर / मेमोरी साइज़ पर भी निर्भर हो सकता है, लेकिन आम तौर पर मुझे लगता है कि मैं bsxfunजब भी संभव हो सकता हूं ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.