Skip to content

Repository files navigation

cuda.ml

CRAN_Status_Badge CRAN downloads

The goal of {cuda.ml} is to provide a simple and intuitive R interface for RAPIDS cuML. RAPIDS cuML is a suite of GPU-accelerated machine learning libraries powered by CUDA. {cuda.ml} is under active development, and currently implements R interfaces for the algorithms listed below (which is a subset of algorithms supported by RAPIDS cuML).

Supported Algorithms

Category Algorithm Notes
Clustering Density-Based Spatial Clustering of Applications with Noise (DBSCAN) Only single-GPU implementation is supported at the moment
K-Means Only single-GPU implementation is supported at the moment
Single-Linkage Agglomerative Clustering
Dimensionality Reduction Principal Components Analysis (PCA) Only single-GPU implementation is supported at the moment
Truncated Singular Value Decomposition (tSVD) Only single-GPU implementation is supported at the moment
Uniform Manifold Approximation and Projection (UMAP) Only single-GPU implementation is supported at the moment
t-Distributed Stochastic Neighbor Embedding (TSNE)
Linear Models for Regression or Classification Linear Regression (OLS)
Ridge, lasso, and elastic-net linear regression
Logistic and multinomial regression
Nonlinear Models for Regression or Classification Random Forest (RF) Classification Training is single-GPU; inference uses nvForest.
Random Forest (RF) Regression Training is single-GPU; inference uses nvForest.
nvForest inference for XGBoost, LightGBM, and Treelite models CPU and GPU inference are supported.
K-Nearest Neighbors (KNN) Classification Brute-force, IVFFlat, and IVFPQ indexes are supported.
K-Nearest Neighbors (KNN) Regression Brute-force, IVFFlat, and IVFPQ indexes are supported.
Support Vector Machine Classifier (SVC)
Epsilon-Support Vector Regression (SVR)

Guides

Examples

Using {cuda.ml} for supervised ML tasks through {parsnip}

{cuda.ml} provides {parsnip} bindings for supervised ML algorithms such as linear_reg, logistic_reg, multinom_reg, rand_forest, nearest_neighbor, svm_rbf, svm_poly, and svm_linear. Install {parsnip} separately to use these optional bindings.

Regularized models follow tidymodels conventions for penalty and mixture. When predictors need scaling, learn and apply it explicitly with a {recipes} step such as step_normalize(all_numeric_predictors()).

The following example shows how {cuda.ml} can be used as a {parsnip} engine to build a SVM classifier.

library(dplyr, warn.conflicts = FALSE)
library(parsnip)
library(cuda.ml)
set.seed(11235)

train_inds <- iris %>%
  mutate(ind = row_number()) %>%
  group_by(Species) %>%
  slice_sample(prop = 0.7)

train_data <- iris[train_inds$ind, ]
test_data <- iris[-train_inds$ind, ]

model <- svm_rbf(mode = "classification", rbf_sigma = 10, cost = 50) %>%
  set_engine("cuda.ml") %>%
  fit(Species ~ ., data = train_data)

preds <- predict(model, test_data)

cat("Confusion matrix:\n\n")
#> Confusion matrix:
preds %>%
  bind_cols(test_data %>% select(Species)) %>%
  yardstick::conf_mat(truth = Species, estimate = .pred_class)
#>             Truth
#> Prediction   setosa versicolor virginica
#>   setosa         15          0         0
#>   versicolor      0         12         1
#>   virginica       0          3        14

Using {cuda.ml} for unsupervised ML tasks

The following example shows how {cuda.ml} can be used for unsupervised ML tasks such as k-means clustering.

library(cuda.ml)

clustering <- cuda_ml_kmeans(
  iris[, which(names(iris) != "Species")],
  k = 3, max_iters = 100, seed = 0L
)

# Expected outcome: there is strong correlation
# between cluster labels and `iris$Species`
str(clustering)
#> List of 4
#>  $ labels   : int [1:150] 1 1 1 1 1 1 1 1 1 1 ...
#>  $ centroids: num [1:3, 1:4] 5.9 5.01 6.85 2.75 3.43 ...
#>  $ inertia  : num 78.9
#>  $ n_iter   : int 100

library(dplyr, warn.conflicts = FALSE)
tibble(cluster_id = clustering$labels, species = iris$Species) %>%
  group_by(cluster_id) %>% count(species)
