|

Implementation of Machine Learning Workflows with NVIDIA cuML, RAPIDS, GPU Benchmarking, Explainability, Clustering, and Model Inference

In this tutorial, we implement NVIDIA cuML as a GPU-accelerated machine studying framework and construct a sensible workflow that demonstrates how RAPIDS can speed up acquainted information science and machine studying duties. We start by configuring the GPU surroundings and inspecting cuml.accel, which lets us speed up present scikit-learn workloads with minimal code adjustments, earlier than shifting to the native cuML API for direct CuPy and cuDF interoperability. We then benchmark CPU and GPU implementations of PCA, Ok-Means, nearest-neighbor search, logistic regression, random forests, and DBSCAN, whereas utilizing synchronized timing to acquire significant efficiency measurements. We additionally construct GPU-based manifold-learning and clustering pipelines with UMAP, t-SNE, HDBSCAN, and trustworthiness metrics; discover high-throughput forest inference with FIL; validate GPU-generated SHAP explanations; carry out hyperparameter optimization with scikit-learn meta-estimators; and lastly serialize educated fashions whereas inspecting portability between GPU and CPU environments.

import os
import sys
import time
import json
import shutil
import warnings
import subprocess
import importlib
import traceback
warnings.filterwarnings("ignore")
QUICK = False
SEED = 42
SCALE = 0.25 if QUICK else 1.0
N_MAIN = int(200_000 * SCALE)
D_MAIN = 64
N_RF = int(50_000 * SCALE)
D_RF = 32
N_NN_INDEX = int(50_000 * SCALE)
N_NN_QUERY = int(5_000 * SCALE)
N_DBSCAN = int(20_000 * SCALE)
N_MANIFOLD = int(60_000 * SCALE)
N_ACCEL = int(80_000 * SCALE)
RESULTS = []
NOTES = []
def banner(title):
   line = "=" * 78
   print(f"n{line}n  {title}n{line}", flush=True)
def part(title, fn, *args, **kwargs):
   banner(title)
   t0 = time.perf_counter()
   strive:
       fn(*args, **kwargs)
   besides Exception:
       print(f"[!] Section skipped resulting from an error:n{traceback.format_exc()}")
   print(f"[section wall time: {time.perf_counter() - t0:.1f}s]", flush=True)
def bootstrap():
   if shutil.which("nvidia-smi") is None:
       elevate SystemExit(
           "No NVIDIA GPU discovered. In Colab: Runtime > Change runtime sort > GPU."
       )
   print(subprocess.run(
       ["nvidia-smi",
        "--query-gpu=name,memory.total,compute_cap,driver_version",
        "--format=csv"],
       capture_output=True, textual content=True).stdout)
   strive:
       import cuml
       print("cuML already obtainable — skipping set up.")
   besides ImportError:
       print("Installing RAPIDS cuML (this takes ~1-3 minutes)...")
       pin = ""
       strive:
           import cudf
           major_minor = ".".be a part of(cudf.__version__.cut up("+")[0].cut up(".")[:2])
           pin = f"=={major_minor}.*"
           print(f"  Pinning to the preinstalled cuDF line: cuml-cu12{pin}")
       besides Exception:
           print("  cuDF not discovered; putting in the newest steady cuml-cu12.")
       cmd = [sys.executable, "-m", "pip", "install", "-q",
              "--extra-index-url=https://pypi.nvidia.com", f"cuml-cu12{pin}"]
       print("$ " + " ".be a part of(cmd))
       rc = subprocess.run(cmd).returncode
       if rc != 0:
           elevate SystemExit(
               "pip set up failed. Alternative that at all times works on Colab:n"
               "  !git clone https://github.com/rapidsai/rapidsai-csp-utils.gitn"
               "  !python rapidsai-csp-utils/colab/pip-install.py"
           )
       importlib.invalidate_caches()
   import cuml
   import cupy
   print(f"cuml   {cuml.__version__}")
   print(f"cupy   {cupy.__version__}")
   strive:
       import cudf
       print(f"cudf   {cudf.__version__}")
   besides Exception:
       cross
   import sklearn
   print(f"sklearn {sklearn.__version__}   (cuML requires scikit-learn >= 1.6)")
