Numpy einsum คำนวณผลิตภัณฑ์ภายนอกตามแนวแกน

Aug 19 2020

ฉันมีสองอาร์เรย์ numpy ที่มีการฝึกอบรมที่เข้ากันได้และต้องการที่จะคำนวณองค์ประกอบผลิตภัณฑ์ด้านนอกที่ชาญฉลาดของการใช้numpy.einsum รูปร่างของอาร์เรย์จะเป็น:

A1 = (i,j,k)
A2 = (i,k,j) 

ดังนั้นอาร์เรย์จึงมีiเมทริกซ์ของรูปร่าง(k,j)และ(j,k)ตามลำดับ

ดังนั้นA1จะมีเมทริกซ์A,B,CและA2จะมีเมทริกซ์D,E,Fผลลัพธ์จะเป็น:

A3 = (A(x)D,B(x)E,C(x)F)

ด้วย(x)การเป็นผู้ดำเนินการผลิตภัณฑ์ภายนอก.

สิ่งนี้จะส่งผลต่อความเข้าใจของฉันตามคำตอบนี้อาร์เรย์A3ของรูปร่างต่อไปนี้:

A3 = (i,j*k,j*k)

จนถึงตอนนี้ฉันได้ลอง:

np.einsum("ijk, ilm -> ijklm", A1, A2)

แต่รูปทรงที่ได้นั้นไม่พอดีกัน

เพื่อเป็นการตรวจสอบความมีสติฉันกำลังทดสอบสิ่งนี้:

A = np.asarray(([1,2],[3,4]))
B = np.asarray(([5,6],[7,8]))

AB_outer = np.outer(A,B)

A_vec = np.asarray((A,A))
B_vec = np.asarray((B,B))

# this line is not correct
AB_vec = np.einsum("ijk, ilm -> ijklm", A_vec,B_vec)

np.testing.assert_array_equal(AB_outer, AB_vec[0])

ขณะนี้เกิดข้อผิดพลาดในการยืนยันเนื่องจากสัญกรณ์ einsum ของฉันไม่ถูกต้อง ฉันยังเปิดรับข้อเสนอแนะใด ๆ ที่สามารถแก้ปัญหานี้ได้และเร็วกว่าหรือเร็วเท่า ๆ กันกับนางไม้ einsum

คำตอบ

3 Divakar Aug 19 2020 at 17:46

เราสามารถขยาย dims และปล่อยให้broadcastingทำงานให้เรา -

(A1[:,:,None,:,None]*A2[:,None,:,None,:]).swapaxes(2,3)

การเรียกใช้ตัวอย่าง -

In [46]: A1 = np.random.rand(3,4,4)
    ...: A2 = np.random.rand(3,4,4)

In [47]: out = (A1[:,:,None,:,None]*A2[:,None,:,None,:]).swapaxes(2,3)

In [48]: np.allclose(np.multiply.outer(A1[0],A2[0]), out[0])
Out[48]: True

In [49]: np.allclose(np.multiply.outer(A1[1],A2[1]), out[1])
Out[49]: True

In [50]: np.allclose(np.multiply.outer(A1[2],A2[2]), out[2])
Out[50]: True

เทียบเท่ากับnp.einsum-

np.einsum('ijk,ilm->ijklm',A1,A2)
1 Valdi_Bo Aug 20 2020 at 01:07

คุณสามารถคำนวณผลลัพธ์ที่กำลังทำงาน:

result = np.einsum('ijk,ikl->ijl', A1, A2)

ฉันตรวจสอบรหัสด้านบนกับข้อมูลการทดสอบต่อไปนี้:

A = np.arange(1, 13).reshape(3, -1)
B = np.arange(2, 14).reshape(3, -1)
C = np.arange(3, 15).reshape(3, -1)
D = np.arange(1, 13).reshape(4, -1)
E = np.arange(2, 14).reshape(4, -1)
F = np.arange(3, 15).reshape(4, -1)
A1 = np.array([A, B, C])
A2 = np.array([D, E, F])

ผลลัพธ์คือ:

array([[[ 70,  80,  90],
        [158, 184, 210],
        [246, 288, 330]],

       [[106, 120, 134],
        [210, 240, 270],
        [314, 360, 406]],

       [[150, 168, 186],
        [270, 304, 338],
        [390, 440, 490]]])

ตอนนี้คำนวณ 3 "ผลลัพธ์บางส่วน":

res_1 = A @ D
res_2 = B @ E
res_3 = C @ F

และตรวจสอบว่าเหมือนกับส่วนที่ต่อเนื่องกันของผลลัพธ์