4、MLflow实战:自动记录(autolog)、嵌套运行(nested runs)、父子运行管理、搜索与查询实验

说实话,MLflow 最让我觉得「真香」的功能,就是 autolog。你想想看,以前做实验的时候,手动记录每个参数、每个指标,代码里到处插着 mlflow.log_param 和 mlflow.log_metric,不仅累,还容易漏。autolog 一出,这些全自动了。

4.1 自动记录(autolog):一键开启,省心省力

autolog 的原理很简单——它通过 monkey-patch 的方式,自动拦截主流框架的训练过程。你只需要在训练开始前调用一行代码,剩下的交给它。

import mlflow

# 开启自动记录
mlflow.autolog()

# 然后正常训练你的模型
# MLflow 会自动记录:参数、指标、模型结构、数据集信息...

我个人习惯在项目入口处就调用 mlflow.autolog(),这样不管后面跑多少个实验,每个实验的细节都会被自动捕获。支持的主流框架包括:TensorFlow、PyTorch、Scikit-learn、XGBoost、LightGBM 等。

autolog 自动记录的内容清单:

  • 参数:学习率、批量大小、层数、优化器配置等
  • 指标:训练损失、验证准确率、F1 分数等
  • 模型:训练完成的模型文件(自动保存为 MLflow 模型格式)
  • 数据集信息:样本数、特征数等
  • 源代码版本:Git commit ID(如果有)

小提示:如果你只想记录某个特定框架,可以指定框架名称:mlflow.autolog(log_input_examples=True, log_model_signatures=True)。我在项目中经常开启 log_input_examples,这样部署时能自动生成输入示例,省了不少事。

4.2 嵌套运行(nested runs):把实验组织成树

单次运行(run)只能记录一个实验。但实际工作中,我们经常需要跑一组对比实验,或者在一个大实验里包含多个子实验。这时候就需要嵌套运行了。

嵌套运行说白了就是「run 里面套 run」。父 run 管理整体实验,子 run 管理具体细节。比如你调参时,父 run 记录「调参任务」,每个子 run 记录一组参数组合的实验结果。

with mlflow.start_run(run_name="调参实验_2024") as parent_run:
    mlflow.log_param("任务", "XGBoost 调参")
    
    # 嵌套子运行
    for lr in [0.01, 0.001, 0.0001]:
        with mlflow.start_run(nested=True, run_name=f"lr={lr}") as child_run:
            # 子 run 自动记录
            mlflow.autolog()
            # 训练代码...
            # 所有指标和参数都会记录到子 run 中

嗯,这里要注意:子 run 的 nested=True 参数不能少。我曾经漏掉这个参数,结果子 run 变成了独立的 run,跟父 run 完全没关系,查实验时乱成一团。

4.3 父子运行管理:实验的树状结构

嵌套运行创建了父子关系,那怎么管理这些关系呢?MLflow 提供了几个实用方法。

方法 作用 使用场景
mlflow.get_run(run_id) 获取指定 run 的详细信息 查看某个子 run 的指标
run.data.tags 获取 run 的标签 判断 run 是否为嵌套运行
mlflow.search_runs() 搜索实验 按条件筛选 run

每个子 run 的标签里会自动添加 mlflow.parentRunId 字段。你可以通过这个字段找到某个父 run 下的所有子 run。

# 获取父 run 下的所有子 run
parent_run_id = "abc123"
filter_string = f"tags.mlflow.parentRunId = '{parent_run_id}'"
child_runs = mlflow.search_runs(
    experiment_ids=["1"],
    filter_string=filter_string
)
print(f"找到 {len(child_runs)} 个子运行")

避坑指南:我曾经在嵌套运行中忘记关闭子 run 的 autolog,导致父 run 也记录了子 run 的指标,数据重复。建议在子 run 内部显式控制 autolog 的作用范围,或者用 mlflow.end_run() 明确结束。

4.4 搜索与查询实验:从海量实验中找到你要的

