4. Qlib实验管理模块

在量化研究中,真正拖慢迭代速度的往往不是模型本身,而是“实验失控”:同一个因子组合跑了十几遍,却记不清哪次用了什么参数;某个回测收益很高,但复现时发现数据区间或随机种子已经丢失。Qlib 的实验管理模块正是为解决这类问题而设计,它通过集成 MLflow,把每一次训练、回测和信号评估都变成可追踪、可查询、可复现的实验记录。

一、核心原理:为什么需要实验管理

Qlib 的工作流本质上是“配置驱动”的:一个 qrun 任务由 YAML 配置定义,包含数据处理器、模型、策略和回测器。如果没有实验管理,这些配置、指标和产物会散落在终端日志和临时目录中。MLflow 提供了三层抽象:

  • Experiment(实验):按研究主题分组,例如“Alpha158-LGBM 调参”或“CSI300 多因子对比”。
  • Run(运行):一次具体的执行,对应一个 YAML 配置的一次完整训练与回测。
  • Metrics / Params / Artifacts:运行过程中记录的指标(IC、ICIR、年化收益)、参数(学习率、树深度)和产物(模型文件、预测结果)。

Qlib 在 qlib.workflow 中封装了 MLflow 的 Recorder,使得用户在配置中开启 mlflow 后,无需手动调用 MLflow API,就能自动完成记录。其核心是 R 对象(Recorder),它既负责本地实验目录管理,也负责与 MLflow Tracking Server 通信。

关键理解:Qlib 的实验记录是“双写”的——本地 mlruns 目录保存完整产物,MLflow Server 保存元数据和指标索引。即使 Server 不可用,本地记录仍可恢复。

二、方法流程:从配置到查询

下面以一次完整的 LightGBM 实验为例,说明从创建实验到查询结果的流程。

  1. 启动 MLflow Tracking Server:在实验机上运行服务,统一存储元数据。
  2. 配置 Qlib 工作流:在 YAML 中声明 mlflow 相关字段。
  3. 执行 qrun:Qlib 自动创建 Run,记录参数、指标和模型。
  4. 查询与对比:通过 MLflow UI 或 Qlib 的 Recorder API 检索结果。
# 启动 MLflow Tracking Server
mlflow server \
  --backend-store-uri sqlite:///mlflow.db \
  --default-artifact-root ./mlruns \
  --host 0.0.0.0 --port 5000

# 设置环境变量,让 Qlib 找到 Server
export MLFLOW_TRACKING_URI=http://127.0.0.1:5000

接下来是 Qlib 工作流配置的关键片段。注意 experiment_name 和 run_name 的命名规范,它们直接决定后续查询效率。

qlib_init:
    provider_uri: "~/.qlib/qlib_data/cn_data"
    region: cn

market: &market csi300
benchmark: &benchmark SH000300

data_handler_config: &data_handler_config
    start_time: 2018-01-01
    end_time: 2022-12-31
    fit_start_time: 2018-01-01
    fit_end_time: 2020-12-31
    instruments: *market

task:
    model:
        class: LGBModel
        module_path: qlib.contrib.model.gbdt
        kwargs:
            loss: mse
            learning_rate: 0.05
            num_leaves: 64
            num_threads: 8
    dataset:
        class: DatasetH
        module_path: qlib.data.dataset
        kwargs:
            handler:
                class: Alpha158
                module_path: qlib.contrib.data.handler
                kwargs: *data_handler_config
            segments:
                train: [2018-01-01, 2020-12-31]
                valid: [2021-01-01, 2021-12-31]
                test: [2022-01-01, 2022-12-31]
    record:
        - class: SignalRecord
          module_path: qlib.workflow.record_temp
        - class: SigAnaRecord
          module_path: qlib.workflow.record_temp
        - class: PortAnaRecord
          module_path: qlib.workflow.record_temp