#> # A tibble: 5 × 3
#> # Groups:   cluster_id [3]
#>   cluster_id species        n
#>        <int> <fct>      <int>
#> 1          0 versicolor    48
#> 2          0 virginica     14
#> 3          1 setosa        50
#> 4          2 versicolor     2
#> 5          2 virginica     36

Using {cuda.ml} for visualizations

{cuda.ml} also features R interfaces for algorithms such as UMAP and t-SNE, which are useful when one needs to visualize clusters of high-dimensional data points by embedding them onto low-dimensional manifolds (i.e., 4 dimensions or fewer).

For example, the code snippet below shows how cuda_ml_umap() can be used to visualize the MNIST hand-written digits dataset, and also, the coloring based on the true label of each sample demonstrates how well the UMAP algorithm transforms different hand writings of the same digit into nearby points in a 2D embedding:

library(cuda.ml)
library(ggplot2)
library(magrittr)

# load mnist
source("data-raw/load-mnist.R")
str(mnist_images)
#>  int [1:28, 1:28, 1:60000] 0 0 0 0 0 0 0 0 0 0 ...
str(mnist_labels)
#>  int [1:60000(1d)] 5 0 4 1 9 2 1 3 1 4 ...


# flatten each image to a 1d array, combine into a matrix with 1 row per image
flatten <- function(img) {
  dim(img) <- NULL
  img
}

flattened_mnist_images <-
  mnist_images %>% asplit(3) %>% lapply(flatten) %>% do.call(rbind, .)

# embed
embedding <- cuda_ml_umap(
  flattened_mnist_images, n_components = 2, n_neighbors = 50,
  local_connectivity = 15, repulsion_strength = 10, seed = 0L
)

str(embedding$transformed_data)
#>  num [1:60000, 1:2] -7.08 -32.55 9.61 20.65 12.25 ...

# visualize
embedding$transformed_data %>%
  as.data.frame() %>%
  dplyr::mutate(Label = factor(mnist_labels)) %>%
  ggplot(aes(x = V1, y = V2, color = Label)) +
  geom_point(alpha = .5, size = .5) +
  labs(title = "UMAP: Uniform Manifold Approximation and Projection",
       subtitle = "Two Dimensional Embedding of MNIST")

A two-dimensional UMAP embedding of MNIST digits colored by digit label.

From this type of visualization, we can qualitatively understand the following about the MNIST dataset:

  • The dataset can be reasonably classified into some number of categories.
  • The right number of categories may be any where between 9 and 11.
  • While there are some categories that are clearly distinguishable from others, there are others that have less clear boundaries with their neighbors.
  • A small fraction of data points did not fit particularly well into any of the categories.
  • Most data points belonging to the same digit category are clustered together in the UMAP output

Installation

Install the R package from CRAN, then prepare its native backend and runtime:

install.packages("cuda.ml")
cuda.ml::cuda_ml_install()

The CRAN package is a portable R installer and loader. It contains no compiled code, so install.packages("cuda.ml") does not need a compiler, CUDA, RAPIDS, Python, or conda. Loading it is silent and side-effect free:

library(cuda.ml)
info <- cuda_ml_backend_info()
stopifnot(
  identical(info$backend, "download"),
  info$backend_available
)

library(cuda.ml) does not inspect the GPU, create a cache, contact the network, or load native code. cuda_ml_backend_info() reports the selected platform and R-version backend, its exact library versions, and whether the managed cache is complete. It does not report whether a GPU can execute a model.

Runtime provisioning

cuda_ml_install() first downloads the small backend archive for the current R minor version from the package’s GitHub Releases. It verifies the archive and native library against hashes shipped in the R package. It then downloads the locked CUDA 13.2.2 and RAPIDS cuML and nvForest 26.06 wheels directly from their upstream Python package hosts. The current runtime is about 1.6 GiB, so this step can take several minutes. Treelite 4.7.0 is linked into the backend and is not a runtime download.

For CPU-only nvForest inference, use cuda_ml_install(device = "cpu"). This installs a separate backend that is roughly 1 MiB to download and 3 MiB when installed. It does not include cuML or any CUDA runtime libraries, and it requires neither an NVIDIA GPU nor an NVIDIA driver. Random forests trained on a GPU by cuda_ml_rand_forest() can be serialized and restored with device = "cpu" on this smaller deployment backend. An existing complete backend installation can also execute nvForest models on CPU; the smaller backend avoids that runtime for CPU-only deployments.

