【问题标题】:Applying non-trivial matrix calculating without for-loop in Numpy在 Numpy 中应用不带 for 循环的非平凡矩阵计算
【发布时间】:2019-08-22 21:53:00
【问题描述】:

简单地尝试为 EM 算法找到计算此更新后协方差矩阵的最佳方法 *

我已经开发了算法,但是使用了 for 循环。我正在尝试确定如何利用 Numpy 矢量化。

cov_c = []
for cluster, u, w in zip(r.T, mu_c, total_weight):
    s = 0
    for n in range(len(d)):
        s += cluster[n]*np.outer(d[n] - u, d[n] - u)
    cov_c.append(s / w)

cov_c 是一个包含两个元素的列表,每个列表都有一个协方差矩阵 (2x2)

    [array([[0.19, 0.23],[0.23, 0.39]]), 
     array([[4.05, -5.01,[-5.018,  6.22]])]

d 和 r 都是二维数组(加权样本) d 是特征向量(100 个样本的 2 个特征),其中 r 是 2 个高斯的每个特征的权重

d.shape
(100, 2)
r.shape
(100, 2)

mu_c 是平均向量的二元素列表

mu_c
[array([ 0.24387682, -0.27793324]), array([ 2.37853451, -1.86454301])]

总重量是一个归一化因子(简单的 2 元素一维数组):

total_weight
array([53.51779102, 46.48220898])

关于如何向量化这个计算有什么建议吗?谢谢!

【问题讨论】:

  • 是的。谢谢你的回答!

标签: python arrays numpy matrix vectorization


【解决方案1】:

我们可以利用 NumPy 数组来利用向量化的 ufunc 操作。此外,由于d 中的列数只是2,我们将简单地沿该轴使用循环(因此只有两次迭代的循环)。因此,我们将使用切片数据而不是在所有方向上扩展数组,这会导致更严重的内存拥塞。我们仍然会在切片数据上利用broadcasting。最后,我们将使用np.einsum 来替换外部减和,这可能是我们获得最多的地方。

我们最终会得到这样的结果 -

mu_c = np.asarray(mu_c)
total_weight = np.asarray(total_weight)

n = d.shape[1]
out = np.empty((n,2,2))
for i in range(n):
    du = d-mu_c[i]
    out[i] = np.einsum('i,ij,ik->jk',r[:,i],du,du)
cov_c_out = out/total_weight[:,None,None]

或者,einsum 部分可以替换为矩阵乘法步骤 -

out[i] = (r[:,i,None]*du).T.dot(du)

为了完整或只是为了好玩,这就是一个完全矢量化的解决方案的样子,这是内存密集型的,因此很可能会更慢 -

dmuc = d[:,None,:]-mu_c
out = np.einsum('ij,ijk,ijl->jkl',r,dmuc,dmuc)

另外,通过将np.einsum 中的optimize 标志设置为True 来使用BLAS。

【讨论】:

  • 内存密集型解决方案实际上不应该更快吗?我正在考虑通常的 CPU/内存权衡,并假设它在这种情况下成立(并且用户足够的内存来支持它)
  • @vlsd 由于数据获取的延迟,计算保持不变的内存密集型对性能没有好处。相比之下,这里的内存密集度更高,因为一方面你有切片,这只是现有 2D 数据的视图,而基于广播的内存密集型创建了一个新的 3D 数组。
  • 我错过了计算保持不变的部分,我只是假设更高的内存解决方案会有更少的周期数:)
猜你喜欢
  • 2013-10-24
  • 1970-01-01
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多