日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python 笔记:爱因斯坦求和 einsum

發布時間:2025/4/5 python 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python 笔记:爱因斯坦求和 einsum 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1 einsum簡介

????????使用愛因斯坦求和約定,可以以簡單的方式表示許多常見的多維線性代數數組運算。

????????給定兩個矩陣A和B,我們想對它們做一些操作,比如 multiply、sum或者transpose等。雖然numpy里面有可以直接使用的接口,能夠實現這些功能,但是使用enisum可以做的更快、更節省空間。

????????舉例說明,我們現在有兩個矩陣A和B。我們想計算A和B的哈達瑪乘積(即逐元素乘積),然后按行求和。

import numpy as np A = np.array([0, 1, 2]) B = np.array([[ 0, 1, 2, 3],[ 4, 5, 6, 7],[ 8, 9, 10, 11]])

? ? ? ? 如果我們不適用einsum的話,也不是不能計算,就是需要寫幾步來完成:

A.reshape(-1,1) ''' array([[0],[1],[2]]) '''A.reshape(-1,1)*B ''' array([[ 0, 0, 0, 0],[ 4, 5, 6, 7],[16, 18, 20, 22]]) '''(A.reshape(-1,1)*B).sum(axis=1) #array([ 0, 22, 76])

? ? ? ? 如果我們使用einsum的話,一行就可以實現:

np.einsum('i,ij->i', A, B) #array([ 0, 22, 76])

? 2 einsum原理

????????????????使用einsum的關鍵是,正確地labelling(標記)輸入數組和輸出數組的axes(軸)。

????????????????我們可以使用字符串(比如:ijk,這種表示方式更常用)或者一個整數列表(比如:[0,1])來標記axes。

? ? ? ? ? ? ? ? 比如,為了實現矩陣乘法,我們可以用einsum這么寫(至于為什么這個是矩陣乘法,我們在后面會說明)

np.einsum('ij,jk->ik', A, B)

????????????????字符串'ij,jk->ik'可以根據'->'的位置來切分,左邊的部分('ij,jk')標記了輸入的axes,右邊的('ik')標記了輸出的axes。

????????????????輸入標記又根據','的位置進行切分,'ij'標記了第一個輸入A的axes,'jk'標記了第二個輸入B的axes。

????????????????'ij'、'jk'的字符長度都是2,對應著A和B為2D數組,'ik'的長度也為2,因此輸出也是2D數組。

? ? ? ? ? ? ? ? 給定輸入

A = np.array([[1, 3, 5],[7, 9, -7],[-5, -3, -1]]) B = np.array([[0, 2,4],[6, 8, 6],[4, 2, 0]])

?????????np.einsum('ij,jk->ik', A, B)可以看作是:

  • 在輸入數組的標記之間,重復字母表示沿這些軸的值將相乘,這些乘積構成輸出數組的值。比如圖中沿著j軸做乘積。
  • 從輸出標記中省略的字母表示沿該軸的值將被求和。比如圖中的輸出沒有包含j軸,因此沿著j軸求和得到了輸出數組中的每一項。
    • 如果輸出的標記是'ijk',那么會得到一個 3x3x3 的矩陣。?

    A = np.array([[1, 3, 5],[7, 9, -7],[-5, -3, -1]]) B = np.array([[0, 2,4],[6, 8, 6],[4, 2, 0]]) np.einsum('ij,jk->ijk', A, B)''' array([[[ 0, 2, 4],[ 18, 24, 18],[ 20, 10, 0]],[[ 0, 14, 28],[ 54, 72, 54],[-28, -14, 0]],[[ 0, -10, -20],[-18, -24, -18],[ -4, -2, 0]]]) '''

?輸出標記是'ik'的時候,并不會創建中間的 3x3x3 的矩陣,而是直接將總和累加到2D數組中。

