8

मैं एक साधारण गतिशील प्रणाली के अनुकरण को अनुकूलित करने की कोशिश कर रहा हूं जिसमें नेटवर्क की प्रतिक्रिया के साथ-साथ इसके पैरामीटर (वजन) सरल रैखिक समीकरणों के अनुसार विकसित होते हैं। सिमुलेशन को लाखों समय के चरणों के लिए चलाने की जरूरत है, लेकिन नेटवर्क का आकार आम तौर पर छोटा होगा। इसलिए, प्रदर्शन मैट्रिक्स-वेक्टर उत्पादों द्वारा कम किया जाता है बल्कि अस्थायी सरणी, बाध्य जांच और अन्य कम दिखाई देने वाले कारकों द्वारा किया जाता है। चूंकि मैं जूलिया के लिए नया हूं, इसलिए मैं प्रदर्शन को और अनुकूलित करने के लिए किसी भी संकेत की सराहना करता हूं।जूलिया: सरल गतिशील प्रणाली के सिमुलेशन को अनुकूलित करें

function train_network(A, T, Of, cs, dt) 
    N, I = size(T) 
    z = zeros(I) 
    r = zeros(N) 

    @inbounds for t in 1:size(cs, 1) 
     # precompute 
     Az = A*z 
     Ofr = Of*r 

     # compute training signal 
     @devec z += dt.*(Az + cs[t] - 0.5.*z) 
     I_teach = T*(Az + cs[t]) 
     Tz  = T*z 

     # rate updates 
     @devec r += dt.*(I_teach - Ofr - 0.1.*r) 

     # weight updates 
     for i in 1:I 
      @devec T[:, i] += dt.*1e-3.*(z[i].*r - T[:, i]) 
     end 

     for n in 1:N 
      @devec Of[:, n] += dt.*1e-3.*(Tz.*r[n] - Of[:, n])  
     end 
    end 
end 

# init parameters 
N, I = 20, 2 
dt = 1e-3 

# init weights 
T = rand(N, I)*N 
A = rand(I, I) 
Of = rand(N, N)/N 

# simulation time & input 
sim_T = 2000 
ts = 0:dt:sim_T 
cs = randn(size(ts, 1), I) 

@time train_network(A, T, Of, cs, dt) 

साथ नेटवर्क (2.000.000 कदम) समय समय पैदावार

3.420486 seconds (26.12 M allocations: 2.299 GB, 6.65% gc time) 

अद्यतन 1

दाऊद सैंडर्स द्वारा सलाह मुझे मिल गया के बाद डेवैक मैक्रो से छुटकारा पा लिया और लूप लिखा। यह वास्तव में सरणी आवंटन कम कर देता है और के बारे में 25% से प्रदर्शन को बढ़ा देता है, यहाँ नया नंबर दिए गए हैं:

2.648113 seconds (18.00 M allocations: 1.669 GB, 5.60% gc time) 

छोटे नेटवर्क का आकार, बड़ा बढ़ावा। अद्यतन सिमुलेशन कोड का एक सारांश here पाया जा सकता है।

अद्यतन 2

स्मृति आवंटन की ज्यादातर मैट्रिक्स वेक्टर उत्पादों की वजह से कर रहे हैं। तो, क्रम में उन मैं एक में जगह BLAS आपरेशन, BLAS.genv !, जो 90% की एक और 25% और स्मृति आवंटन से समय कम कर देता है द्वारा उन उत्पादों की जगह की

1.990031 seconds (2.00 M allocations: 152.589 MB, 0.69% gc time) 

छुटकारा पाने के लिए, अद्यतन कोड here

अद्यतन 3

सबसे बड़ा रैंक -1 अद्यतन भी यथा-स्थान BLAS कार्यों के लिए दो कॉल द्वारा बदला जा सकता है, अर्थात् BLAS.scal! स्केलिंग और BLAS.ger के लिए! रैंक -1 अपडेट के लिए। चेतावनी है कि दोनों कॉल काफी धीमी गति से कर रहे हैं एक से अधिक धागा इस्तेमाल किया जाता है (समस्या OpenBLAS साथ?), तो यह

blas_set_num_threads(1) 

स्थापित करने के लिए 20 के एक नेटवर्क के आकार के लिए समय में एक 15% लाभ है सबसे अच्छा है , और आकार 50 के एक नेटवर्क के लिए 50% की बढ़त के कोई और अधिक स्मृति आवंटन कर रहे हैं, और नए समय

1.638287 seconds (11 allocations: 1.266 KB) 

फिर रहे हैं, अद्यतन कोड here पाया जा सकता है।

अद्यतन 4

मैं अब तक परिणामों की तुलना करने के लिए एक बुनियादी Cython script लिखा था। मुख्य अंतर यह है कि मैं बीएलएएस के लिए किसी भी कॉल का उपयोग नहीं करता हूं लेकिन लूप होता है: निम्न स्तर के बीएलएएस कॉल इंजेक्शन करना साइथन में दर्द होता है, और छोटे नेटवर्क आकारों के लिए numpy dot पर बहुत अधिक ओवरहेड होता है (मैंने कोशिश की ...)।समय