bootstrap()
import numpy as np
import cupy as cp
import cuml
import matplotlib.pyplot as plt
from cuml.datasets import make_classification as gpu_make_classification
from cuml.datasets import make_blobs as gpu_make_blobs
rng = np.random.RandomState(SEED)
cp.random.seed(SEED)
class Timer:
   def __init__(self, label, sync=True):
       self.label = label
       self.sync = sync
   def __enter__(self):
       if self.sync:
           cp.cuda.runtime.deviceSynchronize()
       self.t0 = time.perf_counter()
       return self
   def __exit__(self, *exc):
       if self.sync:
           cp.cuda.runtime.deviceSynchronize()
       self.dt = time.perf_counter() - self.t0
       print(f"    {self.label:<44s} {self.dt:8.3f}s")
       return False
def to_numpy(a):
   if isinstance(a, cp.ndarray):
       return cp.asnumpy(a)
   if hasattr(a, "to_numpy"):
       return a.to_numpy()
   return np.asarray(a)
def document(activity, cpu_s, gpu_s):
   RESULTS.append((activity, cpu_s, gpu_s))
   if cpu_s and gpu_s:
       print(f"    -> {activity}: {cpu_s / gpu_s:.1f}x speedupn")
ACCEL_SCRIPT = f'''
import time
import numpy as np
from sklearn.datasets import make_blobs
from sklearn.decomposition import PCA
from sklearn.cluster import OkMeans
from sklearn.neighbors import NearestNeighbors
from sklearn.linear_model import Ridge
X, y = make_blobs(n_samples={N_ACCEL}, n_features=32, facilities=12, random_state=0)
X = X.astype("float32"); y = y.astype("float32")
t0 = time.perf_counter()
PCA(n_components=8).fit_transform(X)
OkMeans(n_clusters=12, n_init=1, random_state=0).match(X)
NearestNeighbors(n_neighbors=8).match(X[:{N_ACCEL // 2}]).kneighbors(X[:5000])
Ridge(alpha=1.0).match(X, y)
Ridge(alpha=1.0, optimistic=True).match(X[:5000], y[:5000])
print("MODELTIME %.3f" % (time.perf_counter() - t0))
'''
def demo_accel():
   path = "/content material/_accel_demo.py" if os.path.isdir("/content material") else "_accel_demo.py"
   with open(path, "w") as f:
       f.write(ACCEL_SCRIPT)
   def run(cmd, label):
       print(f"n$ {' '.be a part of(cmd[1:])}")
       t0 = time.perf_counter()
       p = subprocess.run(cmd, capture_output=True, textual content=True)
       wall = time.perf_counter() - t0
       out = p.stdout + p.stderr
       model_s = None
       for line in out.splitlines():
           if line.startswith("MODELTIME"):
               model_s = float(line.cut up()[1])
       print(out.strip()[:4000])
       print(f"[{label}] mannequin time = {model_s}s | course of wall = {wall:.1f}s")
       return model_s
   cpu_s = run([sys.executable, path], "inventory sklearn")
   cmd = [sys.executable, "-m", "cuml.accel", "--profile", path]
   gpu_s = run(cmd, "cuml.accel")
   if gpu_s is None:
       gpu_s = run([sys.executable, "-m", "cuml.accel", path], "cuml.accel")
   document("cuml.accel (sklearn script, unmodified)", cpu_s, gpu_s)
   NOTES.append(
       "cuml.accel wanted ZERO supply adjustments; the profile desk above exhibits "
       "which calls ran on GPU and why Ridge(optimistic=True) fell again to CPU."
   )

We configure the tutorial surroundings, outline dataset sizes and benchmarking utilities, and confirm that an NVIDIA GPU is accessible. We set up and initialize RAPIDS cuML when obligatory, arrange CuPy and reproducibility controls, and create synchronized timing and result-tracking helpers. We additionally display cuml.accel by operating an unmodified scikit-learn workload and evaluating its CPU execution with GPU-accelerated execution.

def demo_native_api():
   from cuml.preprocessing import StandardScaler
   from cuml.model_selection import train_test_split
   X, y = gpu_make_blobs(n_samples=50_000, n_features=8, facilities=5,
                         random_state=SEED, dtype=np.float32)
   print(f"cuml.datasets output lives on machine: {sort(X).__module__}, "
         f"form={X.form}, dtype={X.dtype}")
   strive:
       import cudf
       df = cudf.DataFrame(X, columns=[f"f{i}" for i in range(X.shape[1])])
       again = df.values
       ptr_a = X.__cuda_array_interface__["data"][0]
       ptr_b = again.__cuda_array_interface__["data"][0]
       print(f"CuPy ptr  = {hex(ptr_a)}")
       print(f"cuDF->CuPy= {hex(ptr_b)}")
       print("Same machine pointer (true zero-copy)? ", ptr_a == ptr_b)
       print("Note: a column-major DataFrame spherical journey could re-pack; what "
             "issues is that no host (CPU) spherical journey ever occurs.")
       scaled = StandardScaler().fit_transform(df)
       print(f"StandardScaler(cuDF) -> {sort(scaled).__name__}")
   besides Exception as e:
       print(f"cuDF interop skipped: {e}")
   from cuml.decomposition import PCA
   pca = PCA(n_components=3).match(X)
   print(f"default (mirrors enter)      -> {sort(pca.rework(X)).__name__}")
   with cuml.using_output_type("numpy"):
       print(f"inside using_output_type()   -> {sort(pca.rework(X)).__name__}")
   print(f"after the context supervisor    -> {sort(pca.rework(X)).__name__}")
   NOTES.append(
       "Keep output_type as CuPy/cuDF inside a pipeline; changing to NumPy "
       "on each step forces a device->host copy and eats the speedup."
   )
   Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.2, random_state=SEED)
   print(f"train_test_split -> {Xtr.form} / {Xte.form}, nonetheless on machine: "
         f"{isinstance(Xtr, cp.ndarray)}")

We work instantly with the native cuML API and discover how GPU-resident information strikes between CuPy, cuDF, and cuML elements. We examine machine pointers to know zero-copy interoperability and use cuML output-type controls to handle whether or not outcomes stay on the GPU or return as NumPy arrays. We additionally carry out a GPU-native train-test cut up in order that our information stays on the machine all through the workflow.

