2016-08-20 8 views
10

नीचे, मैंने सी-संगत और फोरट्रान-संगत सरणी (C vs FORTRAN memory order) के बीच समेकित संचालन से निपटने के दौरान प्रदर्शन की तुलना की। संख्याओं को कॉलम के अनुसार जोड़े जाने के लिए मैंने axis=0 सेट किया है। मुझे आश्चर्य हुआ कि फोरट्रान-संगत सरणी वास्तव में इसके सी समकक्ष की तुलना में धीमी है। क्या फोर्ट्रान-संगत सरणी में स्तंभों में संगत स्मृति आवंटन नहीं है और इसलिए कॉलम-वार ऑपरेशन में बेहतर है?सी-संगत और फोरट्रान-संगत सरणी संचालन के बीच प्रदर्शन

import numpy as np 
a = np.random.standard_normal((10000, 10000)) 
c = np.array(a, order='C') 
f = np.array(a, order='F') 

Jupyter नोटबुक में,

%timeit c.sum(axis=0) 
10 loops, best of 3: 84.6 ms per loop 
%timeit f.sum(axis=0) 
10 loops, best of 3: 137 ms per loop 
+0

आप यह कर रहे हैं लेकिन पायथन का उपयोग कर ... क्या कुछ अनुकरण नहीं है? –

+0

इसे सत्यापित नहीं कर सकता। मेरे लिए, 'b.sum (अक्ष = 0)' 2.51s है और 'c.sum (अक्ष = 0)' 0.14s – Daniel

+1

'numpy' का कौन सा संस्करण आप उपयोग कर रहे हैं? – romeric

उत्तर

1

उम्मीद है कि चलाते हैं। आप

%timeit f.sum(axis=1) 

का परिणाम जाँच अगर यह भी c के समय के साथ इसी तरह परिणाम देता है। इसी तरह,

%timeit c.sum(axis=1) 

धीमा है।


कुछ स्पष्टीकरण: मान लीजिए आप निम्नलिखित संरचना

|1| |6| 
|2| |7| 
|3| |8| 
|4| |9| 
|5| |10| 

एरिक उल्लेख किया है, इन आपरेशनों reduce के साथ काम किया है। मान लीजिए कि हम कॉलम योग मांग रहे हैं। इसलिए अंतर्ज्ञानी तंत्र इस खेल में नहीं है कि प्रत्येक कॉलम को एक बार, सारांशित और रिकॉर्ड किया जाता है। वास्तव में यह विपरीत ऐसी है कि प्रत्येक पंक्ति एक्सेस किया जाता है और समारोह (यहाँ संक्षेप) समान दो सरणियों a,b होने और

a += b 

को क्रियान्वित करने दोहरा क्या सुपर उल्लेख किया गया है की एक बहुत ही अनौपचारिक तरीका है कि करने के लिए संक्षेप में किया जाता है है documentation of reduce में गूढ़ रूप से। इसके लिए पंक्तियों को संक्षेप में एक्सेस करने की आवश्यकता है हालांकि हम कॉलम योग [1,6] + [2,7] + [3,8] कर रहे हैं ... इसलिए, कार्यान्वयन दिशा ऑपरेशन के आधार पर मायने रखती है लेकिन सरणी नहीं।

2

मुझे लगता है कि यह np.sum() के कार्यान्वयन में है।

IPython साथ
import numpy as np 

A = np.random.standard_normal((10000,10000)) 
C = np.array(A, order='C') 
F = np.array(A, order='F') 

बेंचमार्किंग: उदाहरण के लिए:

In [7]: %timeit C.sum(axis=0) 
10 loops, best of 3: 101 ms per loop 

In [8]: %timeit C.sum(axis=1) 
10 loops, best of 3: 149 ms per loop 

In [9]: %timeit F.sum(axis=0) 
10 loops, best of 3: 149 ms per loop 

In [10]: %timeit F.sum(axis=1) 
10 loops, best of 3: 102 ms per loop 

तो यह बिल्कुल विपरीत व्यवहार कर रहा है के रूप में उम्मीद। लेकिन आइए कुछ अन्य फ़ंक्शन आज़माएं:

