Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
MLOps exists because machine learning systems break the assumptions software engineering is built on. In normal software the behavior is in the code, so versioning the code versions the system. In ML, behavior comes from code plus data plus a trained model plus the live distribution of inputs — change any one and the system behaves differently even though nothing in git moved. That extra dependency on data and a stochastic training process is why you can't just 'deploy and forget' a model, and it's the entire reason this discipline is separate from DevOps. Getting this distinction in your bones is what makes every later practice — versioning data, tracking experiments, monitoring drift — feel necessary rather than ceremonial.
The demo lays the two lifecycles side by side as a checklist, so you can see exactly which steps software has that ML inherits, and which steps (data versioning, training, eval, drift monitoring) are net-new and have no DevOps equivalent.
Use these three in order. Each builds on the one before.
In one paragraph, explain how the machine learning lifecycle differs from the normal software development lifecycle, like I'm new to it.
Walk me through, step by step, why an ML system's behavior depends on data and training and not just code, and what that means for reproducibility.
Given an ML system whose accuracy silently dropped with no code change, walk me through the candidate causes that a software-only mental model would miss, and why.
# What changes the BEHAVIOR of each kind of system?
software_inputs = {"code"}
ml_inputs = {"code", "training_data", "hyperparams", "random_seed",
"trained_weights", "live_input_distribution"}
new_in_ml = ml_inputs - software_inputs
print("ML adds these behavior-determining inputs:", sorted(new_in_ml))
# A consequence: 'it worked yesterday' can break with NO code change,
# because training_data or live_input_distribution moved underneath you.
def can_reproduce(have_code, have_data_version, have_seed, have_weights):
missing = [k for k, v in {
"code": have_code, "data_version": have_data_version,
"seed": have_seed, "weights": have_weights}.items() if not v]
return "reproducible" if not missing else f"NOT reproducible, missing: {missing}"
print(can_reproduce(True, False, True, True)) # missing data_version -> not reproduciblepython3 main.py