Numpy dot () ile Python 3.5+ matris çarpımı arasındaki fark @


119

Geçenlerde Python 3.5'e geçtim ve yeni matris çarpma operatörünün (@) bazen numpy nokta operatöründen farklı davrandığını fark ettim . Örneğin, 3 boyutlu diziler için:

import numpy as np

a = np.random.rand(8,13,13)
b = np.random.rand(8,13,13)
c = a @ b  # Python 3.5+
d = np.dot(a, b)

@Operatör şeklinin bir dizi döndürür:

c.shape
(8, 13, 13)

iken np.dot()fonksiyon dönüşleri:

d.shape
(8, 13, 8, 13)

Aynı sonucu numpy dot ile nasıl yeniden üretebilirim? Başka önemli farklılıklar var mı?


5
Bu sonucu noktadan çıkaramazsınız. Bence insanlar genellikle dot'un yüksek boyutlu girdileri ele almasının yanlış tasarım kararı olduğu konusunda hemfikirdi.
user2357112 Monica'yı

Bu matmulişlevi neden yıllar önce uygulamadılar ? @bir infix operatörü olarak yeni, ancak işlev onsuz da iyi çalışıyor.
hpaulj

Yanıtlar:


140

@Operatör dizinin çağıran __matmul__yöntem değil dot. Bu yöntem, API'de işlev olarak da mevcuttur np.matmul.

>>> a = np.random.rand(8,13,13)
>>> b = np.random.rand(8,13,13)
>>> np.matmul(a, b).shape
(8, 13, 13)

Belgelerden:

matmuldotiki önemli yönden farklıdır .

  • Skalarlarla çarpmaya izin verilmez.
  • Matris yığınları, matrisler elemanmış gibi birlikte yayınlanır.

Son nokta bu temizlemek yapar dotve matmul3D (veya daha yüksek boyutlu) dizileri geçtiğinde yöntemleri farklı davranır. Belgelerden biraz daha alıntı yapmak:

Şunun için matmul:

Bağımsız değişkenlerden biri ND, N> 2 ise, son iki dizinde bulunan ve buna göre yayınlanan bir matris yığını olarak kabul edilir.

Şunun için np.dot:

2-D diziler için matris çarpımına ve 1-D diziler için vektörlerin iç çarpımına (karmaşık birleşme olmadan) eşdeğerdir. N boyutları için, a'nın son ekseni ve ikinciden sona b'nin ekseni üzerindeki toplam çarpım


13
Buradaki karışıklık muhtemelen "@" sembolünü örnek koddaki numpy'nin dot () fonksiyonuna doğrudan eşitleyen sürüm notlarından kaynaklanmaktadır.
Alex K

13

@Ajcr tarafından cevap açıklar dotve matmul(tarafından çağrılan @farklılık sembolü). Basit bir örneğe bakarak, 'matris yığınları' veya tensörler üzerinde çalışırken ikisinin nasıl farklı davrandığını açıkça görebiliriz.

Farklılıkları açıklığa kavuşturmak için 4x4'lük bir dizi alın ve dotürünü ve matmulürünü 3x4x2 'malzeme yığını' veya tensörle iade edin .

import numpy as np
fourbyfour = np.array([
                       [1,2,3,4],
                       [3,2,1,4],
                       [5,4,6,7],
                       [11,12,13,14]
                      ])


threebyfourbytwo = np.array([
                             [[2,3],[11,9],[32,21],[28,17]],
                             [[2,3],[1,9],[3,21],[28,7]],
                             [[2,3],[1,9],[3,21],[28,7]],
                            ])

print('4x4*3x4x2 dot:\n {}\n'.format(np.dot(fourbyfour,twobyfourbythree)))
print('4x4*3x4x2 matmul:\n {}\n'.format(np.matmul(fourbyfour,twobyfourbythree)))

Her işlemin ürünleri aşağıda görünmektedir. İç çarpımın nasıl olduğuna dikkat edin,

... a'nın son ekseni ve sondan ikinci b ekseni üzerindeki toplam çarpım

ve matrisin birlikte yayınlanmasıyla matris ürününün nasıl oluştuğu.

4x4*3x4x2 dot:
 [[[232 152]
  [125 112]
  [125 112]]

 [[172 116]
  [123  76]
  [123  76]]

 [[442 296]
  [228 226]
  [228 226]]

 [[962 652]
  [465 512]
  [465 512]]]

4x4*3x4x2 matmul:
 [[[232 152]
  [172 116]
  [442 296]
  [962 652]]

 [[125 112]
  [123  76]
  [228 226]
  [465 512]]

 [[125 112]
  [123  76]
  [228 226]
  [465 512]]]

