2015-08-12 20 views
8

İki boyutlu diziler A ve B şekline (N, 2, 2) sahip olduğumu, N eksenine göre eleman-2'yi 2x2'nin her birinde bir matris ürünüyle çarpmak istiyorum. matris. Bir döngü uygulamasıyla, bir döngü kullanmadan bunu yapabileceğimin bir yolu var mı? Tensordot'a baktım ama işe yaratamadım. Sanırım tensordot(a, b, axes=([1,2], [2,1])) gibi bir şey isteyebilirim ama bu bana bir NxN matrisi veriyor.3B dizisinin öğe yönündeki ürünü

cevap

9

İlk eksen boyunca her dilim için matris-çoğaltma yapıyorsunuz gibi görünüyor. Aynı için, şöyle np.einsum kullanabilirsiniz -

np.einsum('ijk,ikl->ijl',A,B) 

Süre testleri ve doğrulamak sonuçları -

In [179]: N = 10000 
    ...: A = np.random.rand(N,2,2) 
    ...: B = np.random.rand(N,2,2) 
    ...: 
    ...: def einsum_based(A,B): 
    ...:  return np.einsum('ijk,ikl->ijl',A,B) 
    ...: 
    ...: def forloop(A,B): 
    ...:  N = A.shape[0] 
    ...:  C = np.zeros((N,2,2)) 
    ...:  for i in range(N): 
    ...:   C[i] = np.dot(A[i], B[i]) 
    ...:  return C 
    ...: 

In [180]: np.allclose(einsum_based(A,B),forloop(A,B)) 
Out[180]: True 

In [181]: %timeit forloop(A,B) 
10 loops, best of 3: 54.9 ms per loop 

In [182]: %timeit einsum_based(A,B) 
100 loops, best of 3: 5.92 ms per loop 
+0

Teşekkürler Divakar. Bunu kullanabilmeyi isterdim, ama einsum'u olmayan eski bir numpy sürümü ile sıkışmış durumdayım. Tensordot eşdeğeri bir çağrı var mı? – Remy

+0

Einsum'un nasıl çalıştığını asla anlayamadım. Okuduğun bir şey, sentaksın nasıl çalıştığını öğretti mi? – rayryeng

+1

@rayryeng Sadece resmi belgeler ve onunla uğraşmanın saatleri. İnsanların bunu anlamaya ihtiyacım var. Sadece onunla oynayın, 'permute' ile yaptığınız gibi. Son zamanlarda, [np.any' yerine 'np.einsum' nasıl kullanılacağını [http://stackoverflow.com/a/31824255/3293881], yine bununla oynayarak çözdünüz. – Divakar

0

Sadece tarafından etiketlenir senin Tensörlerin ilk boyuta üzerinde işlemi gerçekleştirmek için ihtiyaç 0:

c = tensordot(a, b, axes=(0,0)) 

Bu, istediğiniz gibi çalışacaktır. Ayrıca bir eksen listesine de ihtiyacınız yoktur, çünkü bu sadece işlemi gerçekleştirdiğiniz bir boyuttur. axes([1,2],[2,1]) ile 2 ve 3 boyutlarını çapraz çarpıyorsunuz. Eğer indeks gösteriminde (Einstein toplama kuralı) yazıyorsanız, bu c[i,j] = a[i,k,l]*b[j,k,l]'a karşılık gelir, böylece tutmak istediğiniz endeksleri daraltın.

DÜZENLEME: Tamam, sorun, iki 3 boyutlu nesnenin tensör ürününün 6d nesnesi olmasıdır. Kasılmalar dizin çiftlerini içerdiğinden, tensordot işlemiyle 3 boyutlu bir nesne elde edemezsiniz. Hile, hesaplamayı ikiye bölmek: önce matris işlemini yapmak için tensordot dizini yaparsınız ve daha sonra 4d nesnesini 3d'ye düşürmek için bir tensör diyagonalini alırsınız. tek bir komut olarak: tensör gösterimde d[i,j,k] = c[i,j,i,k] = a[i,j,l]*b[i,l,k] yılında

d = np.diagonal(np.tensordot(a,b,axes=()), axis1=0, axis2=2) 

.

+0

Çözümünüzle '(10, 2, 2)' yerine '(2, 2, 2, 2)' şeklini alıyorum, bu yüzden bir şeyler yanlış olabilir. – Holt

+0

Üzgünüz, yanlış cevap verdim, lütfen EDIT'ime bakın. – Mattia