A = np.array([[1, 3, 5],[7, 9, -7],[-5, -3, -1]]) B = np.array([[0, 2,4],[6, 8, 6],[4, 2, 0]]) np.einsum('ij,jk->ik', A, B) ''' array([[ 38, 36, 22],[ 26, 72, 82],[-22, -36, -38]]) '''

如果輸出的標記是空,那么輸出整個矩陣的和

A = np.array([[1, 3, 5],[7, 9, -7],[-5, -3, -1]]) B = np.array([[0, 2,4],[6, 8, 6],[4, 2, 0]]) np.einsum('ij,jk->', A, B) #180

?我們可以按任意順序排序不求和的軸。

A = np.array([[1, 3, 5],[7, 9, -7],[-5, -3, -1]]) B = np.array([[0, 2,4],[6, 8, 6],[4, 2, 0]]) np.einsum('ij,jk->kji', A, B)''' array([[[ 0, 0, 0],[ 18, 54, -18],[ 20, -28, -4]],[[ 2, 14, -10],[ 24, 72, -24],[ 10, -14, -2]],[[ 4, 28, -20],[ 18, 54, -18],[ 0, 0, 0]]]) '''

3 einsum分析

3.1?'ij,jk->ijk'? 與 'ij,jk->kji'

?我們一個一個分析一下

A = np.array([[1, 3, 5],[7, 9, -7],[-5, -3, -1]]) B = np.array([[0, 2,4],[6, 8, 6],[4, 2, 0]]) np.einsum('ij,jk->ijk', A, B)''' array([[[ 0, 2, 4],[ 18, 24, 18],[ 20, 10, 0]],[[ 0, 14, 28],[ 54, 72, 54],[-28, -14, 0]],[[ 0, -10, -20],[-18, -24, -18],[ -4, -2, 0]]]) '''

首先,這幾個數字是怎么得到的?

0=1*02=1*24=1*4
18=3*624=3*818=3*6
20=5*410=5*20=5*0
0=7*014=7*228=7*4
54=9*672=9*854=9*6
-28=-7*4-14=-7*20=-7*0
0=-5*0-10=-5*2-20=-5*4
-18=-3*6-24=-3*8-18=-3*6
-4=-1*4-2=-1*20=-1*0

轉換成坐標,有:

[0,0]*[0,0][0,0]*[0,1][0,0]*[0,2]
[0,1]*[1,0][0,1]*[1,1][0,1]*[1,2]
[0,2]*[2,0][0,2]*[2,1][0,2]*[2,2]
[1,0]*[0,0]

[1,0]*[0,2]

[1,0]*[0,4]
[1,1]*[1,0][1,1]*[1,1][1,1]*[1,2]
[1,2]*[2,0][1,2]*[2,1][1,2]*[2,2]
[2,0]*[0,0][2,0]*[0,1][2,0]*[0,2]
[2,1]*[1,0][2,1]*[1,1][2,1]*[1,2]
[2,2]*[2,0][2,2]*[2,1][2,2]*[2,2]
A = np.array([[1, 3, 5],[7, 9, -7],[-5, -3, -1]]) B = np.array([[0, 2,4],[6, 8, 6],[4, 2, 0]]) np.einsum('ij,jk->kji', A, B)''' array([[[ 0, 0, 0],[ 18, 54, -18],[ 20, -28, -4]],[[ 2, 14, -10],[ 24, 72, -24],[ 10, -14, -2]],[[ 4, 28, -20],[ 18, 54, -18],[ 0, 0, 0]]]) '''

?與上面類似,我們就看第一個3*3的矩陣吧

0=1*00=7*00=-5*0
18=3*654=9*6-18=-3*6
20=5*4-28=-7*4-4=-1*4
[0,0]*[0,0][1,0]*[0,0][2,0]*[0,0]
[0,1]*[1,0][1,1]*[1,0][2,1]*[1,0]
[0.2]*[2,0][1,2]*[2,0][2,2]*[2,0]

可以這么考慮 對于 結果矩陣(比如ijk),第【i,j,k】元素的結果等于【i,j】乘以【j,k】

