点击下方标题,迅速定位到你感兴趣的内容

  • 前言
  • 爱因斯坦求和约定
  • einsum介绍
  • einsum应用
  • TensorFlow、PyTorch和Numpy
  • 其他乘法

前言

说明:讲解时会对相关文章资料进行思想、结构、优缺点,内容进行提炼和记录,相关引用会标明出处,引用之处如有侵权,烦请告知删除。
转载请注明:DengBoCong

这里我们来好好探讨一下深度学习中,矩阵乘法的使用,其实主要是围绕einsum来进行探讨,即通过爱因斯坦求和约定来指导矩阵乘法,同时附带陈列其他矩阵乘法的API,方便进行直观感受。本文中的计算框架及版本如下:

  • TensorFlow2.3
  • PyTorch1.7.0
  • Numpy1.19

爱因斯坦求和约定

我们讨论einsum绕不开爱因斯坦求和约定的,爱因斯坦求和约定(Einstein summation convention)是一种标记的约定,又称为爱因斯坦标记法(Einstein notation),在处理关于坐标的方程式时非常有用,用一句话来总结爱因斯坦求和约定,就是:

当式子中任何一个角标出现了两次,并且一次是上标、一次是下标时,那么该式表示的实际上是对这个角标一切可能值的求和。换言之,如果角标 iii 作为上标和下标各出现了一次,那么式子相当于添加了一个关于 iii 的求和符号

我们下面使用线性函数和矩阵运算来对爱因斯坦求和约定进行举例说明:

  • 线性函数:从张量中我们知道,一个1-线性函数可以表示为一个向量,这样的向量常被称为余向量、补向量或者1-形式。通常,我们用下标来表示一个余向量的各分量:a=(a1,a2,a3)a=(a_1,a_2,a_3)a=(a1​,a2​,a3​) ,而用上标来表示一个通常的几何向量:v=(v1,v2,v3)v=(v^1,v^2,v^3)v=(v1,v2,v3)。注意,上标不是乘方,则 aaa 和 vvv 的内积是:
    ∑i=1,2,3aivi\sum_{i=1,2,3}^{}a_iv^ii=1,2,3∑​ai​vi
    用爱因斯坦求和约定, aaa 和 vvv 的内积就可以写为 aivia_iv^iai​vi
  • 矩阵运算:对于矩阵 AAA,我们把其第 iii 行第 jjj 列的元素表示为 AjiA_j^iAji​。则矩阵乘法表示为:如果 A=BCA=BCA=BC,那么 Aji=BkiCjkA_j^i=B_k^iC_j^kAji​=Bki​Cjk​。矩阵 AAA 的迹为 AiiA_i^iAii​

由于重复出现而实际上应该是求和的指标,被称为赝指标或者哑指标(dummy index),因为它们不是真正的指标,而是可以用任意字母代替的。没有求和的指标是固定的,是真正的指标.比如说 BkiCjkB_k^iC_j^kBki​Cjk​ 中 kkk 可以是任何字母,但是 iii 和 jjj 是不可以替换成别的字母的,因为它们由 AjiA_j^iAji​ 决定了。在这里,哑指标实际上是表示遍历全部可能的真指标。

爱因斯坦求和约定的表示方法脱胎于矩阵乘法的要求,但是却不依赖于矩阵行和列的形式,转而关注指标间的配合,相比传统的矩阵表达,能更方便地推广到高阶张量的情形中。本文关于爱因斯坦求和约定的相关点到为止,如果感兴趣其公式,可以参考这一篇文章:爱因斯坦求和约定。

einsum介绍

通过使用einsum函数,我们可以使用爱因斯坦求和约定(Einstein summation convention)在NumPy数组上指定操作。einsum函数由于其强大的表现力和智能循环,它在速度和内存效率方面通常可以超越我们常见的array函数。但缺点是,可能需要一段时间才能理解符号,有时需要尝试才能将其正确的应用于棘手的问题,当然熟悉之后得心应手才是使用关键。

