cuML is a suite of libraries that implement machine learning algorithms and mathematical primitives functions that share compatible APIs with other RAPIDS projects. This tutorial provides a quick intro to the scikit-learn-like library.
Introduction to cuML
cuML is suite of GPU-accelerated machine learning algorithms, designed to accelerate your data science and analytical workloads. From pre-processing data through to training and evaluating models, cuML proivdes a user-friendly API and a wide range of functionality to help you get the most from your GPUs.
Key Concepts
The following key concepts sit at the core of cuML's design, and enable you to get the most out of your data:
1. Where possible, match the scikit-learn API
cuML estimators look and feel just like scikit-learn estimators. You initialize them with key parameters, fit them with a fit method, then call predict or transform for inference.
2. Accept flexible input types, return predictable output types
cuML estimators can accept NumPy arrays, cuDF dataframes, cuPy arrays, 2d PyTorch tensors, and really any kind of standards-based Python array input you can throw at them.
By default, outputs will mirror the data type you provided.
3. Be fast!
On a modern GPU, these can exceed the performance of CPU-based equivalents by a factor of anything from 4x (for a medium-sized linear regression) to over 1000x (for large-scale tSNE dimensionality reduction). In many cases, performance advantages appear as the dataset grows.
In this notebook we step through some of the functionality of cuML, in the context of a standard data science workflow.
We begin importing the cuML module, as well as cuDF, and simulating some data to use in the rest of the notebook.
In the next cell we simulate 100,000 data samples. Each sample has 70 features, and belongs to one of two distinct classes.
Let's take a look at one sample, below:
## Split data into training and testing set
We use the train_test_split function to divide our data into training and testing sets.
We'll use the testing set later to evaluate the performance of the models we train.
Explore and preprocess the data
Now that we have split our data into training and test sets we can begin to apply transformations. Just like scikit-learn, cuML estimators admit the initialise, fit, and predict or transform functionality.
Let's see this in action with a the MaxAbsScaler. This scaler transforms each feature (column) of our data set by scaling it so that the maximum absolute value of each feature is 1.
Similarly, we can use a RobustScaler to transform the data so that each feature is on a similar scale.
This Scaler removes the median and scales the data according to the interquantile range.
And we can inspect properties of the Scaler, such as the scale factor:
Dimensionality Reduction
When exploring our data, we often want to project the features down to 2-dimensions so that we can plot and visualise the data set, and see if we can identify patterns.
We begin by using Principle Component Analysis (PCA), a linear dimensionality reduction technique. PCA requires input data to be on the same scale, so we first transform our data using the RobustScaler.
We can examine the proportion of variance explained by the PCA and inspect the components:
PCA is fast, but there are more sophisticated techniques we can use to possibly expose more structure in the data. Due to the non-linearity of these alternative dimensionality reduction techniques, they are more computationaly expensive. However, we benefit here from the acceleration provided by NVIDIA GPUs and the RAPIDS implementations.
UMAP is a non-linear dimensionality reduction technique:
As you can see, UMAP is notably slower than PCA, but let's see if it allows us to uncover more structure in our data by plotting the projected test data:
Training a model
Now that we've transformed our data, and have been able to identify structure in the data we can go ahead and train a model to distinguish between the two classes of data. Let's start by training a logistic regression model.
Again, we follow the initialise, fit, predict workflow that we used with the scalers and dimensionality reduction techniques earlier in the notebook.
Evaluating the model
cuML provides a range of built in metrics to evaluate model performance.
It looks like this prediction accuracy is only slightly higher than 50%. We would expect similar results by just tossing a coin to allocate classes. Let's inviestigate this further by looking at a confusion matrix:
The confusion matrix tells us that there are many misclassifications in both the '0' and '1' classes. Let's try to train another model and see if we can get better performance:
For our dataset, the k-nearest neighbour model is much better at predicting classes than the Logistic Regression model.
Pipelines
To quote the wonderful scikit-learn documentation, Pipeline "sequentially [applies] a list of transforms and a final estimator" to a dataset.
By collecting transformations and training into a single pipeline, we can confidently do things like cross-validation and hyper-parameter optimization without worrying about data leakage.
cuML transformations and estimators are fully compatible with the scikit-learn Pipeline API.
In our previous examples we used a RobustScaler followed by a k-Nearest neighbour model. Let's put those together in a pipeline:
We can fit the whole pipeline in one command, and make predictions from the raw data, without having to first call the scale, then the model.
Sidebar: comparison with scikit-learn
Although we're using the scikit-learn Pipeline above, all of our data remains on the GPU thoughout the execution. Let's see how long the comparative transformations and modeling take when we run these on the CPU:
So we can run the same pipeline on CPU with no code changes needed, but it is orders of magnitude slower to do so.
Explainability
Model explainability is often critically important. cuML provides a GPU-accelerated SHAP Kernel Explainer and a Permutation Explainer.
Pickling Models
So far, we've only stored our models in memory. This final section demonstrates basic pickling cuML models, and pipelines, for persistence. This allows us to load these models into other environments or programs and use them to make predictions on new data.
We can pickle individual estimators.
We can even pickle the pipeline we made earlier.