Implementacja t-SNE Python: dywergencja Kullbacka-Leiblera

11

t-SNE, jak w [1], działa poprzez stopniowe zmniejszanie dywergencji Kullbacka-Leiblera (KL), aż do spełnienia pewnego warunku. Twórcy t-SNE sugerują wykorzystanie dywergencji KL jako kryterium wydajności dla wizualizacji:

można porównać rozbieżności Kullbacka-Leiblera zgłoszone przez t-SNE. Dziesięć razy można uruchomić t-SNE i wybrać rozwiązanie o najniższej dywergencji KL [2]

Próbowałem dwóch implementacji t-SNE:

  • python : sklearn.manifold.TSNE ().
  • R : tsne, z biblioteki (tsne).

Obie te implementacje, po ustawieniu gadatliwości, drukują błąd (rozbieżność Kullbacka-Leiblera) dla każdej iteracji. Jednak nie pozwalają użytkownikowi uzyskać tych informacji, co wydaje mi się nieco dziwne.

Na przykład kod:

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)

produkuje:

[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

O ile rozumiem, 0.270186 powinno być dywergencją KL. Jednak nie mogę uzyskać tych informacji, ani z modelu, ani z t (co jest prostym numpy.ndarray).

Aby rozwiązać ten problem, mogę: i) Wyliczyć rozbieżność KL samodzielnie, ii) Zrobić coś paskudnego w pythonie do przechwytywania i analizowania danych wyjściowych funkcji TSNE () [3]. Jednak: i) byłoby głupotą, aby ponownie obliczyć rozbieżność KL, gdy TSNE () już ją obliczyła, ii) byłoby trochę nietypowe pod względem kodu.

Czy masz jakieś inne sugestie? Czy istnieje standardowy sposób na uzyskanie tych informacji przy użyciu tej biblioteki?

Wspomniałem, że wypróbowałem bibliotekę tsne R , ale wolę, aby odpowiedzi koncentrowały się na implementacji sklearn w Pythonie .


Bibliografia

[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

żartowniś
źródło

Odpowiedzi:

4

Źródło TSNE w scikit-learn znajduje się w czystym języku Python. fit_transform()Metoda dopasowania faktycznie wywołuje funkcję prywatną, _fit()która następnie wywołuje funkcję prywatną _tsne(). Ta _tsne()funkcja ma zmienną lokalną, errorktóra jest drukowana na końcu dopasowania. Wygląda na to, że można dość łatwo zmienić jeden lub dwa wiersze kodu źródłowego, aby uzyskać tę wartość fit_transform().

Trey
źródło
Zasadniczo, co mógłbym zrobić, to ustawić self.error = error na końcu _tsne (), aby później pobrać go z instancji TSNE. Tak, ale oznaczałoby to zmianę kodu sklearn.manifold i zastanawiałem się, czy programiści wymyślili jakieś inne sposoby uzyskania informacji, a jeśli nie, to dlaczego nie (tj. Czy „błąd” jest przez nich uważany za bezużyteczny?). Ponadto, gdybym zmienił ten kod, potrzebowałbym, aby wszystkie osoby uruchamiające mój kod miały ten sam hack na swoich instalacjach sklearn. Czy to sugerujesz, czy źle to zrozumiałem?
joker
Tak, to sugerowałem jako możliwe rozwiązanie. Ponieważ scikit-learn jest open source, możesz również przesłać swoje rozwiązanie jako żądanie ściągnięcia i sprawdzić, czy autorzy uwzględnią to w przyszłych wydaniach. Nie mogę porozmawiać o tym, dlaczego zawierały lub nie zawierały różnych rzeczy.
Trey,
2
Dzięki. Jeśli ktoś jest tym zainteresowany, github.com/scikit-learn/scikit-learn/pull/3422 .
joker