Implementación de t-SNE Python: divergencia Kullback-Leibler

11

t-SNE, como en [1], funciona reduciendo progresivamente la divergencia Kullback-Leibler (KL), hasta que se cumpla una determinada condición. Los creadores de t-SNE sugieren utilizar la divergencia KL como criterio de rendimiento para las visualizaciones:

puede comparar las divergencias de Kullback-Leibler que informa t-SNE. Está perfectamente bien ejecutar t-SNE diez veces y seleccionar la solución con la divergencia KL más baja [2]

Intenté dos implementaciones de t-SNE:

  • python : sklearn.manifold.TSNE ().
  • R : tsne, de la biblioteca (tsne).

Ambas implementaciones, cuando se establece la verbosidad, imprimen el error (divergencia Kullback-Leibler) para cada iteración. Sin embargo, no permiten que el usuario obtenga esta información, lo que me parece un poco extraño.

Por ejemplo, el código:

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)

produce:

[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

Ahora, hasta donde yo entiendo, 0.270186 debería ser la divergencia KL. Sin embargo, no puedo obtener esta información, ni del modelo ni de t (que es un simple numpy.ndarray).

Para resolver este problema podría: i) Calcular la divergencia de KL por mí mismo, ii) Hacer algo desagradable en python para capturar y analizar la salida de la función TSNE () [3]. Sin embargo: i) sería bastante estúpido volver a calcular la divergencia de KL, cuando TSNE () ya lo haya calculado, ii) sería un poco inusual en términos de código.

¿Tienes alguna otra sugerencia? ¿Existe una forma estándar de obtener esta información utilizando esta biblioteca?

Mencioné que probé la biblioteca tsne de R , pero preferiría las respuestas para centrarme en la implementación de python sklearn.


Referencias

[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] /programming/16571150/how-to-capture-stdout-output-from-a-python-function-call

bufón
fuente

Respuestas:

4

La fuente TSNE en scikit-learn está en Python puro. El fit_transform()método Fit en realidad llama a una _fit()función privada que luego llama a una _tsne()función privada . Esa _tsne()función tiene una variable local errorque se imprime al final del ajuste. Parece que podría cambiar fácilmente una o dos líneas de código fuente para recuperar ese valor fit_transform().

Trey
fuente
Esencialmente, lo que podría hacer es establecer self.error = error al final de _tsne (), para recuperarlo de la instancia de TSNE después. Sí, pero eso significaría cambiar el código sklearn.manifold, y me preguntaba si los desarrolladores pensaron en otras formas de obtener la información o, si no, por qué no lo hicieron (es decir, ¿consideran que el 'error' es inútil?). Además, si cambiara ese código, necesitaría que todas las personas que ejecutan mi código tengan el mismo truco en sus instalaciones de sklearn. ¿Es eso lo que sugieres o me equivoqué?
bromista
Sí, eso es lo que sugerí como una posible solución. Dado que scikit-learn es de código abierto, también puede enviar su solución como una solicitud de extracción y ver si los autores incluirían eso en futuras versiones. No puedo hablar de por qué incluyeron o no varias cosas.
Trey
2
Gracias. Si alguien más está interesado en esto, github.com/scikit-learn/scikit-learn/pull/3422 .
bromista