01 — Deploy & Serve

Model Packaging & Containers#

DeploymentPractice 1 min read
◆ The PatternExporting models into portable, versioned artifacts

A trained model sitting in a notebook is not production-ready. Model packaging wraps your model, its dependencies, and inference code into a self-contained artifact — a Docker image, an ONNX file, or an MLflow model directory — that can be deployed anywhere identically.

Artifact = Model + Dependencies + Inference Code + Config
Packaging ensures every deployment gets the exact same model, libraries, and preprocessing — no "works on my machine" surprises.
// Interactive — packaging pipeline flow
FormatProsBest for
Docker ImageFull environment isolationMicroservice deployments
ONNXFramework-agnostic, optimized runtimeCross-platform inference
MLflow ModelVersioned, metadata-richMLflow ecosystem
BentoML BundleBuilt-in API serverQuick API endpoints
Pickle / JoblibSimple, native PythonPrototyping only
Avoid pickle in production: Pickle files are Python-version-specific, not human-readable, and pose security risks (arbitrary code execution). Use ONNX or framework-native formats for anything beyond prototypes.
Pattern bridge: Model packaging is the deployment equivalent of cross-validation — both enforce separation between what you build and where you test it. In markets, backtesting discipline enforces the same boundary.
Worked example

The same six weights packaged with two requirement files that differ in a single pin — NumPy 1.26.4 against 2.0.0 — get different artifact IDs: e93e1a2e4504 and c538e448aba7. That is the point of packaging: a model is not its weights, it is its weights plus everything they need to run, and a change to either is a new version.

Where it misleads
  • A container is only reproducible if its inputs are pinned. A base image tagged latest or an unpinned pip install builds a different artifact next month.
  • Converting to ONNX or another format can change numerics or drop unsupported operations; compare outputs before and after on real inputs.
  • Loading a pickle runs code. Never load one from a source you do not control.
In code
import hashlib
weights = np.arange(6, dtype=np.float32).reshape(2, 3)     # the trained model, tiny here

def artifact_id(weights, requirements):                    # identity = model bytes + the environment it needs
    h = hashlib.sha256(weights.tobytes())
    h.update(requirements.encode())
    return h.hexdigest()[:12]

a = artifact_id(weights, 'numpy==1.26.4\nscikit-learn==1.4.2')
b = artifact_id(weights, 'numpy==2.0.0\nscikit-learn==1.4.2')     # same weights, one pin changed
Python, in your browser — edit the code and run it again

Assumes import numpy as np and import pandas as pd. Each snippet carries its own example numbers; the comments say which are made up or simulated.

The same idea with a library
# Python — export model as ONNX + Docker
import onnx, torch

# Export PyTorch model to ONNX
dummy = torch.randn(1, 10)
torch.onnx.export(model, dummy, "model.onnx",
                  input_names=["features"],
                  output_names=["prediction"])

# Dockerfile
# FROM python:3.11-slim
# COPY model.onnx requirements.txt serve.py .
# RUN pip install -r requirements.txt
# CMD ["python", "serve.py"]
Sources
  • D. Sculley et al., “Hidden Technical Debt in Machine Learning Systems”, Advances in Neural Information Processing Systems 28, 2015
  • M. Zaharia et al., “Accelerating the Machine Learning Lifecycle with MLflow”, IEEE Data Engineering Bulletin 41(4), 2018
  • Open Neural Network Exchange (ONNX) specification, onnx.ai — the portable model format

Last reviewed October 2026 · How this site checks its content · Report a mistake

Linked from 1
Open in the full reader, with the topic sidebar