我一直在探索不同的降维算法,特别是PCA和T-SNE。我正在采用MNIST数据集的一小部分(约780维),并尝试将原始数据减少到三维,以便将其显示为散点图。可以非常详细地描述T-SNE here。
我正在使用PCA作为T-SNE之前的中间维度缩减步骤,正如source code from their website.上的T-SNE的原始创建者所描述的那样
我发现T-SNE需要永远运行(从 2000 x 25 到 2000 x 3 特征空间需要10-15分钟),而PCA运行相对较快( 2000 x 780 => 2000 X 20 时为几秒钟)。
为什么会这样?我的理论是,在PCA实现中(直接来自主要作者的Python源代码),他利用Numpy点积符来计算X
和X.T
:
def pca(X = Math.array([]), no_dims = 50):
"""Runs PCA on the NxD array X in order to reduce its dimensionality to no_dims dimensions."""
print "Preprocessing the data using PCA..."
(n, d) = X.shape;
X = X - Math.tile(Math.mean(X, 0), (n, 1));
(l, M) = Math.linalg.eig(Math.dot(X.T, X));
Y = Math.dot(X, M[:,0:no_dims]);
return Y;
据我所知,这比标量操作明显更有效,也意味着只有 2N (其中N
是行数)的数据被加载到内存中(您需要加载一行X
和一列X.T
)。
但是,我不认为这是根本原因。 T-SNE肯定还包含向量运算,例如,在计算成对距离D
:
D = Math.add(Math.add(-2 * Math.dot(X, X.T), sum_X).T, sum_X);
或者,在计算P(更高维度)和Q(更低维度)时。但是,在t-SNE中,您必须创建两个 N X N 矩阵来存储每个数据之间的成对距离,一个用于其原始高维空间表示,另一个用于缩小的维度空间。
在计算渐变时,您还必须创建另一个名为N X N
的{{1}}矩阵,即PQ
。
在我看来,这里的内存复杂性是瓶颈。 T-SNE需要 3N ^ 2 的内存。这种方法无法适应本地内存,因此该算法会遇到大量高速缓存行未命中,需要转到全局内存来检索值。
这是对的吗?我如何向客户或合理的非技术人员解释为什么t-SNE比PCA慢?
找到共同作者的Python实现here。
答案 0 :(得分:2)
t-SNE比PCA慢的主要原因是没有针对正在优化的标准的分析解决方案。相反,必须通过梯度下降迭代来近似解决方案。
实际上,这意味着许多for循环。至少不是第129行的主循环for循环,它最多运行max_iter=1000
次。此外,x2p
函数使用for循环遍历所有数据点。
参考实现针对可读性进行了优化,而不是针对计算速度进行了优化。作者也链接到optimised Torch implementation,这应该会加速计算。如果你想留在纯Python中,我建议在Scikit-Learn中实现,这也应该快得多。
答案 1 :(得分:1)
t-SNE试图降低维度,同时保留元素之间距离的分布。
这需要计算所有点之间的距离。成对距离矩阵具有N ^ 2个条目,其中N是示例的数量。