MLOpsThe MLOps lifecycle · MLflow 3.17 · DVC 3.67 · FastAPI · Docker · GitHub Actions · Evidently · Python 3.11+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
50 small wins to finish your pathNext lesson →

The prediction pipeline

The prediction pipeline is the path a single record takes after training: it loads the preprocessor and the model that a training run saved, transforms the record with that fitted preprocessor, and returns one number.

Last updated: 19 Oct, 2026 · MLOps

The model trainer left two files on disk. Training is finished with them; everything from here reads them. The video builds this as its own module under the pipeline folder, a small class with a predict method, and then hands that class to the web app. The class is written here, and the service that calls it comes later in the course.

The two artifacts a training run leaves behind

Both files were written through the same helper, so a reload is symmetric. No other piece of the training run is needed at prediction time: no training data, no pipeline code of your own, no config.

python
# written by the two stages through save_object in src/sp/utils/common.py
joblib.dump(pre, "artifacts/data_transformation/preprocessor.joblib")
joblib.dump(model, "artifacts/model_trainer/model.joblib")
A prediction class that loads the saved model and returns a label · from the Complete End to End Deep Learning Project With MLFLOW,DVC And Deployment · 3:28:14 to 3:29:55

The clip loads a Keras model and prepares its input with tensorflow.keras.preprocessing.image.load_img, which Keras 3 replaced with keras.utils.load_img; this class loads a joblib-saved scikit-learn pipeline, so what carries over is the shape of the class.

Loading the saved objects once

The constructor takes the two paths and loads both objects. Doing it in __init__ rather than inside predict matters once a server is calling this: the files are read once at start-up instead of on every request.

python
from pathlib import Path

import pandas as pd

from sp.utils.common import load_object
python
class PredictPipeline:
    """Loads what a training run saved, and scores one record with it."""

    def __init__(
        self,
        preprocessor_path=Path("artifacts/data_transformation/preprocessor.joblib"),
        model_path=Path("artifacts/model_trainer/model.joblib"),
    ):
        # both files are read once here, not on every request
        self.pre = load_object(preprocessor_path)
        self.model = load_object(model_path)

Turning one record into a row

A record arrives as a dict, one key per feature. Wrapping it in a one-row frame is what lets the preprocessor match by column name, exactly as it did during training. The result is a one-row matrix, and the first value of the prediction is the answer.

python
    def predict(self, record: dict) -> float:
        """Turn one student record into a predicted maths score."""
        df = pd.DataFrame([record])
        return float(self.model.predict(self.pre.transform(df))[0])

Predicting a maths score for one student

The record below is the first row of the dataset with its maths score taken out, so the prediction can be read against the real value of 72.

ExampleOne record through the saved preprocessor and model
import joblib
import pandas as pd

pre = joblib.load("artifacts/data_transformation/preprocessor.joblib")
model = joblib.load("artifacts/model_trainer/model.joblib")

# the first row of the dataset, without the maths score the model has to produce
record = {"gender": "female", "race_ethnicity": "group B",
          "parental_level_of_education": "bachelor's degree", "lunch": "standard",
          "test_preparation_course": "none", "reading_score": 72, "writing_score": 74}

row = pd.DataFrame([record])
print(round(float(model.predict(pre.transform(row))[0]), 2))
  • The answer is 69.34 against a true score of 72, which is inside the average miss of about five marks the trainer reported.
  • The transform came from the saved object, so group B landed in the same one-hot column it occupied during training and the two scores were scaled with the training medians.
  • No training data was touched. The two joblib files are the whole of what serving needs, which is why they are the files a container copies in.

A record that is missing a column

The failure to meet first is the common one: a form or an API call that leaves a field out. The preprocessor was fitted on seven named columns, and it says so.

ExampleA record missing one feature
# the same record with one field left out, the way a web form drops a field
short = {k: v for k, v in record.items() if k != "test_preparation_course"}
print(pre.transform(pd.DataFrame([short])))

The fix is not to patch the preprocessor. It is to reject the request before it reaches this line, with a schema that names every field the model needs, which is how the serving lesson handles it.

Training against predicting

The training runThe prediction pipeline
Readstrain.csv and test.csvTwo joblib files
The preprocessorFitted with fit_transformLoaded and used with transform
Rows at a time800One
RunsWhen you retrainOn every request
ProducesA model and a metrics fileOne number

Where the prediction pipeline sits

  • Behind an API, where a request body becomes the record dict and the returned number becomes the response.
  • Inside a container, where the image carries the two artifacts and this module, which is all that answering a request needs.
  • In a batch job, where the same loaded pair scores a file of records in a loop rather than one at a time.
Watch out. The keys of the record are part of the contract. They have to be the feature column names, spelled as the training frame spelled them, with the target left out. A record carrying math_score as well does not help the model and a record missing a feature stops it, so validate the request against the same schema the training data was checked with.
Try it yourself
  • Change reading_score and writing_score to 95 and read how far the prediction moves.
  • Load the preprocessor and call get_feature_names_out() to see the 19 column names the model was trained on.
  • Pass a list of three records to pd.DataFrame and read three predictions back from one call.

Little by little, you're building something great.