MLOps Zoomcamp 2024 实验跟踪作业实战:用 MLflow 完成出租车时长预测、超参调优与模型注册全流程
【免费下载链接】mlops-zoomcampFree MLOps course from DataTalks.Club. Register here 👇🏼 to get notified about the next cohort项目地址: https://gitcode.com/GitHub_Trending/ml/mlops-zoomcamp
本篇基于 2024 届第 2 周作业文档 展开,完整覆盖从安装 MLflow、预处理 Green Taxi 数据、autolog 训练 RandomForest,到本地部署 tracking server、hyperopt 超参调优和将最优模型推送到模型注册表的全部 6 个练习。读完本篇,你可以按照仓库中的脚本独立完成整个实验跟踪(Experiment Tracking)与模型管理(Model Registry)闭环,并理解每个练习背后对应的仓库源码实现。
1. 作业目标与 Q1:安装 MLflow
该作业的官方目标是:熟悉 MLflow——一个用于实验跟踪与模型管理的工具。整个作业围绕一个真实的回归任务展开:使用Green Taxi Trip Records数据集预测每次行程的时长(duration)。
Q1 要求安装 MLflow 的 Python 包并验证版本:
- 文档建议创建一个独立的 Python 环境(例如使用 conda 环境),再通过
pip或conda在其中安装 MLflow; - 安装完成后执行
mlflow --version查看输出,并在交卷时报告自己的版本号。
这是一个刻意设置的入门步骤:后续所有脚本(训练、调参、注册)都依赖mlflow包提供的autolog、start_run、MlflowClient等 API,版本差异也可能影响 UI 展示与注册表行为,因此先固定并记录版本。
2. Q2:下载与预处理数据(preprocess_data.py 源码解析)
Q2 要求下载 2023 年 1 月、2 月、3 月的 Green Taxi Trip Records parquet 数据(来源于 NYC TLC 官方发布页),然后运行作业脚本:
python preprocess_data.py --raw_data_path <TAXI_DATA_FOLDER> --dest_path ./output文档提示:执行前先进入02-experiment-tracking/homework/目录(即本仓库的 homework 目录),并把<TAXI_DATA_FOLDER>替换为你实际存放数据的位置。该脚本会完成三件事:从<TAXI_DATA_FOLDER>加载数据、在训练集(2023 年 1 月)上拟合一棵DictVectorizer、把预处理后的数据集与DictVectorizer保存到磁盘。
结合 preprocess_data.py 源码,可以看到脚本的具体行为:
- 数据加载与清洗(
read_dataframe函数):读取 parquet 后,用lpep_dropoff_datetime - lpep_pickup_datetime计算 duration 并换算为分钟,只保留时长在[1, 60]分钟之间的记录;同时将PULocationID、DOLocationID转为字符串; - 特征工程(
preprocess函数):把上下车地点拼成组合特征PU_DO = PULocationID + '_' + DOLocationID,与数值特征trip_distance一起构造成 dict 记录,再通过DictVectorizer转为稀疏特征矩阵。注意fit_dv参数:只对训练集调用fit_transform,验证/测试集只做transform,避免数据泄漏; - 月份划分:
run_data_prep按文件名约定加载green_tripdata_2023-01/02/03.parquet,分别作为 train / val / test; - 落盘:
dump_pickle把 4 个对象保存到dest_path——dv.pkl(向量器)、train.pkl、val.pkl、test.pkl(每个数据集是(X, y)元组)。
由此可以直接回答 Q2 的选择题:“OUTPUT_FOLDER 保存了多少个文件?”——从源码的 4 处dump_pickle调用看,答案是4。
3. Q3:用 autolog 训练模型(train.py 的改造方式)
Q3 要求用 Scikit-Learn 的RandomForestRegressor在预处理好的数据上训练,并改造训练脚本启用 MLflow autologging,运行后启动 MLflow UI 确认 run 被正确跟踪。
作业版 train.py 目前是“裸”训练代码:加载train.pkl/val.pkl,用RandomForestRegressor(max_depth=10, random_state=0)训练,在验证集上计算mean_squared_error(..., squared=False)得到 RMSE,但没有任何 MLflow 调用。
对照 solution/train.py,官方答案的改造点只有四处:
import mlflow mlflow.set_tracking_uri("sqlite:///mlflow.db") mlflow.set_experiment("random-forest-train") # 在 run_train 内部: mlflow.sklearn.autolog() # 开启 sklearn 自动日志 with mlflow.start_run(): # 文档 Tip 1 强调:用 start_run 包裹训练代码 rf = RandomForestRegressor(max_depth=10, random_state=0) ...从源码结构看,这正是 autologging 的标准用法:mlflow.sklearn.autolog()会拦截RandomForestRegressor的构造与fit调用,自动记录超参数(如max_depth、random_state等);再配合start_run()把日志归属到当前 run。不要修改模型超参数(文档 Tip 2),以保证训练快速完成且结果可比。
Q3 的选择题问 run 中记录的min_samples_split是多少。由于脚本只显式指定了max_depth=10与random_state=0,其余参数取 Scikit-Learn 默认值,因此 UI 中看到的min_samples_split为2(默认值)。
4. Q4:本地启动 tracking server(含模型注册表)
Q4 要求在本地启动一个 tracking server——这样不仅能跟踪实验,还能访问model registry。具体任务:
- 在本地启动 tracking server;
- 使用SQLite作为 backend store,使用名为
artifacts的文件夹作为 artifacts store; - 保持 server 持续运行,因为后续两个练习(Q5、Q6)都要连接它。
对应的标准启动命令(与课程 模块 2 的 notebook 中的本地 server 用法一致)为:
mlflow server --backend-store-uri sqlite:///mlflow.db --default-artifact-root ./artifacts --serve-artifacts参数含义:
--backend-store-uri sqlite:///mlflow.db:元数据(实验、run、参数、指标)存到本地 SQLite 文件mlflow.db;--default-artifact-root ./artifacts:指定 artifacts(模型文件等)的默认存储目录;--serve-artifacts:让 server 自身负责 artifacts 的上传/下载代理,客户端无需直连文件系统。
Q4 的选择题问“除了backend-store-uri,还需要传什么才能正确配置 server”。从上面命令与选项看,核心答案是default-artifact-root(配套示例中同时携带--serve-artifacts;选项中artifacts-only、artifacts-destination并非该版本的配置项)。
5. Q5:用 hyperopt 调超参并逐次记录(hpo.py 的改造方式)
Q5 要求用hyperopt调优RandomForestRegressor,改造 hpo.py,确保每次调参迭代都把验证 RMSE 记录到 tracking server(即在objective函数中加几行代码),然后不带任何参数直接运行脚本,最后在 UI 中查看实验random-forest-hyperopt的所有 run。注意文档明确:本练习不要使用 autologging,只手动记录回答问题所需的信息——传给objective的超参数列表,以及验证集(2023 年 2 月数据)上的 RMSE。
作业版脚本中objective只返回{'loss': rmse, 'status': STATUS_OK}给 hyperopt,没有任何 MLflow 日志。对照 solution/hpo.py,改造点在objective内:
def objective(params): with mlflow.start_run(): # 每次迭代一个 run mlflow.log_params(params) # 记录本次采样的超参 rf = RandomForestRegressor(**params) rf.fit(X_train, y_train) y_pred = rf.predict(X_val) rmse = mean_squared_error(y_val, y_pred, squared=False) mlflow.log_metric("rmse", rmse) # 记录验证集 RMSE return {'loss': rmse, 'status': STATUS_OK}脚本其余部分保持不变,其调参配置值得注意:
- 顶部
mlflow.set_tracking_uri("http://127.0.0.1:5000")指向 Q4 启动的本地 server,实验名为random-forest-hyperopt; - 搜索空间(
scope.int(hp.quniform(...)))为:max_depth ∈ [1, 20]、n_estimators ∈ [10, 50]、min_samples_split ∈ [2, 10]、min_samples_leaf ∈ [1, 4],且random_state固定为 42; fmin使用tpe.suggest算法,max_evals=num_trials(CLI 默认 15 次),并用rstate = np.random.default_rng(42)固定随机数,保证搜索结果可复现。
Q5 的选择题问“你得到的最优验证 RMSE 是多少”,选项为 4.817 / 5.335 / 5.818 / 6.336。由于random_state与rstate均已固定,15 次 TPE 采样的轨迹是确定的,运行后在 UI 中按metrics.rmse排序即可从上述四个选项里选出最接近的值。
6. Q6:把最优模型推送到模型注册表(register_model.py)
Q6 要求把表现最好的模型提升到模型注册表。仓库提供的 register_model.py 已经实现了前半段逻辑:
- 通过
MlflowClient().search_runs从实验random-forest-hyperopt中按order_by=["metrics.rmse ASC"]取出 top 5 的 run(--top_n默认 5); - 对每个 run,用其超参数重新训练,在新实验
random-forest-best-models中记录val_rmse与test_rmse(测试集为 2023 年 3 月数据); - 顶部调用了
mlflow.sklearn.autolog(),因此模型工件(modelartifact)会被自动记录到每个 run 中,为后续注册提供model_uri。
作业留空的部分(源码中注释掉的client.search_runs(...)与mlflow.register_model(...)),对照 solution/register_model.py 的完整实现:
# 选出 test_rmse 最低的 run experiment = client.get_experiment_by_name(EXPERIMENT_NAME) best_run = client.search_runs( experiment_ids=experiment.experiment_id, run_view_type=ViewType.ACTIVE_ONLY, max_results=top_n, order_by=["metrics.test_rmse ASC"] )[0] # 注册最优模型 run_id = best_run.info.run_id model_uri = f"runs:/{run_id}/model" mlflow.register_model(model_uri, name="rf-best-model")这里有两个文档 Tip 对应的关键点:
- Tip 1:用
MlflowClient的search_runs配合order_by=["metrics.test_rmse ASC"]取排序第一的 run; - Tip 2:
mlflow.register_model需要形如"runs:/<RUN_ID>/model"的model_uri字符串和一个模型名(示例答案取名rf-best-model)。
Q6 的选择题问最优模型的测试 RMSE,选项为 5.060 / 5.567 / 6.061 / 6.568——运行脚本后在 UI 的random-forest-best-models实验中查看注册模型的test_rmse即可作答。
另外需要注意版本相关事实:课程 模块 2 README 明确指出,从 MLflow 2.9 起模型注册表的 stages 已被弃用,应改用模型版本 tags 与 aliases(例如用set_registered_model_alias替代transition_model_version_stage);同时list_experiments已被search_experiments取代。如果你的 MLflow 版本较新,后续操作注册表时应使用这些新 API。
7. 关键文件与操作速查
| 练习 | 脚本 | 核心操作 | 仓库路径 |
|---|---|---|---|
| Q2 | preprocess_data.py | python preprocess_data.py --raw_data_path <TAXI_DATA_FOLDER> --dest_path ./output,产出 4 个 pickle 文件 | homework/preprocess_data.py |
| Q3 | train.py | 加mlflow.sklearn.autolog()+with mlflow.start_run():包裹训练 | homework/train.py、solution/train.py |
| Q4 | — | mlflow server --backend-store-uri sqlite:///mlflow.db --default-artifact-root ./artifacts --serve-artifacts | 本地终端 |
| Q5 | hpo.py | objective内加mlflow.log_params与mlflow.log_metric,连接http://127.0.0.1:5000 | homework/hpo.py、solution/hpo.py |
| Q6 | register_model.py | search_runs(order_by=["metrics.test_rmse ASC"])+mlflow.register_model("runs:/<RUN_ID>/model", ...) | homework/register_model.py、solution/register_model.py |
整份作业的提交入口与答题规则见 homework.md 的 “Submit the results” 一节:答案与选项不完全一致时,选择最接近的一项。整套练习串起来,恰好演示了 MLOps 中实验跟踪到模型治理的最小完整闭环:本地记录单模型训练 → 远程 server 记录调参过程 → 注册表沉淀可复用的最优模型,也为后续模块(编排、部署、监控)提供了可部署的模型来源。
【免费下载链接】mlops-zoomcampFree MLOps course from DataTalks.Club. Register here 👇🏼 to get notified about the next cohort项目地址: https://gitcode.com/GitHub_Trending/ml/mlops-zoomcamp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考