Implementação do t-SNE Python: divergência Kullback-Leibler

11

O t-SNE, como em [1], trabalha reduzindo progressivamente a divergência de Kullback-Leibler (KL), até que uma determinada condição seja atendida. Os criadores do t-SNE sugerem usar a divergência de KL como critério de desempenho para as visualizações:

você pode comparar as divergências de Kullback-Leibler relatadas pelo t-SNE. É perfeitamente adequado executar o t-SNE dez vezes e selecionar a solução com a menor divergência de KL [2]

Eu tentei duas implementações do t-SNE:

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

Ambas as implementações, quando a verbosidade é definida, imprimem o erro (divergência Kullback-Leibler) para cada iteração. No entanto, eles não permitem que o usuário obtenha essas informações, o que me parece um pouco estranho.

Por exemplo, o 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)

produz:

[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

Agora, tanto quanto eu entendo, 0,270186 deve ser a divergência KL. No entanto, não consigo obter essas informações, nem do modelo nem do t (que é um simples numpy.ndarray).

Para resolver esse problema, eu poderia: i) calcular a divergência de KL por conta própria, ii) fazer algo desagradável em python para capturar e analisar a saída da função TSNE () [3]. No entanto: i) seria estúpido recalcular a divergência de KL, quando TSNE () já a calculou, ii) seria um pouco incomum em termos de código.

Você tem alguma outra sugestão? Existe uma maneira padrão de obter essas informações usando esta biblioteca?

Eu mencionei que eu tentei R biblioteca tsne 's, mas eu prefiro as respostas para focar o python implementação sklearn.


Referências

[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

palhaço
fonte

Respostas:

4

A fonte TSNE no scikit-learn está em Python puro. O fit_transform()método Fit está na verdade chamando uma _fit()função privada que, em seguida, chama uma _tsne()função privada . Essa _tsne()função possui uma variável local errorque é impressa no final do ajuste. Parece que você poderia facilmente alterar uma ou duas linhas de código-fonte para que esse valor retornasse fit_transform().

Trey
fonte
Essencialmente, o que eu poderia fazer é definir self.error = error no final de _tsne (), para recuperá-lo da instância TSNE posteriormente. Sim, mas isso significaria alterar o código sklearn.manifold, e eu queria saber se os desenvolvedores pensaram em outras maneiras de obter as informações ou se não, por que não (por exemplo: o 'erro' é considerado inútil por eles?). Além disso, se eu alterasse esse código, todas as pessoas que executam meu código precisariam ter o mesmo hack nas instalações do sklearn. É isso que você sugere, ou eu entendi errado?
Joker
Sim, foi o que sugeri como uma possível solução. Como o scikit-learn é de código aberto, você também pode enviar sua solução como uma solicitação pull e ver se os autores a incluirão em versões futuras. Não sei explicar por que eles incluíram ou não várias coisas.
Trey
2
Obrigado. Se alguém mais estiver interessado nisso, github.com/scikit-learn/scikit-learn/pull/3422 .
Joker