Реализация Python t-SNE: расхождение Кульбака-Лейблера

11

t-SNE, как и в [1], работает путем постепенного уменьшения расхождения Кульбака-Лейблера (KL), пока не будет выполнено определенное условие. Создатели t-SNE предлагают использовать дивергенцию KL в качестве критерия производительности для визуализаций:

Вы можете сравнить расхождения Kullback-Leibler, о которых сообщает t-SNE. Совершенно нормально выполнить t-SNE десять раз и выбрать решение с самой низкой дивергенцией KL [2]

Я попробовал две реализации t-SNE:

  • python : sklearn.manifold.TSNE ().
  • Р . : Цне, из библиотеки (цне).

Обе эти реализации, когда задано многословие, выдают ошибку (расхождение Кульбака-Лейблера) для каждой итерации. Тем не менее, они не позволяют пользователю получать эту информацию, что выглядит немного странно для меня.

Например, код:

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. Однако я не могу получить эту информацию, ни из модели, ни из т (который является простым numpy.ndarray).

Чтобы решить эту проблему, я мог бы: i) самостоятельно рассчитать дивергенцию KL, ii) сделать что-то неприятное в python для захвата и анализа вывода функции TSNE () [3]. Однако: i) было бы довольно глупо пересчитать дивергенцию KL, когда TSNE () уже вычислил ее, ii) было бы немного необычно с точки зрения кода.

У вас есть другие предложения? Есть ли стандартный способ получить эту информацию с помощью этой библиотеки?

Я упоминал, что пробовал библиотеку R 's tsne, но я бы предпочел, чтобы ответы были сосредоточены на реализации python sklearn.


Ссылки

[1] http://nbviewer.ipython.org/urls/gist.githubusercontent.com/AlexanderFabisch/1a0c648de22eff4a2a3e/raw/59d5bc5ed8f8bfd9ff1f7faa749d1b095aa97d5a/tynS

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

[3] /programming/16571150/how-to-capture-stdout-output-from-a-python-function-call

джокер
источник

Ответы:

4

Исходный код TSNE в scikit-learn находится на чистом Python. fit_transform()Метод Fit на самом деле вызывает приватную _fit()функцию, которая затем вызывает приватную _tsne()функцию. Эта _tsne()функция имеет локальную переменную, errorкоторая выводится в конце подгонки. Похоже, вы могли бы довольно легко изменить одну или две строки исходного кода, чтобы вернуть это значение fit_transform().

тройка
источник
По сути, я мог бы установить self.error = error в конце _tsne (), чтобы впоследствии извлечь его из экземпляра TSNE. Да, но это означало бы изменение кода sklearn.manifold, и мне было интересно, подумали ли разработчики о некоторых других способах получения информации или нет, почему они этого не сделали (т. Е. Считают ли они «ошибку» бесполезной для них?). Кроме того, если бы я изменил этот код, мне понадобилось бы, чтобы все люди, выполняющие мой код, имели одинаковый хак в своих установках sklearn. Это то, что вы предлагаете, или я ошибся?
Джокер
Да, именно это я и предложил в качестве возможного решения. Поскольку scikit-learn является открытым исходным кодом, вы также можете отправить свое решение в виде запроса извлечения и посмотреть, будут ли авторы включать его в будущие выпуски. Я не могу говорить, почему они сделали или не включили различные вещи.
Трей
2
Спасибо. Если кто-то еще заинтересован в этом, github.com/scikit-learn/scikit-learn/pull/3422 .
Джокер