Różnica między numpy dot () a Pythonem 3.5+ mnożenie macierzy @

Niedawno przeniosłem się do Pythona 3.5 i zauważyłem, że nowy operator mnożenia macierzy (@)czasami zachowuje się inaczej niż operator numpy dot. W przykładzie dla tablic 3d:

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)

Operator @ zwraca tablicę kształtu:

c.shape
(8, 13, 13)

Podczas gdy funkcja np.dot() zwraca:

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

Jak mogę odtworzyć ten sam wynik za pomocą numpy dot? Czy są jakieś inne znaczące różnice?

Author: Alex Riley, 2015-12-07

3 answers

Operator @ wywołuje metodę tablicy __matmul__, a nie dot. Ta metoda jest również obecna w API jako funkcja np.matmul.

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

Z dokumentacji:

matmul różni się od dot na dwa ważne sposoby.

  • mnożenie przez Skalary jest niedozwolone.
  • stosy macierzy są nadawane razem tak, jakby macierze były elementami.

Ostatni punkt wyjaśnia, że dot i matmul metody zachowują się inaczej, gdy przekazywane są tablice 3D (lub wyższe wymiarowe). Cytując z dokumentacji trochę więcej:

Dla matmul:

Jeśli któryś z argumentów jest N-D, N > 2, jest traktowany jako stos macierzy znajdujących się w dwóch ostatnich indeksach i odpowiednio nadawanych.

Dla np.dot:

Dla macierzy 2-D jest równoważne mnożeniu macierzy, A dla macierzy 1-D iloczynowi wewnętrznemu wektorów (bez sprzężenia złożonego). dla N wymiarów jest iloczynem sumy nad ostatnią osią a i od drugiej do ostatniej z b

 69
Author: Alex Riley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-07 20:44:46

Odpowiedź @ ajcr wyjaśnia, w jaki sposób dot i matmul (wywoływane przez symbol @) różnią się. Patrząc na prosty przykład, widać wyraźnie, jak oba zachowują się inaczej, gdy działają na "stosach matrików" lub tensorach.

Aby wyjaśnić różnice, weź tablicę 4x4 i zwróć dot iloczyn i matmul iloczyn z 2x4x3 "stosem macierzy" lub tensorem.

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


twobyfourbythree = 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*4x2x3 dot:\n {}\n'.format(np.dot(fourbyfour,twobyfourbythree)))
print('4x4*4x2x3 matmul:\n {}\n'.format(np.matmul(fourbyfour,twobyfourbythree)))

Produkty każdej operacji pojawiają się poniżej. Zauważ, jak wygląda produkt dot,

...a suma iloczynu nad ostatnią osią a i od drugiej do ostatniej z b

I w jaki sposób powstaje iloczyn macierzy poprzez transmisję macierzy razem.

4x4*4x2x3 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*4x2x3 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]]]
 5
Author: Nathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-30 01:59:35

W matematyce myślę, że kropka w numpy ma większy sens

Kropka(A,b)_{i,j,k,A,b,c} = \sum_m a_{I,j,k,m}b_{a,b, m, c}

Ponieważ daje iloczyn punktowy, gdy a i b są wektorami, lub mnożenie macierzy, gdy a i b są macierzami


Jeśli chodzi o operację matmul w numpy, składa się ona z części wyniku dot i może być zdefiniowana jako

Matmul(A,b)_{I, j, k, c} = \ sum_m a_ {i, j, k, m}b_{I, j, M, c}


Więc widać, że matmul(A,b) zwraca tablicę o małym kształcie, który ma mniejsze zużycie pamięci i ma większy sens w aplikacjach. W szczególności, łącząc z nadawanie , można uzyskać

Matmul(A,b)_{i, j, k, l} = \ sum_m a_{i, j, k,m} b_ {j, M, L}

Na przykład.

Z powyższych dwóch definicji można zobaczyć wymagania, aby korzystać z tych dwóch operacji. Zakładać a. shape = (s1,s2,s3, S4) i b.shape=(t1, t2, t3, t4)

  • Aby użyć dot(A,b) Potrzebujesz

     1. **t3=s4**;
    
  • Aby użyć matmul (A,b) Potrzebujesz

    1. t3=s4
    2. t2=s2 , lub jeden z t2 i s2 jest 1
    3. t1=s1 , lub jeden z t1 i s1 jest 1

Użyj poniższego kodu, aby przekonać siebie.

Próbka kodu

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
 1
Author: Yong Yang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-17 01:23:29