einsum以一种优雅的方式,表示各种矩阵运算,好处在于你不需要去记和使用计算框架中(TensorFlow|PyTorch|Numpy)点积、外积、转置、矩阵-向量乘法、矩阵-矩阵乘法的函数名字和签名。从某种程度上解决引入不必要的张量变形或转置运算,以及可以省略的中间张量的现象。不仅如此,einsum有时可以编译到高性能代码,事实上,PyTorch最近引入的能够自动生成GPU代码并为特定输入尺寸自动调整代码的张量理解(Tensor Comprehensions)就基于类似einsum的领域特定语言。此外,可以使用opt einsum和tf einsum opt这样的项目优化einsum表达式的构造顺序。

假设我们有两个多维数组A和B,现在让我们要进行如下操作:

  • 以特定方式将A与B相乘以创建新的乘积数组
  • 沿特定轴求和该新数组
  • 以特定顺序转置新数组的轴

einsum帮助我们更快,更高效地执行此操作,当然,NumPy函数的组合(例如multiply,sum和transpose)也可以实现。

einsum应用

我们在这一节用Numpy的einsum进行讲解说明(Numpy中einsum先被开发出来,TensorFlow和PyTorch都在一定程度上参考了它),在下一节,我会将TensorFlow、PyTorch和Numpy的API都贴出来。

在Numpy中,einsum使用格式字符串和任意数量的Numpy张量作为参数调用,并返回结果张量。


格式字符串包含分隔参数说明的逗号(,)和将参数说明与张量的参数分开的箭头(->)。参数说明中的数量和参数的数量必须匹配,并且必须精确地出现一个箭头,后跟一个结果说明


格式字符串中的字符数完全等于该张量的维数。


下面展示einsum()格式字符串的完整示例。 尝试猜测结果将是什么?注意了,0维张量(标量)对于参数和结果均有效,由空字符串“”表示。 再次提醒您,格式字符串必须仅由ASCII小写或大写字母组成。


我们这里使用一个实际的例子来进行说明,首先我们要相乘的两个​​数组是:

A = array([[1, 1, 1],[2, 2, 2],[5, 5, 5]])
B = array([[0, 1, 0],[1, 1, 0],[1, 1, 1]])

我们的矩阵乘法np.einsum(‘ij,jk->ik’, A, B)大致如下:

要了解输出数组的计算方法,请记住以下三个规则:

  • 在输入数组中重复的字母意味着值沿这些轴相乘。乘积结果为输出数组的值。在本例中,我们使用字母 j 两次:A和B各一次。这意味着我们将A每一行与B每列相乘。这只在标记为 j 的轴在两个数组中的长度相同(或者任一数组长度为1)时才有效。

  • 输出中省略的字母意味着沿该轴的值将相加。在这里,j 不包含在输出数组的标签中。通过累加的方式将它从轴上除去,最终数组中的维数减少1。如果输出是’ijk’,我们得到的结果是3x3x3数组(如果我们不提供输出标签,只写箭头,则对整个数组求和)。

  • 我们可以按照我们喜欢的任何顺序返回未没进行累加的轴。如果我们省略箭头’->’,NumPy会将只出现一次的标签按照字母顺序排列(因此实际上’ij,jk->ik’相当于’ij,jk’)。如果我们想控制输出的样子,我们可以自己选择输出标签的顺序。例如,’ij,jk->ki’为矩阵乘法的转置。

现在,我们已经知道矩阵乘法是如何工作的。下图显示了如果我们不对 j 轴进行求和,而是通过写np.einsum(‘ij,jk->ijk’, A, B)将其包含在输出中,我们会得到什么。右边代表 j 轴已经求和:

注意,由于np.einsum(‘ij,jk->ik’, A, B)函数不构造3维数组然后求和,它只是将总和累加到2维数组中。下面是两个表格展示了einsum如何进行各种NumPy操作。我们可以用它来熟悉符号。

  • 让A和B是两个形状兼容的一维数组(也就是说,我们相应的轴的长度要么相等,要么其中一个长度为1):
调用 Numpy等式 描述
(‘i’, A) A 返回数组A的视图
(‘i->’, A) sum(A) 数组A值的总和
(‘i,i->i’, A, B) A * B A和B的数组元素依次相乘
(‘i,i’, A, B) inner(A, B) A和B的点积(内积)
(‘i,j->ij’, A, B) outer(A, B) A和B的外积(叉积)
  • 现在,我们A和B是与之兼容形状的两个二维数组:
调用 Numpy等式 描述
(‘ij’, A) A 返回A的视图
(‘ji’, A) A.T A的转置
(‘ii->i’, A) diag(A) A的主对角线
(‘ii’, A) trace(A) A的主对角线的和
(‘ij->’, A) sum(A) A的值相加
(‘ij->j’, A) sum(A, axis=0) 通过A的轴竖直(列)求和
(‘ij->i’, A) sum(A, axis=1) 通过A的轴水平(行)求和
(‘ij,ij->ij’, A, B) A * B A和B逐元素依次相乘
(‘ij,ji->ij’, A, B) A * B.T A和B的转置逐个元素依次相乘
(‘ij,jk’, A, B) dot(A, B) A和B的矩阵乘法
(‘ij,kj->ik’, A, B) inner(A, B) A和B点积(内积)
(‘ij,kj->ijk’, A, B) A[:, None] * B A的每一行乘以B
(‘ij,kl->ijkl’, A, B) A[:, :, None, None] * B A的每个值乘以B

当处理大量维度时,别忘了einsum允许使用省略号语法’…’。这提供了一种变量的方式标记我们不大感兴趣的轴,例如np.einsum(‘…ij,ji->…’, a, b),仅将a的最后两个轴与2维数组b相乘。

TensorFlow、PyTorch和Numpy

通常,要将元素式方程式转换为方程式字符串,可以使用以下过程(右侧是矩阵乘法示例的中间字符串)

  1. 原始元素式方程式:C[i,k] = sum_j A[i,j] * B[j,k]
  2. 删除变量名称,方括号和逗号:ik = sum_j ij * jk
  3. 将“*”替换成“,”:ik = ij, jk
  4. 去掉求和符号:ik = ij, jk
  5. 输出移到右边,将将“=”替换成“->”:ij,jk->ik
  • TensorFlow2.3:tf.einsum()
tf.einsum(equation, *inputs, **kwargs)
参数:equation:描述计算的字符串,格式与numpy.einsum相同。*inputs:输入(张量),其形状应与方程保持一致。**kwargs:optimize:用于使用opt_einsum查找计算路径的优化策略,可选项包括 'greedy', 'optimal', 'branch-2', 'branch-all' ,'auto',默认是'greedy'name:操作名称(可选)
返回值:张量,形状与方程中一致
示例:# 矩阵相乘einsum('ij,jk->ik', m0, m1)  # output[i,k] = sum_j m0[i,j] * m1[j, k]# 点积einsum('i,i->', u, v)  # output = sum_i u[i]*v[i]# 外积einsum('i,j->ij', u, v)  # output[i,j] = u[i]*v[j]# 转置einsum('ij->ji', m)  # output[j,i] = m[i,j]# 主对角线的和einsum('ii', m)  # output[j,i] = trace(m) = sum_i m[i, i]# 批量矩阵相乘einsum('aij,ajk->aik', s, t)  # out[a,i,k] = sum_j s[a,i,j] * t[a, j, k]
  • PyTorch1.7.0:torch.einsum()
torch.einsum(equation, *operands)
参数:equation:描述计算的字符串,格式与numpy.einsum相同。operands:输入(张量),其形状应与方程保持一致。
示例:
torch.einsum('i,j->ij', x, y)  # 外积
torch.einsum('bn,anm,bm->ba', l, A, r) # 计算torch.nn.functional.bilinear
torch.einsum('bij,bjk->bik', As, Bs) # 批量矩阵相乘
torch.einsum('ii->i', A) # 对角线之和
torch.einsum('...ii->...i', A) # 批量对角线之和
torch.einsum('...ij->...ji', A).shape # 批量转置
  • Numpy1.19:numpy.einsum
