【问题标题】:Speeding up Mahalanobis distance calculation加快马氏距离计算
【发布时间】:2019-08-01 08:07:43
【问题描述】:

背景:

我正在实现一个顺序后向选择算法来从数据集中选择特征。有问题的数据集是 MNIST。我有 60000 个长度为 784 的向量。

该算法要求我从总共 784 个特征中删除一个特征 fi,并在下面的代码中选择剩余的 783 个特征,称为 selection。然后我必须计算每个向量的 Mahalanobis 到它的尊重类的平均值。一旦这个迭代完成,我会遗漏两个特征,然后是三个,依此类推。每次迭代都需要 3 分钟。

我必须选择 500 个特征,因此上述内容重复 500 次,因此总共计算了马氏距离 500 x 784 = 392,000 次。这需要我计算协方差矩阵的逆矩阵。这个协方差矩阵的逆不存在,因为它是奇异的,所以我使用的是 numpy 的 Pseudo-Inverse。

问题

您可以想象,上面的内容非常缓慢。计算伪逆是一个最慢的过程。我想我可以预先计算伪逆然后删除与fi 关联的相应列和行。然而,事实证明这个伪逆矩阵不等于直接从我删除fi 的向量计算的伪逆矩阵。

我的尝试

我已尝试在很大程度上对此进行矢量化处理并处理数组堆栈,结果却发现分解方法较慢。我尝试过 np.einsum、cdist 甚至 numexpr。没有什么真正有用的。

这让我相信,我加快速度的最佳机会是以某种方式将协方差和伪逆计算移出这个循环。这是我当前的代码:

def mahalanobis(self, data, lbls, selection):
    subset data[:,tuple(selection)]

    for n in range(10):
        class_rows = subset[np.where(y == n)]
        mean = np.mean(class_rows, axis = )
        pseudoInverse = pinv(covariance(class_rows))
        delta = C - u
        d[n] = np.mean(np.sum(((delta @ pseudoInverse) * delta), axis = -1))
    return np.mean(d)

问题

如何加快计算速度?从我过去一周所做的测试来看,这个计算中最慢的部分似乎是 pseudoInverse = pinv(covariance(class_rows)) 行。

【问题讨论】:

  • 你知道scipy.spatial.distance.mahalanobis吗?编辑:没关系,它并不比你拥有的快。
  • 是的。它相当有限,因为它只能接受一维数组。
  • 在 numpy 1.16 中,您可以将 hermitian = true 传递给 pinv,这可能会加快速度
  • @Eric 我安装了 1.16 但传递了该关键字 arg。给了我一个错误。文档也没有提到任何关于厄米特论点的内容。
  • 哎呀,直到 1.17,抱歉。无论如何,我的回答是一样的。

标签: numpy vectorization mahalanobis


【解决方案1】:

现在,您的代码基本上是:

def mahalanobis(delta, cov):
    ci = np.linalg.pinv(cov)
    return np.sum(((delta @ ci) * delta), axis=-1)

您可以通过以下方式加快速度:

  • 直接使用svd 而不是pinv,并消除您不使用的共轭。
  • 使用eigh 代替svd,这利用了协方差矩阵的对称性
def mahalanobis_eigh(delta, cov):
    s, u = np.linalg.eigh(cov)
    # note: missing filtering of small s, which you might want to consider adding - pinv already does this for you
    ci = u @ (1/s[...,None] * u.T)
    return np.sum(((delta @ ci) * delta), axis=-1)

值得注意的是,此函数和您的函数都不能正确处理复数值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 2015-02-25
    • 1970-01-01
    • 2018-06-29
    • 2019-07-28
    • 1970-01-01
    相关资源
    最近更新 更多