2016-03-07 70 views
9

में कई tensors के कुशल कमी मैं चार बहुआयामी tensors v[i,j,k], a[i,s,l], w[j,s,t,m], Numpy में x[k,t,n] है, और मुझे टेन्सर z[l,m,n] द्वारा दिए गए गणना करने के लिए कोशिश कर रहा हूँ:अजगर

z[l,m,n] = sum_{i,j,k,s,t} v[i,j,k] * a[i,s,l] * w[j,s,t,m] * x[k,t,n]

सभी tensors हैं अपेक्षाकृत छोटा (कुल में 32k तत्व कम कहें), हालांकि मुझे इस गणना को कई बार करने की ज़रूरत है, इसलिए मैं चाहता हूं कि फ़ंक्शन जितना संभव हो उतना ऊंचा हो।

मैं numpy.einsum इस तरह का उपयोग कर इसे लागू करने की कोशिश की:

z = np.einsum('ijk,isl,jstm,ktn', v, a, w, x) 

लेकिन यह बहुत धीमी थी। s और t (दोनों s और t, बहुत छोटे होते हैं, इसलिए है कि एक समस्या की बहुत अधिक नहीं है) से अधिक योग करने के लिए

z = np.zeros((a.shape[-1],w.shape[-1],x.shape[-1])) 
for s in range(a.shape[1]): 
    for t in range(x.shape[1]): 
    res = np.tensordot(v, a[:,s,:], (0,0)) 
    res = np.tensordot(res, w[:,s,t,:], (0,0)) 
    z += np.tensordot(res, x[:,s,:], (0,0)) 

पाश के लिए एक डबल के अंदर: मैं भी numpy.tensordot कॉल की निम्न क्रम की कोशिश की। यह बहुत बेहतर काम करता है, लेकिन यह अभी भी उतना तेज नहीं है जितना मैं छोड़ दूंगा। मुझे लगता है कि यह उन सभी परिचालनों के कारण हो सकता है जो tensordot को वास्तविक उत्पाद (उदाहरण के लिए अक्षों को अनुमति देने) से पहले आंतरिक रूप से प्रदर्शन करने की आवश्यकता है।

मैं सोच रहा था कि क्या इस तरह के संचालन को लागू करने के लिए एक और अधिक प्रभावी तरीका है। मैं साइथन में इस हिस्से को लागू करने पर भी ध्यान नहीं रखूंगा, लेकिन मुझे यकीन नहीं है कि उपयोग करने के लिए सही एल्गोरिदम क्या होगा।

+0

क्या आप अपना 'numpy.einsum' और 'numpy.tensordot' कार्यान्वयन साझा कर सकते हैं? – Divakar

+0

@ दिवाकर: सुनिश्चित करें। 'Einsum' कार्यान्वयन बस 'z = np.einsum (' ijk, isl, jstm, ktn ', v, a, w, x) है। 'Tensordot' कार्यान्वयन ' res = np.tensordot (v, a, (0,0)) res = np.tensordot (res, w, (0,0)) res = np.tensordot (res , एक्स, (0,0)) ' – Alessandro

+0

कृपया प्रश्न के नीचे" संपादन "बटन का उपयोग करके उन कार्यान्वयन को प्रश्न में जोड़ें। – Divakar

उत्तर

4

भागों में np.tensordot का उपयोग करना, तुम इतनी तरह बातें vectorize कर सकते हैं -

# Perform "np.einsum('ijk,isl->jksl', v, a)" 
p1 = np.tensordot(v,a,axes=([0],[0]))   # shape = jksl 

# Perform "np.einsum('jksl,jstm->kltm', p1, w)" 
p2 = np.tensordot(p1,w,axes=([0,2],[0,1])) # shape = kltm 

# Perform "np.einsum('kltm,ktn->lmn', p2, w)" 
z = np.tensordot(p2,x,axes=([0,2],[0,1]))  # shape = lmn 

रनटाइम परीक्षण और उत्पादन की पुष्टि -

In [15]: def einsum_based(v, a, w, x): 
    ...:  return np.einsum('ijk,isl,jstm,ktn', v, a, w, x) # (l,m,n) 
    ...: 
    ...: def vectorized_tdot(v, a, w, x): 
    ...:  p1 = np.tensordot(v,a,axes=([0],[0]))  # shape = jksl 
    ...:  p2 = np.tensordot(p1,w,axes=([0,2],[0,1])) # shape = kltm 
    ...:  return np.tensordot(p2,x,axes=([0,2],[0,1])) # shape = lmn 
    ...: 

प्रकरण # 1:

In [16]: # Input params 
    ...: i,j,k,l,m,n = 10,10,10,10,10,10 
    ...: s,t = 3,3 # As problem states : "both s and t are very small". 
    ...: 
    ...: # Input arrays 
    ...: v = np.random.rand(i,j,k) 
    ...: a = np.random.rand(i,s,l) 
    ...: w = np.random.rand(j,s,t,m) 
    ...: x = np.random.rand(k,t,n) 
    ...: 

In [17]: np.allclose(einsum_based(v, a, w, x),vectorized_tdot(v, a, w, x)) 
Out[17]: True 

In [18]: %timeit einsum_based(v,a,w,x) 
10 loops, best of 3: 129 ms per loop 

In [19]: %timeit vectorized_tdot(v,a,w,x) 
1000 loops, best of 3: 397 µs per loop 

प्रकरण # 2 (बड़ा डेटासाइज):

In [20]: # Input params 
    ...: i,j,k,l,m,n = 15,15,15,15,15,15 
    ...: s,t = 3,3 # As problem states : "both s and t are very small". 
    ...: 
    ...: # Input arrays 
    ...: v = np.random.rand(i,j,k) 
    ...: a = np.random.rand(i,s,l) 
    ...: w = np.random.rand(j,s,t,m) 
    ...: x = np.random.rand(k,t,n) 
    ...: 

In [21]: np.allclose(einsum_based(v, a, w, x),vectorized_tdot(v, a, w, x)) 
Out[21]: True 

In [22]: %timeit einsum_based(v,a,w,x) 
1 loops, best of 3: 1.35 s per loop 

In [23]: %timeit vectorized_tdot(v,a,w,x) 
1000 loops, best of 3: 1.52 ms per loop 
+0

धन्यवाद! मैंने अपने प्रोग्राम में अपने सदिशित संस्करण को लागू करने की कोशिश की, और यह लूप के लिए डबल का उपयोग करके मेरे संस्करण की तुलना में ~ 20% तेज है। – Alessandro

+0

@Alessandro प्रदर्शन सुधार पर वापस रिपोर्ट करने के लिए धन्यवाद! – Divakar