numpy.einsum(subscripts, *operands, out=None, dtype=None, order='K', casting='safe', optimize=False)
参数:subscripts:描述计算的字符串,除非包含显式指示符“->”以及精确输出形式的下标标签,否则将执行隐式(经典的爱因斯坦求和)计算operands:输入(张量),其形状应与方程保持一致。out:ndarray类型(可选),如果提供,则将计算结果放入此数组中dtype:{data-type, None}(可选),如果提供,则强制使用指定的数据类型计算。 请注意,你可能还必须提供一个更宽松的转换参数以允许进行转换。 默认为None。order:{‘C’, ‘F’, ‘A’, ‘K’}(可选),控制输出的内存布局。其中,‘C’表示C连续的。‘F’表示它应该是Fortran连续的。如果输入全为‘F’,则‘A’表示应为‘F’,否则为‘C’。‘K’表示它应尽可能与输入尽可能靠近布局,包括任意排列的轴。casting:{‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}(可选),控制可能发生的数据类型转换。 不建议将其设置为“unsafe”,因为这会积聚不利影响。其中,“no”表示完全不应该转换数据类型,“equiv”表示仅允许按照字节顺序转换,“safe”表示只允许保留值的强制类型转换。“same_kind”表示仅允许安全类型转换或同一类型(例如float64到float32)内的类型转换。“unsafe”表示可能会进行任何数据转换。optimize:{False, True, ‘greedy’, ‘optimal’}(可选),控制优化策略,如果True将默认设置为“贪心”算法,如果是False则不会进行优化。 还接受np.einsum_path函数的显式收缩列表。

其他乘法

TensorFlow2.3

  • tf.linalg.matmul
tf.linalg.matmul(a, b, transpose_a=False, transpose_b=False, adjoint_a=False, adjoint_b=False,a_is_sparse=False, b_is_sparse=False, name=None)
参数:a:类型为float16, float32, float64, int32, complex64, complex128,并且秩大于1b:和a相同类型和秩transpose_a:如果为True,a在计算前会被转置transpose_b:如果为True,b在计算前会被转置adjoint_a:如果为True,a在计算前会被共轭和转置adjoint_b:如果为True,b在计算前会被共轭和转置a_is_sparse:如果为True,则将a视为稀疏矩阵。b_is_sparse:如果为True,则将b视为稀疏矩阵。name:操作名称(可选)
  • tf.sparse.sparse_dense_matmul
tf.sparse.sparse_dense_matmul(sp_a, b, adjoint_a=False, adjoint_b=False, name=None)
参数:a:SparseTensor或者是密度矩阵,并且秩为2b:和a相同类型,密度矩阵或者是a:SparseTensoradjoint_a:如果为True,a在计算前会被共轭和转置adjoint_b:如果为True,b在计算前会被共轭和转置name:操作名称(可选)
  • tf.math.multiply
tf.math.multiply(x, y, name=None)
参数:a:类型为bfloat16, half, float32, float64, uint8, int8, uint16, int16, int32, int64, complex64, complex128的张量b:和a相同类型name:操作名称(可选)

Pytorch1.7.0

  • torch.matmul
torch.matmul(input, other, *, out=None)
参数:input:第一个用于乘法的张量other:第二个用于乘法的张量out:可选,输出张量

Numpy1.19

  • numpy.matmul()
numpy.matmul(x1, x2, /, out=None, *, casting='same_kind', order='K', dtype=None, subok=True[, signature, extobj])
参数:x1, x2:输入数组out:输出储存的位置,如果提供,则其形状必须与签名(n,k),(k,m)->(n,m)相匹配。 如果未提供或没有,则返回一个新分配的数组。**kwargs:对于其他仅关键字参数,参考文档

参考文献

  • TensorFlow2.3
  • Pytorch1.7.0
  • Numpy1.19
  • einsum满足你一切需要:深度学习中的爱因斯坦求和约定
  • NumPy中einsum的基本介绍
  • Einstein Summation in Numpy

