Use cuda.ml with tidymodels

cuda.ml registers parsnip engines for its supervised models. This gives the models the same specification, fitting, and prediction interface as other parsnip engines while training with cuML. Use the direct cuda.ml API when you need an algorithm that has no parsnip specification or detailed control over a solver. See Getting started for installation and runtime setup.

Available model specifications

Loading cuda.ml registers the engine name "cuda.ml" for these parsnip specifications:

parsnip specification mode prediction types
linear_reg() regression "numeric"
logistic_reg() classification "class", "prob"
multinom_reg() classification "class", "prob"
rand_forest() classification "class", "prob"
rand_forest() regression "numeric"
nearest_neighbor() classification "class", "prob"
nearest_neighbor() regression "numeric"
svm_rbf() classification "class"
svm_rbf() regression "numeric"
svm_poly() classification "class"
svm_poly() regression "numeric"
svm_linear() classification "class"
svm_linear() regression "numeric"

The SVM engines do not register probability predictions. In particular, predict(fitted_svm, new_data, type = "prob") is not supported. Use logistic_reg(), multinom_reg(), rand_forest(), or nearest_neighbor() when a classification workflow requires probabilities.

Use logistic_reg() for a two-level outcome and multinom_reg() for an outcome with more than two levels. Both specifications call cuda_ml_logistic_reg(); the outcome determines whether cuda.ml uses its binary or multinomial loss.

Set the engine

Set the mode and common arguments in a parsnip specification, then select the cuda.ml engine:

library(cuda.ml)
library(parsnip)

forest_spec <- rand_forest(
  mode = "classification",
  mtry = 2,
  trees = 500,
  min_n = 5
) |>
  set_engine(
    "cuda.ml",
    max_depth = 20,
    n_bins = 256
  )

set.seed(1)
forest_fit <- fit(forest_spec, class ~ ., data = modeldata::hpc_data)

class_predictions <- predict(forest_fit, modeldata::hpc_data, type = "class")
probabilities <- predict(forest_fit, modeldata::hpc_data, type = "prob")

Arguments in the model specification, such as mtry, are common parsnip arguments. Arguments in set_engine(), such as max_depth, are specific to cuda.ml. Put each argument in only one place.

Preprocess with a recipe

cuda.ml’s supervised models require numeric predictors. Scaling is especially important for KNN and SVM models because their fits depend on distances or margins. It is also usually appropriate for penalized linear and logistic models. Fit preprocessing parameters on the training data only, then apply the same recipe to assessment or production data.

This example normalizes the predictors before fitting an exact KNN classifier. A workflow keeps the preprocessing and model specifications together. fit() estimates the recipe from the training data before fitting the cuda.ml model, and predict() applies the recipe to new data before calling the model engine.

library(cuda.ml)
library(parsnip)
library(recipes)
library(workflows)

set.seed(1)
training_rows <- sample(
  seq_len(nrow(modeldata::two_class_dat)),
  floor(0.8 * nrow(modeldata::two_class_dat))
)
training_data <- modeldata::two_class_dat[training_rows, ]
testing_data <- modeldata::two_class_dat[-training_rows, ]

classifier_recipe <- recipe(Class ~ ., data = training_data) |>
  step_normalize(all_numeric_predictors())

knn_spec <- nearest_neighbor(
  mode = "classification",
  neighbors = 5,
  dist_power = 2
) |>
  set_engine(
    "cuda.ml",
    algo = "brute",
    metric = "euclidean"
  )

knn_workflow <- workflow() |>
  add_recipe(classifier_recipe) |>
  add_model(knn_spec)

knn_fit <- fit(knn_workflow, data = training_data)

results <- cbind(
  truth = testing_data$Class,
  predict(knn_fit, testing_data, type = "class"),
  predict(knn_fit, testing_data, type = "prob")
)
head(results)

The parsnip KNN engine defaults to algo = "ivfflat" and metric = "euclidean". ivfflat performs approximate neighbor search. Set algo = "brute", as above, when exact search is required. The direct cuda_ml_knn() interface defaults to brute-force search. The cuda.ml engine does not map parsnip’s weight_func argument; leave it as NULL.

