Logging and loading models

MLflow · Essentials · 12 min

A logged model carries its dependencies and interface, so others can load and use it without your training code.

Each flavor module has log_model, e.g. mlflow.sklearn.log_model(model, name="model"). In MLflow 3 this creates a LoggedModel, a first-class entity with its own ID, linked to the active run. The return value (ModelInfo) has a model_uri such as models:/m-....

A logged model directory contains:

  • MLmodel: a YAML file listing flavors, signature and metadata,
  • the serialized model (for sklearn, a pickle-free model.skops file by default in recent 3.x releases),
  • requirements.txt, conda.yaml and python_env.yaml with pinned dependencies,
  • an optional input_example.

Load it two ways:

  • Native flavor: mlflow.sklearn.load_model(uri) returns the original estimator with all its methods.
  • pyfunc: mlflow.pyfunc.load_model(uri) returns a generic PyFuncModel whose predict(data) works the same for every flavor, which is what serving and batch scoring use.

URIs you will see: models:/<model_id>, runs:/<run_id>/<path> for older-style references, and models:/<name>/<version> or models:/<name>@<alias> for registered models.

Always pass an input_example (a few rows of real input): MLflow infers the signature from it and validates that the model can be loaded and called. Version mismatches between the training and loading environments are the most common loading problem; the logged requirements tell you what to install.

Example

import mlflow
from sklearn.datasets import load_diabetes
from sklearn.linear_model import Ridge

X, y = load_diabetes(return_X_y=True, as_frame=True)
model = Ridge(alpha=0.5).fit(X, y)

with mlflow.start_run():
    info = mlflow.sklearn.log_model(model, name="ridge", input_example=X.head(3))

print(info.model_uri.startswith("models:/"))   # True (MLflow 3 LoggedModel URI)

native = mlflow.sklearn.load_model(info.model_uri)
print(type(native).__name__, native.alpha)     # Ridge 0.5

generic = mlflow.pyfunc.load_model(info.model_uri)
print(generic.predict(X.head(2)).round(1))     # same predictions as native.predict
print(generic.metadata.get_input_schema().input_names()[:3])  # ['age', 'sex', 'bmi']

Remember

  • <flavor>.log_model(model, name=...) creates a LoggedModel with an MLmodel file and pinned requirements
  • Load natively for full API, or via mlflow.pyfunc for a uniform predict
  • Pass input_example so a signature is inferred and the model is validated

Watch out for

  • Loading a model in an environment with different library versions than the ones logged in requirements.txt, causing deserialization errors.
  • Logging tree-based sklearn models with skops serialization without listing their types in skops_trusted_types (or choosing serialization_format="cloudpickle"), which fails with an untrusted-types error.

Check yourself

  1. What does mlflow.pyfunc.load_model return?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: mlflow.org/docs/latest/ml/model/