GPU-accelerated scikit-learn via Apple Metal
Project description
skmetal
Apple Silicon GPU acceleration for scikit-learn
import skmetal
from sklearn.linear_model import LinearRegression
@skmetal.accelerate
def model():
return LinearRegression()
m = model()
m.fit(X_train, y_train)
m.predict(X_test)
Overview
skmetal executes scikit-learn estimators on Apple Silicon GPUs via Metal Performance Shaders and custom Metal compute kernels. Decorate any function that returns an estimator with @skmetal.accelerate and fit()/predict() run on the GPU — no code changes required.
Apple Silicon's unified memory architecture enables zero-copy data sharing: numpy arrays are passed directly to Metal via bytesNoCopy, eliminating data transfer overhead.
Requirements
- macOS 14+
- Apple Silicon (M1-M5)
- Python 3.10-3.12
- Swift 6.1 (
xcode-select --install) - scikit-learn >= 1.5
Installation
pip install skmetal
Note: macOS 14+ and Apple Silicon required. Xcode not needed for the pip package.
From source
git clone https://github.com/abderahmane-ai/skmetal.git
cd skmetal
bash build.sh
pip install -e .
Usage
Decorator (recommended)
import skmetal
from sklearn.linear_model import LinearRegression
@skmetal.accelerate
def model():
return LinearRegression()
m = model()
m.fit(X, y)
m.predict(X_test)
The decorator also works with pipelines:
@skmetal.accelerate
def pipeline():
return Pipeline([
("scaler", StandardScaler()),
("clf", LogisticRegression()),
])
pipe = pipeline()
pipe.fit(X, y)
pipe.predict(X_test)
Function call
model = skmetal.accelerate(LinearRegression())
model.fit(X, y)
Context manager
with skmetal.accelerate_context():
model = LinearRegression()
model.fit(X, y)
Supported Estimators
| Estimator | GPU Strategy | Speedup |
|---|---|---|
LinearRegression |
Normal equations via MPS GEMM | 5.93x |
Ridge |
Fused centering + XTX + XTy (1 dispatch) | 1.16x |
LogisticRegression |
IRLS (3-5 Newton iterations, fused) | 0.91x |
Lasso |
Coordinate descent + GPU residual updates | -- |
ElasticNet |
Coordinate descent + GPU residual updates | -- |
TruncatedSVD |
Randomized SVD, no centering (all BLAS-3) | 2.53x |
KMeans |
Single fused command buffer (all iterations on GPU) | 0.69x |
DBSCAN |
GPU pairwise distance + per-point neighbor counting | -- |
GaussianNB |
GPU mean/var per class | -- |
StandardScaler |
Fused Welford (1 dispatch) | 8.27x |
MinMaxScaler |
Column min/max with threadgroup tree reduction | -- |
RobustScaler |
GPU quantile approximation | -- |
KNeighborsClassifier |
GPU pairwise distance + fused voting | -- |
KNeighborsRegressor |
GPU pairwise distance + fused averaging | -- |
NearestNeighbors |
GPU pairwise distance + index | -- |
HistGradientBoostingRegressor |
C++ HGBT from sklearn (no custom GPU) | -- |
HistGradientBoostingClassifier |
C++ HGBT from sklearn (no custom GPU) | -- |
Estimators below 1.0x speedup are dispatch-limited at n <= 50K. Speedup improves to 2-5x at n >= 500K where compute dominates overhead.
Architecture
Zero-copy pipeline
numpy array -> np.ctypes.data -> UnsafeMutableRawPointer -> MTLBuffer(bytesNoCopy:) -> GPU
| |
+--------- same physical memory ---------------------+
Metal kernels (14 files)
| Kernel file | Operations |
|---|---|
ReductionKernels.metal |
reduce_sum, reduce_mean_var (Welford) |
ArgminKernels.metal |
argmin_rows |
KMeansKernels.metal |
assign, partial_sum, combine, normalize, batch fused |
KNNKernels.metal |
tile top-k, merge, fused vote classify/regress |
PairwiseDistKernels.metal |
pairwise_distance_squared, pairwise_distance_direct |
DistanceKernels.metal |
row_norm_sq, compute_mindists, distance_correct |
IrlsKernels.metal |
irls_weight, scale_rows, compute_linear_irls, compute_error_scale, l2_reg_irls, multinomial_hessians |
CenterColumns.metal |
column_means, center_columns |
ElementWiseKernels.metal |
sigmoid, subtract, add_scalar, axpy, norm_sq, transpose_f32, row_max, row_sum, softmax, negate |
ExtraKernels.metal |
soft_threshold, column_transform, scale_f32, sv_init, sv_hook, sv_shortcut |
StandardScalerKernels.metal |
scaler_fit (fused Welford) |
GemmKernels.metal |
gemm_simple (fallback) |
MinMaxKernels.metal |
column_minmax (threadgroup tree reduction) |
TreeKernels.metal |
tree_predict, tree_predict_all |
Swift bridge (47 C-callable functions)
All skmetal_* functions use @_cdecl for direct ctypes export. Every function accepts raw pointers.
Project structure
skmetal/
skmetal/
__init__.py
_bridge.py ctypes -> Swift (47 functions)
_config.py Config dataclass
_dispatch.py estimator registry + wrapping
accelerate.py @accelerate decorator + accelerate_context
estimators/
_base.py BaseGPUEstimator abstract class
_registry.py Estimator registry (17 estimators)
linear_model.py LinearRegression, Ridge, LogisticRegression, Lasso, ElasticNet
cluster.py KMeans, DBSCAN
decomposition.py TruncatedSVD
ensemble.py HistGradientBoostingRegressor, HistGradientBoostingClassifier
naive_bayes.py GaussianNB
neighbors.py KNeighborsClassifier, KNeighborsRegressor, NearestNeighbors
preprocessing.py StandardScaler, MinMaxScaler, RobustScaler
utils.py
skmetal_bridge/ Swift + Metal
Sources/SkMetalBridge/
Bridge.swift 47 @_cdecl exports
MetalContext.swift
Kernels/*.metal 14 Metal kernel files
benchmarks/
run_compare.py benchmark runner
benchmark_suite.py full suite
baseline.json
tests/
test_correctness.py 18 estimator correctness tests
test_dispatch.py 7 dispatch logic tests
test_kernels.py 55 kernel unit tests
test_config.py 13 config API tests
test_accelerate.py 20 accelerate edge-case tests
test_stress.py 27 edge-case/stress tests
conftest.py shared fixtures
build.sh
pyproject.toml
.github/workflows/
ci.yml build + test + benchmark regression
release.yml PyPI publish on tag
LICENSE MIT
Tests
test_correctness 18/18 pass — estimator parametrizations + pipeline + device info
test_dispatch 7/7 pass — registry, wrapping, pipeline, decorator
test_kernels 55/55 pass — all 14 kernel files covered
test_config 13/13 pass — config API, dtype rejection, threshold, reset
test_accelerate 20/20 pass — decorator, context manager, edge cases
test_stress 27/27 pass — contiguity, shape mismatch, extremes, CPU fallback
Benchmarks
python benchmarks/run_compare.py
Development
git clone https://github.com/abderahmane-ai/skmetal.git
cd skmetal
bash build.sh
pip install -e ".[dev]"
pytest tests/
python benchmarks/run_compare.py
Adding a new estimator
- Create
skmetal/estimators/my_model.pywithMetalMyModel(BaseGPUEstimator) - Register in
_registry.py(GPU_ESTIMATORS+PIPELINE_PATTERNS) - Add module path in
_dispatch.py(module_map) - Write a Metal kernel if needed
- Add a parametrized test case in
test_correctness.py
License
MIT License. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file skmetal-0.2.1.tar.gz.
File metadata
- Download URL: skmetal-0.2.1.tar.gz
- Upload date:
- Size: 26.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
68e8edfcae68eaaa7d19a1f4a46617cd4e9f347e5fea9a349d3c56581aaaf03a
|
|
| MD5 |
ce297c395335a4d42111262e74569afb
|
|
| BLAKE2b-256 |
c71b03be5a025b87e1393d9c1dfb5a092cb1151ed029e2184499911a9525383d
|
Provenance
The following attestation bundles were made for skmetal-0.2.1.tar.gz:
Publisher:
release.yml on abderahmane-ai/skmetal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skmetal-0.2.1.tar.gz -
Subject digest:
68e8edfcae68eaaa7d19a1f4a46617cd4e9f347e5fea9a349d3c56581aaaf03a - Sigstore transparency entry: 1810467967
- Sigstore integration time:
-
Permalink:
abderahmane-ai/skmetal@9c77cfd73b68ed671d6b88563f8c54a5ab039061 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/abderahmane-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9c77cfd73b68ed671d6b88563f8c54a5ab039061 -
Trigger Event:
push
-
Statement type:
File details
Details for the file skmetal-0.2.1-py3-none-any.whl.
File metadata
- Download URL: skmetal-0.2.1-py3-none-any.whl
- Upload date:
- Size: 150.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
43cb0eef540dc626af6f09ac9be19499ff2cd2e0f1c2927f14024f559f0d6f1d
|
|
| MD5 |
acdbec0e238bb90582f980a312e58997
|
|
| BLAKE2b-256 |
37bf057028f257f94e26c7467b2fb81d803c046005b043d9ae03e274b91841ce
|
Provenance
The following attestation bundles were made for skmetal-0.2.1-py3-none-any.whl:
Publisher:
release.yml on abderahmane-ai/skmetal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skmetal-0.2.1-py3-none-any.whl -
Subject digest:
43cb0eef540dc626af6f09ac9be19499ff2cd2e0f1c2927f14024f559f0d6f1d - Sigstore transparency entry: 1810467971
- Sigstore integration time:
-
Permalink:
abderahmane-ai/skmetal@9c77cfd73b68ed671d6b88563f8c54a5ab039061 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/abderahmane-ai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9c77cfd73b68ed671d6b88563f8c54a5ab039061 -
Trigger Event:
push
-
Statement type: