2013-03-10 6 views
7

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

मैं अहस्ताक्षरित पूर्णांक सूचकांक उपयोग कर रहा था के अनुसार पहुँच तेजी लाने के लिए: http://docs.cython.org/src/userguide/numpy_tutorial.html#tuning-indexing-further

वैसे भी मैंने सोचा कि यह अहस्ताक्षरित ints उपयोग करने के लिए हानिरहित था।

cpdef function(np.ndarray[np.float32_t, ndim=2] response, max_loc): 
    cdef unsigned int x, y 
    x, y = int(max_loc[0]), int(max_loc[1]) 
    x2, y2 = int(max_loc[0]), int(max_loc[1]) 
    print response[y,x], type(response[y,x]), response.dtype 
    print response[y2,x2], type(response[y2,x2]), response.dtype 
    print 2*(response[y,x] - min(response[y,x-1], response[y,x+1])) 
    print 2*(response[y2,x2] - min(response[y2,x2-1], response[y2,x2+1])) 

प्रिंट:

इस कोड को देखते हैं?

0.959878861904 <type 'float'> float32 
0.959879 <type 'numpy.float32'> float32 
1.04306024313 
1.04306030273 

इस क्यों होता है !!! क्या यह एक बग है?

ठीक है, यहाँ का अनुरोध एक ही प्रकार और मूल्यों है कि मैं अपने मूल कार्य में प्रयोग किया जाता के साथ एक SSCCE है के रूप में

cpdef function(): 
    cdef unsigned int x, y 
    max_loc2 = np.asarray([ 15., 25.], dtype=float) 
    cdef np.ndarray[np.float32_t, ndim=2] response2 = np.zeros((49,49), dtype=np.float32)  
    x, y = int(max_loc2[0]), int(max_loc2[1]) 
    x2, y2 = int(max_loc2[0]), int(max_loc2[1]) 

    response2[y,x] = 0.959878861904 
    response2[y,x-1] = 0.438348740339 
    response2[y,x+1] = 0.753262758255 


    print response2[y,x], type(response2[y,x]), response2.dtype 
    print response2[y2,x2], type(response2[y2,x2]), response2.dtype 
    print 2*(response2[y,x] - min(response2[y,x-1], response2[y,x+1])) 
    print 2*(response2[y2,x2] - min(response2[y2,x2-1], response2[y2,x2+1])) 

प्रिंट

0.959878861904 <type 'float'> float32 
0.959879 <type 'numpy.float32'> float32 
1.04306024313 
1.04306030273 

मैं अजगर 2.7.3 का उपयोग 0.18 और msvc9 cython एक्सप्रेस

+1

तुम सच में 'तुलना करने के लिए अहस्ताक्षरित int'' बनाम हस्ताक्षर किए int' चाहते हैं, बजाय 'अहस्ताक्षरित int' बनाम' की PyObject' या जो कुछ-कुछ और-Cython-चुनता है, आप की जरूरत है 'cdef int x2, y2'। – abarnert

+1

