Skip to main content

fastumap

UMAP in pure numpy + scipy, built so that importing it costs almost nothing.

cold import added to image
import umap (umap-learn) ~21 s (laptop) · 148 s (0.5 vCPU ×4) ~172 MB
import fastumap ~12 ms 0 MB

That gap is the reason this library exists. umap-learn's kernels are numba, and numba compiles them with LLVM the first time you import it — seconds on a laptop, minutes on a small CPU-throttled container. Here's the catch: numpy and scipy are just as compiled underneath, they just ship precompiled in the wheel, so they load in milliseconds. So the fix isn't to drop compiled code — it's to stop compiling at import time. fastumap keeps the UMAP math and leaves nothing to JIT when it loads.

Why import cost matters

It bites hardest on a small, CPU-throttled container — a fraction of a vCPU, a few workers, a health check that polls from the first second. Every worker pays the import, so the compile stacks up fast:

  • import umap ≈ 4 CPU-seconds, and pynndescent alone JIT-compiles 46 @njit functions.
  • Through a 0.5 vCPU, 4-worker cgroup that becomes ~148 s — past a ~120 s health check, so the container is killed before it serves one request.
  • More cores barely help (37.8 s at 1 CPU, 16.1 s at 2), because the compile is serial.
  • A baked numba cache doesn't save you (eager signatures skip it), and NUMBA_DISABLE_JIT=1 runs ~100× slower.

fastumap sidesteps all of it — it imports in ~12 ms, on every worker.

Quality vs umap-learn

Within 0.01–0.02 neighbour-overlap of umap-learn, ahead on global structure, and it buries PCA and the random control. Real MNIST (784-dim, single thread, make bench):

