3. 实验跟踪入门

在金融建模中,一次“跑通模型”并不等于一次“可复现的实验”。你可能用同一份行情数据、同一套特征工程,却因为随机种子、学习率、滑窗长度或手续费假设不同,得到完全不同的回测曲线。MLflow 实验跟踪要解决的核心问题,就是把这些“看不见的差异”变成可查询、可比较、可追溯的记录。本节从最基础的两个概念——Experiment 与 Run——出发,带你完成一次完整的记录动作。

核心原理:Experiment 是容器,Run 是执行实例

很多初学者会把 Experiment 理解成“一次实验”,这是最常见的认知偏差。在 MLflow 中,Experiment 是一个逻辑分组容器,通常对应一个业务问题或一个研究方向,例如“A股多因子选股”“信用违约预测”“期权波动率曲面拟合”。而 Run 是这个容器内的一次具体执行,对应一次训练、一次回测或一次参数扫描中的单个组合。

因此,一个 Experiment 下可以包含成百上千个 Run。每个 Run 拥有独立的 run_id、开始时间、结束时间、状态(RUNNING / FINISHED / FAILED / KILLED),并挂载四类核心信息:参数(Params)、指标(Metrics)、工件(Artifacts)和标签(Tags)。参数是输入,指标是输出,工件是产物,标签是检索维度。理解这四者的分工,比记住 API 名称更重要。

一句话记忆:Experiment 回答“我在研究什么问题”,Run 回答“我这一次具体怎么做的、结果如何”。

Experiment 与 Run 的层级与数据挂载关系 Experiment: A股多因子选股 experiment_id = 1024 Run #1 run_id: a1b2c3 Params: lr=0.01, window=20 Metrics: sharpe=1.42 Artifacts: model.pkl Tags: stage=baseline Run #2 run_id: d4e5f6 Params: lr=0.05, window=60 Metrics: sharpe=0.87 Artifacts: model.pkl Tags: stage=tuning Run #3 run_id: g7h8i9 Params: lr=0.05, window=20 Metrics: sharpe=1.65 Artifacts: model.pkl Tags: stage=best

方法流程:一次完整的记录动作

下面以“多因子选股回测”为例,演示从创建 Experiment 到记录 Run 的标准流程。假设你已经在本地或服务器上配置好 MLflow Tracking Server,环境变量 MLFLOW_TRACKING_URI 指向该服务。

  1. 设置或创建 Experiment。如果实验已存在则复用,不存在则创建,避免每次运行都产生新实验。
  2. 启动 Run。使用 with mlflow.start_run() 上下文管理器,确保异常时 Run 状态能正确标记为 FAILED。
  3. 记录参数。把学习率、滑窗长度、手续费率、随机种子等输入写入 Params。
  4. 记录指标。把夏普比率、最大回撤、年化收益、IC 均值等评估结果写入 Metrics。
  5. 记录工件。把模型文件、回测净值曲线图、特征重要性表等写入 Artifacts。
  6. 打标签。用 Tags 标记阶段、负责人、数据版本,便于后续检索。
import mlflow
import mlflow.sklearn

mlflow.set_tracking_uri("http://127.0.0.1:5000")
mlflow.set_experiment("A股多因子选股")

with mlflow.start_run(run_name="lr005_win20") as run:
    # 1. 记录参数
    mlflow.log_param("learning_rate", 0.05)
    mlflow.log_param("window", 20)
    mlflow.log_param("commission", 0.0003)
    mlflow.log_param("seed", 42)

    # 2. 训练与回测(此处省略具体建模代码)
    sharpe, max_drawdown, annual_return = 1.65, -0.12, 0.23

    # 3. 记录指标
    mlflow.log_metric("sharpe", sharpe)
    mlflow.log_metric("max_drawdown", max_drawdown)
    mlflow.log_metric("annual_return", annual_return)

    # 4. 记录工件
    mlflow.log_artifact("reports/equity_curve.png")
    mlflow.sklearn.log_model(model, "model")

    # 5. 打标签
    mlflow.set_tag("stage", "best")
    mlflow.set_tag("owner", "quant_team")

    print("run_id:", run.info.run_id)

运行结束后,打开 MLflow UI,你会在“A股多因子选股”实验下看到这条 Run,并能直接对比不同 Run 的指标列。这就是实验跟踪最直接的收益:把散落在终端和笔记本里的结果,变成一张可排序的表格。

案例场景:参数扫描中的 Run 组织

假设你要对学习率和滑窗长度做网格搜索,共 3×3=9 个组合。此时不要创建 9 个 Experiment,而应在同一个 Experiment 下创建 9 个 Run。每个 Run 记录自己的参数组合和对应指标,最后在 UI 中按 sharpe 降序排列,即可快速定位最优组合。若把每个组合都建成独立 Experiment,实验列表会迅速膨胀,失去分组意义。

记录对象API 方法金融场景示例是否可覆盖
参数 Paramslog_paramlearning_rate=0.05不可覆盖
指标 Metricslog_metricsharpe=1.65可多次记录形成序列
工件 Artifactslog_artifactequity_curve.png同名可覆盖
标签 Tagsset_tagstage=best可覆盖

误区与复盘

误区一:把 Experiment 当 Run 用。每次调参都新建 Experiment,导致实验列表爆炸,无法横向对比。正确做法是同一研究方向共用一个 Experiment。

误区二:只记指标不记参数。看到 sharpe=1.65 却不知道对应哪组超参数,实验记录等于白做。参数和指标必须成对出现。

误区三:工件路径混乱。把大文件直接写进代码目录再上传,容易造成路径冲突。建议统一使用 reports/、models/ 等约定目录。

复盘建议:每次 Run 结束后,检查三件事——参数是否完整、指标是否包含风险维度(如最大回撤)、工件是否可复现。金融实验尤其要记录数据版本和手续费假设,否则回测结果无法复现。