def demo_benchmarks():
   from sklearn.decomposition import PCA as skPCA
   from sklearn.cluster import OkMeans as skKMeans, DBSCAN as skDBSCAN
   from sklearn.neighbors import NearestNeighbors as skNN
   from sklearn.linear_model import LogisticRegression as skLR
   from sklearn.ensemble import RandomForestClassifier as skRF
   from cuml.decomposition import PCA as cuPCA
   from cuml.cluster import OkMeans as cuKMeans, DBSCAN as cuDBSCAN
   from cuml.neighbors import NearestNeighbors as cuNN
   from cuml.linear_model import LogisticRegression as cuLR
   from cuml.ensemble import RandomForestClassifier as cuRF
   print(f"Generating {N_MAIN:,} x {D_MAIN} on the GPU...")
   Xg, yg = gpu_make_classification(n_samples=N_MAIN, n_features=D_MAIN,
                                    n_informative=32, n_classes=4,
                                    random_state=SEED)
   Xg = Xg.astype(cp.float32)
   yg = yg.astype(cp.int32)
   Xc, yc = cp.asnumpy(Xg), cp.asnumpy(yg)
   print(f"  machine array: {Xg.nbytes / 1e6:.0f} MBn")
   print("PCA (n_components=16)")
   with Timer("sklearn", sync=False) as t:
       skPCA(n_components=16, random_state=SEED).fit_transform(Xc)
   cpu = t.dt
   with Timer("cuML") as t:
       cuPCA(n_components=16, random_state=SEED).fit_transform(Xg)
   document("PCA", cpu, t.dt)
   print("OkMeans (okay=16)")
   with Timer("sklearn", sync=False) as t:
       skKMeans(n_clusters=16, n_init=1, max_iter=100,
                random_state=SEED).match(Xc)
   cpu = t.dt
   with Timer("cuML") as t:
       cuKMeans(n_clusters=16, n_init=1, max_iter=100,
                random_state=SEED).match(Xg)
   document("OkMeans", cpu, t.dt)
   print(f"NearestNeighbors okay=16 ({N_NN_INDEX:,} index / {N_NN_QUERY:,} question)")
   idx_g, q_g = Xg[:N_NN_INDEX], Xg[N_NN_INDEX:N_NN_INDEX + N_NN_QUERY]
   idx_c, q_c = cp.asnumpy(idx_g), cp.asnumpy(q_g)
   with Timer("sklearn (brute)", sync=False) as t:
       skNN(n_neighbors=16, algorithm="brute", n_jobs=-1).match(idx_c).kneighbors(q_c)
   cpu = t.dt
   with Timer("cuML") as t:
       d_gpu, i_gpu = cuNN(n_neighbors=16).match(idx_g).kneighbors(q_g)
   document("NearestNeighbors", cpu, t.dt)
   print("LogisticRegression (multinomial, lbfgs/QN)")
   with Timer("sklearn", sync=False) as t:
       sk_lr = skLR(max_iter=200, n_jobs=-1).match(Xc, yc)
   cpu = t.dt
   with Timer("cuML") as t:
       cu_lr = cuLR(max_iter=200).match(Xg, yg)
   document("LogisticRegression", cpu, t.dt)
   print(f"    accuracy  sklearn={sk_lr.rating(Xc, yc):.4f}  "
         f"cuML={float((cu_lr.predict(Xg) == yg).imply()):.4f}  "
         "(completely different solvers, so small variations are anticipated)n")
   print(f"RandomForestClassifier (100 timber, depth 12, {N_RF:,} x {D_RF})")
   Xr_g, yr_g = gpu_make_classification(n_samples=N_RF, n_features=D_RF,
                                        n_informative=16, n_classes=2,
                                        random_state=SEED)
   Xr_g = Xr_g.astype(cp.float32)
   yr_g = yr_g.astype(cp.int32)
   Xr_c, yr_c = cp.asnumpy(Xr_g), cp.asnumpy(yr_g)
   with Timer("sklearn", sync=False) as t:
       skRF(n_estimators=100, max_depth=12, n_jobs=-1,
            random_state=SEED).match(Xr_c, yr_c)
   cpu = t.dt
   with Timer("cuML") as t:
       cu_rf = cuRF(n_estimators=100, max_depth=12, n_bins=128,
                    n_streams=4, random_state=SEED).match(Xr_g, yr_g)
   document("RandomForest (match)", cpu, t.dt)
   globals()["_RF_ARTIFACTS"] = (cu_rf, Xr_g, yr_g, Xr_c, yr_c)
   print(f"DBSCAN ({N_DBSCAN:,} x 8)")
   Xd_g, _ = gpu_make_blobs(n_samples=N_DBSCAN, n_features=8, facilities=6,
                            cluster_std=0.6, random_state=SEED,
                            dtype=np.float32)
   Xd_c = cp.asnumpy(Xd_g)
   with Timer("sklearn", sync=False) as t:
       lab_c = skDBSCAN(eps=0.9, min_samples=8, n_jobs=-1).fit_predict(Xd_c)
   cpu = t.dt
   with Timer("cuML") as t:
       lab_g = cuDBSCAN(eps=0.9, min_samples=8).fit_predict(Xd_g)
   document("DBSCAN", cpu, t.dt)
   print(f"    clusters discovered: sklearn={len(set(lab_c.tolist())) - 1}, "
         f"cuML={len(set(cp.asnumpy(lab_g).tolist())) - 1}n")

We benchmark scikit-learn and cuML implementations of PCA, Ok-Means, nearest neighbors, logistic regression, random forests, and DBSCAN. We generate datasets on the GPU, synchronize CUDA operations for truthful timing, and document the speedup every accelerated algorithm achieves. We additionally evaluate mannequin habits and retain the educated cuML random forest in order that we will reuse it later within the tutorial.

