2015-11-15 3 views
76

मुझे एक सिमुलेशन (फोरट्रान में लिखे गए) से तापमान वितरण का प्रतिनिधित्व करने वाला 512^3 सरणी मिलता है। सरणी एक बाइनरी फ़ाइल में संग्रहीत है जो आकार में लगभग 1/2 जी है। मुझे इस सरणी के न्यूनतम, अधिकतम और माध्य को जानने की आवश्यकता है और जैसा कि मुझे जल्द ही फोरट्रान कोड को समझने की आवश्यकता होगी, मैंने इसे जाने का फैसला किया और निम्नलिखित बहुत ही आसान दिनचर्या के साथ आया।मेरे फोरट्रान दिनचर्या से कितना तेज़ हो सकता है?

integer gridsize,unit,j 
    real mini,maxi 
    double precision mean 

    gridsize=512 
    unit=40 
    open(unit=unit,file='T.out',status='old',access='stream',& 
     form='unformatted',action='read') 
    read(unit=unit) tmp 
    mini=tmp 
    maxi=tmp 
    mean=tmp 
    do j=2,gridsize**3 
     read(unit=unit) tmp 
     if(tmp>maxi)then 
      maxi=tmp 
     elseif(tmp<mini)then 
      mini=tmp 
     end if 
     mean=mean+tmp 
    end do 
    mean=mean/gridsize**3 
    close(unit=unit) 

यह मेरे द्वारा उपयोग की जाने वाली मशीन पर लगभग 25 सेकंड प्रति फ़ाइल लेता है। यही कारण है कि मुझे नहीं बल्कि लंबे समय से किया जा रहा है के रूप में मारा और इसलिए मैं आगे चला गया और अजगर में निम्नलिखित किया:

import numpy 

    mmap=numpy.memmap('T.out',dtype='float32',mode='r',offset=4,\ 
            shape=(512,512,512),order='F') 
    mini=numpy.amin(mmap) 
    maxi=numpy.amax(mmap) 
    mean=numpy.mean(mmap) 

अब, मैं इस पाठ्यक्रम के तेजी से होने की उम्मीद है, लेकिन मैं वास्तव में उड़ा दिया गया था। यह समान स्थितियों के तहत एक सेकंड से भी कम समय लेता है। मेरा फोरट्रान दिनचर्या (जिसे मैं 128-बिट फ्लोट्स के साथ भी चलाता हूं, से एक दूसरे से विचलित होता है, इसलिए मैं इसे और अधिक भरोसा करता हूं) लेकिन केवल 7 वें महत्वपूर्ण अंक पर।

कितना तेज़ हो सकता है? मेरा मतलब है कि आपको इन मानों को खोजने के लिए किसी सरणी के प्रत्येक प्रविष्टि को देखना है, है ना? क्या मैं अपने फोरट्रान दिनचर्या में इतनी बेवकूफी कर रहा हूं कि इसमें इतना समय लगेगा?

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

टिप्पणी में सवालों के जवाब देने के लिए:

  • हाँ, यह भी मैं 32-बिट और 64-बिट तैरता साथ फोरट्रान दिनचर्या भाग गया, लेकिन यह प्रदर्शन पर कोई प्रभाव नहीं पड़ा ।
  • मैंने iso_fortran_env का उपयोग किया जो 128-बिट फ्लोट प्रदान करता है।
  • 32-बिट फ्लोट का उपयोग करना मेरा मतलब काफी दूर है, इसलिए सटीकता वास्तव में एक मुद्दा है।
  • मैंने अलग-अलग फ़ाइलों पर अलग-अलग फ़ाइलों पर दोनों रूटीन चलाए, इसलिए कैशिंग को तुलना में तुलना में उचित होना चाहिए था?
  • मैंने वास्तव में खुले एमपी की कोशिश की, लेकिन एक ही समय में विभिन्न पदों पर फ़ाइल से पढ़ने के लिए। अपनी टिप्पणियां और उत्तर पढ़ने के बाद यह वास्तव में बेवकूफ लगता है और यह दिनचर्या को बहुत अधिक समय तक ले जाता है। मैं इसे सरणी संचालन पर आज़मा सकता हूं लेकिन शायद यह भी आवश्यक नहीं होगा।
  • फ़ाइलें वास्तव में आकार में 1/2 जी हैं, जो एक टाइपो था, धन्यवाद।
  • मैं अब सरणी कार्यान्वयन का प्रयास करूंगा।

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