实验多了之后,手动翻 UI 找实验简直是噩梦。MLflow 的搜索功能可以帮你精准定位。

搜索的核心是 mlflow.search_runs(),它支持多种过滤条件:

  • 按实验 ID:experiment_ids=["1", "2"]
  • 按参数:filter_string="params.learning_rate = '0.001'"
  • 按指标:filter_string="metrics.accuracy > 0.9"
  • 按标签:filter_string="tags.mlflow.runName = '实验A'"
  • 组合条件:filter_string="params.model = 'xgboost' and metrics.f1 > 0.85"
# 搜索所有准确率大于 0.9 且使用 XGBoost 的实验
results = mlflow.search_runs(
    experiment_ids=["1"],
    filter_string="params.model = 'xgboost' and metrics.accuracy > 0.9",
    order_by=["metrics.accuracy DESC"],
    max_results=10
)

# 结果是一个 DataFrame,可以直接分析
print(results[["run_id", "params.learning_rate", "metrics.accuracy"]])

你想想看,如果手动记录,要找到「准确率 > 0.9 的 XGBoost 实验」得翻多少日志?用 search_runs 一行代码搞定。

我的习惯:每次实验结束后,我会用 search_runs 把最佳实验的 run_id 保存到一个配置文件中。这样后续部署、对比、回滚都直接引用这个 ID,不会搞混。

4.5 知识体系总览

下面这张图概括了本章的核心逻辑:autolog 负责自动采集数据,嵌套运行构建实验的树状结构,搜索查询帮你从树中快速定位目标。

MLflow 实验管理核心流程 MLflow 实验管理核心流程 autolog 自动采集 嵌套运行(父子关系) 子运行 1(lr=0.01) 子运行 2(lr=0.001) search_runs 搜索查询 autolog 采集 → 嵌套运行组织 → search_runs 检索,形成完整实验管理闭环 支持按参数、指标、标签组合过滤,结果以 DataFrame 返回

4.6 实战:完整的工作流

最后,我把这些知识点串起来,给你一个可以直接用的实战模板。

import mlflow
import xgboost as xgb
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

# 1. 设置实验
mlflow.set_experiment("iris_classification")

# 2. 开启 autolog
mlflow.autolog()

# 3. 父运行:整体调参任务
with mlflow.start_run(run_name="xgboost_tuning") as parent_run:
    mlflow.log_param("task", "XGBoost hyperparameter tuning")
    
    # 准备数据
    data = load_iris()
    X_train, X_test, y_train, y_test = train_test_split(
        data.data, data.target, test_size=0.2, random_state=42
    )
    
    # 4. 嵌套子运行:每组参数
    for lr in [0.1, 0.01, 0.001]:
        with mlflow.start_run(nested=True, run_name=f"lr_{lr}"):
            model = xgb.XGBClassifier(
                learning_rate=lr,
                n_estimators=100,
                max_depth=3
            )
            model.fit(X_train, y_train)
            
            # autolog 会自动记录参数和指标
            # 你不需要手动 log 任何东西

# 5. 搜索最佳实验
results = mlflow.search_runs(
    experiment_ids=[mlflow.get_experiment_by_name("iris_classification").experiment_id],
    filter_string="tags.mlflow.parentRunId = '{}'".format(parent_run.info.run_id),
    order_by=["metrics.test_score DESC"]
)

best_run_id = results.iloc[0]["run_id"]
print(f"最佳实验 run_id: {best_run_id}")

这个模板我用了大半年,从数据准备到调参到结果检索,一条龙搞定。你只需要替换模型和数据,就能直接跑起来。

核心要点回顾:

  • autolog 自动记录参数、指标、模型,省去手动 log 的繁琐
  • 嵌套运行用 nested=True 创建父子关系,组织对比实验
  • 父子关系通过 mlflow.parentRunId 标签维护
  • search_runs 支持按参数、指标、标签组合过滤,结果直接分析