2
nokta (a, b) [i, j, k, m] = toplam (a [i, j ,:] * b [k,:, m]) ------ gibi dokümantasyon şöyle diyor:
a'nın

Ancak iyi bir yakalama, 3x4x2. Matrisi oluşturmanın başka bir yolu, a = np.arange(24).reshape(3, 4, 2)3x4x2 boyutlarında bir dizi oluşturmaktır.
Nathan

8

Sadece FYI @ve onun uyuşmuş muadilleri dotve matmulhepsi kabaca eşit derecede hızlı. ( Bir proje olan perfplot ile oluşturulmuş arsa .)

görüntü açıklamasını buraya girin

Grafiği yeniden oluşturmak için kod:

import perfplot
import numpy


def setup(n):
    A = numpy.random.rand(n, n)
    x = numpy.random.rand(n)
    return A, x


def at(data):
    A, x = data
    return A @ x


def numpy_dot(data):
    A, x = data
    return numpy.dot(A, x)


def numpy_matmul(data):
    A, x = data
    return numpy.matmul(A, x)


perfplot.show(
    setup=setup,
    kernels=[at, numpy_dot, numpy_matmul],
    n_range=[2 ** k for k in range(12)],
    logx=True,
    logy=True,
)

7

Matematikte, uyuşuk noktanın daha mantıklı olduğunu düşünüyorum.

nokta (a, b) _ {i, j, k, a, b, c} =formül

a ve b vektör olduğunda iç çarpımı veya a ve b matris olduğunda matris çarpımını verdiğinden


Numpy'de matmul işlemine gelince , nokta sonucu bölümlerinden oluşur ve şu şekilde tanımlanabilir:

> matmul (a, b) _ {i, j, k, c} =formül

Böylece, matmul (a, b) 'nin küçük bir şekle sahip, daha az bellek tüketen ve uygulamalarda daha anlamlı olan bir dizi döndürdüğünü görebilirsiniz . Özellikle yayıncılık ile birleştirerek ,

matmul (a, b) _ {i, j, k, l} =formül

Örneğin.


Yukarıdaki iki tanımdan, bu iki işlemi kullanmak için gereksinimleri görebilirsiniz. A.shape = (s1, s2, s3, s4) ve b.shape = (t1, t2, t3, t4) olduğunu varsayalım

  • Kullanmak için (a, b) nokta İhtiyacınız

    1. t3 = s4 ;
  • Kullanmak için matmul (a, b) ihtiyacınız

    1. t3 = s4
    2. t2 = s2 veya t2 ve s2'den biri 1
    3. t1 = s1 veya t1 ve s1'den biri 1

Kendinizi ikna etmek için aşağıdaki kod parçasını kullanın.

Kod örneği

import numpy as np
for it in xrange(10000):
    a = np.random.rand(5,6,2,4)
    b = np.random.rand(6,4,3)
    c = np.matmul(a,b)
    d = np.dot(a,b)
    #print 'c shape: ', c.shape,'d shape:', d.shape

    for i in range(5):
        for j in range(6):
            for k in range(2):
                for l in range(3):
                    if not c[i,j,k,l] == d[i,j,k,j,l]:
                        print it,i,j,k,l,c[i,j,k,l]==d[i,j,k,j,l] #you will not see them

np.matmulvektörler üzerindeki iç çarpımı ve matrisler üzerindeki matris çarpımını da verir.
Subhaneil Lahiri

2

np.einsumEndekslerin nasıl tahmin edildiğini gösteren bir karşılaştırma aşağıda verilmiştir.

np.allclose(np.einsum('ijk,ijk->ijk', a,b), a*b)        # True 
np.allclose(np.einsum('ijk,ikl->ijl', a,b), a@b)        # True
np.allclose(np.einsum('ijk,lkm->ijlm',a,b), a.dot(b))   # True

0

MATMUL ve DOT ile yaşadığım deneyim

MATMUL kullanmaya çalışırken sürekli "ValueError: Aktarılan değerlerin şekli (200, 1), endeksler (200, 3)" oluyor. Hızlı bir çözüm istedim ve aynı işlevselliği sağlamak için DOT'u buldum. DOT kullanırken herhangi bir hata almıyorum. Doğru cevabı aldım

MATMUL ile

X.shape
>>>(200, 3)

type(X)

>>>pandas.core.frame.DataFrame

w

>>>array([0.37454012, 0.95071431, 0.73199394])

YY = np.matmul(X,w)

>>>  ValueError: Shape of passed values is (200, 1), indices imply (200, 3)"

DOT ile

YY = np.dot(X,w)
# no error message
YY
>>>array([ 2.59206877,  1.06842193,  2.18533396,  2.11366346,  0.28505879, 

YY.shape

>>> (200, )
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.