अधिक महत्वपूर्ण बात: क्या आप हमें एक [एसएससीसीई] (http://sscce.org) दे सकते हैं जो समस्या का प्रदर्शन करता है, और सटीक संस्करण जो आप उपयोग कर रहे हैं। चूंकि जोश संस्करण के नमूने मानों का उपयोग करते हुए मेरे पास प्रत्येक संस्करण तक पहुंच है, इसलिए मुझे हमेशा int, unsigned int, और निर्दिष्ट नहीं किया जाता है (प्रासंगिक मामलों में अपेक्षित प्रिंट सटीक अंतर को छोड़कर)। – abarnert

+0

आप इसके साथ सही हैं। अगर मैं cdef int x2 घोषित करता हूं, y2 मुझे यह अंतर नहीं मिलता है, तो वास्तव में यह cdef int या unsigned int बनाम पायओब्जेक्ट-या-जो कुछ भी है- साइथन-चुनता – martinako

उत्तर

7

मैंने मॉड्यूल के लिए जेनरेट किए गए सी स्रोत को पढ़ने में आसान बनाने के लिए प्रश्न में उदाहरण को संशोधित किया। मुझे केवल उस तर्क को देखने में दिलचस्पी है जो सरणी से np.float32 ऑब्जेक्ट प्राप्त करने के बजाय पाइथन float ऑब्जेक्ट्स बनाता है।

मैं विस्तार मॉड्यूल संकलित करने के लिए pyximport का उपयोग कर रहा हूं। यह जेनरेट सी फ़ाइल को ~/.pyxbld (शायद %userprofile%\.pyxbld विंडोज़) की उपनिर्देशिका में सहेजता है।

import numpy as np 
import pyximport 
pyximport.install(setup_args={'include_dirs': [np.get_include()]}) 

open('_tmp.pyx', 'w').write(''' 
cimport numpy as np 
cpdef function(np.ndarray[np.float32_t, ndim=2] response, max_loc): 
    cdef unsigned int p_one, q_one 
    p_one = int(max_loc[0]) 
    q_one = int(max_loc[1]) 
    p_two = int(max_loc[0]) 
    q_two = int(max_loc[1]) 
    r_one = response[q_one, p_one] 
    r_two = response[q_two, p_two] 
''') 

import _tmp 
assert(hasattr(_tmp, 'function')) 

यहां रुचि के अनुभाग के लिए जेनरेट किया गया सी कोड है (इसे पढ़ने में आसान बनाने के लिए थोड़ा सुधार हुआ)। यह पता चला है कि जब आप सी unsigned int इंडेक्स चर का उपयोग करते हैं, तो जेनरेट कोड सीधे सरणी बफर से डेटा पकड़ता है और PyFloat_FromDouble पर कॉल करता है, जो इसे double पर ले जाता है। दूसरी ओर, जब आप पाइथन int इंडेक्स चर का उपयोग करते हैं, तो यह सामान्य दृष्टिकोण लेता है। यह एक ट्यूपल बनाता है और PyObject_GetItem पर कॉल करता है। इस तरह np.float32 dtype का सही सम्मान करने के लिए ndarray की अनुमति देता है।

#define __Pyx_BufPtrStrided2d(type, buf, i0, s0, i1, s1) \ 
    (type)((char*)buf + i0 * s0 + i1 * s1) 

    /* "_tmp.pyx":9 
*  p_two = int(max_loc[0]) 
*  q_two = int(max_loc[1]) 
*  r_one = response[q_one, p_one]    # <<<<<<<<<<<<<< 
*  r_two = response[q_two, p_two] 
*/ 
    __pyx_t_3 = __pyx_v_q_one; 
    __pyx_t_4 = __pyx_v_p_one; 
    __pyx_t_5 = -1; 

    if (unlikely(__pyx_t_3 >= (size_t)__pyx_bshape_0_response)) 
    __pyx_t_5 = 0; 
    if (unlikely(__pyx_t_4 >= (size_t)__pyx_bshape_1_response)) 
    __pyx_t_5 = 1; 

    if (unlikely(__pyx_t_5 != -1)) { 
    __Pyx_RaiseBufferIndexError(__pyx_t_5); 
    { 
     __pyx_filename = __pyx_f[0]; 
     __pyx_lineno = 9; 
     __pyx_clineno = __LINE__; 
     goto __pyx_L1_error; 
    } 
    } 

    __pyx_t_1 = PyFloat_FromDouble((
    *__Pyx_BufPtrStrided2d(
     __pyx_t_5numpy_float32_t *, 
     __pyx_bstruct_response.buf, 
     __pyx_t_3, __pyx_bstride_0_response, 
     __pyx_t_4, __pyx_bstride_1_response))); 

    if (unlikely(!__pyx_t_1)) { 
    __pyx_filename = __pyx_f[0]; 
    __pyx_lineno = 9; 
    __pyx_clineno = __LINE__; 
    goto __pyx_L1_error; 
    } 

    __Pyx_GOTREF(__pyx_t_1); 
    __pyx_v_r_one = __pyx_t_1; 
    __pyx_t_1 = 0; 

    /* "_tmp.pyx":10 
*  q_two = int(max_loc[1]) 
*  r_one = response[q_one, p_one] 
*  r_two = response[q_two, p_two]    # <<<<<<<<<<<<<< 
*/ 
    __pyx_t_1 = PyTuple_New(2); 

    if (unlikely(!__pyx_t_1)) { 
    __pyx_filename = __pyx_f[0]; 
    __pyx_lineno = 10; 
    __pyx_clineno = __LINE__; 
    goto __pyx_L1_error; 
    } 

    __Pyx_GOTREF(((PyObject *)__pyx_t_1)); 
    __Pyx_INCREF(__pyx_v_q_two); 
    PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_v_q_two); 
    __Pyx_GIVEREF(__pyx_v_q_two); 
    __Pyx_INCREF(__pyx_v_p_two); 
    PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_v_p_two); 
    __Pyx_GIVEREF(__pyx_v_p_two); 

    __pyx_t_2 = PyObject_GetItem(
    ((PyObject *)__pyx_v_response), 
    ((PyObject *)__pyx_t_1)); 

    if (!__pyx_t_2) { 
    __pyx_filename = __pyx_f[0]; 
    __pyx_lineno = 10; 
    __pyx_clineno = __LINE__; 
    goto __pyx_L1_error; 
    } 

    __Pyx_GOTREF(__pyx_t_2); 
    __Pyx_DECREF(((PyObject *)__pyx_t_1)); 
    __pyx_t_1 = 0; 
    __pyx_v_r_two = __pyx_t_2; 
    __pyx_t_2 = 0; 