def demo_manifold():
   from cuml.manifold import UMAP, TSNE
   from cuml.metrics import trustworthiness
   X, y = gpu_make_blobs(n_samples=N_MANIFOLD, n_features=48, facilities=8,
                         cluster_std=1.6, random_state=SEED, dtype=np.float32)
   print(f"information: {X.form}")
   embeddings = {}
   for n_neighbors, min_dist in [(15, 0.1), (50, 0.0)]:
       key = f"UMAP(n_neighbors={n_neighbors}, min_dist={min_dist})"
       with Timer(key) as t:
           emb = UMAP(n_neighbors=n_neighbors, min_dist=min_dist,
                      n_components=2, random_state=SEED).fit_transform(X)
       sub = slice(0, min(5000, X.form[0]))
       tw = trustworthiness(X[sub], emb[sub], n_neighbors=10)
       print(f"      trustworthiness = {tw:.4f}")
       embeddings[key] = (emb, t.dt, tw)
   with Timer("TSNE(methodology='fft')") as t:
       tsne_emb = TSNE(n_components=2, perplexity=30,
                       random_state=SEED).fit_transform(X)
   embeddings["TSNE"] = (tsne_emb, t.dt, float("nan"))
   best_key = max([k for k in embeddings if k.startswith("UMAP")],
                  key=lambda okay: embeddings[k][2])
   emb = embeddings[best_key][0]
   print(f"nClustering the '{best_key}' embedding with GPU HDBSCAN")
   strive:
       from cuml.cluster import HDBSCAN
       with Timer("HDBSCAN") as t:
           hdb = HDBSCAN(min_cluster_size=max(int(50 * SCALE), 5),
                         min_samples=10, prediction_data=True).match(emb)
       labels = cp.asarray(hdb.labels_)
       n_clusters = int(labels.max()) + 1
       noise = float((labels == -1).imply())
       print(f"      clusters={n_clusters}  noise fraction={noise:.3f}")
       strive:
           from cuml.metrics.cluster import adjusted_rand_score
           print(f"      adjusted Rand index vs floor fact: "
                 f"{adjusted_rand_score(y, labels):.4f}")
       besides Exception as e:
           print(f"      ARI skipped: {e}")
       strive:
           from cuml.cluster.hdbscan import all_points_membership_vectors
           mv = all_points_membership_vectors(hdb)
           print(f"      soft-cluster membership matrix: {tuple(mv.form)}")
       besides Exception as e:
           print(f"      tender clustering skipped: {e}")
   besides Exception as e:
       print(f"      HDBSCAN step skipped: {e}")
   fig, axes = plt.subplots(1, 3, figsize=(16, 5))
   keys = checklist(embeddings)[:3]
   for ax, okay in zip(axes, keys):
       e = to_numpy(embeddings[k][0])
       c = to_numpy(y)
       ax.scatter(e[:, 0], e[:, 1], c=c, s=1.5, cmap="tab10", alpha=0.6)
       ax.set_title(f"{okay}n{embeddings[k][1]:.2f}s", fontsize=9)
       ax.set_xticks([]); ax.set_yticks([])
   plt.suptitle("GPU manifold studying (coloured by ground-truth cluster)")
   plt.tight_layout(); plt.present()

We construct an unsupervised GPU pipeline utilizing UMAP and t-SNE to scale back high-dimensional information into two-dimensional embeddings. We consider UMAP configurations with the trustworthiness metric, choose the strongest embedding, and apply HDBSCAN to establish clusters and noise factors. We then visualize the ensuing embeddings and evaluate their constructions utilizing the identified ground-truth cluster labels.

