CSC3119 ยท Module 2 of 9

Model Persistence: Pickle vs Joblib & Pipeline Packaging

Serialize trained estimators, scalers, and encoders safely for zero-downtime serving

~56 min to study properly

Once an ML model is trained in memory, it will disappear as soon as the Python script terminates. Model serialization converts live Python objects into byte streams for disk storage or network transfer.

Checkpoint ยท the examiner asks

Explain why saving an isolated model estimator without its preprocessing pipeline breaks production deployments, and describe the security vulnerability inherent in Python pickle deserialization.

In one minute

Serialisation turns a trained model into bytes on disk. Joblib beats pickle for NumPy-heavy models (memory-mapping, compression). Always save the whole Pipeline โ€” preprocessing plus model โ€” or the API receives unscaled, unencoded inputs. Pickle/joblib can execute arbitrary code on load, so only load files from trusted, checksummed sources.

Traps examiners look for
  • Saving only the classifier and re-implementing preprocessing in the API.
  • Loading a .pkl from an unknown URL.
  • Saving with one library version and loading with another without pinning.
Read

Study notes

01What serialisation is for

A trained model lives in RAM; when the Python process ends, it's gone. Serialisation converts the live object โ€” its learned weights, tree structures, fitted scaler means โ€” into bytes that can be written to disk or sent over a network, and deserialisation rebuilds the object later, in another process or on another machine.

That's what lets you train once (on a laptop or a GPU VM) and serve many times (in a container on Render or a hospital server).

02pickle vs joblib

Python's built-in pickle handles almost any object. joblib builds on it but is optimised for objects containing large NumPy arrays โ€” which is what scikit-learn models are (a RandomForest is mostly arrays of thresholds and leaf values):

picklejoblib
Large NumPy arrayscopied byte by bytestored efficiently, can be memory-mapped
Compressionmanualbuilt in: compress=3, zlib/lz4
Multiple workerseach loads a full copymemory-mapped arrays can be shared
Typical usegeneral Python objectsscikit-learn models and pipelines
joblib.dump(pipeline, "models/stroke_pipeline.joblib", compress=3)
pipeline = joblib.load("models/stroke_pipeline.joblib")

For deep learning or cross-language serving you'd use framework formats (PyTorch state_dict, ONNX) instead.

03Save the pipeline, not just the classifier

The model was trained on preprocessed features: imputed BMI, scaled age and glucose, one-hot encoded categories. If you save only XGBClassifier, the API receives raw JSON like {"age": 67, "work_type": "Private"} and either:

  • crashes (could not convert string to float: 'Private'), or worse
  • gets numeric-only rows that aren't scaled, and returns confident garbage.

That's training-serving skew. Saving the whole fitted Pipeline (preprocessing + model) means one object takes raw input and does everything exactly as in training. Save alongside it a metadata file: model version, training date, library versions, feature names, validation metrics.

04Unpickling is code execution

pickle (and therefore joblib) can reconstruct objects by calling functions โ€” the __reduce__ protocol. A malicious file can tell the loader to run os.system("โ€ฆ"). Loading a model file is equivalent to running a program written by whoever made the file.

Rules for production:

  • Only load artifacts you (or your CI) produced.
  • Verify a checksum (SHA-256) or signature before loading; store models in a controlled model registry (MLflow, a private bucket).
  • Never load a .pkl from an email attachment, a public URL or a user upload.
  • Pin library versions: a model pickled with scikit-learn 1.3 may fail or behave differently in 1.5.
Watch it done

Worked examples

Worked example 1

Compressed artifact size

A 400-tree RandomForest has ~0.35 MB of arrays per tree. Saved with joblib at a 3.5ร— compression ratio, how large is the file?

    Worked example 2

    Diagnosing a broken API

    After deployment, /predict returns 500 with 'ValueError: could not convert string to float: Private'. Training accuracy was fine. What happened?

      Vocabulary

      Key terms

      Pickle Security in Production

      Major AI platforms like Hugging Face and PyTorch now recommend SafeTensors and ONNX over raw pickles because hundreds of public CVEs have demonstrated arbitrary remote code execution via poisoned pickle files.

      Practise

      Quick check

      0 of 8 correct so far. Wrong answers come with an explanation โ€” and the buddy can unpack them.

      Q1Why is joblib preferred over standard pickle for saving large Random Forest classifiers?

      Q2What should you do to prevent malicious remote code execution when loading saved ML models?

      Q3Why is joblib preferred over pickle for scikit-learn models?

      Q4Which artifact should the stroke API load?

      Q5What risk does pickle.load() carry?

      Q6A model saved with scikit-learn 1.3 is loaded in 1.5. What can happen?

      Q7What belongs in model metadata?

      Q8How should you verify a model file before loading it in production?

      Exam-style

      Written practice

      Short answer5 marks

      Compare pickle and joblib for persisting machine-learning models.

      Short answer5 marks

      Why must preprocessing be saved together with the model? Give the failure you would see if it isn't.

      Long answer10 marks

      Describe a safe, reproducible process for packaging and deploying the stroke model artifact, from training to loading in the API, including security controls.

      Watch

      Videos

      Fresh picks are chosen by AI every day.
      Hands-on

      Model Serialization Benchmark: Pickle vs Joblib & Pipeline Packaging

      4 guided tasks: predict, experiment, explain โ€” then challenge yourself. Plus 1 coding exercise you run right in the browser.

      Start the lab