मैं क्या @Alexander Vogt और @casey उनके जवाब में सुझाव लागू किया है, और यह जितनी जल्दी numpy के रूप में है, लेकिन के रूप में @Luaan मैं हो सकता है ने कहा अब मैं एक सटीक समस्या है प्राप्त। 32-बिट फ्लोट सरणी का उपयोग करके sum द्वारा गणना की गई औसत 20% बंद है।

... 
real,allocatable :: tmp (:,:,:) 
double precision,allocatable :: tmp2(:,:,:) 
... 
tmp2=tmp 
mean=sum(tmp2)/size(tmp) 
... 

समस्या हल करता है लेकिन कंप्यूटिंग समय बढ़ाता है (बहुत अधिक नहीं, लेकिन ध्यान से)। क्या इस मुद्दे को हल करने का कोई बेहतर तरीका है? मुझे फ़ाइल से एकल को सीधे युगल पढ़ने का कोई तरीका नहीं मिला। और numpy इससे कैसे बचें?

अब तक सभी मदद के लिए धन्यवाद।

+10

क्या आपने 128-बिट फ्लोट के बिना फोरट्रान रूटीन का प्रयास किया था? मुझे किसी भी हार्डवेयर से अवगत नहीं है जो वास्तव में उनको समर्थन करता है, इसलिए उन्हें सॉफ़्टवेयर में करना होगा। – user2357112

+4

क्या होगा यदि आप एक सरणी का उपयोग करके फोरट्रान संस्करण का प्रयास करते हैं (और विशेष रूप से एक अरब के बजाय एक पढ़ने का उपयोग करते हुए)? – francescalus

+9

क्या आपने फोरट्रान में सरणी ऑपरेटरों का उपयोग करने पर विचार किया था? फिर, आप 'minval()', 'maxval()', और 'sum()' कोशिश कर सकते हैं?इसके अलावा, आप फोरट्रान में संचालन के साथ आईओ मिश्रण कर रहे हैं, लेकिन पायथन में नहीं - यह उचित तुलना नहीं है ;-) –

उत्तर

108

आपका फोरट्रान कार्यान्वयन दो प्रमुख कमियों ग्रस्त:

  • आप मिश्रण आईओ और संगणना (और प्रवेश द्वारा फ़ाइल प्रविष्टि से पढ़ें)।
  • आप वेक्टर/मैट्रिक्स संचालन का उपयोग नहीं करते हैं।

इस कार्यान्वयन तुम्हारा के रूप में ही कार्रवाई करने में करता है और तेजी से 20 का एक पहलू से मेरी मशीन पर है:

program test 
    integer gridsize,unit 
    real mini,maxi,mean 
    real, allocatable :: tmp (:,:,:) 

    gridsize=512 
    unit=40 

    allocate(tmp(gridsize, gridsize, gridsize)) 

    open(unit=unit,file='T.out',status='old',access='stream',& 
     form='unformatted',action='read') 
    read(unit=unit) tmp 

    close(unit=unit) 

    mini = minval(tmp) 
    maxi = maxval(tmp) 
    mean = sum(tmp)/gridsize**3 
    print *, mini, maxi, mean 

end program 

विचार एक ही बार में एक सरणी tmp में पूरी फ़ाइल में पढ़ने के लिए है । फिर, मैं सीधे सरणी पर MAXVAL, MINVAL, और SUM फ़ंक्शंस का उपयोग कर सकता हूं।


सटीकता मुद्दे के लिए: बस डबल परिशुद्धता मानों का उपयोग और के रूप में

mean = sum(real(tmp, kind=kind(1.d0)))/real(gridsize**3, kind=kind(1.d0)) 

केवल मामूली गणना समय बढ़ जाती है मक्खी पर रूपांतरण कर रही। मैंने ऑपरेशन तत्व-वार और स्लाइस में प्रदर्शन करने की कोशिश की, लेकिन इससे डिफ़ॉल्ट अनुकूलन स्तर पर केवल आवश्यक समय बढ़ गया।

-O3 पर, तत्व-वार जोड़ सरणी ऑपरेशन से ~ 3% बेहतर प्रदर्शन करता है। डबल और सिंगल परिशुद्धता संचालन के बीच का अंतर मेरी मशीन पर 2% से कम है - औसत पर (व्यक्ति कहीं अधिक विचलित हो जाता है)।