cuda_ml_install() does not require a GPU or NVIDIA driver, and repeated calls reuse the completed cache. It does not load the backend or initialize CUDA. Model operations do not provision the runtime implicitly; when the cache is absent, they report the installation command. After provisioning, GPU-backed operations require only a supported NVIDIA GPU and driver.

The default cache is tools::R_user_dir("cuda.ml", "cache"). Set CUDA_ML_CACHE_DIR to use a different location:

Sys.setenv(CUDA_ML_CACHE_DIR = "/opt/cuda-ml-cache")
cuda.ml::cuda_ml_install()

For an internal or offline mirror, set CUDA_ML_BACKEND_MIRROR to an https:// or file:// directory containing the exact locked backend archive. Hash verification remains enabled.

Supported systems

Prebuilt backends target Linux x86_64 with glibc 2.28 or newer rather than a specific distribution. This includes current Ubuntu, Debian, RHEL-compatible, and WSL2 Linux distributions that meet the glibc requirement. Following the RAPIDS 26.06 platform requirements, the binary requires an NVIDIA driver version 580 or newer and supports GPU compute capabilities 7.5, 8.0, 8.6, 8.9, 9.0, 10.0, and 12.0. The compute capability 12.0 PTX image also provides forward compatibility for newer GPUs supported by CUDA, following CUDA’s forward-compatibility model.

Native Windows, macOS, Linux ARM64, musl-based Linux distributions, and glibc versions older than 2.28 are not currently supported.

Build the backend from source

To compile the native backend directly on the host without Docker or a prebuilt cuda.ml backend, install GNU C++ 14 or newer and run:

cuda.ml::cuda_ml_install(source = TRUE)

The default managed source build downloads and verifies about 1.7 GiB of exact locked build artifacts from PyPI and GitHub. These provide CUDA Toolkit 13.2.2, cuML and nvForest 26.06, Treelite 4.7.0, CMake, and Ninja. Python, Conda, Docker, a system CUDA Toolkit, a system RAPIDS installation, and a GPU are not required for the build. Linux x86_64 with glibc 2.28 or newer and GNU C++ 14 or newer are required. The installer prefers g++-14, then g++, on PATH; set CUDA_ML_CXX to override this discovery.

The toolchain and compiled backend are cached under CUDA_ML_CACHE_DIR, or the default cuda.ml user cache. Calling the function again with the same inputs is a no-op. By default, a managed build detects the distinct CUDA-visible GPU compute capabilities reported by nvidia-smi and compiles their real targets. It honors CUDA_VISIBLE_DEVICES. If detection is unavailable, it uses the package’s portable GPU architecture list, so GPU-free build hosts remain supported.

This usually reduces build time and backend size, but the resulting backend supports only the detected GPU architectures. Use architectures = "portable" to force a relocatable build, or architectures = "native" to require successful detection. You can also supply an explicit semicolon-separated CMake CUDA architecture list, for example architectures = "86-real;89-real".

To use a native toolchain already installed on the host and make no downloads, provide every build input explicitly:

Sys.setenv(
  CUDA_HOME = "/usr/local/cuda-13.2",
  CUML_PREFIX = "/opt/rapids-26.06",
  CUML_CUDA_ARCHITECTURES = "86-real",
  CUDA_ML_CXX = "/usr/bin/g++-14"
)
cuda.ml::cuda_ml_install(source = TRUE, dependencies = "host")

This host pathway requires CUDA Toolkit 13.2.2; a CUML_PREFIX containing cuML and nvForest 26.06, Treelite 4.7.0 headers, and lib/libtreelite_static.a; GNU C++ 14 or newer; and CMake 3.21.1 or newer. The CUDA, RAPIDS, and Treelite prefixes must remain in place because the compiled backend links to their libraries.

Packaging

CRAN installation and checks are network-free. The package contacts the network only when cuda_ml_install() is called explicitly. Native backend archives are built in a pinned manylinux 2.28 container, audited for their glibc and libstdc++ requirements, and hosted as GitHub Release assets. One archive is published for each supported R minor version.

Development version

A development installation uses the same downloaded backend pathway:

# install.packages("devtools")
devtools::install_github("mlverse/cuda.ml")
cuda.ml::cuda_ml_install()

Appendix

Inspect MNIST images
plot_mnist(1:64)
A grid of 64 MNIST handwritten digit images.

About

R interface for cuML

Topics

Resources

Stars

40 stars

Watchers

5 watching

Forks

Releases

Packages

Used by

Contributors

Languages