Skip to content

Commit 6719b6c

Browse files
authored
Merge pull request #7503 from rapidsai/release/25.12
Forward-merge release/25.12 into main
2 parents 6b42da5 + 78cf0e7 commit 6719b6c

File tree

2 files changed

+75
-43
lines changed

2 files changed

+75
-43
lines changed

python/cuml/cuml/manifold/t_sne.pyx

Lines changed: 62 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ cdef extern from "cuml/manifold/tsne.h" namespace "ML" nogil:
104104

105105
# Changed in scikit-learn version 1.5: Parameter name changed from n_iter to max_iter.
106106
if Version(sklearn.__version__) >= Version("1.5.0"):
107-
_SKLEARN_N_ITER_PARAM = "max_iter"
107+
_SKLEARN_MAX_ITER_PARAM = "max_iter"
108108
else:
109-
_SKLEARN_N_ITER_PARAM = "n_iter"
109+
_SKLEARN_MAX_ITER_PARAM = "n_iter"
110110

111111
_SUPPORTED_METRICS = {
112112
"l2": DistanceType.L2SqrtExpanded,
@@ -173,7 +173,6 @@ cdef _init_params(self, int n_samples, TSNEParams &params):
173173
adaptive_learning = _check_mapping(
174174
self, "learning_rate_method", {"adaptive": True, "none": False, None: False}
175175
)
176-
n_iter = _check_numeric(self, "n_iter", gt=0)
177176
min_grad_norm = _check_numeric(self, "min_grad_norm", ge=0)
178177
angle = _check_numeric(self, "angle", ge=0, le=1)
179178
n_neighbors = _check_numeric(self, "n_neighbors", gt=0)
@@ -188,7 +187,19 @@ cdef _init_params(self, int n_samples, TSNEParams &params):
188187
if n_samples < 2:
189188
raise ValueError("TSNE requires >= 2 samples")
190189

191-
exaggeration_iter = min(exaggeration_iter, self.n_iter)
190+
if self.n_iter != "deprecated":
191+
warnings.warn(
192+
(
193+
"`n_iter` was deprecated in 25.12 and will be removed in 26.02. "
194+
"Please use `max_iter` instead."
195+
),
196+
FutureWarning,
197+
)
198+
max_iter = _check_numeric(self, "n_iter", gt=0)
199+
else:
200+
max_iter = _check_numeric(self, "max_iter", gt=0)
201+
202+
exaggeration_iter = min(exaggeration_iter, max_iter)
192203
if n_neighbors > 1023:
193204
warnings.warn(
194205
f"n_neighbors ({n_neighbors}) should be < 1024, "
@@ -237,7 +248,7 @@ cdef _init_params(self, int n_samples, TSNEParams &params):
237248
params.min_gain = 0.01
238249
params.pre_learning_rate = pre_learning_rate
239250
params.post_learning_rate = post_learning_rate
240-
params.max_iter = n_iter
251+
params.max_iter = max_iter
241252
params.min_grad_norm = min_grad_norm
242253
params.pre_momentum = pre_momentum
243254
params.post_momentum = post_momentum
@@ -283,11 +294,18 @@ class TSNE(Base,
283294
learning_rate : float (default 200.0)
284295
The learning rate usually between (10, 1000). If this is too high,
285296
t-SNE could look like a cloud / ball of points.
286-
n_iter : int (default 1000)
297+
max_iter : int (default 1000)
287298
The more epochs, the more stable/accurate the final embedding.
288299
n_iter_without_progress : int (default 300)
289300
Currently unused. When the KL Divergence becomes too small after some
290301
iterations, terminate t-SNE early.
302+
n_iter : int (default 1000)
303+
304+
.. deprecated:: 25.12
305+
``n_iter`` has been renamed to ``max_iter`` to better match the
306+
API of ``sklearn.manifold.TSNE``. ``n_iter`` is deprecated in favor
307+
of ``max_iter`` and will be removed in 26.02.
308+
291309
min_grad_norm : float (default 1e-07)
292310
The minimum gradient norm for when t-SNE will terminate early.
293311
Used in the 'exact' and 'fft' algorithms. Consider reducing if
@@ -417,8 +435,9 @@ class TSNE(Base,
417435
"early_exaggeration",
418436
"late_exaggeration",
419437
"learning_rate",
420-
"n_iter",
438+
"max_iter",
421439
"n_iter_without_progress",
440+
"n_iter",
422441
"min_grad_norm",
423442
"metric",
424443
"metric_params",
@@ -469,8 +488,8 @@ class TSNE(Base,
469488
# For now have `learning_rate="auto"` just use cuml's default
470489
params["learning_rate"]: model.learning_rate
471490

472-
if (max_iter := getattr(model, _SKLEARN_N_ITER_PARAM, None)) is not None:
473-
params["n_iter"] = max_iter
491+
if (max_iter := getattr(model, _SKLEARN_MAX_ITER_PARAM, None)) is not None:
492+
params["max_iter"] = max_iter
474493

475494
return params
476495

@@ -489,7 +508,7 @@ class TSNE(Base,
489508
"init": self.init,
490509
"random_state": self.random_state,
491510
"method": method,
492-
_SKLEARN_N_ITER_PARAM: self.n_iter,
511+
_SKLEARN_MAX_ITER_PARAM: self.max_iter,
493512
}
494513
return params
495514

@@ -511,44 +530,45 @@ class TSNE(Base,
511530
**super()._attrs_to_cpu(model)
512531
}
513532

514-
def __init__(self, *,
515-
n_components=2,
516-
perplexity=30.0,
517-
early_exaggeration=12.0,
518-
late_exaggeration=1.0,
519-
learning_rate=200.0,
520-
n_iter=1000,
521-
n_iter_without_progress=300,
522-
min_grad_norm=1e-07,
523-
metric='euclidean',
524-
metric_params=None,
525-
init='random',
526-
random_state=None,
527-
method='fft',
528-
angle=0.5,
529-
n_neighbors=90,
530-
perplexity_max_iter=100,
531-
exaggeration_iter=250,
532-
pre_momentum=0.5,
533-
post_momentum=0.8,
534-
learning_rate_method='adaptive',
535-
square_distances=True,
536-
precomputed_knn=None,
537-
verbose=False,
538-
handle=None,
539-
output_type=None):
540-
541-
super().__init__(handle=handle,
542-
verbose=verbose,
543-
output_type=output_type)
544-
533+
def __init__(
534+
self,
535+
*,
536+
n_components=2,
537+
perplexity=30.0,
538+
early_exaggeration=12.0,
539+
late_exaggeration=1.0,
540+
learning_rate=200.0,
541+
max_iter=1000,
542+
n_iter_without_progress=300,
543+
n_iter="deprecated",
544+
min_grad_norm=1e-07,
545+
metric='euclidean',
546+
metric_params=None,
547+
init='random',
548+
random_state=None,
549+
method='fft',
550+
angle=0.5,
551+
n_neighbors=90,
552+
perplexity_max_iter=100,
553+
exaggeration_iter=250,
554+
pre_momentum=0.5,
555+
post_momentum=0.8,
556+
learning_rate_method='adaptive',
557+
square_distances=True,
558+
precomputed_knn=None,
559+
verbose=False,
560+
handle=None,
561+
output_type=None,
562+
):
563+
super().__init__(handle=handle, verbose=verbose, output_type=output_type)
545564
self.n_components = n_components
546565
self.perplexity = perplexity
547566
self.early_exaggeration = early_exaggeration
548567
self.late_exaggeration = late_exaggeration
549568
self.learning_rate = learning_rate
550-
self.n_iter = n_iter
569+
self.max_iter = max_iter
551570
self.n_iter_without_progress = n_iter_without_progress
571+
self.n_iter = n_iter
552572
self.min_grad_norm = min_grad_norm
553573
self.metric = metric
554574
self.metric_params = metric_params

python/cuml/tests/test_tsne.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ def test_tsne_large(nrows, ncols, method):
219219
tsne = TSNE(
220220
random_state=1,
221221
exaggeration_iter=1,
222-
n_iter=2,
222+
max_iter=2,
223223
method=method,
224224
min_grad_norm=1e-12,
225225
)
@@ -430,5 +430,17 @@ def test_tsne_n_iter(algorithm):
430430
n_samples=1000, n_features=64, centers=5, random_state=42
431431
)
432432
model = TSNE(n_components=2, random_state=42).fit(X)
433+
assert model.n_iter_ > 0
434+
assert model.n_iter_ <= model.max_iter
435+
436+
437+
def test_tsne_n_iter_deprecated():
438+
X, _ = make_blobs(
439+
n_samples=1000, n_features=64, centers=5, random_state=42
440+
)
441+
model = TSNE(n_components=2, random_state=42, n_iter=2)
442+
with pytest.warns(FutureWarning, match="n_iter"):
443+
model.fit(X)
444+
433445
assert model.n_iter_ > 0
434446
assert model.n_iter_ <= model.n_iter

0 commit comments

Comments
 (0)