experiment_name: "alpha158_lgbm_tuning"
run_name: "lr005_leaves64"

执行 qrun workflow_config.yaml 后,Qlib 会输出类似日志:

[INFO] Recorder initialized: mlruns/1/xxxx
[INFO] Params logged: learning_rate=0.05, num_leaves=64
[INFO] Metrics logged: IC=0.0421, ICIR=0.318, annual_return=0.156
[INFO] Artifacts saved: model.pkl, pred.pkl, report_normal_1day.pkl

三、案例场景:参数调优与结果查询

假设我们需要对比三组 LightGBM 参数,判断哪组在 ICIR 上表现最好。传统做法是手动记录 Excel,而使用 Qlib + MLflow 后,可以直接用代码查询。

from qlib.workflow import R

# 查询指定实验下的所有运行
experiment = R.get_exp(experiment_name="alpha158_lgbm_tuning")
runs = experiment.list_recorders()

for recorder in runs:
    metrics = recorder.list_metrics()
    params = recorder.list_params()
    print(f"Run ID: {recorder.id}")
    print(f"  learning_rate: {params.get('learning_rate')}")
    print(f"  num_leaves: {params.get('num_leaves')}")
    print(f"  IC: {metrics.get('IC')}, ICIR: {metrics.get('ICIR')}")
    print(f"  Annual Return: {metrics.get('annual_return')}")

输出结果可以整理为下表,便于快速决策:

Run 名称 learning_rate num_leaves IC ICIR 年化收益
lr005_leaves64 0.05 64 0.0421 0.318 15.6%
lr010_leaves32 0.10 32 0.0387 0.276 12.3%
lr003_leaves128 0.03 128 0.0455 0.341 17.2%

从表中可见,lr003_leaves128 在 ICIR 和年化收益上均最优。但需要注意,该组参数可能过拟合验证集,因此还应结合回测的最大回撤和换手率综合判断。MLflow UI 中可以直接勾选多个 Run 进行平行坐标图对比,快速识别参数与指标的关联趋势。

建议在 run_name 中嵌入关键参数,例如 lr003_leaves128,这样即使不打开 MLflow UI,也能从运行列表快速定位目标实验。

四、误区与复盘

在实际教学中,初学者常陷入以下误区:

  • 误区一:只记录指标,不记录数据区间。 如果两次实验的 fit_end_time 不同,IC 对比毫无意义。务必将数据切分参数写入 kwargs,Qlib 会自动记录。
  • 误区二:实验名称随意起。 例如用 test1、test2 命名,几周后完全无法回忆。应按“数据集_模型_日期”规范命名。
  • 误区三:忽略 Artifacts 管理。 模型文件 model.pkl 和预测结果 pred.pkl 是复现的关键,Qlib 默认保存,但需确认 artifact_path 未被覆盖。
  • 误区四:MLflow Server 与本地目录混用。 若同时设置 MLFLOW_TRACKING_URI 和本地 mlruns,可能造成记录分裂。建议统一使用 Server,本地仅作缓存。
删除实验目录前务必确认 MLflow Server 中已同步元数据。直接删除本地 mlruns 会导致 Artifacts 丢失,而 Server 中的指标记录将变成“空壳”,无法复现。

复盘一次典型故障:某学员在 Jupyter Notebook 中多次运行同一单元格,导致同一 run_name 下产生多个 Run,指标被覆盖。解决方案是每次运行前调用 R.start() 时显式指定新的 run_name,或使用 R.get_exp().start_run() 自动生成唯一 ID。Qlib 的 Recorder 在 qrun 模式下会自动处理,但在交互式编程中需要手动管理生命周期。

掌握实验管理后,量化研究将从“手工作坊”升级为“流水线”:每一次信号评估都有据可查,每一次参数调整都可追溯,团队协作时也能共享同一套实验索引。这正是 Qlib 集成 MLflow 的核心价值——让研究过程本身成为可积累的资产。