In [17]: %timeit np.amax(C, axis=0) 
1 loop, best of 3: 173 ms per loop 

In [18]: %timeit np.amax(C, axis=1) 
10 loops, best of 3: 70.4 ms per loop 

In [13]: %timeit np.amax(F,axis=0) 
10 loops, best of 3: 72 ms per loop 

In [14]: %timeit np.amax(F,axis=1) 
10 loops, best of 3: 168 ms per loop 

निश्चित रूप से, यह संतरे सेब है। लेकिन np.amax() धुरी के साथ काम करता है जैसा कि योग करता है और प्रत्येक पंक्ति/कॉलम के लिए एक तत्व के साथ वेक्टर देता है। और जैसा व्यवहार करेगा उतना व्यवहार करेगा।

In [25]: C.strides 
Out[25]: (80000, 8) 

In [26]: F.strides 
Out[26]: (8, 80000) 

हमें बताता है कि सरणियों वास्तव में रो-आदेश और कॉलम-क्रम में पैक किया जाता है और उस दिशा में पाशन बहुत तेजी से होना चाहिए। उदाहरण के लिए जब तक राशि प्रत्येक पंक्ति को पंक्ति से जोड़ती है क्योंकि यह कॉलम के साथ कॉलम योग (अक्ष = 0) प्रदान करने के लिए यात्रा करती है। लेकिन .pyd के अंदर peeking के मतलब के बिना मैं सिर्फ अनुमान लगा रहा हूँ।

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

percusse लिंक से: http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.reduce.html

, एक के बाद एक के आयाम को कम कर देता एक धुरी के साथ ufunc लगाने से।

a.shape = (N_0, ..., N_i, ..., N_ {M-1}) दें। फिर ufunc.reduce (ए, अक्ष = i) [k_0, .., k_ {i-1}, k_ {i + 1}, .., k_ {m-1}] = पुनरावृत्त जे के परिणामस्वरूप परिणाम (N_i), संचयी प्रत्येक को ufunc लागू करने के एक [k_0, .., k_ {i-1}, जे, k_ {i + 1}, .., k_ {एम -1}]

तो (अक्ष = 0) स्यूडोकोड में, F.sum बुला जब:

for j=cols #axis=0 
    for i=rows #axis=1 
     sum(j,i)=F(j,i)+sum(j-1,i) 

तो यह वास्तव में पंक्ति पर पुनरावृति होगी जब स्तंभ राशि की गणना, स्तंभ-प्रमुख के क्रम में काफी धीमा है। इस तरह के व्यवहार में अंतर की व्याख्या होगी।

एरिक का लिंक हमें कार्यान्वयन के साथ प्रदान करता है, किसी कारण के लिए पर्याप्त मात्रा में कोड के माध्यम से जाने के लिए उत्सुक है।

+0

तो क्या आप एक सरणी के प्रकार का सुझाव देने के लिए आवश्यक रूप से प्रदर्शन से संबंधित नहीं हैं और हम बेहतर परीक्षण करेंगे प्रत्येक मामला? – Nicholas

+0

नहीं, यह निश्चित रूप से प्रदर्शन से संबंधित है। लेकिन हां, यदि आपके पास कुछ प्रदर्शन महत्वपूर्ण बेंचमार्किंग है तो अंगूठे के नियमों की तुलना में बेहतर विचार है, खासकर ब्लैक बॉक्स एल्गोरिदम के साथ। [लिंक] (http://www.scipy-lectures.org/advanced/optimizing/index.html) उस व्यवहार का उपयोग करता है जिसे हम एक उदाहरण के रूप में उम्मीद करते हैं, यह बताते हुए .sum (axis = 0) एक पर धीमी गति के आदेश होंगे बड़े मैट्रिक्स। और डैनियल ने टिप्पणियों में कहा कि उन्होंने ऐसा व्यवहार भी देखा है। तो यह संस्करण भी निर्भर हो सकता है। मैं पाइथन 3.5.2 के साथ बेवकूफ 1.11.1 चला रहा हूँ। – Tapio

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