t-SNE Python 实现:Kullback-Leibler 散度

数据挖掘 机器学习 Python
2021-10-10 05:57:47

与 [1] 中一样,t-SNE 的工作原理是逐步减少 Kullback-Leibler (KL) 散度,直到满足某个条件。
t-SNE 的创建者建议使用 KL 散度作为可视化的性能标准:

您可以比较 t-SNE 报告的 Kullback-Leibler 散度。运行 t-SNE 十次完全没问题,并选择具有最低 KL 散度的解决方案 [2]

我尝试了 t-SNE 的两种实现:

  • 蟒蛇sklearn.manifold.TSNE()
  • R:,tsnelibrary(tsne)

这两种实现都在设置详细度时打印每次迭代的错误(Kullback-Leibler 散度)。但是,他们不允许用户获取此信息,这对我来说有点奇怪。

例如,代码:

import numpy as np
from sklearn.manifold import TSNE
X = np.array([[0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 1]])
model = TSNE(n_components=2, verbose=2, n_iter=200)
t = model.fit_transform(X)

产生:

[t-SNE] Computing pairwise distances...
[t-SNE] Computed conditional probabilities for sample 4 / 4
[t-SNE] Mean sigma: 1125899906842624.000000
[t-SNE] Iteration 10: error = 6.7213750, gradient norm = 0.0012028
[t-SNE] Iteration 20: error = 6.7192064, gradient norm = 0.0012062
[t-SNE] Iteration 30: error = 6.7178683, gradient norm = 0.0012114
...
[t-SNE] Error after 200 iterations: 0.270186

现在,据我了解,0.270186应该是 KL 散度。但是,我无法从模型t(这是一个简单的numpy.ndarray)中获取此信息。

为了解决这个问题,我可以:

  1. 自己计算KL散度,
  2. 在 python 中做一些讨厌的事情来捕获和解析TSNE()函数的输出 [3]。

然而:

  1. 重新计算KL散度会很愚蠢,当TSNE()已经计算过它时,
  2. 在代码方面会有点不寻常。

你还有什么建议吗?是否有使用此库获取此信息的标准方法?

我提到我尝试了R的 tsne 库,但我更希望答案专注于python sklearn 实现。


参考

[1] http://nbviewer.ipython.org/urls/gist.githubusercontent.com/AlexanderFabisch/1a0c648de22eff4a2a3e/raw/59d5bc5ed8f8bfd9ff1f7faa749d1b095aa97d5a/t-SNE.ipynb

[2] http://homepage.tudelft.nl/19j49/t-SNE.html

[3] https://stackoverflow.com/questions/16571150/how-to-capture-stdout-output-from-a-python-function-call

1个回答

scikit-learn 中的 TSNE 源代码是纯 Python 的。Fitfit_transform()方法实际上是调用一个私有_fit()函数,然后调用一个私有_tsne()函数。_tsne()函数有一个局部变量error,在拟合结束时打印出来。似乎您可以很容易地更改一两行源代码以将该值返回到fit_transform().