scikit-learn
keras
machine learning
model persistence
Python tutorial

how to save a scikit-learn pipline with keras regressor inside to disk?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Saving a scikit-learn pipeline that includes a Keras regressor can fail if wrapper choice and serialization strategy are not aligned. Older wrapper classes are fragile with pickling, especially across version upgrades. The reliable approach in modern projects is using scikeras with explicit model factory functions and controlled dependency versions.

Use scikeras Instead of Deprecated Wrappers

The old tensorflow.keras.wrappers.scikit_learn utilities are limited and often create persistence issues. scikeras is designed for scikit-learn compatibility and generally serializes more predictably.

Install dependencies:

bash
pip install scikeras scikit-learn tensorflow joblib

Build a pipeline:

python
1import numpy as np
2from sklearn.pipeline import Pipeline
3from sklearn.preprocessing import StandardScaler
4from scikeras.wrappers import KerasRegressor
5from tensorflow import keras
6
7
8def build_model():
9    model = keras.Sequential([
10        keras.layers.Input(shape=(4,)),
11        keras.layers.Dense(16, activation='relu'),
12        keras.layers.Dense(1)
13    ])
14    model.compile(optimizer='adam', loss='mse')
15    return model
16
17pipe = Pipeline([
18    ('scale', StandardScaler()),
19    ('reg', KerasRegressor(model=build_model, epochs=20, batch_size=16, verbose=0))
20])
21
22x = np.random.rand(200, 4).astype('float32')
23y = (x[:, 0] * 2.0 + x[:, 1] * 0.5).astype('float32')
24
25pipe.fit(x, y)

This gives scikit-learn style fit and predict while preserving Keras model internals.

Save and Load the Pipeline with joblib

Once trained, serialize the entire pipeline.

python
1import joblib
2
3joblib.dump(pipe, 'regression_pipeline.joblib')
4loaded = joblib.load('regression_pipeline.joblib')
5
6sample = np.random.rand(3, 4).astype('float32')
7print(loaded.predict(sample))

This works when the model-building function is importable at load time and package versions are compatible.

Keep Model Factory Importable

A common persistence error happens when build_model is defined in interactive scope that is unavailable during load in another process. Put model factories in importable modules.

Example project structure:

  • models.py contains build_model
  • training script imports from models.py
  • inference script also imports from models.py

This reduces deserialization surprises in production jobs.

Versioning and Reproducibility Strategy

Serialization is not only about bytes on disk. You also need metadata:

  • scikit-learn version
  • TensorFlow version
  • scikeras version
  • feature order and schema
  • preprocessing assumptions

Write a sidecar metadata file:

python
1import json
2import sklearn
3import tensorflow as tf
4import scikeras
5
6meta = {
7    'sklearn': sklearn.__version__,
8    'tensorflow': tf.__version__,
9    'scikeras': scikeras.__version__,
10    'features': ['f1', 'f2', 'f3', 'f4']
11}
12
13with open('regression_pipeline.meta.json', 'w', encoding='utf-8') as f:
14    json.dump(meta, f, indent=2)

When loading, compare runtime versions against metadata and fail early if major mismatch exists.

Alternative: Save Keras Model and sklearn Steps Separately

For strict portability, some teams save Keras model separately and rebuild sklearn preprocessing around it. This increases code complexity but can simplify cross-version migration if monolithic pipeline loading becomes unstable.

Still, for many applications, one serialized pipeline artifact with scikeras plus metadata is the best balance.

Add a Deployment Smoke Test

After loading, run a deterministic smoke inference in startup checks. This confirms artifact readability and output shape before traffic is accepted.

python
1import numpy as np
2
3probe = np.zeros((1, 4), dtype='float32')
4out = loaded.predict(probe)
5print('smoke prediction shape:', out.shape)

Small checks like this catch broken artifacts early and make rollout failures easier to diagnose.

Common Pitfalls

A common pitfall is using deprecated wrappers and expecting stable serialization across environments.

Another issue is defining model factory in notebook cell, then loading artifact from a different runtime where that symbol does not exist.

Teams also forget feature schema tracking, so loaded model receives columns in wrong order.

Version drift between training and inference environments is another frequent source of hard-to-debug failures.

Finally, avoid treating successful local load as proof of production safety. Test load and predict in clean environment that mirrors deployment.

Summary

  • Prefer scikeras for sklearn-compatible Keras pipeline persistence.
  • Serialize pipeline with joblib and keep model factory importable.
  • Track dependency and feature metadata next to artifact.
  • Validate loading in deployment-like environments, not only local notebooks.
  • Use separate model and preprocessing artifacts only when portability needs justify extra complexity.

Course illustration
Course illustration

All Rights Reserved.