मैं Matlab 2019a में कई आयामों के साथ एक आईआरआर की गणना करने की कोशिश कर रहा हूँ। मेरा सूत्र सिद्धांत में काम करता है (अभी के लिए "वापसी की कई दरें" चेतावनी को अनदेखा कर रहा है), लेकिन समस्या यह है कि बड़े मैट्रिक्स के लिए, यानी noScenarios> 5 या तो, कोड बहुत धीमा हो जाता है। इसके लिए प्रोग्रामिंग विकल्प क्या हैं? मैंने fsolve भी कोशिश की लेकिन मुझे लगता है कि यह तेज़ नहीं है।

कृपया ध्यान दें कि चूंकि मैं गणित में कोई दरार नहीं हूं, इसलिए "ब्रेंट की विधि" जैसा एक साधारण कुंजी शब्द मेरे लिए पर्याप्त नहीं है (उदाहरण के लिए रिटर्न आईआरआर की आंतरिक दर की गणना करने का सबसे कुशल तरीका क्या है?)। मुझे यह जानना होगा कि ए) इसे मैटलैब में कैसे कार्यान्वित किया जाए, और बी) यदि यह बहुत बेवकूफ सबूत है ताकि कुछ भी गलत न हो? शुक्रिया!

clc
clear
close all

noScenarios = 50;

CF = ones(300,noScenarios,noScenarios,noScenarios);
CF = [repmat(-300, 1,noScenarios,noScenarios,noScenarios); CF];

for scenarios1 = 1:noScenarios
    for scenarios2 = 1:noScenarios
        for scenarios3 = 1:noScenarios
            IRR3dimensional(scenarios1,scenarios2,scenarios3) = irr(CF(:,scenarios1,scenarios2,scenarios3));
        end
    end
end
7
LenaH 4 जून 2019, 11:33

1 उत्तर

सबसे बढ़िया उत्तर

आईआरआर की गणना करने के लिए, आपको एक बहुपद समीकरण को हल करना होगा। यह प्रत्येक नकदी प्रवाह वेक्टर के लिए अलग से किया जाना है। इसलिए, irr को एक बहुआयामी मैट्रिक्स में लागू करने से निष्पादन समय में सुधार नहीं होता है। मुझे संदेह है कि मैटलैब अभी भी आंतरिक रूप से एक लूप का उपयोग करता है।

आप fsolve के अनुकूलन विकल्पों के साथ खेलकर कुछ गति प्राप्त करने में सक्षम हो सकते हैं लेकिन एक बड़े सुधार की संभावना बहुत कम है। संभवतः, मैटलैब डेवलपर्स ने पहले से ही पर्याप्त रूप से अच्छा दृष्टिकोण चुना है।

इस प्रकार, आपका एकमात्र अन्य विकल्प समांतरता है। यदि आपके पास सर्वर तक पहुंच है या आपके लैपटॉप/डेस्कटॉप में कई सीपीयू हैं, तो आप समानांतर में irr फ़ंक्शन चलाकर अपना रन टाइम कम कर सकते हैं। (आपको शायद समानांतर कंप्यूटिंग टूलबॉक्स की भी आवश्यकता है।)

मैंने आपके उदाहरण को थोड़ा सा संशोधित किया है ताकि यादृच्छिक नकदी प्रवाह मूल्यों का उपयोग किया जा सके ताकि इसे जांचना आसान हो सके। हालांकि, मैंने परिदृश्यों और समय बिंदुओं की संख्या कम कर दी, ताकि timeit फ़ंक्शन उचित समय में कई सिमुलेशन चला सके। (इसके अलावा, कृपया ध्यान रखें कि निष्पादन समय समय बिंदुओं की संख्या में घातीय लगता है।)

t = 150;
noScenarios = 10;
noThreads = 4;

CF = rand(t,noScenarios,noScenarios,noScenarios);
CF = [-rand(1,noScenarios,noScenarios,noScenarios); CF];

h1 = @() f1(CF, noScenarios);
fprintf("%0.4f : single thread, loop\n", timeit(h1))

h2 = @() f2(CF, noScenarios);
fprintf("%0.4f : single thread, vectorized\n", timeit(h2))

poolObj = parpool('local', noThreads);
h3 = @() f3(CF, noScenarios);
fprintf("%0.4f : parallelized outer loop\n", timeit(h3))
delete(poolObj);

poolObj = parpool('local', noThreads);
h4 = @() f4(CF, noScenarios);
fprintf("%0.4f : parallelized inner loop\n", timeit(h4))
delete(poolObj);

