Skip to content

Commit

Permalink
add simplicial_set_embedding to umap (#278)
Browse files Browse the repository at this point in the history
* add simplicial_set_embedding to umap

* add not to

* add release note

* fix typo
  • Loading branch information
Intron7 authored Oct 21, 2024
1 parent 962ceba commit 3f11a28
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 29 deletions.
2 changes: 1 addition & 1 deletion docs/release-notes/0.10.11.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
```{rubric} Features
```


```{rubric} Performance
```

Expand All @@ -16,3 +15,4 @@
* Adds support for `rapids-24.10` {pr}`277` {smaller}`S Dicks`
* Updates testing to use `rapids-24.10` {pr}`277` {smaller}`S Dicks`
* Updates `docker` image to use `rapids-24.10` {pr}`277` {smaller}`S Dicks`
* `tl.UMAP` now uses `simplicial_set_embedding` for `rapids>=24.10` {pr}`278` {smaller}`S Dicks`
86 changes: 58 additions & 28 deletions src/rapids_singlecell/tools/_umap.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@

from typing import TYPE_CHECKING, Literal

import cuml
import cupy as cp
from cuml.manifold.simpl_set import simplicial_set_embedding
from cuml.manifold.umap import UMAP
from cuml.manifold.umap_utils import find_ab_params
from cupyx.scipy import sparse
from packaging.version import parse as parse_version
from scanpy._utils import NeighborsView
from sklearn.utils import check_random_state

Expand Down Expand Up @@ -149,37 +154,62 @@ def umap(
) # 0 is not a valid value for rapids, unlike original umap

n_obs = adata.shape[0]
n_neighbors = neigh_params["n_neighbors"]
if neigh_params.get("method") == "rapids":
knn_dist = neighbors["distances"].data.reshape(n_obs, n_neighbors)
knn_indices = neighbors["distances"].indices.reshape(n_obs, n_neighbors)
pre_knn = (knn_indices, knn_dist)
if parse_version(cuml.__version__) < parse_version("24.10"):
# `simplicial_set_embedding` is bugged in cuml<24.10. This is why we use `UMAP` instead.
n_neighbors = neigh_params["n_neighbors"]
if neigh_params.get("method") == "rapids":
knn_dist = neighbors["distances"].data.reshape(n_obs, n_neighbors)
knn_indices = neighbors["distances"].indices.reshape(n_obs, n_neighbors)
pre_knn = (knn_indices, knn_dist)
else:
pre_knn = None

if init_pos == "auto":
init_pos = "spectral" if n_obs < 1000000 else "random"

umap = UMAP(
n_neighbors=n_neighbors,
n_components=n_components,
metric=neigh_params.get("metric", "euclidean"),
metric_kwds=neigh_params.get("metric_kwds", None),
n_epochs=n_epochs,
learning_rate=alpha,
init=init_pos,
min_dist=min_dist,
spread=spread,
negative_sample_rate=negative_sample_rate,
a=a,
b=b,
random_state=random_state,
output_type="numpy",
precomputed_knn=pre_knn,
)

X_umap = umap.fit_transform(X)
else:
pre_knn = None

if init_pos == "auto":
init_pos = "spectral" if n_obs < 1000000 else "random"

umap = UMAP(
n_neighbors=n_neighbors,
n_components=n_components,
metric=neigh_params.get("metric", "euclidean"),
metric_kwds=neigh_params.get("metric_kwds", None),
n_epochs=n_epochs,
learning_rate=alpha,
init=init_pos,
min_dist=min_dist,
spread=spread,
negative_sample_rate=negative_sample_rate,
a=a,
b=b,
random_state=random_state,
output_type="numpy",
precomputed_knn=pre_knn,
)
pre_knn = neighbors["connectivities"]

if init_pos == "auto":
init_pos = "spectral" if n_obs < 1000000 else "random"

X_umap = simplicial_set_embedding(
data=cp.array(X),
graph=sparse.coo_matrix(pre_knn),
n_components=n_components,
initial_alpha=alpha,
a=a,
b=b,
negative_sample_rate=negative_sample_rate,
n_epochs=n_epochs,
init=init_pos,
random_state=random_state,
metric=neigh_params.get("metric", "euclidean"),
metric_kwds=neigh_params.get("metric_kwds", None),
)
X_umap = cp.asarray(X_umap).get()

key_obsm, key_uns = ("X_umap", "umap") if key_added is None else [key_added] * 2
adata.obsm[key_obsm] = umap.fit_transform(X)
adata.obsm[key_obsm] = X_umap

adata.uns[key_uns] = {"params": stored_params}
return adata if copy else None

0 comments on commit 3f11a28

Please sign in to comment.