Open-source project
CannyLab/tsne-cuda avatar
CannyLab/tsne-cuda

tsne-cuda runs FIt-SNE on the GPU but still only produces two dimensions

GPU Accelerated t-SNE for CUDA with Python bindings

1,958 stars138 forksCudaBSD-3-Clause

At a glance

What is it?
TSNE-CUDA is a CUDA implementation of the FIt-SNE algorithm with Python bindings that mirror sklearn.manifold.TSNE. It is fast on large inputs and deliberately narrow elsewhere: n_components is fixed at 2, and CUDA 9.0 or later has to come from a source build.
Who is it for?
Adopt tsne-cuda when you repeatedly embed large point sets and sklearn or Multicore-TSNE has become the bottleneck, and switch by changing the import in existing code. Do not adopt it for anything other than 2D output, since more dimensions are not planned.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 93 days ago.
What is it written in?
Mainly Cuda, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The benchmark claims are the project's argument, so read them closely

The README leads with speed numbers and they deserve the same scrutiny. It states the implementation of t-SNE can be up to 1200x faster than sklearn, or up to 50x faster than Multicore-TSNE when used with the right GPU. The qualifiers are in the sentence: with the right GPU, and up to.

The concrete dataset figures are more grounded. On MNIST, the README states t-SNE-CUDA runs on the raw pixels, 60000 images by 768 dimensions, in under 7 seconds. On CIFAR-10 it runs on classifier output, 50000 images by 1024 dimensions, in under 6 seconds, while the full pixel set takes under 12 seconds.

That CIFAR line contains the practical warning. The README explains that Euclidean distance is a poor metric in raw pixel space, leading to poor quality embeddings. The speedup on pixels is therefore not something to want; you are meant to embed features rather than pixels, and the faster pixel path produces a worse picture.

The quality comparison is stated separately from the timing comparison: the embeddings do not differ significantly from the state of the art implementations, and the MNIST cluster comparison gives MULTICORE-4 at 501s, BH-TSNE at 1156s and t-SNE-CUDA at 6.98s. We have not run these, and the figures come from the project's own README.

One caveat about the synthetic benchmark: the README notes the dashed lines on sklearn, BH-TSNE and MULTICORE-4 are projected times assuming an O(n log n) implementation. Projected, not measured.

The Python API is a deliberate clone of sklearn.manifold.TSNE

The migration story is short because the wrapper mirrors sklearn. The README states the Python wrappers subscribe to the same API as sklearn.manifold.TSNE, and the usage is a single import swap.

python
from tsnecuda import TSNE
X_embedded = TSNE(n_components=2, perplexity=15, learning_rate=10).fit_transform(X)

That means perplexity and learning_rate carry the same meaning they carry in sklearn, and fit_transform returns the embedding in the shape you would expect. For an existing notebook, the change is the import line.

The one parameter you cannot carry over is the number of components. The README states only n_components=2 is supported, and explains that more dimensions would require significant changes to the code, with no current plans to add them. If your pipeline compares 2D and 3D embeddings, the 3D case stays in sklearn.

The repository also exposes a C++ interface, with a Basic-Usage:-Cxx page in the wiki alongside the Python usage page. That matters for anyone embedding this as a library rather than a Python dependency, since the two have different installation paths.

CUDA availability splits installation into three paths

Installation is the awkward part, and the README splits it by CUDA version.

bash
conda install tsnecuda -c conda-forge

That path covers CUDA 10.1 and 10.2 with prebuilt binaries. For CUDA 9.0 and later, the README says the project supports source installation and points to the wiki for current instructions, and INSTALL.md at the repository root is the file it links to. The CMakeLists.txt, the cmake/ directory and the packaging/ directory are what a source build uses.

The practical consequence for a team is that the install method is chosen by your driver and CUDA toolkit, not by preference. A machine on a newer CUDA than 10.2 is building from source, which means a compiler toolchain and a C++ build in your environment. If your CI image pins an old CUDA, the conda channel is available; if it floats, expect to maintain a source build.

The example scripts in the repository, examples/mnist.py and examples/cifar.py, are the closest thing to a smoke test for a new install, since they correspond to the two datasets quoted in the benchmarks.

