【问题标题】:How can I vectorize the dot product in Python?如何在 Python 中矢量化点积?
【发布时间】:2019-01-27 22:35:23
【问题描述】:

我想计算点积的 N 组,对于每个组假设它是一个 (4,3) 矩阵,称为 x_i。于是我将这些N个矩阵向量化成一个(N,4,3)矩阵,如:

 [[[1,2,3],
   [4,5,6],
   [7,8,9],
   [0,1,2]],
     ...
   [7,2,2],
   [4,2,4],
   [7,1,9],
   [3,1,2]]].  #  #N matrices

如果我分别计算 x_i 和 x_i.T 的每个点积:

np.dot(x_i, x_i.T)

它会得到一个 (4,4) 矩阵。

但是向量化后如何计算这些?

最终结果应该是(N,4,4)。

【问题讨论】:

    标签: python numpy vectorization dot-product


    【解决方案1】:

    您可以生成 3D 列表。我会这样:

    N=[]
    for n in range (len(N)):
        N.append(n,np.dot(x_i, x_i.T))
    

    【讨论】:

    • 你不应该将变量命名为list,因为这是一个内置函数并且它不是向量化的,因为你使用的是for循环。
    • 我理解你关于名字的观点,但为什么你说它也不是矢量化的?
    【解决方案2】:
    In [31]: x = np.arange(5*12).reshape(5,4,3)
    In [32]: x@x.transpose(0,2,1)
    Out[32]: 
    array([[[    5,    14,    23,    32],
            [   14,    50,    86,   122],
            [   23,    86,   149,   212],
            [   32,   122,   212,   302]],
    
           [[  509,   626,   743,   860],
            [  626,   770,   914,  1058],
            [  743,   914,  1085,  1256],
            [  860,  1058,  1256,  1454]],
    
           [[ 1877,  2102,  2327,  2552],
            [ 2102,  2354,  2606,  2858],
            [ 2327,  2606,  2885,  3164],
            [ 2552,  2858,  3164,  3470]],
    
           [[ 4109,  4442,  4775,  5108],
            [ 4442,  4802,  5162,  5522],
            [ 4775,  5162,  5549,  5936],
            [ 5108,  5522,  5936,  6350]],
    
           [[ 7205,  7646,  8087,  8528],
            [ 7646,  8114,  8582,  9050],
            [ 8087,  8582,  9077,  9572],
            [ 8528,  9050,  9572, 10094]]])
    In [33]: _.shape
    Out[33]: (5, 4, 4)
    

    检查

    In [34]: x[0,...].dot(x[0,...].T)
    Out[34]: 
    array([[  5,  14,  23,  32],
           [ 14,  50,  86, 122],
           [ 23,  86, 149, 212],
           [ 32, 122, 212, 302]])
    

    @matmul 在最后两个维度上进行点积,同时将第一个维度视为“i”维度。

    x.tanspose(0,2,1) 切换最后两个维度,保持第一个不变。对于二维数组x.transpose()x.transpose(1,0)。就是你表达的x_i.T

    dot 一样,a@b 的关键是a 的最后一个维度与b 的倒数第二个维度一起使用。

    【讨论】:

    • 感谢您的帮助,我对 x@x.transpose(0,2,1) 不熟悉。但我注意到它也有效!我将查看文档并检查原因。再次感谢
    • 我添加了一些注释。
    • 解释得很清楚!!我现在明白了,再次感谢:)
    【解决方案3】:

    似乎np.einsum 可以做到这一点

    x = np.arange(5*12).reshape(5,4,3)
    np.einsum("nik, njk->nij", x, x)
    

    【讨论】:

      【解决方案4】:

      np.matmul 可以解决问题:

      N=2; m=4; n=3
      x = np.ones((N,m,n))
      np.matmul(x,x.transpose(0,2,1))
      
      array([[[3., 3., 3., 3.],
          [3., 3., 3., 3.],
          [3., 3., 3., 3.],
          [3., 3., 3., 3.]],
      
         [[3., 3., 3., 3.],
          [3., 3., 3., 3.],
          [3., 3., 3., 3.],
          [3., 3., 3., 3.]]])
      

      形状检查:

      np.matmul(x,x.reshape((N,n,m))).shape
      

      (2, 4, 4)

      P.S.,正如 hpaulj 在评论中提到的那样,这个解决方案基本上等同于他的!

      【讨论】:

      • matmul 可以表示为@ 运算符。 reshape 与转置不同。您的代码有效,因为您的 x 全部为 1。
      • 谢谢!!这就是我要找的!使用这种方法进行矢量化与使用循环一样,我得到了相同的结果。但现在,我想知道何时使用 np.matmul 或 np.dot。
      • @Yan-JenHuang 这个答案或许可以帮助你理解 dot 和 matmul 之间的区别:stackoverflow.com/questions/34142485/…
      猜你喜欢
      • 2018-12-25
      • 1970-01-01
      • 1970-01-01
      • 2017-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多