{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "ZhTWAPo7X5-I" }, "source": [ "# Zero Code Change Acceleration: Getting Started with cuml.accel" ] }, { "cell_type": "markdown", "metadata": { "id": "BinKvOgMYOCp" }, "source": [ "The cuml.accel accelerator mode allows you to bring GPU-accelerated computing to existing machine learning workflows with zero code changes required. By simply loading the cuml.accel extension, your existing scikit-learn, UMAP, and HDBSCAN code can automatically leverage GPU acceleration for supported algorithms.\n", "\n", "This notebook demonstrates how to use cuml.accel with practical examples across different machine learning tasks." ] }, { "cell_type": "markdown", "metadata": { "id": "qC3fevZecnns" }, "source": [ "With classical machine learning, there is a wide range of interesting problems we can explore. In this brief introduction we demonstrate a typical classification workflow." ] }, { "cell_type": "markdown", "metadata": { "id": "M37-8qsDa2Pe" }, "source": [ "## Classification Example\n" ] }, { "cell_type": "markdown", "metadata": { "id": "vT5RNLwdce-O" }, "source": [ "Let's load a dataset and see how we can use scikit-learn to classify that data. For this example we'll use the Coverage Type dataset, which contains a number of features that can be used to predict forest cover type, such as elevation, aspect, slope, and soil-type.\n", "\n", "More information on this dataset can be found at https://archive.ics.uci.edu/dataset/31/covertype." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "PKt2Lje5lYQw" }, "outputs": [], "source": [ "import pandas as pd\n", "from sklearn.ensemble import RandomForestClassifier\n", "from sklearn.model_selection import train_test_split\n", "from sklearn.metrics import classification_report, accuracy_score" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "rLHSPlLnv-1y" }, "outputs": [], "source": [ "url = \"https://archive.ics.uci.edu/ml/machine-learning-databases/covtype/covtype.data.gz\"\n", "\n", "# Column names for the dataset (from UCI Covertype description)\n", "columns = ['Elevation', 'Aspect', 'Slope', 'Horizontal_Distance_To_Hydrology', 'Vertical_Distance_To_Hydrology',\n", " 'Horizontal_Distance_To_Roadways', 'Hillshade_9am', 'Hillshade_Noon', 'Hillshade_3pm',\n", " 'Horizontal_Distance_To_Fire_Points', 'Wilderness_Area1', 'Wilderness_Area2', 'Wilderness_Area3',\n", " 'Wilderness_Area4', 'Soil_Type1', 'Soil_Type2', 'Soil_Type3', 'Soil_Type4', 'Soil_Type5', 'Soil_Type6',\n", " 'Soil_Type7', 'Soil_Type8', 'Soil_Type9', 'Soil_Type10', 'Soil_Type11', 'Soil_Type12', 'Soil_Type13',\n", " 'Soil_Type14', 'Soil_Type15', 'Soil_Type16', 'Soil_Type17', 'Soil_Type18', 'Soil_Type19', 'Soil_Type20',\n", " 'Soil_Type21', 'Soil_Type22', 'Soil_Type23', 'Soil_Type24', 'Soil_Type25', 'Soil_Type26', 'Soil_Type27',\n", " 'Soil_Type28', 'Soil_Type29', 'Soil_Type30', 'Soil_Type31', 'Soil_Type32', 'Soil_Type33', 'Soil_Type34',\n", " 'Soil_Type35', 'Soil_Type36', 'Soil_Type37', 'Soil_Type38', 'Soil_Type39', 'Soil_Type40', 'Cover_Type']\n", "\n", "data = pd.read_csv(url, header=None)\n", "data.columns=columns" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "53P_F5oHmh9F", "outputId": "da81ae3e-9725-4a99-d11e-e65f57a99d73" }, "outputs": [], "source": [ "data.shape" ] }, { "cell_type": "markdown", "metadata": { "id": "7Mz-yThWmlqg" }, "source": [ "Next, we'll separate out the classification variable (Cover_Type) from the rest of the data. This is what we will aim to predict with our classification model. We can also split our dataset into training and test data using the scikit-learn train_test_split function." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "heVSKrDLxdN3" }, "outputs": [], "source": [ "X, y = data.drop('Cover_Type', axis=1), data['Cover_Type']\n", "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)" ] }, { "cell_type": "markdown", "metadata": { "id": "OVl1oBxxm44k" }, "source": [ "Now that we have our dataset split, we're ready to run a model. To start, we will just run the model using the sklearn library with a starting max depth of 5 and all of the features. Note that we can set n_jobs=-1 to utilize all available CPU cores for fitting the trees -- this will ensure we get the best performance possible on our system's CPU. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 115 }, "id": "T0Y2HUgykyLY", "outputId": "5977bcbc-9c5e-45bd-9714-3d4814c22e72" }, "outputs": [], "source": [ "%%time\n", "\n", "clf = RandomForestClassifier(n_estimators=100, max_depth=5, max_features=1.0, n_jobs=-1)\n", "clf.fit(X_train, y_train)" ] }, { "cell_type": "markdown", "metadata": { "id": "_B7glDK8nWMQ" }, "source": [ "In about 2 minutes, we were able to fit our tree model using scikit-learn. This is not bad! Let's use the model we just trained to predict coverage types in our test dataset and take a look at the accuracy of our model." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "SLP-K7qynwWg", "outputId": "d9239568-ca10-48e8-e6bb-4436d5e028a4" }, "outputs": [], "source": [ "y_pred = clf.predict(X_test)\n", "accuracy_score(y_test, y_pred)" ] }, { "cell_type": "markdown", "metadata": { "id": "UAFu5rDwn6VK" }, "source": [ "We can also print out a full classification report to better understand how we predicted different Coverage_Type categories." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "AO3owg5PnwYW", "outputId": "3dea9a3b-b08d-4206-952d-dcd30b7fa20d" }, "outputs": [], "source": [ "print(classification_report(y_test, y_pred))" ] }, { "cell_type": "markdown", "metadata": { "id": "FRdxW-MpoJAt" }, "source": [ "With scikit-learn, we built a model that was able to be trained in just a couple minutes. From the accuracy report, we can see that we predicted the correct class around 70% of the time, which is not bad but could certainly be improved.\n", "\n", "Often we want to run several different random forest models in order to optimize our hyperparameters. For example, we may want to increase the number of estimators, or modify the maximum depth of our tree. When running dozens or hundreds of different hyperparameter combinations, things start to become quite slow and iteration takes a lot longer.\n", "\n", "We provide some sample code utilizing GridSearchCV below to show what this process might look like. All of these combinations would take a LONG time to run if we spend 2 minutes fitting each model." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "4qFknPIWpXcs" }, "outputs": [], "source": [ "\"\"\"\n", "from sklearn.model_selection import GridSearchCV\n", "\n", "# Define the parameter grid to search over\n", "param_grid = {\n", " 'n_estimators': [50, 100, 200],\n", " 'max_depth': [None, 10, 20, 30],\n", " 'min_samples_split': [2, 5, 10],\n", " 'min_samples_leaf': [1, 2, 4],\n", " 'max_features': ['auto', 'sqrt', 'log2'],\n", " 'bootstrap': [True, False]\n", "}\n", "\n", "grid_search = GridSearchCV(estimator=clf, param_grid=param_grid, cv=5)\n", "grid_search.fit(X_train, y_train)\n", "\"\"\"" ] }, { "cell_type": "markdown", "metadata": { "id": "5-BtB1RdqKp0" }, "source": [ "Now let's load cuml.accel and try running the same code again to see what kind of acceleration we can get." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "U31QyneR6BXJ", "outputId": "feebde4b-66bf-45e6-feaa-fd3f1bd9bc57" }, "outputs": [], "source": [ "%load_ext cuml.accel" ] }, { "cell_type": "markdown", "metadata": { "id": "TNLZVjtxqTmc" }, "source": [ "After loading the IPython magic, we need to import the sklearn estimators we wish to use again." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "MVWHm7H9qS2T" }, "outputs": [], "source": [ "from sklearn.ensemble import RandomForestClassifier" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 115 }, "id": "8v0QxJXrViiR", "outputId": "5510c2ad-5ea7-4cb7-c3b0-0527d836fc6b" }, "outputs": [], "source": [ "%%time\n", "\n", "clf = RandomForestClassifier(n_estimators=100, max_depth=5, max_features=1.0, n_jobs=-1)\n", "clf.fit(X_train, y_train)" ] }, { "cell_type": "markdown", "metadata": { "id": "fqJC2jtmqpva" }, "source": [ "That was much faster! Using cuML we're able to train this random forest model in just seconds instead of minutes. One thing to note is that cuML's implementation of RandomForestClassifier doesn't utilize the `n_jobs` parameter like scikit-learn, but we still accept it which makes it easier to use this accelerator with zero code changes.\n", "\n", "Let's take a look at the same accuracy score and classification report to compare the model's performance." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "eVre6kav6iaS", "outputId": "2c240c5f-b7c2-4eac-98b5-aee48bd4dcc7" }, "outputs": [], "source": [ "y_pred = clf.predict(X_test)\n", "cr = classification_report(y_test, y_pred)\n", "print(cr)" ] }, { "cell_type": "markdown", "metadata": { "id": "8xkoz247VsIX" }, "source": [ "Out of the box, the model performed about the same as the scikit-learn implementation. Because this model ran so much faster, we can quickly iterate on the hyperparameter configuration and find a model that performs better with excellent speedups." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 115 }, "id": "mfZamg7FVoPe", "outputId": "19d44cd9-9863-495b-ac8d-067118fd9c22" }, "outputs": [], "source": [ "%%time\n", "\n", "clf = RandomForestClassifier(n_estimators=100, max_depth=30, max_features=1.0, n_jobs=-1)\n", "clf.fit(X_train, y_train)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "E97LObEYVocu", "outputId": "e560b1a6-1b12-4cb5-bc66-09b3530af692" }, "outputs": [], "source": [ "y_pred = clf.predict(X_test)\n", "print(classification_report(y_test, y_pred))" ] }, { "cell_type": "markdown", "metadata": { "id": "DmcwmqN4q4cv" }, "source": [ "With a model that runs in just seconds, we can perform hyperparameter optimization using a method like the grid search shown above, and have results in just minutes instead of hours." ] }, { "cell_type": "markdown", "metadata": { "id": "9IXkjC6MLZoj" }, "source": [ "## CPU Fallback\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "id": "9zSIAHaKn7oa" }, "source": [ "There are some algorithms and functionality from scikit-learn, UMAP, and HDBSCAN that are *not* implemented in cuML. For cases where the underlying functionality is not supported on GPU, the cuML accelerator will gracefully fall back and execute on the CPU instead.\n", "\n", "For example, cuML's RandomForest estimator does not support sparse inputs." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%time\n", "\n", "from scipy import sparse\n", "\n", "X_train_sparse = sparse.csr_matrix(X_train)\n", "\n", "clf = RandomForestClassifier(n_estimators=100, max_depth=5, max_features=1.0, n_jobs=-1)\n", "clf.fit(X_train_sparse, y_train)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see that the model took longer to fit because it had to fall back to the CPU, but the code executed without errors." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "rBB16r0in-1F", "outputId": "5a5cfef5-ea8e-4240-e866-4138b7f700b1" }, "outputs": [], "source": [ "y_pred = clf.predict(X_test)\n", "print(classification_report(y_test, y_pred))" ] } ], "metadata": { "accelerator": "GPU", "colab": { "gpuType": "T4", "provenance": [] }, "kernelspec": { "display_name": "rapids-25.10", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.7" } }, "nbformat": 4, "nbformat_minor": 0 }