function res = f1(CF, noScenarios)
    res = zeros(noScenarios, noScenarios, noScenarios);
    for scenarios1 = 1:noScenarios
        for scenarios2 = 1:noScenarios
            for scenarios3 = 1:noScenarios
                res(scenarios1,scenarios2,scenarios3) = irr(CF(:,scenarios1,scenarios2,scenarios3));
            end
        end
    end
end

function res = f2(CF, noScenarios)
    res = reshape(irr(CF), noScenarios, noScenarios, noScenarios);
end

function res = f3(CF, noScenarios)
    res = zeros(noScenarios, noScenarios, noScenarios);
    parfor scenarios1 = 1:noScenarios
        for scenarios2 = 1:noScenarios
            for scenarios3 = 1:noScenarios
                res(scenarios1,scenarios2,scenarios3) = irr(CF(:,scenarios1,scenarios2,scenarios3));
            end
        end
    end
end

function res = f4(CF, noScenarios)
    res = zeros(noScenarios, noScenarios, noScenarios);
    for scenarios1 = 1:noScenarios
        for scenarios2 = 1:noScenarios
            parfor scenarios3 = 1:noScenarios
                res(scenarios1,scenarios2,scenarios3) = irr(CF(:,scenarios1,scenarios2,scenarios3));
            end
        end
    end
end

जब मैंने इस कोड को 4 सीपीयू और 16 जीबी मेमोरी वाले सर्वर पर चलाया, तो मुझे निम्नलिखित परिणाम मिले।

19.9357 : single thread, loop
20.4318 : single thread, vectorized
...
5.6346 : parallelized outer loop
...
12.4640 : parallelized inner loop

जैसा कि आप देख सकते हैं, irr का सदिश संस्करण लूप पर कोई लाभ प्रदान नहीं करता है। इस मामले में, यह थोड़ा धीमा है। मेरे अन्य परीक्षणों में, यह कभी-कभी थोड़ा तेज था।

हालांकि, आप अपने बाहरी लूप को parfor फ़ंक्शन के साथ समानांतर करके अपने रन टाइम को काफी कम कर सकते हैं। यह सबसे आंतरिक लूप को समानांतर करने से बेहतर है क्योंकि प्रत्येक बैच में एक निश्चित निष्पादन ओवरहेड होता है। इसलिए, बड़ी संख्या में छोटे बैचों की तुलना में बड़ी संख्या में बड़े बैचों का ओवरहेड कम होता है।

यहां बताया गया है कि समांतरता कैसे काम करती है। सबसे पहले, आप नीचे दिए गए कमांड के साथ स्थानीय वर्कर थ्रेड्स का एक पूल बनाते हैं। सुनिश्चित करें कि आपके पास सीपीयू की संख्या से अधिक नहीं है। parpool अनिश्चित काल तक प्रतीक्षा कर सकता है जब तक कि सभी स्थानीय कर्मचारी नहीं बन जाते हैं और यह केवल एक स्थानीय कार्यकर्ता बना सकता है यदि सीपीयू उपलब्ध हो।

poolObj = parpool('local', noThreads);

पूल निर्माण में कुछ सेकंड लग सकते हैं। यही कारण है कि मैंने इसे उस समारोह के बाहर ले जाया जो मैंने समय दिया था। बड़ी नौकरियों के लिए, कुल निष्पादन समय की तुलना में पूल बनाने का समय महत्वहीन है।

यहां, मैं पूल ऑब्जेक्ट को एक वेरिएबल में सहेजता हूं और बाद में इसे हटा देता हूं। हालाँकि, यह वैकल्पिक है। 30 मिनट की निष्क्रियता के बाद या जब मैटलैब समाप्त हो जाता है तो पूल डिफ़ॉल्ट रूप से नष्ट हो जाता है।

उसके बाद, आप एक for लूप को प्रतिस्थापित करते हैं जिसे आप parfor कॉल के साथ समानांतर करना चाहते हैं, यानी for scenarios1 = 1:noScenarios parfor scenarios1 = 1:noScenarios बन जाता है। डिफ़ॉल्ट रूप से, parfor सभी उपलब्ध श्रमिकों का उपयोग करेगा लेकिन आप parfor (scenarios1 = 1:noScenarios, maxWorkers) के साथ उपयोग करने के लिए अनुमत अधिकतम श्रमिकों की संख्या भी निर्दिष्ट कर सकते हैं। ध्यान दें, हालांकि, निष्पादन आदेश की गारंटी नहीं है, अर्थात पांचवें पुनरावृत्ति को तीसरे पुनरावृत्ति से पहले निष्पादित किया जा सकता है।

2
rbrisk 18 जून 2019, 17:22