Разница между numpy dot() и Python 3.5 + матричное умножение @


Я недавно перешел на Python 3.5 и заметил новый оператор умножения матрицы (@) иногда ведет себя иначе, чем numpy dot оператора. Например, для 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)

The @ оператор возвращает массив форма:

c.shape
(8, 13, 13)

С np.dot() функция возвращает:

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

как я могу воспроизвести тот же результат с numpy dot? Есть ли другие существенные отличия?

3 59

3 ответа:

The @ оператор вызывает массив __matmul__ метод, а не dot. Этот метод также присутствует в API как функция np.matmul.

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

из документации:

matmul отличается от dot двумя важными способами.

  • умножение на скаляры не допускается.
  • стеки матриц транслируются вместе, как если бы матрицы были элементами.

последний пункт дает понять, что dot и matmul методы ведут себя по-разному при передаче трехмерных (или многомерных) массивов. Цитируя из документации еще несколько:

на matmul:

если любой из аргументов N-D, N > 2, он обрабатывается как стек матриц, находящихся в последних двух индексах, и транслируется соответственно.

на np.dot:

Для 2-D массивы эквивалентны умножению матрицы, а для 1-D массивов-внутреннему произведению векторов (без комплексного сопряжения). для n измерений это произведение суммы по последней оси a и предпоследней из b

ответ @ajcr объясняет, как dot и matmul (вызывается командой @ символ) отличаются. Глядя на простой пример, ясно видно, как эти два ведут себя по-разному при работе с "стеками матриц" или тензорами.

чтобы уточнить различия, возьмите массив 4x4 и верните dot продукта и matmul продукт с 2x4x3 'стек матриц' или тензор.

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)))

продукты каждой операции приведены ниже. Обратите внимание, как точка продукт есть,

...произведение суммы по последней оси a и предпоследней из b

и как матричный продукт формируется путем трансляции матрицы вместе.

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]]]

в математике, я думаю точка в numpy имеет больше смысла

точка(А,Б)_sum_m Ох{Я,J,к,м}, что{А,Б,М,с}

так как он дает точечное произведение, когда A и b являются векторами, или умножение Матрицы, когда A и b являются матрицами


Как matmul операция в numpy, она состоит из частей точка результат, и его можно определить как

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


Итак, вы можете видеть, что matmul (a,b) возвращает массив с небольшую форму, который имеет меньшее потребление памяти и имеет больше смысла в приложениях. В частности, в сочетании с вещания вы можете узнать

matmul(a,b)_{i,j,k,l} = \sum_m a_{i,j,k,m}b_{j,m,l}

для образец.


из приведенных выше двух определений вы можете увидеть требования к использованию этих двух операций. Предположим a. shape=(s1,s2,s3,s4) и b. shape=(t1,t2,t3,t4)

  • использовать точка (a,b) вам нужно

     1. **t3=s4**;
    
  • использовать matmul (a,b) вам нужно

    1. t3=s4
    2. t2=s2, или один из t2 и s2 является 1
    3. t1=s1, или один из t1 и s1 равен 1

использовать следующий фрагмент кода, чтобы убедить себя.

пример кода

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