n method wall overlap@15 ↑ global corr ↑
5000 fastumap 26 s 0.333 0.310
5000 umap-learn 73 s 0.344 0.329
10000 fastumap 72 s 0.267 0.279
10000 umap-learn 83 s 0.274 0.286
20000 fastumap 110 s 0.188 0.323
20000 umap-learn 31 s 0.205 0.316
  • Wins at 5k/10k, loses at 20k — the brute-force O(n²) kNN catches up with it (approximate kNN is roadmap #15). PCA sits at ~0.02–0.06 overlap: a linear method can't compete locally.
  • umap-learn's times here reuse the numba compile paid on the first fit; a fresh process pays ~20 s every time — the cost fastumap exists to avoid.
  • chunk_count=10 closes most of the local-overlap gap (~5× slower, still deterministic). Default 1 is the fast path.

overlap@k = share of each point's k input neighbours still neighbours after projection (read it against random). global corr = Spearman corr of all pairwise distances, before vs after.

Install

pip install fastumap        # numpy + scipy, nothing else

Use

from fastumap import umap_project, spectral_project

xy  = umap_project(x, 2)                     # (n, 2)
xyz = umap_project(x, 3)                     # (n, 3)
cos = umap_project(x, 2, metric="cosine")    # text / CLS embeddings
  • cosine for encoder embeddings — euclidean on unnormalised vectors is dominated by length, not the direction that carries meaning.
  • pca_dim=100 for wide inputs (e.g. 1024-dim): pre-reduces before the kNN, overlap holds within ~0.01, off by default.

Same input + seed → bit-identical output across processes. umap_project also takes n_neighbors, min_dist, spread, n_epochs, negative_sample_rate, random_state.

In a server

Thread-safe — fresh RNG per call, no module-level state, so await asyncio.to_thread(umap_project, x, 2) is fine.

Don't refit every request. Fit once, place new points:

model = fit(window, 2)          # cache it — UMAPModel pickles
xy    = transform(model, pts)   # per request: cheap, stable across requests
  • transform ≈ refit? Keeps ~72% of a full refit's local overlap. Good for placing in-distribution points against a fixed window; refit when the window itself shifts.
  • Gone stale? Watch new-point distance to nearest training neighbour. Drifts to 2–3× the training mean → time to refit. (A timer is a weak proxy.)
  • Memory: ~20 MB per cached 5000×1024 model (train kept as float32).
  • Rolling window ("add these, drop old ones") and sparse input: not supported — both would need a rebuild. Densify sparse first; fit/transform cover the append-only case.

Speed, honestly

At 1024-dim, n=5000, fastumap is ~2× slower per call than umap-learn (~38–53 s vs ~22 s). That's inherent — a vectorised numpy SGD can't match numba's in-place walk. Use fastumap when cold-start / import cost dominates; reach for umap-learn when per-call latency on big high-dimensional batches does.

Optional Rust accelerator (rust/) — ~1.7–1.9× faster with better overlap, one abi3 wheel for Python 3.11+. Auto-detected when installed; the base stays pure numpy+scipy and is the fallback.

Guarantees (each pinned by a test)

  • numpy + scipy only at runtime — no numba, llvmlite, sklearn, or compiled code of ours.
  • Import < 200 ms · deterministic (bit-identical) · thread-safe.
  • Memory-bounded — the n×n distance matrix is never built (blocked kNN); < 200 MB at 5000×1024.
  • 2-D and 3-D, both first-class · typed, pyright strict.

Testing

make check     # lint + typecheck + tests (mirrors CI's gate)
make tox       # across Python 3.11 / 3.12 / 3.13
make fargate   # import + fit timing under docker --cpus=0.5 --memory=2g

--cpus is a CFS quota (throttles total CPU-time like a container cgroup), so the numbers mean what they will on 0.5 vCPU.

Not affiliated with UMAP

An independent reimplementation of the UMAP algorithm (McInnes, Healy, Melville, arXiv:1802.03426) — not endorsed by the authors, and not a drop-in replacement. MIT licensed.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastumap-0.1.13.tar.gz (35.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastumap-0.1.13-py3-none-any.whl (23.6 kB view details)

Uploaded Python 3

File details

Details for the file fastumap-0.1.13.tar.gz.

File metadata

  • Download URL: fastumap-0.1.13.tar.gz
  • Upload date:
  • Size: 35.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fastumap-0.1.13.tar.gz
Algorithm Hash digest
SHA256 0f265e2b561cb4391f35e5ce00529b3ef594b099f1c72979638cda0bda073bdc
MD5 75b7f13c1955767284fc6454d9b053a0
BLAKE2b-256 76966971faec8c69b16ea7433c76bcec3df2795e4674c682ebae878be85af003

See more details on using hashes here.

File details

Details for the file fastumap-0.1.13-py3-none-any.whl.

File metadata

  • Download URL: fastumap-0.1.13-py3-none-any.whl
  • Upload date:
  • Size: 23.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fastumap-0.1.13-py3-none-any.whl
Algorithm Hash digest
SHA256 10aaa6997fad9b6779779606c1a86617515975b655df0bea2278d1eb5713ec38
MD5 36dc309a6f6ffd5c4e0edbdc0c298f40
BLAKE2b-256 2bcaebbdc28023c9c9595cffc4d16034eded85d2bd32aa1e15eb0feb8d8e090d

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.29

1 file

0.2.28

1 file

0.2.27

6 files

0.2.26

1 file

0.2.20

6 files

0.2.19

6 files

0.2.18

6 files

0.2.17

6 files

0.2.16

5 files

0.2.15

5 files

0.2.14

5 files

0.2.13

5 files

0.2.12

5 files

0.2.11

5 files

0.2.10

5 files

0.2.9

5 files

0.2.8

5 files

0.2.7

5 files

0.2.6

3 files

0.2.5

3 files

0.2.4

3 files

0.2.3

3 files

0.2.2

3 files

0.2.1

3 files

0.2.0

2 files

0.1.26

2 files

0.1.25

2 files

0.1.24

2 files

0.1.23

2 files

0.1.22

2 files

0.1.21

2 files

0.1.20

2 files

0.1.19

2 files

0.1.18

2 files

0.1.16

2 files

0.1.15

2 files

0.1.14

2 files

This release

0.1.13 This release

2 files

0.1.12

2 files

0.1.11

2 files

0.1.10

2 files

0.1.9

2 files

0.1.8

2 files

0.1.7

2 files

0.1.6

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page