背景:
我正在实现顺序向后选择算法,以从数据集中选择要素。有问题的数据集是MNIST。我有60000个长度为784的向量。
该算法要求我从总共784个特征中省略一个特征fi
,然后选择其余783个特征,在下面的代码中称为selection
。然后,我必须计算每个向量的Mahalanobis,以其为尊重等级的平均值。完成此迭代后,我将省略两个功能,然后再删除三个,依此类推。这些迭代每次都需要3分钟。
我必须选择500个特征,因此以上操作重复了500次,因此总共计算了Mahalanobis距离500 x 784 = 392,000
次。这需要我计算协方差矩阵的逆。该协方差矩阵的逆不存在,因为它是奇异的,所以我使用的是numpy的伪逆。
问题
您可以想象上面的过程非常慢。计算伪逆是最慢的过程。我以为我可以预先计算伪逆,然后删除与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))
行。
答案 0 :(得分:0)
现在,您的代码本质上是:
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
ic = u @ (1/s[...,None] * u.T)
return np.sum(((delta @ ci) * delta), axis=-1)
值得注意的是,对于复杂的值,此函数或您的函数都无法正常工作。