ความแตกต่างระหว่าง numpy dot () และการคูณเมทริกซ์ Python 3.5+ @


119

ฉันเพิ่งย้ายไป Python 3.5 และสังเกตเห็นผู้ประกอบการคูณเมทริกซ์ใหม่ (@)บางครั้งทำงานแตกต่างกันจากจุด numpyผู้ประกอบการ ตัวอย่างเช่นสำหรับอาร์เรย์ 3 มิติ:

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 ได้อย่างไร มีความแตกต่างที่สำคัญอื่น ๆ หรือไม่?


5
คุณไม่สามารถรับผลลัพธ์นั้นจากจุด ฉันคิดว่าคนทั่วไปเห็นด้วยว่าการจัดการอินพุตที่มีมิติสูงของ dot เป็นการตัดสินใจออกแบบที่ผิด
user2357112 รองรับ Monica

เหตุใดจึงไม่ใช้matmulฟังก์ชันนี้เมื่อหลายปีก่อน @เนื่องจากตัวดำเนินการ infix เป็นของใหม่ แต่ฟังก์ชันนี้ก็ใช้งานได้ดีเช่นกันถ้าไม่มีมัน
hpaulj

คำตอบ:


140

@ผู้ประกอบการเรียกร้องของอาเรย์วิธีการไม่ได้__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วิธีการทำงานแตกต่างกันเมื่อส่งผ่านอาร์เรย์ 3 มิติ (หรือมิติที่สูงกว่า) อ้างจากเอกสารเพิ่มเติม:

สำหรับmatmul:

หากอาร์กิวเมนต์ใดเป็น ND, N> 2 จะถือว่าเป็นกลุ่มเมทริกซ์ที่อยู่ในดัชนีสองตัวสุดท้ายและออกอากาศตามนั้น

สำหรับnp.dot:

สำหรับอาร์เรย์ 2 มิติจะเทียบเท่ากับการคูณเมทริกซ์และสำหรับอาร์เรย์ 1-D กับผลคูณภายในของเวกเตอร์ (โดยไม่มีการผันคำกริยาที่ซับซ้อน) สำหรับ N มิติคือผลรวมของแกนสุดท้ายของ a และวินาทีที่สองไปสุดท้ายของ b


13
ความสับสนที่นี่อาจเป็นเพราะบันทึกประจำรุ่นซึ่งถือเอาสัญลักษณ์ "@" มาเทียบกับฟังก์ชัน dot () ของ numpy ในโค้ดตัวอย่างโดยตรง
Alex K

13

คำตอบโดย @ajcr อธิบายว่าdotและmatmul(เรียกโดย@สัญลักษณ์) แตกต่างกันอย่างไร จากการดูตัวอย่างง่ายๆเราจะเห็นได้อย่างชัดเจนว่าทั้งสองมีพฤติกรรมที่แตกต่างกันอย่างไรเมื่อทำงานกับ 'stacks of matricies' หรือ tensors

ในการชี้แจงความแตกต่างให้ใช้อาร์เรย์ 4x4 และส่งคืนdotผลิตภัณฑ์และmatmulผลิตภัณฑ์ด้วย 'stack of matricies' หรือ tensor 3x4x2

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,threebyfourbytwo)))
print('4x4*3x4x2 matmul:\n {}\n'.format(np.matmul(fourbyfour,threebyfourbytwo)))

ผลิตภัณฑ์ของแต่ละการดำเนินการปรากฏด้านล่าง สังเกตว่าผลิตภัณฑ์ดอทเป็นอย่างไร

... ผลรวมของแกนสุดท้ายของ a และวินาทีที่สองไปสุดท้ายของ b

และผลิตภัณฑ์เมทริกซ์เกิดขึ้นได้อย่างไรโดยการกระจายเมทริกซ์เข้าด้วยกัน

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
dot (a, b) [i, j, k, m] = sum (a [i, j ,:] * b [k,:, m]) ------- เช่นเอกสารบอกว่า: มันเป็น ผลรวมของผลคูณในแกนสุดท้ายของ a และแกนที่สองถึงสุดท้ายของ b:
Ronak Agrawal

จับได้ดีขนาด 3x4x2 อีกวิธีหนึ่งในการสร้างเมทริกซ์คือการa = np.arange(24).reshape(3, 4, 2)สร้างอาร์เรย์ที่มีขนาด 3x4x2
นาธาน

8

แค่ FYI @และเทียบเท่าdotกับmatmulตัวเลขและทั้งหมดก็เร็วพอ ๆ กัน (พล็อตที่สร้างขึ้นด้วยเพอร์พล็อตโครงการของฉัน)

ใส่คำอธิบายภาพที่นี่

รหัสเพื่อสร้างพล็อตซ้ำ:

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

ในทางคณิตศาสตร์ฉันคิดว่าจุดในตัวเลขมีความหมายมากกว่า

จุด (a, b) _ {i, j, k, a, b, c} =สูตร

เนื่องจากให้ผลิตภัณฑ์ดอทเมื่อ a และ b เป็นเวกเตอร์หรือการคูณเมทริกซ์เมื่อ a และ b เป็นเมทริกซ์


สำหรับการดำเนินการmatmulใน numpy จะประกอบด้วยส่วนของdot result และสามารถกำหนดเป็น

> matmul (a, b) _ {i, j, k, c} =สูตร

ดังนั้นคุณจะเห็นว่าmatmul (a, b)ส่งคืนอาร์เรย์ที่มีรูปร่างเล็กซึ่งมีการใช้หน่วยความจำน้อยกว่าและมีความหมายมากกว่าในแอปพลิเคชัน โดยเฉพาะอย่างยิ่งเมื่อรวมกับการออกอากาศคุณจะได้รับ

matmul (a, b) _ {i, j, k, 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

np.matmulยังให้ผลิตภัณฑ์ดอทบนเวกเตอร์และผลิตภัณฑ์เมทริกซ์บนเมทริกซ์
Subhaneil Lahiri

2

นี่คือการเปรียบเทียบnp.einsumเพื่อแสดงวิธีการคาดการณ์ดัชนี

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 และ DOT

ฉันได้รับ "ValueError: รูปร่างของค่าที่ส่งผ่านคือ (200, 1) ดัชนีบ่งบอกถึง (200, 3)" เมื่อพยายามใช้ MATMUL ฉันต้องการวิธีแก้ปัญหาอย่างรวดเร็วและพบว่า DOT ให้ฟังก์ชันเดียวกัน ฉันไม่ได้รับข้อผิดพลาดใด ๆ ในการใช้ DOT ฉันได้รับคำตอบที่ถูกต้อง

กับ MATMUL

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

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

YY.shape

>>> (200, )
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.