def demo_fil():
   from sklearn.ensemble import RandomForestClassifier as skRF
   n = int(30_000 * SCALE)
   Xg, yg = gpu_make_classification(n_samples=n, n_features=24,
                                    n_informative=12, n_classes=2,
                                    random_state=SEED)
   Xg = Xg.astype(cp.float32)
   Xc, yc = cp.asnumpy(Xg), cp.asnumpy(yg.astype(cp.int32))
   print("Training a 200-tree sklearn forest on CPU (the mannequin to be served)...")
   sk_model = skRF(n_estimators=200, max_depth=10, n_jobs=-1,
                   random_state=SEED).match(Xc, yc)
   with Timer("sklearn.predict_proba (CPU)", sync=False) as t:
       p_cpu = sk_model.predict_proba(Xc)[:, 1]
   cpu = t.dt
   fil = None
   strive:
       from cuml.fil import ForestInference
   besides Exception as e:
       print(f"cuml.fil unavailable on this construct ({e}); skipping. "
             "On newer stacks use the standalone nvForest library as an alternative.")
       return
   for kwargs in ({"is_classifier": True, "output_type": "numpy"},
                  {"output_class": True, "output_type": "numpy"},
                  {}):
       strive:
           fil = ForestInference.load_from_sklearn(sk_model, **kwargs)
           print(f"Loaded into FIL with kwargs={kwargs or '{}'}")
           break
       besides Exception as e:
           print(f"  load_from_sklearn(**{kwargs}) -> {sort(e).__name__}: {e}")
   if fil is None:
       print("Could not load the forest into FIL on this construct; skipping.")
       return
   strive:
       fil.optimize(batch_size=Xg.form[0])
       print("Ran fil.optimize() to auto-tune structure/chunk measurement for this batch.")
   besides Exception:
       cross
   fil.predict_proba(Xg[:1024])
   with Timer("FIL predict_proba (GPU)") as t:
       p_gpu = fil.predict_proba(Xg)
   document("Forest inference (200 timber)", cpu, t.dt)
   p_gpu = to_numpy(p_gpu)
   p_gpu = p_gpu[:, 1] if p_gpu.ndim == 2 and p_gpu.form[1] == 2 else p_gpu.ravel()
   print(f"    max |prob distinction| vs sklearn: {np.abs(p_gpu - p_cpu).max():.2e} "
         "(FIL defaults to float32, so ~1e-6 is regular)")
   NOTES.append(
       "FIL/nvForest is the piece that issues in manufacturing: the identical educated "
       "artifact, served with GPU-class throughput and no retraining."
   )

We give attention to accelerating inference for tree-based fashions after coaching. We prepare a scikit-learn random forest on the CPU, load it into the cuML Forest Inference Library when supported, and optimize the inference configuration for the present GPU batch measurement. We evaluate CPU and GPU prediction occasions and validate that the anticipated possibilities stay numerically constant.

def demo_explainer():
   from cuml.linear_model import Ridge
   from cuml.explainer import PermutationExplainer
   n, d = int(20_000 * SCALE), 12
   X = cp.asarray(rng.randn(n, d), dtype=cp.float32)
   true_coef = cp.asarray(rng.uniform(-3, 3, measurement=d), dtype=cp.float32)
   y = (X @ true_coef + 0.1 * cp.asarray(rng.randn(n), dtype=cp.float32))
   mannequin = Ridge(alpha=1e-3).match(X, y)
   coef = cp.asarray(mannequin.coef_).ravel()
   background = X[:200]
   to_explain = X[200:220]
   with Timer("PermutationExplainer (GPU)") as t:
       expl = PermutationExplainer(mannequin=mannequin.predict, information=background,
                                   random_state=SEED)
       shap_values = expl.shap_values(to_explain)
   shap_values = cp.asarray(shap_values)
   analytic = (to_explain - background.imply(axis=0)) * coef
   err = float(cp.abs(shap_values - analytic).max())
   print(f"    max |SHAP - analytical linear SHAP| = {err:.4f}")
   print("    (permutation SHAP is sampling-based, so a small residual is "
         "anticipated; the sample should match)")
   base = float(mannequin.predict(background).imply())
   recon = cp.asarray(shap_values).sum(axis=1) + base
   precise = cp.asarray(mannequin.predict(to_explain)).ravel()
   print(f"    additivity residual (imply |sum(phi)+base - f(x)|) = "
         f"{float(cp.abs(recon - precise).imply()):.4f}")
   imp = to_numpy(cp.abs(shap_values).imply(axis=0))
   order = np.argsort(imp)[::-1]
   plt.determine(figsize=(8, 3.5))
   plt.bar(vary(d), imp[order], colour="#76b900")
   plt.xticks(vary(d), [f"f{i}" for i in order])
   plt.ylabel("imply |SHAP|")
   plt.title("GPU SHAP function significance (cuml.explainer.PermutationExplainer)")
   plt.tight_layout(); plt.present()