+0

ठीक है, यह बताता है क्यों! तो मुझे लगता है कि यह साइथन में एक बग है। – martinako

+0

इसे कैसे कामयाब करें? फ्लोट 32 पर हर एक्सेस कास्टिंग करना मेरे लिए अच्छा नहीं लग रहा है, सरणी पहले ही फ्लोट 32 – martinako

+1

है, आप तेजी से गणना के लिए 'r_one'' np.float32_t' टाइप कर सकते हैं। प्रिंटिंग एक पाइथन 'फ्लोट 'बनाता है, लेकिन यह सिर्फ आउटपुट के लिए है। – eryksun

2

मेरी मशीन पर इसके साथ खेलना, मुझे कोई फर्क नहीं पड़ता। मैं cython जादू के साथ IPython नोटबुक का उपयोग कर रहा:

In [1]: 

%load_ext cythonmagic 

In [12]: 

%%cython 

import numpy as np 
cimport numpy as np 

cpdef function(np.ndarray[np.float32_t, ndim=2] response, max_loc): 
    cdef unsigned int x, y 
    x, y = int(max_loc[0]), int(max_loc[1]) 
    x2, y2 = int(max_loc[0]), int(max_loc[1]) 
    #return 2*(response[y,x] - min(response[y,x-1], response[y,x+1])), 2*(response[y2,x2] - min(response[y2,x2-1], response[y2,x2+1])) 
    print response[y,x], type(response[y,x]), response.dtype 
    print response[y2,x2], type(response[y2,x2]), response.dtype 
    print 2*(response[y,x] - min(response[y,x-1], response[y,x+1])) 
    print 2*(response[y2,x2] - min(response[y2,x2-1], response[y2,x2+1])) 

In [13]: 

a = np.random.normal(size=(10,10)).astype(np.float32) 
m = [3,2] 
function(a,m) 

0.586090564728 <type 'float'> float32 
0.586091 <type 'numpy.float32'> float32 
4.39655685425 
4.39655685425 

परिणामों के प्रथम जोड़ी, अंतर प्रिंट बयान का सिर्फ उत्पादन सटीक है। साइथन का आप किस संस्करण का उपयोग कर रहे हैं? इंडेक्स उत्तर को प्रभावित करने की बेहद असंभव हैं क्योंकि यह केवल स्मृति की एक निश्चित लंबाई तक पहुंच रहा है कि numpy सरणी का डेटा विशेषता भंडारण कर रही है।

+0

पर काम कर रहा हूं यह वास्तव में एक जवाब नहीं है ... लेकिन यह कल्पना करना मुश्किल है कि आप इस सब को एक टिप्पणी में कैसे फिट कर सकते हैं (यहां तक ​​कि पेस्टबिन या जो कुछ भी लिंक के साथ), इसलिए मुझे यकीन नहीं है कि आप और क्या चाहते हैं किया जा सकता था। और यह निश्चित रूप से उपयोगी जानकारी है। – abarnert

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