深度学习矩阵乘法的终极奥义einsum,结合多个计算框架上的使用相关推荐

  1. 一文让你完全弄懂逻辑回归和分类问题实战《繁凡的深度学习笔记》第 3 章 分类问题与信息论基础(上)(DL笔记整理系列)

    好吧,只好拆分为上下两篇发布了>_< 终于肝出来了,今天就是除夕夜了,祝大家新快乐!^q^ <繁凡的深度学习笔记>第 3 章 分类问题与信息论基础 (上)(逻辑回归.Softm ...

  2. NTT高级科学家:光子是深度学习的未来!光子有望替代电子计算机加速神经网络计算...

    来源:AI科技评论 作者:Ryan Hamerly 编译:陈彩娴 近日,来自日本 NTT 研究所的高级科学家 Ryan Hamerly 在 IEEE Spectrum 上发表了一篇文章("T ...

  3. 入门大爆炸式发展的深度学习,你先要了解这4个最流行框架

    来源:大数据DT 作者:卢誉声 本文约2800字,建议阅读9分钟. 可以预见,深度学习在近年内都会是最流行.最有效的机器学习方法之一. [ 导读 ]对深度学习做出巨大贡献的Yoshua Bengio, ...

  4. 使用深度学习检测DGA(域名生成算法)——LSTM的输入数据本质上还是词袋模型...

    from:http://www.freebuf.com/articles/network/139697.html DGA(域名生成算法)是一种利用随机字符来生成C&C域名,从而逃避域名黑名单检 ...

  5. 2.3)深度学习笔记:超参数调试、Batch正则化和程序框架

    目录 1)Tuning Process 2)Using an appropriate scale to pick hyperparameters 3)Hyperparameters tuning in ...

  6. 基于深度学习的新闻摘要生成算法实现与详解(Encoder-Decoder框架模型)

    目录 摘要: 文本摘要生成概述: Encoder-Decoder模式思想: 数据集描述: 模型构建与代码描述(LSTM+Attention) 总结: 参考文献: 摘要: 摘要是文本的主要内容和核心思想 ...

  7. python数据库开发 dga_使用深度学习检测DGA(域名生成算法)——LSTM的输入数据本质上还是词袋模型...

    from:http://www.freebuf.com/articles/network/139697.html DGA(域名生成算法)是一种利用随机字符来生成C&C域名,从而逃避域名黑名单检 ...

  8. Python实现深度学习MNIST手写数字识别(单文件,非框架,无需GPU,适合初学者)

    注: 本文根据阿卡蒂奥的Python深度学习博客文章代码进行调整,修复了少量问题,原文地址:https://blog.csdn.net/akadiao/article/details/78175737 ...

  9. 详解深度学习之经典网络架构(十):九大框架汇总

    目录 0.概览 1.个人心得 2.总结 本文是对本人前面讲的的一些经典框架的汇总. 纯手打,如果有不足之处,可以在评论区里留言. 0.概览 (1)详解深度学习之经典网络架构(一):LeNet (2)详 ...

最新文章

  1. expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.spring
  2. 优秀的缓存工具Memcached
  3. [share]PHP购物车类的源码
  4. CentOS 7 安装Boost 1.61
  5. ElementUI中el-upload中怎样限制上传文件的格式
  6. win10安装windows live writer 错误:OnCatalogResult:0x80190194
  7. (十二)nodejs循序渐进-高性能游戏服务器框架pomelo之创建一个游戏聊天服务器
  8. JavaScript中带示例的String repeat()方法
  9. 【转载】生怕我等着急了的扬州程序员
  10. Python知识总结(二)
  11. mysql 分区 mycat 分片_Mysql系列六:(Mycat分片路由原理、Mycat常用分片规则及对应源码介绍)...
  12. 软考资料合集/软考真题合集(软件设计师/网络工程师/系统分析师/系统架构师/软件测评师/程序员等)
  13. POS机31个基础知识你了解多少?
  14. 第二章 马原刷题(1)
  15. php-ftm,FTM/MTF的激素种类
  16. 电脑网络中看到不工作组计算机,win7系统看不到工作组计算机怎么办?win7系统看不到工作组计算机解决方法...
  17. 计算机键盘重复,win7系统电脑键盘打字时总是出现重复字符的解决方法
  18. 作为前端,如何帮帝都的朋友租到合适的房子
  19. HTML5小游戏笑说米,活跃气氛的70个小游戏 带动气氛的小游戏
  20. 计算机课程设计收费管理系统,C语言机房收费管理系统课程设计

热门文章

  1. 甘特图(别名:横道图、条状图)的画法
  2. Linux系统中如何查找大文件或目录文件夹的方法
  3. 华为 中兴 海康嵌入式软件工程师面试题
  4. JavaWeb(华清远见)
  5. 基于OpenCV的人脸识别自助商店(源码&部署视频)
  6. 用Python吐槽国产综艺节目!
  7. LaTex排版 正文间距(段行列间距)调整与表格调整(宽度, 合并, 表注)
  8. android app签名详解
  9. 使用swiper组件的transform属性导致文字模糊的解决办法
  10. java仙侠回合制单机游戏_2019回合仙侠手游排行榜 好玩的回合制单机仙侠手游推荐...