|
20 | 20 | from time import time |
21 | 21 | import numpy as np |
22 | 22 | from scipy.sparse import issparse |
| 23 | +import daal4py |
| 24 | +from daal4py.sklearn._utils import daal_check_version, sklearn_check_version |
23 | 25 |
|
24 | 26 | from sklearn.manifold import TSNE as BaseTSNE |
25 | 27 | from sklearn.decomposition import PCA |
|
28 | 30 | from sklearn.utils import check_random_state, check_array |
29 | 31 |
|
30 | 32 | from ..neighbors import NearestNeighbors |
31 | | -from .._utils import sklearn_check_version |
32 | 33 | from .._device_offload import support_usm_ndarray |
33 | 34 |
|
34 | 35 | if sklearn_check_version('0.22'): |
@@ -88,6 +89,48 @@ def fit(self, X, y=None): |
88 | 89 | """ |
89 | 90 | return super().fit(X, y) |
90 | 91 |
|
| 92 | + def _daal_tsne(self, P, n_samples, X_embedded): |
| 93 | + """Runs t-SNE.""" |
| 94 | + # t-SNE minimizes the Kullback-Leiber divergence of the Gaussians P |
| 95 | + # and the Student's t-distributions Q. The optimization algorithm that |
| 96 | + # we use is batch gradient descent with two stages: |
| 97 | + # * initial optimization with early exaggeration and momentum at 0.5 |
| 98 | + # * final optimization with momentum at 0.8 |
| 99 | + |
| 100 | + # N, nnz, n_iter_without_progress, n_iter |
| 101 | + size_iter = np.array([[n_samples], [P.nnz], [self.n_iter_without_progress], |
| 102 | + [self.n_iter]], dtype=P.dtype) |
| 103 | + params = np.array([[self.early_exaggeration], [self._learning_rate], |
| 104 | + [self.min_grad_norm], [self.angle]], dtype=P.dtype) |
| 105 | + results = np.zeros((3, 1), dtype=P.dtype) # curIter, error, gradNorm |
| 106 | + |
| 107 | + if P.dtype == np.float64: |
| 108 | + daal4py.daal_tsne_gradient_descent( |
| 109 | + X_embedded, |
| 110 | + P, |
| 111 | + size_iter, |
| 112 | + params, |
| 113 | + results, |
| 114 | + 0) |
| 115 | + elif P.dtype == np.float32: |
| 116 | + daal4py.daal_tsne_gradient_descent( |
| 117 | + X_embedded, |
| 118 | + P, |
| 119 | + size_iter, |
| 120 | + params, |
| 121 | + results, |
| 122 | + 1) |
| 123 | + else: |
| 124 | + raise ValueError("unsupported dtype of 'P' matrix") |
| 125 | + |
| 126 | + # Save the final number of iterations |
| 127 | + self.n_iter_ = int(results[0][0]) |
| 128 | + |
| 129 | + # Save Kullback-Leiber divergence |
| 130 | + self.kl_divergence_ = results[1][0] |
| 131 | + |
| 132 | + return X_embedded |
| 133 | + |
91 | 134 | def _fit(self, X, skip_num_points=0): |
92 | 135 | """Private function to fit the model using X as training data.""" |
93 | 136 | if isinstance(self.init, str) and self.init == 'warn': |
@@ -293,6 +336,16 @@ def _fit(self, X, skip_num_points=0): |
293 | 336 | # Laurens van der Maaten, 2009. |
294 | 337 | degrees_of_freedom = max(self.n_components - 1, 1) |
295 | 338 |
|
| 339 | + daal_ready = self.method == 'barnes_hut' and self.n_components == 2 and \ |
| 340 | + self.verbose == 0 and daal_check_version((2021, 'P', 600)) |
| 341 | + |
| 342 | + if daal_ready: |
| 343 | + X_embedded = check_array(X_embedded, dtype=[np.float32, np.float64]) |
| 344 | + return self._daal_tsne( |
| 345 | + P, |
| 346 | + n_samples, |
| 347 | + X_embedded=X_embedded |
| 348 | + ) |
296 | 349 | return self._tsne( |
297 | 350 | P, |
298 | 351 | degrees_of_freedom, |
|
0 commit comments