IT story

numpy dot ()과 Python 3.5+ 행렬 곱셈의 차이점 @

hot-time 2020. 8. 30. 19:46
반응형

numpy dot ()과 Python 3.5+ 행렬 곱셈의 차이점 @


저는 최근에 Python 3.5로 이동했고 새로운 행렬 곱셈 연산자 (@)가 때때로 numpy 도트 연산자 와 다르게 작동 하는 것을 발견했습니다 . 예를 들어 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)

@연산자 형태의 배열을 반환

c.shape
(8, 13, 13)

np.dot()함수가 반환 하는 동안 :

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

numpy dot으로 동일한 결과를 어떻게 재현 할 수 있습니까? 다른 중요한 차이점이 있습니까?


@연산자는 배열의 호출 __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)

문서에서 :

matmuldot두 가지 중요한 점에서 다릅니다 .

  • 스칼라에 의한 곱셈은 허용되지 않습니다.
  • 행렬의 스택은 마치 행렬이 요소 인 것처럼 함께 브로드 캐스트됩니다.

마지막 요점은 3D (또는 더 높은 차원의) 배열을 전달할 때 dotmatmul메서드가 다르게 작동 한다는 것을 분명히 합니다. 문서에서 좀 더 인용하면 :

대상 matmul:

인수 중 하나가 ND, N> 2이면 마지막 두 인덱스에있는 행렬 스택으로 처리되고 그에 따라 브로드 캐스트됩니다.

대상 np.dot:

2 차원 배열의 경우 행렬 곱셈과 동일하고 1 차원 배열의 경우 벡터의 내적 (복소 켤레 없음)에 해당합니다. N 차원의 경우 a의 마지막 축과 b의 마지막에서 두 번째 축에 대한 합계 제품입니다.


@ajcr의 대답은 dotmatmul( @기호로 호출 됨 )가 어떻게 다른지 설명합니다 . 간단한 예를 살펴보면 'stacks of matricies'또는 tensor에서 작동 할 때 두 가지가 어떻게 다르게 작동하는지 분명히 알 수 있습니다.

차이점을 명확히하기 위해 4x4 배열을 사용하고 2x4x3 'stack of matricies'또는 tensor로 dot제품과 matmul제품을 반환합니다 .

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와에서 더 의미가 있습니다

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

since it gives the dot product when a and b are vectors, or the matrix multiplication when a and b are matrices


As for matmul operation in numpy, it consists of parts of dot result, and it can be defined as

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


So, you can see that matmul(a,b) returns an array with a small shape, which has smaller memory consumption and make more sense in applications. In particular, combining with broadcasting, you can get

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

for example.


From the above two definitions, you can see the requirements to use those two operations. Assume a.shape=(s1,s2,s3,s4) and b.shape=(t1,t2,t3,t4)

  • To use dot(a,b) you need

     1. **t3=s4**;
    
  • To use matmul(a,b) you need

    1. t3=s4
    2. t2=s2, or one of t2 and s2 is 1
    3. t1=s1, or one of t1 and s1 is 1

Use the following piece of code to convince yourself.

Code sample

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

Just FYI, @ and its numpy equivalents dot and matmul are all roughly equally fast. (Plot created with perfplot, a project of mine.)

enter image description here

Code to reproduce the plot:

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

참고URL : https://stackoverflow.com/questions/34142485/difference-between-numpy-dot-and-python-3-5-matrix-multiplication

반응형