Serialize fitted scikit-learn models to safetensors + JSON
Project description
skeights
Serialize fitted scikit-learn models to safetensors + JSON.
No pickle. No joblib. Just weights and config.
Why?
Pickle is the default way to save sklearn models, but it's insecure (arbitrary code execution on load), fragile (breaks across versions), and opaque (you can't inspect what's inside without loading it).
skeights splits a model into two layers:
.json: hyperparameters, fitted scalars, and structural config. Human-readable, greppable, diffable. You can inspect how a model is configured without deserializing it or running any code..safetensors: the numeric bulk (coefficients, tree split arrays, leaf values) as dense typed arrays in the safetensors format. Typed binary arrays instead of numbers encoded as text, which matters most for large tree ensembles.
Why safetensors specifically: it is memory-mappable, language-agnostic, and widely adopted across the ML ecosystem. The weight payload is readable outside Python and outside skeights. Loading safetensors does not execute arbitrary code.
[!NOTE] skeights does not use pickle or joblib. The JSON state file names the Python classes to instantiate (e.g.
sklearn.linear_model.Ridge), but the loader only allows imports fromsklearn,lightgbm, andxgboost. Arbitrary module imports from crafted JSON files are blocked.
When to use something else
There are other tools for serializing sklearn models. Here is when to reach for them instead.
skops is the actively maintained, scikit-learn-adjacent option for secure persistence, referenced in sklearn's own docs. It covers pipelines, XGBoost, LightGBM, has compression, model inspection, and Hugging Face Hub integration. Reach for skops if you want the broadest, most battle-tested secure persistence and do not need to inspect model config without loading it. Use skeights if you want human-readable, diffable model configuration.
sklearn-migrator is purpose-built for loading models across different sklearn versions, with a peer-reviewed paper behind it. Reach for it if cross-version migration is your problem. skeights does not guarantee cross-version support. Note that sklearn-migrator does not yet cover pipelines, XGBoost, or LightGBM, which skeights does.
Note: the feature descriptions of skops and sklearn-migrator above reflect their state as of mid-2026. Check their current docs for the latest.
Install
pip install skeights
Compatibility
Requires scikit-learn >= 1.5, LightGBM >= 4.4 (optional), XGBoost >= 2.1 (optional). CI tests against scikit-learn 1.5, 1.6, and latest; LightGBM 4.4 and latest; XGBoost 2.1 and latest.
Saved models are forward-compatible on a best-effort basis: we test loading fixtures saved on older library versions with newer ones, but don't guarantee cross-version compatibility. skeights will emit a warning when loading a model saved with a different library version.
Usage
import skeights
from sklearn.linear_model import Ridge
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
# Fit your model as usual
pipe = Pipeline([
("scaler", StandardScaler()),
("model", Ridge(alpha=0.1)),
])
pipe.fit(X_train, y_train)
# Save
skeights.save(pipe, "model.safetensors", "model.json")
# Load and predict
loaded = skeights.load("model.safetensors", "model.json")
predictions = loaded.predict(X_test)
API
| Function | Description |
|---|---|
save(estimator: BaseEstimator, arrays_path: str, state_path: str, format: str | None = None) -> None |
Serialize to safetensors + JSON files |
load(arrays_path: str, state_path: str) -> BaseEstimator |
Load from files, return fitted estimator |
serialize(estimator: BaseEstimator, format: str | None = None) -> tuple[dict, dict] |
Return (state_dict, arrays_dict) in memory |
deserialize(state: dict, arrays: dict) -> BaseEstimator |
Reconstruct estimator from dicts |
get_model_params(estimator: BaseEstimator) -> dict |
Recursively extract hyperparameters |
set_model_params(estimator: BaseEstimator, params: dict) -> None |
Recursively set hyperparameters |
Supported estimators
| Status | Estimators |
|---|---|
| Supported | Ridge, Lasso, LinearRegression, LogisticRegression, and other linear models. MLPRegressor/MLPClassifier. DecisionTreeRegressor/Classifier, RandomForestRegressor/Classifier, GradientBoostingRegressor/Classifier, HistGradientBoostingRegressor/Classifier. LGBMRegressor/Classifier (columnar tensors or native text), XGBRegressor/Classifier (columnar tensors or native JSON). GaussianProcessRegressor/Classifier (including composite kernels). TransformedTargetRegressor. StandardScaler, MinMaxScaler, RobustScaler. Pipeline composed of any of the above. |
| Not yet implemented | CatBoost, other ensemble meta-estimators (VotingClassifier, StackingRegressor, etc.), PCA and other decomposition transforms. Open an issue or PR if you need any of these. |
| Not planned | Cross-version sklearn migration (use sklearn-migrator). General-purpose secure persistence with broad estimator coverage (use skops). |
Tree model formats
LightGBM and XGBoost models are serialized as columnar tensors by default: split features, thresholds, child pointers, and leaf values are stored as typed numpy arrays in safetensors, with only small scalar config (objective, feature names, etc.) in JSON.
This gives 30-85% smaller files compared to the native format and makes the JSON human-readable. To use the native format instead:
skeights.save(model, "model.safetensors", "model.json", format="native")
Artifacts saved with older versions of skeights (before columnar support) are loaded transparently, no migration needed.
License
MIT
Project details
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 skeights-0.3.0.tar.gz.
File metadata
- Download URL: skeights-0.3.0.tar.gz
- Upload date:
- Size: 2.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2621838d5df8fa872c11720a303dad71ab84e13974c012de514ac88d852bef5d
|
|
| MD5 |
7280273325ad034cad4994722939dc8e
|
|
| BLAKE2b-256 |
74d23748e5530e5d07abc402be24cff3a2e98db9083c60d27d60bbe6353eeb8c
|
Provenance
The following attestation bundles were made for skeights-0.3.0.tar.gz:
Publisher:
publish.yml on carbon-re/skeights
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skeights-0.3.0.tar.gz -
Subject digest:
2621838d5df8fa872c11720a303dad71ab84e13974c012de514ac88d852bef5d - Sigstore transparency entry: 2163421703
- Sigstore integration time:
-
Permalink:
carbon-re/skeights@9c3fb9ba900feeb74e93440fe1dc729fde12a36f -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/carbon-re
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9c3fb9ba900feeb74e93440fe1dc729fde12a36f -
Trigger Event:
push
-
Statement type:
File details
Details for the file skeights-0.3.0-py3-none-any.whl.
File metadata
- Download URL: skeights-0.3.0-py3-none-any.whl
- Upload date:
- Size: 27.8 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 |
e4f41dd856b0a1993b69f5a93e672c4470c5683623698cc52aa71b31db2c0444
|
|
| MD5 |
f52e4745d05f8897aa4975527bde6451
|
|
| BLAKE2b-256 |
98b318fa2bc91f607a6369ccc6c98c20ffc256018f0e1d7ba02077b0e196742a
|
Provenance
The following attestation bundles were made for skeights-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on carbon-re/skeights
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skeights-0.3.0-py3-none-any.whl -
Subject digest:
e4f41dd856b0a1993b69f5a93e672c4470c5683623698cc52aa71b31db2c0444 - Sigstore transparency entry: 2163421717
- Sigstore integration time:
-
Permalink:
carbon-re/skeights@9c3fb9ba900feeb74e93440fe1dc729fde12a36f -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/carbon-re
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9c3fb9ba900feeb74e93440fe1dc729fde12a36f -
Trigger Event:
push
-
Statement type: