矩阵操作万能函数 einsum 详细解析(通法教你如何看懂并写出einsum表达式)

这篇具有很好参考价值的文章主要介绍了矩阵操作万能函数 einsum 详细解析(通法教你如何看懂并写出einsum表达式)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文内容

可能你在某个地方听说了einsum,然后不会写,或者看不懂。这篇文章将会一步一步教会你如何使用(通法哦,只要学会方法就全会了)。

Einsum函数简介

ein 就是爱因斯坦的ein,sum就是求和。einsum就是爱因斯坦求和约定,其实作用就是把求和符号省略,就这么简单。举个例子:

我们现在有一个矩阵

A 2 × 2 = ( 1 2 3 4 ) A_{2\times 2} = \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix} A2×2=(1324)

我们想对A的“行”进行求和得到矩阵B(向量B),用公式表示,则为:

B i = ∑ j A i j = B 2 = ( 3 7 ) B_{i} = \sum_j A_{ij} = B_2 = \begin{pmatrix} 3 \\ 7 \end{pmatrix} Bi=jAij=B2=(37)

对于这个求和符号,爱因斯坦说看着有点多余,要不就省略了吧,然后式子就变成了:

B i = A i j B_i = A_{ij} Bi=Aij

用einsum表示呢,则为: torch.einsum("ij->i", A)->符号就相当于等号,->左边的ij就相当于 A i j A_{ij} Aij,->右边的i就相当于 B i B_i Bieinsum接收的第一个参数为einsum表达式,后面的参数为等号右边的矩阵。

不只是pytorch里有,numpy,tensonflow这些里面都有einsum。
这里的 i , j i,j i,j是指代A的下标,也可以换成其他字母

到这里,如果悟性好的同学应该就已经彻底懂了。但应该还有很多同学和我一样处于懵逼状态,所以接下来我会讲解如何看懂一个einsum公式和如何写出einsum表达式。

如何看懂一个einsum式子

当我们拿到一个einsum表达式后,第一步是要写出它的数学表达式。例如,我们有如下一个einsum表达式:

A = torch.Tensor(range(2*3*4)).view(2, 3, 4)
C = torch.einsum("ijk->jk", A)

则,该式子的数学表达式为:

C j k = A i j k C_{jk} = A_{ijk} Cjk=Aijk

第二步,补充 ∑ \sum 符号,那如何补,补几个, ∑ \sum 下面放什么呢?这里就要看左右两边下标的差异了,要补的 ∑ \sum 符号就是右边的下标减左边的下标。在这个例子中,右边有 i j k ijk ijk,而左边是 j k jk jk,差了一个 i i i,所以补 ∑ i \sum_i i。最终为:

C j k = ∑ i A i j k C_{jk} = \sum_i A_{ijk} Cjk=iAijk

第三步,用笔纸画出(或脑补出)这个等式到底干了些啥,对于该等式,可以画为:

矩阵操作万能函数 einsum 详细解析(通法教你如何看懂并写出einsum表达式)

这样就可以很容易看出来,它是将 i i i行都给加一起了,等价于 C = A.sum(dim=0)

第四步,尝试用for循环复现,其实einsum还是很好复现的,就按照公式写for循环就行了,求和的部分用+=

i, j, k = A.shape[0], A.shape[1], A.shape[2] # 得到 i, j, k
C_ = torch.zeros(j, k) # 初始化 C_ , 用来保存结果
for i_ in range(i): # 遍历 i
    for k_ in range(k): # 遍历 j
        for j_ in range(j): # 遍历 k
            C_[j_][k_] += A[i_][j_][k_] # 求和
C, C_
(tensor([[12., 14., 16., 18.],
         [20., 22., 24., 26.],
         [28., 30., 32., 34.]]),
 tensor([[12., 14., 16., 18.],
         [20., 22., 24., 26.],
         [28., 30., 32., 34.]]))

可以看到,我们的for循环结果和einsum的结果一致。

到这里,如何看懂einsum就结束了,按照上面四步走,多加练习即可。

如何看懂一个einsum式子(实战)

我也练几个。先来一个简单的。

A = torch.Tensor(range(2*3)).view(2, 3)
B = torch.einsum("ij->ji", A)

第一步,写出数学表达式

B j i = A i j B_{ji} = A_{ij} Bji=Aij

第二步,添加 ∑ \sum 符号,这里左边是 j i ji ji,右边是 i j ij ij,不多不少,正正好,所以不需要(也不能)增添 ∑ \sum 符号。

第三步,画出矩阵的变换过程

矩阵操作万能函数 einsum 详细解析(通法教你如何看懂并写出einsum表达式)

哦,这不就是求转置矩阵嘛。

第四步,使用for循环复现

i, j = A.shape[0], A.shape[1] # 得到 i, j
B_ = torch.zeros(j, i) # 初始化 B_ , 用来保存结果
for i_ in range(i): # 遍历 i
    for j_ in range(j): # 遍历 j
        B_[j_][i_] = A[i_][j_]  # 因为不需要求和,所以这里用=,而不是+=“”
B, B_
(tensor([[0., 3.],
         [1., 4.],
         [2., 5.]]),
 tensor([[0., 3.],
         [1., 4.],
         [2., 5.]]))

接下来来个难的。

A = torch.Tensor(range(2*3*4*5)).view(2, 3, 4, 5)
B = torch.Tensor(range(2*3*7*8)).view(2, 3, 7, 8)
C = torch.einsum("ijkl,ijmn->klmn", A, B)

如果等式右边有多个矩阵,则用逗号分割。

第一步,写出数学表达式

C k l m n = A i j k l B i j m n C_{klmn} = A_{ijkl}B_{ijmn} Cklmn=AijklBijmn

第二步,补充求和符号,右边有 i j k l m n ijklmn ijklmn,左边有 k l m n klmn klmn,左边少了 i j ij ij,所以补两个求和符号,即 ∑ i ∑ j \sum_i \sum_j ij。最终为:

C k l m n = ∑ i ∑ j A i j k l B i j m n C_{klmn} =\sum_i \sum_j A_{ijkl}B_{ijmn} Cklmn=ijAijklBijmn

注意这里 A i j k l B i j m n A_{ijkl}B_{ijmn} AijklBijmn可不是矩阵相乘,而是两个数字相乘,因为 A i j k l A_{ijkl} Aijkl B i j m n B_{ijmn} Bijmn都是数字

第三步,画出矩阵变换过程。四维太难画了,脑补吧。

第四步,使用for循环进行复现

i,j,k,l,m,n = A.shape[0],A.shape[1],A.shape[2],A.shape[3],B.shape[2],B.shape[3]
C_ = torch.zeros(k,l,m,n)
for i_ in range(i):
    for j_ in range(j):
        for k_ in range(k):
            for l_ in range(l):
                for m_ in range(m):
                    for n_ in range(n):
                        # 由于有求和符号,所以用+=
                        C_[k_][l_][m_][n_] += A[i_][j_][k_][l_]*B[i_][j_][m_][n_]
C == C_
tensor([[[[True, True, True,  ..., True, True, True],
		  ...........................
          [True, True, True,  ..., True, True, True]]]])

einsum特殊写法补充

  1. 若等号左边就是一个数,那么->左边什么都不用写,例如:

b = ∑ i j k A i j k b = \sum_{ijk} A_{ijk} b=ijkAijk

A = torch.Tensor(range(1*2*3)).view(1, 2, 3)
b = torch.einsum("ijk->", A) # 由于b是一个数,没有下标,所以->右边什么都不用写
b
tensor(15.)
  1. 若下标过多,或不确定,则可以省略,例如:

B ∗ = ∑ i A i ∗ B_{*} = \sum_{i} A_{i*} B=iAi

A = torch.Tensor(range(1*2*3)).view(1, 2, 3)
B = torch.einsum("i...->...", A)  # 省略号表示*
B.size()
torch.Size([2, 3])

目前为止,你应该可以看得懂einsum表达式了,若看不懂,大概率是因为公式的问题,确实有些求和公式很复杂,你可以慢慢拆解求和公式,看看具体表示的什么含义。

如何写出einsum表达式

要写出einsum表达式也很简单,只要将上面的步骤反过来就行了,①先画出你要做的矩阵运算;②尝试用for循环实现;③写出数学表达式;④写出einsum表达式,并验证

接下来,我们用矩阵相乘公式来进行演示。第一步,我们要画出矩阵相乘的操作过程,如下:

矩阵操作万能函数 einsum 详细解析(通法教你如何看懂并写出einsum表达式)

第二步,尝试使用for循环实现

A = torch.Tensor(range(2*3)).view(2, 3)
B = torch.Tensor(range(3*4)).view(3, 4)
C = torch.zeros(i, k)
i, j, k = 2, 3, 4
for i_ in range(i):
    for j_ in range(j):
        for k_ in range(k):
            C[i_][k_] += A[i_][j_]*B[j_][k_]

第三步,写出数学表达式

C i k = A i j B j k C_{ik} = A_{ij}B_{jk} Cik=AijBjk

第3.2步,补充求和符号,左边是 i k ik ik,右边是 i j k ijk ijk,少了 j j j,补 ∑ j \sum_j j

C i k = ∑ j A i j B j k C_{ik} = \sum_j A_{ij}B_{jk} Cik=jAijBjk

第四步,写出einsum表达式并验证

D = torch.einsum("ij,jk->ik", A, B) 
E = A@B
C, D, E
(tensor([[20., 23., 26., 29.],
         [56., 68., 80., 92.]]),
 tensor([[20., 23., 26., 29.],
         [56., 68., 80., 92.]]),
 tensor([[20., 23., 26., 29.],
         [56., 68., 80., 92.]]))



参考资料:

einsum is all you need: https://www.youtube.com/watch?v=pkVwUVEHmfI文章来源地址https://www.toymoban.com/news/detail-404110.html

到了这里,关于矩阵操作万能函数 einsum 详细解析(通法教你如何看懂并写出einsum表达式)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【矩阵分析】矩阵幂级数 发散 条件 || 幂级数 与 解析函数 的关系 || 幂级数 收敛半径r 的求法

    【矩阵分析】矩阵幂级数 发散 条件 || 幂级数 与 解析函数 的关系 || 幂级数 收敛半径r 的求法

      “人生不能像做菜,把所有的料都准备好了才下锅。”     🎯作者主页: 追光者♂🔥          🌸个人简介:   💖[1] 计算机专业硕士研究生💖   🌿[2] 2023年城市之星领跑者TOP1(哈尔滨)🌿   🌟[3] 2022年度博客之星人工智能领域TOP4🌟   🏅[4] 阿里云社区特邀专家博

    2024年02月12日
    浏览(5)
  • 手把手教你在Linux/Windows系统使用Nginx部署多个前端项目【详细操作】

    手把手教你在Linux/Windows系统使用Nginx部署多个前端项目【详细操作】

            需求:项目上线需要将前端的前台和后台部署在服务器上提供用户进行使用,部署在不同的服务器直接在服务器安装nginx即可。但是在内网安装还是有点麻烦,因为需要联网,如果是内网可以参考Linux安装Nginx并部署前端项目【内/外网-保姆级教程】_MXin5的博客-CSDN博

    2024年02月14日
    浏览(15)
  • 14.IIC核心函数与万能驱动

    14.IIC核心函数与万能驱动

    目录 IIC核心函数 i2c_add_adapter() i2c_add_driver()宏 i2c_transfer() i2c_master_send() i2c_master_recv() i2c_transfer_buffer_flags() 万能的i2c驱动(i2c-dev.c文件) i2c_dev_init() i2cdev_attach_adapter() i2cdev_fops结构体 i2cdev_open() i2cdev_read() i2cdev_write() IIC驱动实验:读取mpu6050数据 mpu6050 添加设备树iomuxc子节点

    2024年02月10日
    浏览(5)
  • C语言《超详细解析内存函数》

    C语言《超详细解析内存函数》

    memcpy指的是C使用的内存拷贝函数。 函数原型: (一)、参数: de:指向用于存储内容的目标数组,类型强制转换为void 指针。 sr:指向要复制的数据源,类型强制转换为void 指针 n:要被复制的字节数。 为什么要使用void* ,当传参的时候我们不知道传的是什么类型,而void就像

    2024年02月14日
    浏览(8)
  • 【运维】手把手教你在Linux/Windows系统使用Nginx部署多个前端项目【详细操作】

    【运维】手把手教你在Linux/Windows系统使用Nginx部署多个前端项目【详细操作】

            需求:项目上线需要将前端的前台和后台部署在服务器上提供用户进行使用,部署在不同的服务器直接在服务器安装nginx即可。但是在内网安装还是有点麻烦,因为需要联网,如果是内网可以参考Linux安装Nginx并部署前端项目【内/外网-保姆级教程】_MXin5的博客-CSDN博

    2024年02月08日
    浏览(12)
  • Numpy实现8x8国际象棋棋盘矩阵详细实现思路解析

    Numpy实现8x8国际象棋棋盘矩阵详细实现思路解析

    步骤一: 先找到以1开头的行,然后在找到以0开头的列。 步骤二: 再找到以0开头的行,然后在找到以1开头的列。 注意点:在当我们遇到不同的数组题目,比如利用数组创建一个金字塔数组,还有交叉数组,这里我们要多利用numpy的切片操作,这可以方便我们很多。在刚刚的

    2024年02月08日
    浏览(10)
  • 最常用头文件函数大全,最详细解析!!!

    最常用头文件函数大全,最详细解析!!!

    相信我们在写程序的时候一定会遇到很多的函数,面对不同的函数的时候就要遇到不同的头文件。有时候我们往往因为自己忘记或者不知道头文件所对应的函数而感到苦恼,那么这篇文章相信一定可以帮到你。   这个头文件最常用,一般在使用scanf和printf的时候都需要用到否

    2024年02月03日
    浏览(7)
  • 【C++】类的默认成员函数----const成员函数(超详细解析)

    【C++】类的默认成员函数----const成员函数(超详细解析)

    目录 一、前言 二、const成员函数  🍎const修饰类的成员函数  💦问题1  💦问题2 💦针对const成员函数的常考面试题(重点!!) 🍐取地址及const取地址操作符重载 三、共勉    在我们前面学习的 类 中,我们会定义 成员变量 和 成员函数 ,这些我们自己定义的函数都是普

    2024年04月14日
    浏览(9)
  • 万能自动点击器连点器,连击器的作用解析

    万能自动点击器连点器,连击器的作用解析

    而在互联网时代,在用户需要进行频繁操作、特别是重复性操作的情况下万能自动点击器连点器应运而生。本文将探讨这些工具如何帮助我们实现计算机自动化操作,万能自动点击器连点器有什么作用?   一.万能自动点击器连点器定义 万能自动点击器连点器是用于计算机简

    2024年02月08日
    浏览(11)
  • React Hook - useState函数的详细解析

    在上一篇文章中, 我用到useState来让大家体验一下hooks函数 那么接下来我们来先研究一下上面核心的一段代码代表什么意思 useState来自react,需要从react中导入,是一个hook函数, 官方中也将它成为State Hook, 它与class组件里面的 this.state 提供的功能完全相同; 一般来说,在函数退出

    2024年01月25日
    浏览(15)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包