CPU times: user 3.46 s, sys: 6 ms, total: 3.47 s, Wall time: 3.47 s 

जो लगभग मूल संस्करण के समान है (जिसमें से अब तक 50% बंद हो गया है)।

+1

'उप' फ़ंक्शन के साथ मैट्रिक्स स्लाइस को प्रतिस्थापित करने से थोड़ा बढ़ावा मिल सकता है, क्योंकि कोई भी टुकड़ा अस्थायी सरणी आवंटित करेगा। –

+0

प्रिय कॉलिन, सुझाव के लिए धन्यवाद! क्या आपके पास इस व्यवहार के बारे में कोई संदर्भ है? मैंने सोचा कि मानक इंडेक्सिंग स्लाइस के लिए केवल एक छोटा सा रूप है, और उप अनिवार्य रूप से टुकड़ा है लेकिन पीछे आयामों के संबंध में थोड़ा अलग व्यवहार के साथ, सिमुलेशन कोड के संबंध में, सभी स्लाइसों को अब स्पष्ट लूप द्वारा प्रतिस्थापित किया जाता है, इसलिए मुझे यकीन नहीं है इस मामले में 'उप' का उपयोग कैसे करें। – user45893

+1

जांचें [यहां] (http://julia.readthedocs.org/en/latest/manual/arrays/) और "सबएरे" पर एक शब्द खोज करें। किसी सरणी के किसी * तत्व * को इंडेक्स करना अस्थायी स्मृति आवंटित नहीं करता है। एक सरणी के किसी भी * टुकड़ा * इंडेक्सिंग टुकड़ा के अनुरूप एक अस्थायी सरणी बना देगा। 'sub' एक 'SubArray' बनाकर इसके आसपास हो जाता है जो अनिवार्य रूप से मूल सरणी को संदर्भित करने के लिए उपयोग किए गए सूचकांक का एक सेट है। 'SubArray' पर ऑपरेशंस स्मृति में अस्थायी सरणी बनाने के बजाय मूल सरणी का संदर्भ देता है, इसलिए मेरी मूल टिप्पणी। हालांकि, यदि आपके पास अब कोई स्लाइस नहीं है तो सभी आवश्यक नहीं :-) –

उत्तर

5

हालांकि आप Devectorize.jl पैकेज का उपयोग कर रहे हैं, लेकिन मेरा सुझाव है कि आप उन सभी वेक्टरीकृत ऑपरेशंस को स्पष्ट रूप से सरल लूप के रूप में लिखें। मुझे उम्मीद है कि यह आपको एक महत्वपूर्ण प्रदर्शन बढ़ावा देगा।

Devectorize पैकेज निश्चित रूप से एक महान योगदान है, लेकिन हुप्स को देखने के लिए यह माध्यम से कूदता है आप के लिए गंदे काम करने के लिए, आप कुछ इस तरह (पैकेज README से एक उदाहरण) कर सकते हैं:

using Devectorize 

a = rand(2,2); 
b = rand(2,2); 
c = rand(2,2); 

julia> macroexpand(:(@devec r = exp(a + b) .* sum(c))) 

यहां, macroexpand एक ऐसा फ़ंक्शन है जो आपको बताता है कि @devec मैक्रो इसके तर्क (शेष रेखा पर कोड) का विस्तार करता है। मैं यहां आउटपुट दिखाकर आश्चर्य को खराब नहीं करूंगा, लेकिन यह केवल for लूप नहीं है जिसे आप हाथ से लिखेंगे।

इसके अलावा, तथ्य यह है कि आपके पास विशाल आवंटन है, यह बताता है कि सभी वेक्टर परिचालनों का सही ढंग से निपटाया जा रहा है।

वैसे, पहले एक छोटा सा रन करना न भूलें ताकि आप संकलन चरण का समय न लें।

[टेंगेंशियल नोट: यहां, exp वह फ़ंक्शन है जो map(exp, a+b) के समतुल्य मैट्रिक्स के प्रत्येक तत्व को सामान्य घातीय कार्य लागू करता है। expm एक मैट्रिक्स का घातीय देता है। exp के ऐसे उपयोगों को बहिष्कृत करने की बात हुई है।]

+0

प्रिय डेविड, कूल सुझाव के लिए धन्यवाद! डेवैक मैक्रो को प्रतिस्थापित करना वास्तव में समय और आवंटन से 25% बंद करता है (अद्यतन प्रदर्शन आंकड़े देखें)। इसके अलावा, मैक्रोएक्सपैंड के बारे में जानना एक अच्छी बात है। समय की जांच के संबंध में, मैं आमतौर पर टाइमिट मैक्रो का उपयोग एक अतिरिक्त संकलन चरण के साथ करता हूं। – user45893

+0

यह जानना दिलचस्प होगा कि यह सी या फोरट्रान संस्करण से कैसे तुलना करता है। मैं वास्तव में स्पष्ट बीएलएएस कॉल पर जाने का सुझाव नहीं दे रहा था, लेकिन ऐसा लगता है कि यह एक अच्छा विचार था। –

+0

वैसे, आपको आवश्यकता नहीं है। * एक स्केलर द्वारा वेक्टर को गुणा करने के लिए, * करेगा। –

संबंधित मुद्दे