program test 
    integer gridsize,unit, i, j 
    real mini,maxi 
    integer :: t1, t2, rate 
    real, allocatable :: tmp (:,:,:) 
    real, allocatable :: work(:) 
! double precision :: mean 
    real :: mean 
    real :: slange 

    call system_clock(count_rate=rate) 
    call system_clock(t1) 
    gridsize=512 
    unit=40 

    allocate(tmp(gridsize, gridsize, gridsize), work(gridsize)) 

    open(unit=unit,file='T.out',status='old',access='stream',& 
     form='unformatted',action='read') 
    read(unit=unit) tmp 

    close(unit=unit) 

    mini = minval(tmp) 
    maxi = maxval(tmp) 

! mean = sum(tmp)/gridsize**3 
! mean = sum(real(tmp, kind=kind(1.d0)))/real(gridsize**3, kind=kind(1.d0)) 
    mean = 0.d0 
    do j=1,gridsize 
    do i=1,gridsize 
     mean = mean + slange('1', gridsize, 1, tmp(:,i,j),gridsize, work) 
    enddo !i 
    enddo !j 
    mean = mean/gridsize**3 

    print *, mini, maxi, mean 
    call system_clock(t2) 
    print *,real(t2-t1)/real(rate) 

end program 

इस मैट्रिक्स स्तंभों पर एक सटीक मैट्रिक्स 1-नोर्म SLANGE उपयोग करता है:


यहाँ एक बहुत ही तेजी से LAPACK का उपयोग कर कार्यान्वयन है। रन-टाइम एकल परिशुद्धता सरणी फ़ंक्शंस का उपयोग करके दृष्टिकोण से भी तेज़ है - और सटीक समस्या नहीं दिखाता है।

+4

गणना के साथ इनपुट मिश्रण क्यों इसे धीमा कर देता है? उन्हें दोनों को पूरी फाइल पढ़नी है, जो बाधा होगी। और अगर ओएस Readahead करता है, फोरट्रान कोड आई/ओ के लिए ज्यादा इंतजार नहीं करना चाहिए। – Barmar

+2

@ बाड़ार आपके पास अभी भी फ़ंक्शन कॉल ओवरहेड और लॉजिक होगा, यह जांचने के लिए कि डेटा हर बार कैश में है या नहीं। – Overv

54

numpy तेज़ है क्योंकि आपने पायथन में अधिक कुशल कोड लिखा है (और अधिक संख्यात्मक बैकएंड अनुकूलित फोर्ट्रान और सी में लिखा गया है) और फोरट्रान में बहुत ही अक्षम कोड।

अपने पायथन कोड को देखें। आप एक बार में पूरी सरणी लोड करते हैं और फिर उन कार्यों को कॉल करते हैं जो सरणी पर काम कर सकते हैं।

अपने किलेर कोड को देखें। आप एक समय में एक मान पढ़ते हैं और इसके साथ कुछ ब्रांचिंग तर्क करते हैं।

आपकी विसंगति का बहुमत खंडित IO है जिसे आपने फोरट्रान में लिखा है।

आप फर्मन को उसी तरह लिख सकते हैं जैसे आपने पाइथन लिखा था और आप पाएंगे कि यह इस तरह से बहुत तेज चलता है।

program test 
    implicit none 
    integer :: gridsize, unit 
    real :: mini, maxi, mean 
    real, allocatable :: array(:,:,:) 

    gridsize=512 
    allocate(array(gridsize,gridsize,gridsize)) 
    unit=40 
    open(unit=unit, file='T.out', status='old', access='stream',& 
     form='unformatted', action='read') 
    read(unit) array  
    maxi = maxval(array) 
    mini = minval(array) 
    mean = sum(array)/size(array) 
    close(unit) 
end program test 
+0

क्या इस तरह से गणना की गई अर्थ 'numpy'' 'mean' कॉल के समान सटीकता प्राप्त करती है? मुझे इसके बारे में कुछ संदेह हैं। – Bakuriu

+1

@ बाकुरीयू नहीं, ऐसा नहीं है। सिकंदर वोगेट के उत्तर और प्रश्न पर मेरे संपादन देखें। – user35915

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