Tree models do not generally need normalization. A recipe can still be useful for creating numeric indicators or applying other preprocessing learned from the training set.

Tune common arguments

cuda.ml registers standard dials parameter metadata for the following parsnip arguments:

specification registered arguments
linear_reg() penalty, mixture
logistic_reg(), multinom_reg() penalty, mixture
rand_forest() mtry, trees, min_n
nearest_neighbor() neighbors, dist_power
svm_rbf() cost, margin, rbf_sigma
svm_poly() cost, margin, degree, scale_factor
svm_linear() cost, margin

These arguments can use tune::tune() in a tuning workflow. margin maps to the epsilon tube and affects SVM regression only; do not tune it for an SVM classifier.

Engine arguments are not registered as dials parameters. Keep them fixed in set_engine() unless you define an explicit dials parameter and range for the tuning workflow. Useful engine arguments include:

engine examples of engine-specific arguments
linear regression fit_intercept; route-specific options described below
logistic and multinomial regression fit_intercept, tol, class_weight, max_iter, linesearch_max_iter, lbfgs_memory, penalty_normalized
random forest bootstrap, sample_fraction, max_depth, max_leaves, n_bins, min_samples_leaf, split_criterion, min_impurity_decrease, max_batch_size, n_streams, seed
nearest neighbor algo, metric
SVM coef0, tol, max_iter, nochange_steps, cache_size

Parsnip case weights are not currently supported by the cuda.ml engine. For per-observation weights, use sample_weight with cuda_ml_logistic_reg() or sample_weights with cuda_ml_svm() directly.

Consult the corresponding cuda_ml_*() reference page before setting these arguments. For example, random-forest split criteria differ between classification and regression, and approximate KNN algorithms support fewer distance metrics than brute-force KNN.

Linear regression routing

The linear_reg() engine selects a cuda.ml solver from penalty and mixture:

values direct function
penalty = NULL or penalty = 0 cuda_ml_ols()
positive penalty, mixture = 0 cuda_ml_ridge()
positive penalty, mixture = 1 or NULL cuda_ml_lasso()
positive penalty, 0 < mixture < 1 cuda_ml_elastic_net()

Only pass options supported by the selected function. For example, method is an OLS option, while max_iter, tol, and selection apply to the lasso and elastic-net routes. If the solver itself is part of the decision, use the named direct functions so that the relationship between the function and its arguments remains explicit.

Choose between parsnip and the direct API

Use parsnip when you want to compare engines through common specifications, use a tidymodels tuning workflow, or consume standard parsnip prediction types. Parsnip delegates training and prediction to cuda.ml’s public model functions.

The direct API includes several capabilities that have no parsnip specification:

Capability parsnip Direct cuda.ml API
Linear, logistic, random-forest, KNN, and RBF, polynomial, or linear SVM models Supported Supported
Clustering and dimensionality reduction Not available Agglomerative clustering, DBSCAN, k-means, PCA, tSVD, UMAP, and t-SNE
Transform and inverse-transform operations Not available cuda_ml_transform() and cuda_ml_inverse_transform()
Stochastic-gradient-descent linear regression No dedicated route cuda_ml_sgd()
Hyperbolic-tangent SVM No matching specification cuda_ml_svm(kernel = "tanh")
External tree-ensemble inference and inspection Not available nvForest load, predict, model-info, leaf-ID, per-tree, import, and export functions

Most algorithm-specific arguments for supported parsnip models remain available through set_engine(). Use the named direct function when selecting the algorithm or solver is part of the analysis, or when passing predictors and outcomes directly is preferable to a parsnip workflow.

For example, cuda.ml’s direct SVM interface supports a "tanh" kernel, but parsnip registration is limited to the RBF, polynomial, and linear SVM specifications.

direct_fit <- cuda_ml_svm(
  Class ~ .,
  data = modeldata::two_class_dat,
  kernel = "tanh",
  cost = 2,
  gamma = 0.1,
  coef0 = 0
)

direct_predictors <- subset(modeldata::two_class_dat, select = -Class)
direct_predictions <- predict(direct_fit, direct_predictors)

See Save and restore models before moving a fitted model to another R process or deployment host.