精华内容
下载资源
问答
  • 爱因斯坦 Sommation 就像 Numpy 的 einsum 输入 : - str : 像'ik,kj-> ij'这样的字符串- varargin : 双重调用输出 : -出:双用法 : 矩阵乘法 C = A*B A(ik)*B(kj) = C(ij) -> C=einsum('ik,kj->ij',A,B) 限制: -...
  • opt_einsum_fx 正在开发中 使用opt_einsum和PyTorch FX图形重写进行Einsum优化。 该库当前支持: 将多个枚举融合为一个 使用库优化einsum 用标量常量融合乘法和除法,包括通过与einsum之类的运算进行融合,这些...
  • pytorch einsum, numpy einsum

    2021-04-19 14:05:33
    什么是einsum? 爱因斯坦求和约定: https://zhuanlan.zhihu.com/p/101157166 https://en.wikipedia.org/wiki/Einstein_notation 为什么用? 简洁, 强大 具体例子 pytorch和numpy一样的,这里以pytorch为例. 矩阵乘...

    什么是einsum?

    爱因斯坦求和约定:

    https://zhuanlan.zhihu.com/p/101157166
    https://en.wikipedia.org/wiki/Einstein_notation
    

    为什么用?

    简洁, 强大

    具体例子

    pytorch和numpy一样的,这里以pytorch为例.

    矩阵乘矩阵, C = A x B

    eg1. (ij, jk -> ik), 实际上就是

    [C]ik=j[A]ij×[B]jk [C]_{ik} = \sum_{j} [A]_{ij} \times [B]_{jk}

    >>> A = torch.Tensor([[1,1],[2,2]])
    >>> B = torch.Tensor([[1,-1],[-1,1]])
    >>> torch.einsum("ij, jk -> ik", A, B)
    tensor([[0., 0.],
            [0., 0.]])
    

    eg2. (mij, jk -> mik), 相当于在eg1中的m个A分别乘以B,得到m个相应的C

    >>> mA = torch.stack([a, a+1, a+2], dim=0)
    >>> mA
    tensor([[[1., 1.],
             [2., 2.]],
    
            [[2., 2.],
             [3., 3.]],
    
            [[3., 3.],
             [4., 4.]]])
    >>> mA.shape
    torch.Size([3, 2, 2])
    >>> B = torch.Tensor([[1,1],[1,1]])
    >>> torch.einsum("mij, jk -> mik", mA, B)
    tensor([[[2., 2.],
             [4., 4.]],
    
            [[4., 4.],
             [6., 6.]],
    
            [[6., 6.],
             [8., 8.]]])
    

    矩阵乘向量

    eg3. (mij, j -> mi).

    >>> b = torch.Tensor([1,-1])
    >>> torch.einsum("mij, j -> mi", mA, b)
    tensor([[0., 0.],
            [0., 0.],
            [0., 0.]])
    

    eg4. (bnf, n -> bf).

    相当于对n个f维向量加权求和.

    >>> 
    a = torch.arange(12).reshape(3,2,2).float()
    print(a)
    weighted = 2 * torch.ones(2)
    print(weighted)
    b = torch.einsum('bnf, n -> bf', a, weighted)
    print(b)
    print(b.shape)
    >>>
    output:
    tensor([[[ 0.,  1.],
             [ 2.,  3.]],
    
            [[ 4.,  5.],
             [ 6.,  7.]],
    
            [[ 8.,  9.],
             [10., 11.]]])
    tensor([2., 2.])
    tensor([[ 4.,  8.],
            [20., 24.],
            [36., 40.]])
    torch.Size([3, 2])
    

    高维Tensor乘法

    eg5. (bnft, knm -> bkmft).

    看起来有点复杂,其实很简单:
    bnft相当于b个mA, knm 相当于k个B,那么bkmft,相当于b个mA分别乘以k个B。

    但是你会发现,mA是三维的(nft),B是二维的(nm),这其实等同于eg2。

    观察最后的结果(bkmft)里,bk就是b个mA乘以k个B,所以一共有b*k个tensor运算结果,存到了b维和k维。

    剩下的mft = nft *nm,实际上要让这个等式成立,必须要变成mft = mn * nft, 即nm转置为mn,然后 分别乘以t个nf,即,t个矩阵乘法:mn×nf=mfmn \times nf = mf

    >>> mA.shape
    torch.Size([3, 2, 2])
    >>> bmA = torch.stack([mA,-mA], dim=0)
    >>> bmA.shape
    torch.Size([2, 3, 2, 2])
    >>> B = torch.Tensor([[1,1],[1,-1]])
    >>> kB = torch.stack([B,B,B],dim=1)
    >>> kB.shape
    torch.Size([2, 3, 2])
    >>> torch.einsum("bnft, lnm -> blmft", bmA, lB).shape
    torch.Size([2, 2, 2, 2, 2])
    >>> torch.mm(kB[1].transpose(0,1), bmA[0,:,:,0])
    tensor([[ 6.,  9.],
            [-6., -9.]])
    >>> torch.einsum("bnft, knm -> bkmft", bmA, kB)[0,1,:,:,0]
    tensor([[ 6.,  9.],
            [-6., -9.]])
    

    从最后两个code可以看到,用kB中的第二个(index=1)B,进行转置后,乘以第一个mA中的第一个nf,即(t这个维度取第一个,index=0)的结果,等同于einsum结果中对应位置的矩阵(即b=0,k=1,t=0)。

    eg6. (bkmft, k -> bmft). 高维Tensor乘以向量。

    相当于对左边的 bkb*kmftmft 进行了一个加权求和(权重会乘以每一个元素),权重就是右边的k维向量。

    >>> C = torch.einsum("bnft, knm -> bkmft", bmA, kB)
    >>> b = torch.Tensor([1, 2]) # 权重第一个mft就是1,第二个mft就是2.
    >>> torch.einsum("bkmft, k -> bmft", C, b)
    tensor([[[[ 18.,  18.],
              [ 27.,  27.]],
    
             [[ -6.,  -6.],
              [ -9.,  -9.]]],
    
    
            [[[-18., -18.],
              [-27., -27.]],
    
             [[  6.,   6.],
              [  9.,   9.]]]])
    
    展开全文
  • einsum初探

    2020-07-03 11:50:30
    Einsum 是干嘛的? 使用爱因斯坦求和约定,可以以简单的方式表示许多常见的多维线性代数数组运算。举个栗子:给定两个矩阵A和B,我们想对它们做一些操作,比如 multiply、sum或者transpose。虽然numpy里面有可以...

    Einsum 是干嘛的?

    使用爱因斯坦求和约定,可以以简单的方式表示许多常见的多维线性代数数组运算。举个栗子:给定两个矩阵A和B,我们想对它们做一些操作,比如 multiply、sum或者transpose。虽然numpy里面有可以直接使用的接口,能够实现这些功能,但是使用enisum可以做的更快、更节省空间。比如:

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

    我们想计算A和B的element-wise乘积,然后按行求和。如果不使用einsum接口,需要先对A做reshape到和B一样的形状,创建一个临时的数组A[:, np.newaxis],然后在做乘积并按行求和:

    (A[:, np.newaxis] * B).sum(axis=1)
    array([ 0, 22, 76])

    使用einsum接口,不需要创建reshape后的临时数组,只是简单地对行中的乘积求和,这样会加速三倍:

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

    如何使用 einsum

    使用einsum的关键是,正确地labelling(标记)输入数组和输出数组的axes(轴)。我们可以使用字符串(比如:ijk,这种表示方式更常用)或者一个整数列表(比如:[0,1])来标记axes。 再来举个栗子:为了实现矩阵乘,我们可以这么写

    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, 1, 1],
                  [2, 2, 2],
                  [5, 5, 5]])
    B = np.array([[0, 1, 0],
                  [1, 1, 0],
                  [1, 1, 1]])
    np.einsum('ij,jk->ik', A, B)可以看作是:

    • 在输入数组的标记之间,重复字母表示沿这些轴的值将相乘,这些乘积构成输出数组的值。比如图中沿着j轴做乘积。
    • 从输出标记中省略的字母表示沿该轴的值将被求和。比如图中的输出没有包含j轴,因此沿着j轴求和得到了输出数组中的每一项。
      • 如果输出的标记是'ijk',那么会得到一个 3x3x3 的矩阵。
        • 输出标记是'ik'的时候,并不会创建中间的 3x3x3 的矩阵,而是直接将总和累加到2D数组中。

      • 如果输出的标记是空,那么输出整个矩阵的和。
    • 我们可以按任意顺序返回不求和的轴。

    我们将不指定'->'和输出标记称为 explicit mode。 如果不指定'->'和输出标记,numpy会将输入标记中只出现一次的标记按照字母表顺序,作为输出标记(也就是 implicit mode,后面会详细介绍)。

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

    在explicit mode中,我们可以指定输出标记的顺序,比如:'ij,jk->ki'表示对矩阵乘做转置。

    Einsum 中的常用

    对应的 einsum调用方式:

    • 向量操作:A、B均为向量

    • 向量操作:A、B均为2D矩阵

    注意

    • einsum求和时不提升数据类型,如果使用的数据类型范围有限,可能会得到意外的错误:
    a = np.ones(300, dtype=np.int8)
    print(np.sum(a)) # correct result
    print(np.einsum('i->', a)) # produces incorrect result
    300
    44
    • einsum 在implicit mode可能不会按预期的顺序排列轴
    M = np.arange(24).reshape(2,3,4)
    print(np.einsum('kij', M).shape) # 不是预期
    print(np.einsum('ijk->kij', M).shape) #符合预期
    (3, 4, 2)
    (4, 2, 3)
    np.einsum('kij', M) 实际上等价于 np.einsum('kij->ijk', M),因为 implicit mode 下,einsum会认为根据输入标记,按照字母表顺序排序,作为输出标记。
    • 最后,einsum 也不总是numpy中的最快的选择。
    dot和inner函数之类的功能通常会链接到BLAS库方法,性能可能胜过einsum。 还有tensordot函数。 在多个输入数组上进行操作时,einsum似乎很慢。

    看到这里就基本满足常用的要求啦,如果想深入了解大把细节,可以越过华丽丽的分割线,勇往直前!

    ------------------------------ 华丽丽的分割线 ------------------------------

    numpy 中的 einsum

    import numpy as np
    # 给定两个向量,下面要用到
    a = np.array([1, 2, 3])
    b = np.array([4, 5, 6])
    # 给定两个矩阵,下面要用到
    A = np.array([[1, 2], [3, 4]])
    B = np.array([[5, 6], [7, 8]])

    接口定义:

    numpy.einsum(subscripts, *operands, out=None, dtype=None, order='K', casting='safe', optimize=False)

    参数:

    xxx表示可选参数中的默认值)

    • subscripts : str,指定求和的操作,可以是多个,用逗号分开。除非包含显式指示符“->”以及精确输出形式的下标标签,否则将执行隐式(经典的爱因斯坦求和)计算。
    • operands : list of array_like,输入。
    • out : ndarray, optional,指定输出。
    • dtype : {data-type, None}, optional,可以指定运算的数据类型,可能需要用户提供类型转换接口。默认为None。
    • order : {‘C’, ‘F’, ‘A’, ‘K’}, optional,控制输出的内存布局。'C'=contiguous;'F'=Fortran contiguous;'A'表示输入为'F'时输出为'F',否则输出为'C';'K'表示输出的layout应该尽可能和输入一致。
    • casting : {‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, optional,指定可能发生的数据类型转换,不推荐使用'unsafe'。
      • ‘no’ 表示不做数据类型转换。
      • ‘equiv’ 表示仅允许字节顺序更改。
      • ‘safe’ 表示只允许保留值的强制类型转换。
      • ‘same_kind’ 表示仅允许安全类型转换或同一类型(例如float64到float32)内的类型转换。
      • ‘unsafe’ 表示可以进行任何数据转换。
    • optimize : {False, True, ‘greedy’, ‘optimal’}, optional,控制是否进行中间优化。默认False,不做优化;设为True则使用greedy算法。还接受np.einsum_path函数的提供的列表。

    Returns:

    • output : ndarray

    在implicit模式下,选择的下标很重要,因为输出按字母顺序重新排序。例如,在二维矩阵中:

    np.einsum('ij,jh', A, B) # 返回的是矩阵乘的转置,因为'h'本来应该是在'i'的后面,但是这里反序了
    array([[19, 43],
           [22, 50]])

    相比,在explicit模式下

    np.einsum('ij,jh->ih', A, B) # 指定了输出下标标签的顺序,因此效果等价于矩阵乘法 np.matmul(A,B)
                                # 相比之下,implicit 模式的 np.einsum('ij,jh', A, B) 效果等价于矩阵乘的转置
    array([[19, 43],
           [22, 50]])

    einsum 默认不会 broadcast,需要指定省略号(...)来启用。默认的NumPy样式广播是通过在每项的左侧添加省略号。

    另一种使用 enisum 的方式是:einsum(op0, sublist0, op1, sublist1, ..., [sublistout])。如果没有指定输出格式,将以 implicit 模式计算,否则将在 explicit 模式执行。

    np.einsum(A, [0,0])
    5

    optimize参数优化 einsum 表达式的收缩顺序,对于具有三个或更多操作数的收缩,这可以大大增加计算效率,但需要在计算过程中增加内存占用量。

    来一些对比:

    1. 求矩阵的迹:
    print(np.einsum('ii', A)) # implicit mode
    print(np.einsum(A, [0,0]))# einsum(op0, sublist0, op1, sublist1, ..., [sublistout])方式 implicit mode
    print(np.trace(A))
    5
    5
    5
    1. 矩阵的对角元素
    print(np.einsum('ii->i', A)) # explicit mode
    print(np.einsum(A, [0,0], [0]))# einsum(op0, sublist0, op1, sublist1, ..., [sublistout])方式 explicit mode
    print(np.diag(A))
    [1 4]
    [1 4]
    [1 4]
    1. 对指定维度求和
    print(np.einsum('ij->i', A)) # explicit mode
    print(np.einsum(A, [0,1], [0]))# einsum(op0, sublist0, op1, sublist1, ..., [sublistout])方式 explicit mode
    print(np.sum(A, axis=1))
    [3 7]
    [3 7]
    [3 7]

    对于高维的数组,可以使用省略号来对指定轴求和

    print(np.einsum('...j->...', A)) # explicit mode
    print(np.einsum(A, [Ellipsis,1], [Ellipsis])) # einsum(op0, sublist0, op1, sublist1, ..., [sublistout])方式 explicit mode
    [3 7]
    [3 7]
    1. 计算矩阵转置,或根据指定的 axes 调整矩阵
    print(np.einsum('ji', A)) # implicit mode
    print(np.einsum('ij->ji', A))# explicit mode
    print(np.einsum(A, [1,0])) # einsum(op0, sublist0, op1, sublist1, ..., [sublistout])方式 implicit mode
    print(np.einsum(A, [1,0], [0,1])) # einsum(op0, sublist0, op1, sublist1, ..., [sublistout])方式 explicit mode
    print(np.transpose(A, axes=[1,0]))
    [[1 3]
     [2 4]]
    [[1 3]
     [2 4]]
    [[1 3]
     [2 4]]
    [[1 3]
     [2 4]]
    [[1 3]
     [2 4]]
    1. 向量内积
    print(np.einsum('i,i', a, a)) # implicit mode
    print(np.einsum(a, [0], b, [0]))# einsum(op0, sublist0, op1, sublist1, ..., [sublistout])方式 implicit mode
    print(np.inner(a, a))
    14
    32
    14
    1. 矩阵向量乘积
    k = np.array([1,2])
    print(np.einsum('ij,j', A, k)) # implicit mode
    print(np.einsum(A, [0,1], k, [1]))# einsum(op0, sublist0, op1, sublist1, ..., [sublistout])方式 implicit mode
    print(np.einsum('ij,j->i', A, k)) # explicit mode
    print(np.einsum('...j,j->...', A, k)) # explicit mode with broadcast
    print(np.dot(A, k))
    [ 5 11]
    [ 5 11]
    [ 5 11]
    [ 5 11]
    [ 5 11]
    1. Broadcasting
    print(np.einsum('...,...', 3, A)) # implicit mode
    print(np.einsum(',ij', 3, A))# explicit mode
    print(np.einsum(3, [Ellipsis], A, [Ellipsis]))
    print(np.multiply(3, A))
    [[ 3  6]
     [ 9 12]]
    [[ 3  6]
     [ 9 12]]
    [[ 3  6]
     [ 9 12]]
    [[ 3  6]
     [ 9 12]]
    1. Tensor Contraction
    m = np.arange(60.).reshape(3,4,5)
    n = np.arange(24.).reshape(4,3,2)
    print(np.einsum('ijk,jil->kl', m, n)) # explicit mode
    print(np.einsum(a, [0,1,2], b, [1,0,3], [2,3])) # einsum(op0, sublist0, op1, sublist1, ..., [sublistout])方式 explicit mode
    print(np.tensordot(a,b, axes=([1,0],[0,1]))) #
    [[4400. 4730.]
     [4532. 4874.]
     [4664. 5018.]
     [4796. 5162.]
     [4928. 5306.]]
    [[4400. 4730.]
     [4532. 4874.]
     [4664. 5018.]
     [4796. 5162.]
     [4928. 5306.]]
    [[4400. 4730.]
     [4532. 4874.]
     [4664. 5018.]
     [4796. 5162.]
     [4928. 5306.]]
    1. 链式数组操作: For more complicated contractions, speed ups might be achieved by repeatedly computing a ‘greedy’ path or pre-computing the ‘optimal’ path and repeatedly applying it, using an einsum_path insertion. Performance improvements can be particularly significant with larger arrays. 待补充
       

    TODO: Tensorflow 中的 einsum; Pytorch 中的 einsum

    参考:

    展开全文
  • numpy einsum

    2018-03-15 16:24:25
    What does einsum do?Imagine that we have two multi-dimensional arrays, A and B. Now let's suppose we want to...multiply A with B in a particular way to create new array of products; and then ...

    What does einsum do?

    Imagine that we have two multi-dimensional arrays, A and B. Now let's suppose we want to...

    • multiply A with B in a particular way to create new array of products; and then maybe
    • sum this new array along particular axes; and then maybe
    • transpose the axes of the new array in a particular order.

    There's a good chance that einsum will help us do this faster and more memory-efficiently that combinations of the NumPy functions like multiplysum and transpose will allow.

    How does einsum work?

    Here's a simple (but not completely trivial) example. Take the following two arrays:

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

    We will multiply A and B element-wise and then sum along the rows of the new array. In "normal" NumPy we'd write:

    >>> (A[:, np.newaxis] * B).sum(axis=1)
    array([ 0, 22, 76])

    So here, the indexing operation on A lines up the first axes of the two arrays so that the multiplication can be broadcast. The rows of the array of products is then summed to return the answer.

    Now if we wanted to use einsum instead, we could write:

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

    The signature string 'i,ij->i' is the key here and needs a little bit of explaining. You can think of it in two halves. On the left-hand side (left of the ->) we've labelled the two input arrays. To the right of ->, we've labelled the array we want to end up with.

    Here is what happens next:

    • A has one axis; we've labelled it i. And B has two axes; we've labelled axis 0 as i and axis 1 as j.

    • By repeating the label i in both input arrays, we are telling einsum that these two axes should be multiplied together. In other words, we're multiplying array A with each column of array B, just like A[:, np.newaxis] * B does.

    • Notice that j does not appear as a label in our desired output; we've just used i (we want to end up with a 1D array). By omitting the label, we're telling einsum to sum along this axis. In other words, we're summing the rows of the products, just like .sum(axis=1) does.

    That's basically all you need to know to use einsum. It helps to play about a little; if we leave both labels in the output, 'i,ij->ij', we get back a 2D array of products (same as A[:, np.newaxis] * B). If we say no output labels, 'i,ij->, we get back a single number (same as doing (A[:, np.newaxis] * B).sum()).

    The great thing about einsum however, is that is does not build a temporary array of products first; it just sums the products as it goes. This can lead to big savings in memory use.

    A slightly bigger example

    To explain the dot product, here are two new arrays:

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

    We will compute the dot product using np.einsum('ij,jk->ik', A, B). Here's a picture showing the labelling of the A and B and the output array that we get from the function:

    enter image description here

    You can see that label j is repeated - this means we're multiplying the rows of A with the columns of B. Furthermore, the label j is not included in the output - we're summing these products. Labels i and k are kept for the output, so we get back a 2D array.

    It might be even clearer to compare this result with the array where the label j is not summed. Below, on the left you can see the 3D array that results from writing np.einsum('ij,jk->ijk', A, B)(i.e. we've kept label j):

    enter image description here

    Summing axis j gives the expected dot product, shown on the right.

    Some exercises

    To get more of feel for einsum, it can be useful to implement familiar NumPy array operations using the subscript notation. Anything that involves combinations of multiplying and summing axes can be written using einsum.

    Let A and B be two 1D arrays with the same length. For example, A = np.arange(10) and B = np.arange(5, 15).

    • The sum of A can be written:

      np.einsum('i->', A)
    • Element-wise multiplication, A * B, can be written:

      np.einsum('i,i->i', A, B)
    • The inner product or dot product, np.inner(A, B) or np.dot(A, B), can be written:

      np.einsum('i,i->', A, B) # or just use 'i,i'
    • The outer product, np.outer(A, B), can be written:

      np.einsum('i,j->ij', A, B)

    For 2D arrays, C and D, provided that the axes are compatible lengths (both the same length or one of them of has length 1), here are a few examples:

    • The trace of C (sum of main diagonal), np.trace(C), can be written:

      np.einsum('ii', C)
    • Element-wise multiplication of C and the transpose of DC * D.T, can be written:

      np.einsum('ij,ji->ij', C, D)
    • Multiplying each element of C by the array D (to make a 4D array), C[:, :, None, None] * D, can be written:

      np.einsum('ij,kl->ijkl', C, D)  
    展开全文
  • einsum:爱因斯坦求和约定

    千次阅读 2020-08-16 18:27:08
    在Tensorflow、Numpy和PyTorch中都提供了使用einsum的api,einsum是一种能够简洁表示点积、外积、转置、矩阵-向量乘法、矩阵-矩阵乘法等运算的领域特定语言。在Tensorflow等计算框架中使用einsum,操作矩阵运算时...

    在Tensorflow、Numpy和PyTorch中都提供了使用einsum的api,einsum是一种能够简洁表示点积、外积、转置、矩阵-向量乘法、矩阵-矩阵乘法等运算的领域特定语言。在Tensorflow等计算框架中使用einsum,操作矩阵运算时可以免于记忆和使用特定的函数,并且使得代码简洁,高效。
    如对矩阵ARI×KA∈R^{I\times K}和矩阵BRK×JB∈R^{K\times J}做矩阵乘,然后对列求和,最终得到向量cRJc∈R^J,即:

    使用爱因斯坦求和约定表示为:
    在这里插入图片描述
    在Tensorflow、Numpy和PyTorch中对应的einsum字符串为:ik,kj->j。在上面的字符串中,隐式地省略了重复的下标k,表示在该维度矩阵乘;另外输出中未指明下标i,表示在该维度累加。

    Numpy、PyTorch和Tensorflow中的einsum

    einsum在Numpy中的实现为np.einsum,在PyTorch中的实现为torch.einsum,在Tensorflow中的实现为tf.einsum,均使用同样的函数签名einsum(equation,operands),其中,equation传入爱因斯坦求和约定的字符串,而operands则是张量序列。在Numpy、Tensorflow中是变长参数列表,而在PyTorch中是列表。上述例子中,在Tensorflow中可写作:tf.einsum('ik,kj->j',mat1,mat2)。 其中,mat1、mat2为执行该运算的两个张量。注意:这里的(i,j,k)的命名是任意的,但在一个表达式中要一致。
    PyTorch和Tensorflow像Numpy支持einsum的好处之一就是,einsum可以用于深度网络架构的任意计算图,并且可以反向传播。在Numpy和Tensorflow中的调用格式如下:在这里插入图片描述
    其中,□是占位符,表示张量维度;arg1,arg3是矩阵,arg2是三阶张量,运算结果是矩阵。注意:einsum处理可变数量的输入。上面例子中,einsum制定了三个参数的操作,但同样可以操作一个参数、两个参数和三个参数及以上的操作。

    典型的einsum表达式

    内积:又称点积、点乘,对应位置数字相乘,结果是一个标量,有见向量内积和矩阵内积等。
    向量a和向量b的内积:
    在这里插入图片描述
    内积几何意义:在这里插入图片描述
    外积:又称叉乘、叉积、向量积,行向量矩阵乘列向量,结果是二阶张量。注意到:张量的外积作为张量积的同义词。外积是一种特殊的克罗内克积。
    向量a和向量b 的外积:
    在这里插入图片描述
    外积的几何意义:
    在这里插入图片描述
    其中,
    在这里插入图片描述
    由于PyTorch可以实时输出运算结果,以PyTorch使用einsum表达式为例。

    矩阵转置 Bji=Aij

    a=torch.arange(6).reshape(2,3)
    >>>tensor([[0, 1, 2],
               [3, 4, 5]])
    torch.einsum('ij->ji',[a])
    >>>tensor([[0, 3],
              [1, 4],
              [2, 5]])
    

    求和 b=Aijb=\sum{\sum{A_{ij}}}

    a=torch.arange(6).reshape(2,3)
    >>>tensor([[0, 1, 2],
               [3, 4, 5]])
    torch.einsum('ij->',[a])
    >>>tensor(15)
    

    列求和(列维度不变,行维度消失) bj=Aijb_j=\sum{A_{ij}}

    a=torch.arange(6).reshape(2,3)
    >>>tensor([[0, 1, 2],
               [3, 4, 5]])
    torch.einsum('ij->j',[a])
    >>>tensor([ 3.,  5.,  7.])
    

    列求和(列维度不变,行维度消失) bi=Aijb_i=\sum{A_{ij}}

    a=torch.arange(6).reshape(2,3)
    >>>tensor([[0, 1, 2],
               [3, 4, 5]])
    torch.einsum('ij->i', [a])
    >>>tensor([  3.,  12.])
    

    矩阵-向量相乘
    在这里插入图片描述

    a=torch.arange(6).reshape(2,3)
    >>>tensor([[0, 1, 2],
               [3, 4, 5]])
    torch.einsum('ik,k->i',[a,b])
    >>>tensor([  5.,  14.])
    

    矩阵-矩阵乘法
    在这里插入图片描述

    a=torch.arange(6).reshape(2,3)
    b=torch.arange(15).reshape(3,5)
    >>>tensor([[0, 1, 2],
               [3, 4, 5]])
               
    >>>tensor([[ 0,  1,  2,  3,  4],
               [ 5,  6,  7,  8,  9],
               [10, 11, 12, 13, 14]])
    torch.einsum('ik,kj->ij',[a,b])
    >>>tensor([[ 25,  28,  31,  34,  37],
               [ 70,  82,  94, 106, 118]])
    

    点积
    向量
    在这里插入图片描述

    a=torch.arange(3)
    b=torch.arange(3,6)
    >>>tensor([0, 1, 2])
    >>>tensor([3, 4, 5])
    torch.einsum('i,i->',[a,b])
    >>>tensor(14.)
    

    矩阵
    在这里插入图片描述

    a=torch.arange(6).reshape(2,3)
    b=torch.arange(6,12).reshape(2,3)
    >>>tensor([[0, 1, 2],
               [3, 4, 5]])
    
    >>>tensor([[ 6,  7,  8],
               [ 9, 10, 11]])
    torch.einsum('ij,ij->',[a,b])
    >>>tensor(145.)
    

    外积
    在这里插入图片描述

    a=torch.arange(3)
    b=torch.arange(3,7)
    >>>tensor([0, 1, 2])
    >>>tensor([3, 4, 5, 6])
    torch.einsum('i,j->ij',[a,b])
    >>>tensor([[  0.,   0.,   0.,   0.],
               [  3.,   4.,   5.,   6.],
               [  6.,   8.,  10.,  12.]])
    

    batch矩阵乘
    在这里插入图片描述

    a=torch.randn(3,2,5)
    b=torch.randn(3,5,3)
    >>>tensor([[[-1.4131e+00,  3.8372e-02,  1.2436e+00,  5.4757e-01,  2.9478e-01],
                [ 1.3314e+00,  4.4003e-01,  2.3410e-01, -5.3948e-01, -9.9714e-01]],
    
               [[-4.6552e-01,  5.4318e-01,  2.1284e+00,  9.5029e-01, -8.2193e-01],
                [ 7.0617e-01,  9.8252e-01, -1.4406e+00,  1.0071e+00,  5.9477e-01]],
    
              [[-1.0482e+00,  4.7110e-02,  1.0014e+00, -6.0593e-01, -3.2076e-01],
               [ 6.6210e-01,  3.7603e-01,  1.0198e+00,  4.6591e-01, -7.0637e-04]]])
    
    >>>tensor([[[-2.1797e-01,  3.1329e-04,  4.3139e-01],
                [-1.0621e+00, -6.0904e-01, -4.6225e-01],
                [ 8.5050e-01, -5.8867e-01,  4.8824e-01],
                [ 2.8561e-01,  2.6806e-01,  2.0534e+00],
                [-5.5719e-01, -3.3391e-01,  8.4069e-03]],
    
               [[ 5.2877e-01,  1.4361e+00, -6.4232e-01],
                [ 1.0813e+00,  8.5241e-01, -1.1759e+00],
                [ 4.9389e-01, -1.7523e-01, -9.5224e-01],
                [-1.3484e+00, -5.4685e-01,  8.5539e-01],
                [ 3.7036e-01,  3.4368e-01, -4.9617e-01]],
    
               [[-2.1564e+00,  3.0861e-01,  3.4261e-01],
                [-2.3679e+00, -2.5035e-01,  1.8104e-02],
                [ 1.1075e+00,  7.2465e-01, -2.0981e-01],
                [-6.5387e-01, -1.3914e-01,  1.5205e+00],
                [-1.6561e+00, -3.5294e-01,  1.9589e+00]]])
    torch.einsum('ijk,ikl->ijl',[a,b])
    >>>tensor([[[ 1.3170, -0.7075,  1.1067],
                [-0.1569, -0.2170, -0.6309]],
    
               [[-0.1935, -1.3806, -1.1458],
                [-0.4135,  1.7577,  0.3293]],
    
               [[ 4.1854,  0.5879, -2.1180],
                [-1.4922,  0.7846,  0.7267]]])
    

    张量缩约
    batch矩阵相乘是张量缩约的一个特例,比如有两个张量,一个n阶张量ARI1×l2×...×InA∈R^{I_1\times l_2 \times ... \times I_n}​,一个m阶张量BRJ1×J2×...×JmB∈R^{J_1 \times J_2 \times...\times J_m​}。取n=4,m=5,假定维度I2=J3I_2=J_3​且I3=J5I_3=J_5​,将这两个张量在这两个维度上(A张量的第2、3维度,B张量的第3、5维度)相乘,获得新张量CRI1×I4×J1×J2×J4C∈R^{I_1 \times I_4 \times J_1 \times J_2 \times J_4}​,如下所示:
    在这里插入图片描述

    a=torch.randn(2,3,5,7)
    b=torch.randn(11,13,3,17,5)
    
    torch.einsum('pqrs,tuqvr->pstuv', [a, b]).shape
    >>>torch.Size([2, 7, 11, 13, 17])
    

    多张量计算
    如前所述,einsum可用于超过两个张量的计算,以双线性变换为例:
    在这里插入图片描述

    a=torch.randn(2,3)
    b=torch.randn(5,3,7)
    c=torch.randn(2,7)
    
    torch.einsum('ik,jkl,il->ij',[a,b,c]).shape
    >>>torch.Size([2,5])
    
    展开全文
  • pytorch的einsum

    2020-04-17 23:20:42
    # -*- coding: utf-8 -*- import torch # 转置 a = torch.arange(6).reshape(2, 3) ...b = torch.einsum('ij->ji', [a]) print(b.size()) print(b) # 求和 b = torch.einsum('ij->', [a]) ...
  • tf.einsum

    千次阅读 2018-06-04 12:40:19
    tf.einsum(equation, *inputs) 例子: tf.einsum(‘ij,jk->ik’, ts1,ts2) #矩阵乘法 tf.einsum(‘ij->ji’,ts1) #矩阵转置
  • einsum的使用

    2020-03-30 18:04:01
    Pytorch中,numpy,tensorflow , einsum详解。 https://zhuanlan.zhihu.com/p/74462893
  • Pytorch中的einsum

    2021-03-31 09:30:43
    本文主要介绍如何使用Pytorch中的爱因斯坦求和(einsum),掌握einsum的基本用法。 einsum的安装 在安装pytorch的虚拟环境下输入以下命令: pip install opt_einsum 爱因斯坦求和约定 在数学中,...
  • NumPy中的einsum函数是什么?einsum函数如何使用? 我在网上发现了一篇相关的文章,描述的十分清楚。 贴上链接:NumPy中的einsum函数是什么?einsum函数如何使用?...
  • einsum的基础使用

    千次阅读 2018-07-21 13:48:20
    einsum全称为Einstein summation convention,是一种求和的范式,在很多基于多维张量的张量运算库,如numpy,tensorflow,pytorch中都有所应用。einsum可以用一种很简单的,统一的方式去表示很多多维张量的运算。让...
  • 参考链接 ... 从einsum表达式恢复为...result=torch.einsum(′xx,xx,xx→xx′,arg1,arg2,arg3)result=torch.einsum\left ( '\textrm{xx,xx,xx}\rightarrow \textrm{xx}',arg1,arg2,arg3\right )result=torch.einsum(′xx
  • NumPy's einsum

    2018-12-05 16:43:50
    NumPy 中的一个函数 einsum 的用法,参见:https://stackoverflow.com/questions/26089893/understanding-numpys-einsum
  • tf.einsum—爱因斯坦求和约定

    千次阅读 2019-04-08 20:53:01
    1. einsum记法 如果你像我一样,发现记住PyTorch/TensorFlow中那些计算点积、外积、转置、矩阵-向量乘法、矩阵-矩阵乘法的函数名字和签名很费劲,那么einsum记法就是我们的救星。einsum记法是一个表达以上这些运算...
  • pytorch中的einsum函数

    2021-07-21 10:35:40
    einsum函数 einsum函数在文档中的解释为: 即,该函数提供了一种使用爱因斯坦求和约定来计算多线性表达式的方法(即乘积和) 爱因斯坦求和约定(Einstein summation convention) 关于爱因斯坦求和约定的详细运算...
  • Einsum in PyTorch✍️

    2021-05-27 21:35:08
    Einsum是一种domain-specific language 域指定语言,可以高性能的实现诸如:dot products, outer product, 矩阵转置 transposes,矩阵向量乘法以及矩阵矩阵之间的乘法。其在numpy、tensorflow、pytorch等框架中可以大大...
  • <div><p>Support numpy like einsum optimization. <p>See https://github.com/dgasmith/opt_einsum I will implement 'greedy' option only in this PR.</p><p>该提问来源于开源项目:cupy/cupy</p>...
  • Einsum Is All You Need

    2020-10-17 15:43:15
    一直弄不清楚这个einsum,今天花了些时间学习,以下是学习记录。 首先是找到了这个视频 https://www.youtube.com/watch?v=CLrTj7D2fLM&ab_channel=FacultyofKhan Why use Einsum Extremely Convenient and ...
  • 程序: import torch ...einsum = torch.einsum('ijk,js->isk',t,w) print(einsum.shape,'einsum shape') print(einsum) t_T=t.transpose(2,1) result = torch.matmul(t_T,w).transpose(2,1) print(result.
  • einsum全称Einstein summation convention(爱因斯坦求和约定),又称为爱因斯坦标记法。einsum的写法省去了求和符号,显得更加简洁。 常规 einsum c=∑iaibic=\sum_ia_ib_ic=∑i​ai​bi​ c=aibic=a_ib_ic...
  • PYTORCH torch.einsum 函数

    千次阅读 2020-09-10 15:15:38
    以爱因斯坦求和的形式任意定义想要进行的矩阵乘法的操作,可以内部指定输出转置,功能多样,形式灵活。 #theta_phi: nxtxg ...output = torch.einsum('ntg, ncg->nct', theta_phi, g) #output: nxcxt
  • tf.einsum()简单使用

    万次阅读 2018-08-10 11:16:53
    tf.einsum einsum( equation, *inputs) 一般来说, 方程是从较熟悉的元素方程得到: 删除变量名称、括号和逗号; 用 “*” 替换 “,”; 删除总和标志; 将输出移到右侧,并将 “=” 替换为 “-&gt;&...
  • 【torch.einsum

    2021-02-17 16:28:48
    爱因斯坦简记法,能简洁表示各种矩阵向量的操作,例如矩阵转置、乘法、求和等等,pytorch中调用API为torch.einsum,第一个参数是字符串,表示对张量的操作,定义不同字符串表示不同操作 例子 矩阵转置 字符串为ij-&...
  • einsum方法详解(爱因斯坦求和) einsum是pytorch、numpy中一个十分优雅的方法,如果利用得当,可完全代替所有其他的矩阵计算方法,不过这需要一定的学习成本。本文旨在详细解读einsum方法的原理,并给出一些基本...
  • numpy.einsum()

    2019-12-06 11:33:43
    https://stackoverflow.com/questions/37714462/numpy-einsum-broadcasting https://obilaniu6266h16.wordpress.com/2016/02/04/einstein-summation-in-numpy/ ...
  • einsum以一种优雅的方式,表示各种矩阵运算,好处在于你不需要去记和使用计算框架中(TensorFlow|PyTorch|Numpy)点积、外积、转置、矩阵-向量乘法、矩阵-矩阵乘法的函数名字和签名。从某种程度上解决引入不必要的...
  • PyTorch 中的 tensordot 以及 einsum 函数介绍 前言 最近发现这两个函数用得越来越频繁, 比如在 DCN 网络的实现中就用到了(详见 Deep Cross Network (深度交叉网络, DCN) 介绍与代码分析), 但是过段时间又忘记这两个...
  • numpy.einsum-学习笔记

    千次阅读 2017-11-08 03:39:43
    numpy.einsum-学习笔记

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,219
精华内容 487
关键字:

einsum