3.2?'ij,jk->ik'??

A = np.array([[1, 3, 5],[7, 9, -7],[-5, -3, -1]]) B = np.array([[0, 2,4],[6, 8, 6],[4, 2, 0]]) np.einsum('ij,jk->ik', A, B) ''' array([[ 38, 36, 22],[ 26, 72, 82],[-22, -36, -38]]) '''

我們前面?'ij,jk->ijk'的結果是?

0=1*02=1*24=1*4
18=3*624=3*818=3*6
20=5*410=5*20=5*0
0=7*014=7*228=7*4
54=9*672=9*854=9*6
-28=-7*4-14=-7*20=-7*0
0=-5*0-10=-5*2-20=-5*4
-18=-3*6-24=-3*8-18=-3*6
-4=-1*4-2=-1*20=-1*0

這邊相當于

????????

38=0+18+2036=2+24+1022=4+18
26=54-2872=14+72-1482=54+28
-22=-18-4-36=-10-24-2-38=-20-18

可以這么考慮 對于 結果矩陣(比如ik),第【i,k】元素的結果等于:對所有的j,【i,j】乘以【j,k】的結果的和

4 常用的Einsum

4.1 向量篇

('i',A)

向量A的一個視圖

可以看成'i->i',即結果的第i位,是A的第i位

('i->', A)

sum(A)

可以看成'i->0',即結果的第0位,是A的第i位的和

('i,i->i', A,B)

向量A,B對應位置相乘

'i,i->i':結果的第i位,是A和B的第i位的積?

('i,i->', A,B)

向量A,B的內積

?'i,i->':可以看成'i,i->0' 結果的第0位,是A和B的第i位的積 再求和?

('i,j->ij', A,B)

向量A,B的外積

?'i,j->ij':結果的第i行第j列,是A的第i個元素和B的第j個元素的乘積

?4.2 矩陣篇

('ij', A)

返回矩陣A

看成'ij->ij' ,結果的第i行第j列,是A的第i行第j列

('ji->ij', A)

返回矩陣A的轉置

結果的第i行第j列的元素是A的第j行第i列的元素?

('ii->i', A)

矩陣A的對角線元素

結果的第i個元素是A的第i行第i列的元素?

('ij->', A)

矩陣A的元素之和

可以看成'ij->0' 結果的第0位是A的第i行第j列的元素,再求和?

('ij->j', A)

A縱向求和

結果的第j個元素是,對所有的i,A的第(i,j)個元素的和?

('ij->i', A)

A橫向求和

結果的第i個元素是,對所有的j,A的第(i,j)個元素的和?

('ij,ij->ij', A,B)

矩陣A,B相應位置的乘積

結果第i,j個元素,是A的第(i,j)個元素和B的第(i,j)個元素的乘積?

('ij,ji->ij', A,B)

矩陣A和? 矩陣B的轉置? ?相應位置的乘積

結果第i,j個元素,是A的第(i,j)個元素和B的第(j,i)個元素的乘積?

('ij,jk->ik', A,B)

A,B的矩陣乘積

結果的第(i,k)個元素等于A的第(i,j)個元素乘以B的第(j,k)個元素?

('ij,kj->ik', A,B)

矩陣A和矩陣B的內積

('ij,kl->jikl', A,B)

A的每個元素乘以矩陣B

結果的 第(j,i,k,l)個元素是A的(i,j)和B的(k,l)的乘積?

('dn,nd->',A,B)

相當于tr(AB)

?

?5 顯示表明和隱式表明

我們將指定'->'和輸出標記稱為 explicit mode。

如果不指定'->'和輸出標記,numpy會將輸入標記中只出現一次的標記按照字母表順序,作為輸出標記(也就是 implicit mode)。

'ij,jk->ik' 等價于 'ij,jk'

參考文章:einsum初探 - 知乎 (zhihu.com)

總結

以上是生活随笔為你收集整理的python 笔记:爱因斯坦求和 einsum的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。