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).
| 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) |
- Get started with cuda.ml
- Install and manage cuda.ml
- Use cuda.ml with tidymodels
- Save and restore models
- nvForest inference and deployment
{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 14The 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{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")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
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.
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.
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.
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.
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.
A development installation uses the same downloaded backend pathway:
# install.packages("devtools")
devtools::install_github("mlverse/cuda.ml")
cuda.ml::cuda_ml_install()