def demo_hpo():
   from sklearn.model_selection import RandomizedSearchCV
   from cuml.ensemble import RandomForestClassifier as cuRF
   n = int(60_000 * SCALE)
   X, y = gpu_make_classification(n_samples=n, n_features=24, n_informative=14,
                                  n_classes=3, random_state=SEED)
   X = cp.asnumpy(X.astype(cp.float32))
   y = cp.asnumpy(y.astype(cp.int32))
   param_dist = {
       "n_estimators": [50, 100, 200],
       "max_depth": [8, 12, 16],
       "max_features": [0.3, 0.5, 0.8],
       "n_bins": [64, 128, 256],
   }
   search = RandomizedSearchCV(
       cuRF(random_state=SEED, n_streams=1),
       param_distributions=param_dist,
       n_iter=8, cv=3, n_jobs=1, random_state=SEED, verbose=0,
   )
   with Timer("RandomizedSearchCV over cuML RF (8 x 3 suits)", sync=True) as t:
       search.match(X, y)
   print(f"    finest CV accuracy: {search.best_score_:.4f}")
   print(f"    finest params     : {json.dumps(search.best_params_)}")
   NOTES.append(
       "Because every match is seconds as an alternative of minutes, you'll be able to afford an actual "
       "search house as an alternative of one hand-tuned guess."
   )

We use cuML’s GPU-based permutation explainer to calculate SHAP values for a Ridge regression mannequin and validate these explanations towards the analytical linear answer. We check SHAP additivity and visualize function significance to verify that the computed attributions behave as anticipated. We additionally mix cuML estimators with scikit-learn’s RandomizedSearchCV to carry out cross-validated hyperparameter optimization whereas becoming the mannequin on the GPU.

def demo_persistence():
   import pickle
   artwork = globals().get("_RF_ARTIFACTS")
   if artwork is None:
       from cuml.ensemble import RandomForestClassifier as cuRF
       Xg, yg = gpu_make_classification(n_samples=int(20_000 * SCALE),
                                        n_features=16, n_classes=2,
                                        random_state=SEED)
       Xg = Xg.astype(cp.float32); yg = yg.astype(cp.int32)
       mannequin = cuRF(n_estimators=50, max_depth=10, random_state=SEED).match(Xg, yg)
   else:
       mannequin, Xg, yg, _, _ = artwork
   earlier than = to_numpy(mannequin.predict(Xg[:1000]))
   path = "/content material/cuml_rf.pkl" if os.path.isdir("/content material") else "cuml_rf.pkl"
   with open(path, "wb") as f:
       pickle.dump(mannequin, f)
   size_mb = os.path.getsize(path) / 1e6
   with open(path, "rb") as f:
       restored = pickle.load(f)
   after = to_numpy(restored.predict(Xg[:1000]))
   print(f"    pickled mannequin: {size_mb:.2f} MB at {path}")
   print(f"    predictions an identical after spherical journey: {np.array_equal(earlier than, after)}")
   print("    cuML makes use of cloudpickle internally, so fashions educated below "
         "cuml.accel will be loaded and utilized by plain scikit-learn on a "
         "CPU-only machine.")
   print("    SECURITY: by no means unpickle a mannequin file from an untrusted supply.")
