【问题标题】:Taking dot products of high dimensional numpy arrays采用高维 numpy 数组的点积
【发布时间】:2017-08-27 10:49:50
【问题描述】:

我正在尝试在三个 numpy 数组之间进行点积。但是,我正在努力解决这个问题。

问题如下:

我分别有两个 (4,) 形状的 numpy 数组 ab,以及一个形状为 (4, 4, 3) 的 numpy 数组 c

import numpy as np

a = np.array([0, 1, 2, 3])
b = np.array([[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
          [[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]],
          [[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]],
          [[4, 4, 4], [4, 4, 4], [4, 4, 4], [4, 4, 4]]])
c = np.array([4, 5, 6, 7])

我想以这样一种方式计算点积,即我的结果是一个 3 元组。也就是说,首先用ba,然后用c 点,如果需要,进行转置。换句话说,我想计算abc 之间的点积,就好像c 的形状为(4, 4),但我想要一个三元组作为结果。

我试过了:

重塑ac,然后计算点积:

a = np.reshape(a, (4, 1))
c = np.reshape(c, (4, 1))

tmp = np.dot(a.T, b) # now has shape (1, 4, 3)
result = np.dot(tmp, c) 

理想情况下,我现在应该:

print(result.shape)
>> (1, 1, 3) 

但我得到了错误

ValueError:形状 (1,4,3) 和 (4,1) 未对齐:3 (dim 2) != 4 (dim 0)

我也尝试过使用 numpy 中的 tensordot 函数,但没有运气。

【问题讨论】:

  • 你能把结果行拆分成语句吗?更容易看出哪个点积失败了。
  • 错误很明显:您正在尝试在不同大小的事物上计算点积。
  • 您在寻找这样的东西吗? np.dot(np.dot(a, b).T, c) ;结果是array([360, 360, 360])
  • @DavidEhrmann 我知道它们的尺寸不同。我希望 numpy 会自动分布在最后一个轴上。也就是说,如果有意义的话,点积将在两个第一轴上运行。 (1, 4) (4, 1) @kmario23 np.dot(np.dot(a, b).T, c) 不起作用,因为 ab 都是形状 (1, 4)

标签: python arrays numpy matrix dot-product


【解决方案1】:

基本的dot(A,B) 规则是:A 的最后一个轴与 B 的第二个到最后一个轴

In [965]: a.shape
Out[965]: (4,)
In [966]: b.shape
Out[966]: (4, 4, 3)

a(和c)是1d。它的 (4,) 可以与b 的第二个 (4) 点在一起:

In [967]: np.dot(a,b).shape
Out[967]: (4, 3)

在相同的输出中使用c 会产生一个 (3,) 数组

In [968]: np.dot(c, np.dot(a,b))
Out[968]: array([360, 360, 360])

这种组合使用等效的einsum 可能会更清晰:

In [971]: np.einsum('i,jik,j->k',a,b,c)
Out[971]: array([360, 360, 360])

但是如果我们想让a 作用于b 的第一轴呢?使用einsum 很容易做到:

In [972]: np.einsum('i,ijk,j->k',a,b,c)
Out[972]: array([440, 440, 440])

要对dot 做同样的事情,我们只需切换ac

In [973]: np.dot(a, np.dot(c,b))
Out[973]: array([440, 440, 440])

或者转置b的轴:

In [974]: np.dot(c, np.dot(a,b.transpose(1,0,2)))
Out[974]: array([440, 440, 440])

如果ac 的长度不同,这个换位问题会更清楚。例如(2,) 和 (4,) 与 (2,4,3) 或 (4,2,3)。


tmp = np.dot(a.T, b) # now has shape (1, 4, 3)

你有一个 (1,4a) 点缀着 (4,4a,3)。结果是 (1,4,3)。我添加了a 来识别轴何时合并。

要应用 (4,1) c,我们必须做同样的转置:

In [977]: np.dot(c[:,None].T, np.dot(a[:,None].T, b))
Out[977]: array([[[360, 360, 360]]])
In [978]: _.shape
Out[978]: (1, 1, 3)

np.dot(c[None,:], np.dot(a[None,:], b)) 在没有转置的情况下也会这样做。


我希望 numpy 会自动分布在最后一个轴上。也就是说,如果有意义的话,点积将在两个第一轴上运行。

鉴于我在开头引用的dot 规则,这没有任何意义。但是,如果我们转置b,使 (3) 轴位于第一个,它可以“随身携带”,使用最后一个和第二个到最后一个。

In [986]: b.transpose(2,0,1).shape
Out[986]: (3, 4, 4)
In [987]: np.dot(a, b.transpose(2,0,1)).shape
Out[987]: (3, 4)
In [988]: np.dot(np.dot(a, b.transpose(2,0,1)),c)
Out[988]: array([440, 440, 440])

(4a).(3, 4a, 4c) -> (3, 4c)
(3, 4c). (4c) -> 3

【讨论】:

    【解决方案2】:

    您将 (1,4,3) 矩阵乘以 (4,1) 矩阵,所以这是不可能的,因为您在 b 中有 3 页 (1,4) 矩阵。如果您想将矩阵 b 的每一页乘以 c,只需将每一页分别相乘即可。

    a = np.array([0, 1, 2, 3])
    b = np.array([[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
          [[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]],
          [[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]],
          [[4, 4, 4], [4, 4, 4], [4, 4, 4], [4, 4, 4]]])
    c = np.array([4, 5, 6, 7])
    
    a = np.reshape(a, (4, 1))
    c = np.reshape(c, (4, 1))
    
    tmp = np.dot(a.T, b) # now has shape (1, 4, 3)
    result = np.dot(tmp[:,:,0], c)
    for i in range(1,3):
        result = np.dstack((result, np.dot(tmp[:,:,i], c)))
    print np.shape(result)
    

    所以你有大小 (1,1,3) 的结果

    【讨论】:

      【解决方案3】:

      不是自动的,但可以完成工作:

      np.einsum('i,ijk,j->k',a,b,c)
      # array([440, 440, 440])
      

      这会计算形状为 (3,) 的 d,使得 d_k = sum_{ij} a_i b_{ijk} c_j

      【讨论】:

        猜你喜欢
        • 2013-07-16
        • 2021-03-27
        • 1970-01-01
        • 2016-07-09
        • 1970-01-01
        • 2021-11-24
        • 1970-01-01
        • 2017-06-15
        • 1970-01-01
        相关资源
        最近更新 更多