Version 4 rebuilt the build system after three years of silence

The release history has a gap worth noting. Version 3.0.1 shipped on 2022-02-07, then nothing until 4.0.0 and 4.0.1, both on 2026-07-22 within hours of each other. The last push to the repository was on 2026-07-22, so the project has been quiet for the roughly three months since.

That pattern reads as a maintenance burst rather than a steady cadence. It does not mean the project is dead, and it does not mean you can expect regular patches. The practical read is that you should pin an exact version and expect to handle CUDA compatibility yourself.

The repository is a C++ project with a Python layer rather than a pure Python package: the primary language is Cuda, and the tree includes src/, third_party/, examples/, packaging/ and a visualization/ directory. That shape means the conda and PyPI artifacts are built binaries, and the Python import is a binding to a compiled extension rather than an implementation in Python.

The CUDA versions listed in the README badge run from 10.1 through 12.2, and the badge is the project's own statement of which toolkits it built against.

Where a GPU t-SNE is the wrong choice

Two cases stand out.

The first is anything needing more than two dimensions. This is a stated limitation rather than a rough edge, and there is no workaround inside the library.

The second is input size. A GPU t-SNE exists to amortise a large neighbour search and a large gradient optimisation over many points. The README's own synthetic benchmark sweeps from 1K to 10M points, and the quality comparison in the README is on MNIST. For a few thousand points, the transfer cost of moving data to the device and back is not paid back by a faster kernel, and sklearn's implementation is simpler to debug. The README does not give a crossover point, so the honest answer is that you have to measure your own data.

The other alternative is staying on CPU with Multicore-TSNE, which the README compares against directly and which avoids the CUDA dependency entirely. If your deployment environment has no GPU, that comparison is not worth having.

Provenance, citation and licensing

The implementation is a CUDA port of FIt-SNE, and the README is explicit that this is built on top of existing work: L. van der Maaten's paper, the FIt-SNE and Multicore-TSNE implementations, BHTSNE, the LONESTAR-GPU project, FAISS, GTest, CXXopts and OrangeOwl's CUDA utilities. A bibliography in the README is not padding here; it tells you which pieces of the numerical method come from where.

The associated paper is GPU accelerated t-distributed stochastic neighbor embedding by Chan, Rao, Huang and Canny, in Journal of Parallel and Distributed Computing, volume 131, pages 1 to 13, 2019, and the README asks for a citation if the library was useful in research.

Licensing is BSD-3 for this project's own code, and the README notes that the vendored components remain under their own licences. The LICENSE file is at the repository root. If you are shipping a product that links this, the FAISS and GTest terms are the ones to read alongside it.

Editorial conclusion

Adopt tsne-cuda when you repeatedly embed large point sets and sklearn or Multicore-TSNE has become the bottleneck, and switch by changing the import in existing code. Do not adopt it for anything other than 2D output, since more dimensions are not planned. Before installing, check the INSTALL.md instructions for your CUDA version, because the prebuilt conda packages cover only CUDA 10.1 and 10.2.

Frequently asked questions

How do I install tsne-cuda?

For CUDA 10.1 and 10.2, run conda install tsnecuda -c conda-forge. For CUDA 9.0 and later the README points to source installation, with the current instructions in INSTALL.md and the wiki.

Is the tsne-cuda Python API the same as sklearn?

Yes. The README states the Python wrappers subscribe to the same API as sklearn.manifold.TSNE, so switching is a change of import: from tsnecuda import TSNE, then TSNE(n_components=2, perplexity=15, learning_rate=10).fit_transform(X).

Can tsne-cuda produce more than two dimensions?

No. The README states only n_components=2 is supported, and that more dimensions would require significant changes to the code. There are no current plans to add them.

Does tsne-cuda need CUDA installed on my machine?

Yes. The primary language is Cuda and the Python import binds a compiled extension, so a CUDA toolkit is required. Prebuilt conda binaries exist only for CUDA 10.1 and 10.2; newer toolkits need a source build.

Official sources

  1. CannyLab/tsne-cuda on GitHub
  2. Issues
  3. License: BSD-3-Clause
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cannylab-tsne-cuda.svg)](https://hysenlabs.com/projects/cannylab-tsne-cuda)

Was this useful?