Technologies · Compute

Machine learning, out of core.

clio-ml is a library of classic machine-learning algorithms (the Spark MLlib set) written over CLIO Core's paged vectors. A dataset larger than GPU memory trains without hand-sizing anything; its pages stream from host memory, NVMe or DAOS through a GPU cache.

Algorithms
30+ modules
Backends
CPU, CUDA, SYCL
Data
Any CTE tier, including DAOS
Compared with
Spark MLlib, oneDAL, Dask-ML

Key takeaways

  • clio-ml: the Spark MLlib algorithm set, over 30 modules, on CPU, CUDA and SYCL.
  • Trains out of core: data larger than GPU memory streams from the tiers you compose.
  • Measured 8-59x faster per iteration than Spark MLlib.
  • 8-59xfaster per iteration than Spark MLlib, 1-16 nodes
  • flattime per iteration from 1 to 16 nodes (weak scaling)
  • 9 of 10more algorithms faster than Spark, 1.1-32x
  • 4-6xless memory than Spark on 61 GB of data

What it is

clio-ml has more than thirty algorithm modules: the MLlib set (k-means, linear, logistic and multinomial regression, linear SVM, naive Bayes, PCA, decision trees, random forests, gradient-boosted trees, Gaussian mixtures, bisecting k-means, ALS, LDA, word2vec, k-nearest neighbors and more) plus neural models (MLP, CNN, LSTM, GNN) and a PyTorch integration. The thirteen benchmarked on this page are the classic algorithms. Each algorithm is a CLIO Core module built on three shared paged engines (k-means, generalized linear models, and a generic pass over the data) with CPU, CUDA and SYCL kernels. Training data lives in a gpu_vector: the GPU keeps a page cache of a size you choose, and the rest of the data stays on whatever tiers the runtime composes, from host RAM to a DAOS container.

Against Spark MLlib, oneDAL and Dask-ML

Setup: Aurora. clio-ml uses one Intel GPU tile per node (of 12). Spark 3.5.6 MLlib uses all CPU cores of the node (2x Sapphire Rapids, 208 hardware threads, 1 TB). All systems train on bit-identical generated rows, 10M rows per node, 10 iterations, median of 2 timed repetitions. Milliseconds per iteration, lower is better:

k-means, 1 node
  • clio-ml67.7
  • Spark MLlib558.6
  • oneDAL (1 tile)230.0
  • Dask-ML396.7
k-means, 16 nodes
  • clio-ml73.7
  • Spark MLlib2,031.0
  • oneDAL (1 tile)234.0
  • Dask-ML1,547.0
Linear regression, 1 node
  • clio-ml31.3
  • Spark MLlib683.5
  • Dask-ML801.4
Linear regression, 16 nodes
  • clio-ml35.2
  • Spark MLlib2,082.2
  • Dask-ML462.7
Logistic regression, 1 node
  • clio-ml32.0
  • Spark MLlib278.0
  • oneDAL (1 tile)170.8
  • Dask-ML638.4
Logistic regression, 16 nodes
  • clio-ml37.8
  • Spark MLlib1,153.3
  • oneDAL (1 tile)245.9
  • Dask-ML1,245.6

Milliseconds per iteration, lower is better. oneDAL solves linear regression in closed form, so it has no per-iteration time there. clio-ml's time stays flat from 1 to 16 nodes while Spark's grows 3.6x; tuning Spark's executor layout does not change that. 8-node results are in the benchmark notes.

Speedup per iteration over Spark MLlib, higher is better:

  • linreg, 16 nodes59.1x
  • linreg, 8 nodes39.1x
  • logreg, 16 nodes30.5x
  • k-means, 16 nodes27.6x
  • logreg, 1 node8.7x
  • k-means, 1 node8.3x

Read these before quoting a speedup

  • An iteration is not the same progress everywhere. clio-ml's linear and logistic regression use batch gradient descent; MLlib uses L-BFGS. To the same linear model on one node, clio-ml takes 30 iterations in 0.94 s and Spark 6.8 s: 7.3x, not 21.8x.
  • For logistic regression, the others reach a good model first. Spark (L-BFGS) and oneDAL (newton-cg) reach a lower log-loss in fewer iterations than clio-ml's current optimizer. A second-order solver for the binary GLMs is the open gap.
  • oneDAL is the strongest baseline. Its k-means does the same work (identical final cost) at 3.2-3.4x clio-ml's time per iteration, and its closed-form linear regression beats clio-ml to the model.
  • clio-ml uses one of a node's twelve GPU tiles; Spark and Dask use the whole CPU side.

More algorithms, one node

Whole-fit times, 10M rows in memory, same data on both sides, against Spark MLlib. Where both systems report the same metric, accuracies agree to about three digits.

  • Bisecting k-means31.7x
  • Linear SVM15.1x
  • Naive Bayes12.3x
  • Multinomial logistic3.5x
  • Gaussian mixture3.3x
  • PCA2.8x
  • MLP2.5x
  • Gradient-boosted trees1.8x
  • Decision tree1.1x
  • Random forest0.2x

Whole-fit speedup over Spark MLlib, 10M rows on one node, higher is better (1.0x = Spark).

Bar chart of whole-fit time per algorithm for clio-ml, Spark MLlib and Dask-ML on 10M rows
Fit time per algorithm, 10M rows, one Aurora node.

Random forest is slower because clio-ml currently fits its trees one after another; Spark grows all trees together level by level.

Out of core: 61 GB on one node

500M rows (61 GB) on one node, with clio-ml's GPU cache capped well below the data size; evicted pages go to a host-DRAM tier. Spark and Dask hold the whole dataset in host memory.

k-means seconds per iteration, 500M rows (lower is better)
  • clio-ml, 4 GB cache5.05
  • clio-ml from DAOS5.58
  • Dask-ML7.10
  • Spark MLlib17.13
Total memory for 61 GB of data, GB (lower is better)
  • clio-ml68.9
  • Dask-ML198.6
  • Spark MLlib332.6
Total memory against seconds per iteration for clio-ml, Spark and Dask on 500M rows
Memory used against time per iteration, 500M rows (61 GB) on one node. Lower left is better.

clio-ml used 69-112 GB in total across cache sizes; Dask about 200 GB and Spark 333-455 GB for the same data. Dask's linear regression was ahead of clio-ml out of core (2.67 vs 4.34 s per iteration). These are single runs.

Where to go next