def demo_summary():
   rows = [(t, c, g) for (t, c, g) in RESULTS if c and g]
   if not rows:
       print("No comparable timings had been collected.")
       return
   w = max(len(r[0]) for r in rows)
   print(f"{'activity'.ljust(w)}   {'CPU (s)':>9} {'GPU (s)':>9} {'speedup':>9}")
   print("-" * (w + 32))
   for t, c, g in rows:
       print(f"{t.ljust(w)}   {c:9.3f} {g:9.3f} {c / g:8.1f}x")
   labels = [r[0] for r in rows][::-1]
   speeds = [r[1] / r[2] for r in rows][::-1]
   plt.determine(figsize=(9, 0.55 * len(labels) + 2))
   bars = plt.barh(labels, speeds, colour="#76b900")
   for b, s in zip(bars, speeds):
       plt.textual content(b.get_width() * 1.02, b.get_y() + b.get_height() / 2,
                f"{s:.1f}x", va="heart", fontsize=9)
   plt.axvline(1.0, colour="gray", ls="--", lw=1)
   plt.xscale("log")
   plt.xlabel("speedup vs CPU (log scale, larger is healthier)")
   plt.title(f"cuML {cuml.__version__} on this Colab GPU")
   plt.tight_layout(); plt.present()
   print("nTakeaways")
   for i, n in enumerate(NOTES, 1):
       print(f"  {i}. {n}")
   print("""
 Caveats value internalizing:
  * Speedups are size-dependent. Under ~10k rows, PCIe switch and kernel
    launch overhead often dominate, and the CPU wins. Benchmark YOUR shapes.
  * Always deviceSynchronize() earlier than stopping a timer, otherwise you time nothing.
  * cuML matches scikit-learn's API, not its actual numerics: completely different solvers,
    float32 defaults, and non-deterministic reductions produce small deltas.
  * Multi-GPU / multi-node: swap cuml.X for cuml.dask.X with a LocalCUDACluster.
 Where to go subsequent:
  * cuml.accel compatibility matrix : https://docs.nvidia.com/cuml/steady/cuml-accel/compatibility/
  * Profiling accelerated code      : %%cuml.accel.profile and %%cuml.accel.line_profile
  * Multi-GPU information                 : https://docs.nvidia.com/cuml/steady/dask_multigpu_guide/
  * Walkthrough notebooks           : https://github.com/NVIDIA/cuml/tree/important/notebooks
""")
_t_all = time.perf_counter()
part("1. cuml.accel — zero code change acceleration of inventory scikit-learn",
       demo_accel)
part("2. Native cuML API: cuDF/CuPy interop, zero-copy, output varieties",
       demo_native_api)
part("3. CPU vs GPU benchmark harness", demo_benchmarks)
part("4. UMAP -> trustworthiness -> HDBSCAN pipeline", demo_manifold)
part("5. High-throughput forest inference (FIL / nvForest)", demo_fil)
part("6. GPU SHAP with cuml.explainer, validated analytically", demo_explainer)
part("7. Hyperparameter search over cuML estimators", demo_hpo)
part("8. Serialization and GPU -> CPU portability", demo_persistence)
part("9. Summary", demo_summary)
print(f"nTotal tutorial wall time: {time.perf_counter() - _t_all:.1f}s")

We serialize a educated cuML random forest with pickle, restore it, and confirm that its predictions stay unchanged after the spherical journey. We combination the CPU and GPU timing outcomes collected all through the tutorial and visualize the ensuing speedups on a logarithmic chart. Finally, we run each tutorial part in sequence, print the amassed sensible takeaways, and report the full runtime of the entire workflow.

In conclusion, we applied a complete understanding of how NVIDIA cuML integrates GPU acceleration into each present scikit-learn workflows and totally GPU-native machine studying pipelines. We in contrast computational efficiency throughout a number of core algorithms, managed device-resident information effectively with CuPy and cuDF, evaluated unsupervised representations and clustering high quality, accelerated tree-model inference, and generated interpretable SHAP explanations instantly on the GPU. We additionally confirmed that acquainted scikit-learn utilities similar to RandomizedSearchCV can work alongside cuML estimators, preserving established machine studying growth patterns whereas benefiting from GPU execution.


Check out the FULL CODES here. Also, be at liberty to comply with us on Twitter and don’t neglect to hitch our 150k+ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.

Need to associate with us for selling your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar and so on.? Connect with us

The put up Implementation of Machine Learning Workflows with NVIDIA cuML, RAPIDS, GPU Benchmarking, Explainability, Clustering, and Model Inference appeared first on MarkTechPost.

Similar Posts