首页
/ Qlib Meta Controller 深度解析:用 Meta-Task、Meta-Dataset 与 Meta-Model 引导预测模型工作流

Qlib Meta Controller 深度解析:用 Meta-Task、Meta-Dataset 与 Meta-Model 引导预测模型工作流

2026-09-05 19:51:50作者:劳婵绚Shirley

本文围绕 Qlib 的 Meta Controller 组件(文档见 meta.rst)展开:先讲清 Meta-Task、Meta-Dataset、Meta-Model 三类抽象的职责边界与 API 契约,再结合仓库中自带的 DDG-DA 完整实现,剖析"元信息生产 → 元模型训练 → 推理引导 → 改写基座任务"的端到端调用链,并给出运行基准样例所需的配置与命令,帮助你理解如何基于 Meta Controller 自定义自己的元学习模型来适应市场动态变化。

1. Meta Controller 的定位:给预测模型"导学"

Meta Controller 的核心目标是:学习一系列预测任务(forecasting tasks)之间的规律性模式,并利用学到的模式去引导后续的预测任务。文档原文将其描述为"provides guidance to Forecast Model"。

在 Qlib 的常规工作流中,一个任务(task)由数据集(dataset)与模型(model)配置组成,由 Trainer 串行训练。而 Meta Controller 在任务之上加了一层"元层"(meta-level):元模型不直接预测股票收益,而是观察"多个基座任务各自学得怎么样",从中提炼出可迁移的知识,再反过来影响基座预测模型的工作流。

从源码结构看,这一组件的抽象骨架位于 qlib/model/meta/ 包,包含三个文件:

抽象 源码位置 职责
MetaTask qlib/model/meta/task.py 元学习框架的基本元素,保存可喂给元模型的数据
MetaTaskDataset qlib/model/meta/dataset.py 控制元信息(meta-information)的生成过程,负责为元模型提供训练数据
MetaModel 及子类 qlib/model/meta/model.py 控制工作流:用 fit 训练、用 inference 给出引导信息

三者构成一条清晰的数据流:MetaTaskDataset.prepare_tasks() 产出若干 MetaTask → 元模型 fit() 消费这些元任务完成训练 → 元模型 inference() 输出"引导信息"(如改写后的任务定义、样本权重等)→ 引导信息被应用回基座预测模型。

2. MetaTask:元学习的基本数据单元

文档指出:一个 Meta Task 实例保存了可供 Meta Model 使用的数据;多个 Meta Task 实例可以共享同一个 Data Handler,这一共享关系由 Meta Dataset 控制。

qlib/model/meta/task.py 的源码看,MetaTask 的构造签名是:

MetaTask(task: dict, meta_info: object, mode: str = PROC_MODE_FULL)
  • task:被元模型增强的 Qlib 任务定义(dict 配置);
  • meta_info:喂给元模型的原始输入信息,初始化时会保存原始值,后续再做处理;
  • mode:数据处理模式,源码定义了三种:
模式常量 取值 含义(源码注释)
PROC_MODE_FULL "full" 训练用:训练任务需要 X、y、X_test、y_test 齐全
PROC_MODE_TEST "test" 测试用:测试任务不需要完整的训练/测试对
PROC_MODE_TRANSFER "transfer" 元模型可迁移到其他数据集时:只需要 meta_info

源码中还提供了两个关键方法:get_dataset() 通过 init_instance_by_config(self.task["dataset"]) 从任务配置中初始化出 Dataset 实例(这就是"多个 MetaTask 共享 Data Handler"的实现入口——数据集配置相同即可复用);get_meta_input() 返回处理后的 meta_info,供元模型直接消费(文档中提到的 prepare_task_data() 在现行源码中对应的就是这条"取出可直接喂入元模型的数据"的语义)。

3. MetaDataset:元信息的生成器

Meta Dataset 负责元信息的生成流程,"为训练 Meta Model 提供数据"。用户应通过 prepare_tasks 获取一组 MetaTask 实例。

qlib/model/meta/dataset.pyMetaTaskDataset 的契约:

  • 构造参数 segmentsDict[Text, Tuple]float)指示数据如何切分;初始化时元数据集就已维护好 meta-tasks 列表;
  • prepare_tasks(segments):传入单个 segment 名或 segment 列表,返回对应的一批 meta-task(多 segment 时返回嵌套列表 [[tasks in seg1], ...]);源码中内置了如下调用示例:
# get the train segment and the test segment, both of them are lists
train_meta_tasks, test_meta_tasks = meta_dataset.prepare_tasks(["train", "test"])
  • 抽象方法 _prepare_seg(segment) 留给具体实现:负责为单个 segment 准备好训练数据。

值得注意的是源码类注释中明确写出的迁移性设计意图:"A meta-model trained on meta-dataset A and then applied to meta-dataset B"——即在元数据集 A 上训练的元模型,其输入特征应当能在元数据集 B 上复用,因此实现 _prepare_seg 时必须保证 meta 输入的结构在数据集之间是可对齐的。

仓库自带的完整实现是 qlib/contrib/meta/data_selection/dataset.py 中的 MetaDatasetDS,它把"任务模板如何展开成滚动任务序列、每个任务的元输入如何计算"全部落地:

  • task_tpl:可以是单个任务模板 dict(此时用 RollingGenstep/trunc_days 滚动生成任务序列),也可以是已排好时间顺序的任务 list(直接使用);
  • step:滚动步长;trunc_days:基于测试起点截断的天数,源码注释特别强调 "trunc_days is very important",用于屏蔽与未来信息重叠的数据;
  • exp_name:元信息来源,可以是实验名(str,自动用 InternalData.setup() 训练一批代理模型并统计其表现)或已准备好的 InternalData 实例;
  • segments:float 表示用于训练的 meta-task 比例;str 则保证该日期落在测试集中;
  • hist_step_n:元信息的历史步数(数据相似性信息的回溯长度);
  • task_mode / fill_method:分别控制元任务的数据处理模式(对应 MetaTask 的三种模式)与元信息缺失值的填充策略("max""maxseg""zero")。

其中元输入的核心数据结构是 MetaTaskDS.processed_meta_input,包含:

  • time_perf:形状 <hist_step_n * step, data pieces> 的时间表现矩阵,刻画"各数据段上历史代理模型的表现";
  • time_belong<sample, data pieces> 的 0/1 归属矩阵,标记每个训练样本属于哪个时间数据段(见 MetaTaskDS 的 docstring);
  • FULL 模式下还会附带 X / y / X_test / y_test / test_idx,即该基座任务的训练/测试特征标签数据。

4. MetaModel:三种引导基座工作流的方式

文档将 Meta Model 的使用归纳为两步:用 fit 训练元模型;元模型实例通过 inference 给出有用信息来引导工作流。抽象基类 qlib/model/meta/model.py 只有两个抽象方法:

@abc.abstractmethod
def fit(self, *args, **kwargs): ...

@abc.abstractmethod
def inference(self, *args, **kwargs) -> object: ...

基类注释进一步按"干预基座学习流程的阶段"把引导分成两类,对应两个子类:

4.1 MetaTaskModel:直接改写任务定义

"This type of meta-model may interact with task definitions directly... They guide the base tasks by modifying the base task definitions."

MetaTaskModel 约定了签名:fit(meta_dataset) 从 meta-dataset 取出准备好的 meta-task 并学习知识;inference(meta_dataset) -> List[dict] 在推理时输出一批修改后的任务定义,这些任务可以直接被 Qlib trainer 执行。也就是说,这一类元模型的作用方式是"任务级"的——它把学到的知识物化成对基座任务的修改(例如给样本加权、调整数据范围),而不是在训练循环内部插入逻辑。DDG-DA 正是这一类。

4.2 MetaGuideModel:参与基座模型的训练过程

"This type of meta-model participates in the training process of the base forecasting model... guide the base forecasting models during their training to improve their performances."

MetaGuideModelMetaTaskModel 同样继承 MetaModelfit/inference 抽象,但从源码结构看,它的定位是让元模型在基座预测模型的训练期间持续互动(例如在训练循环中提供正则项、损失调制等),属于"训练过程级"的引导。用户实现自定义元模型时,可按需选择继承哪一个子类。

4.3 自定义元模型的实现要点

综合以上契约,实现一个自己的元模型大致是三步:

  1. 继承 MetaTaskDataset,实现 _prepare_seg(segment),返回一批构造好的 MetaTask(task, meta_info, mode)
  2. 继承 MetaModel(或 MetaTaskModel / MetaGuideModel),实现 fitinference
  3. 在滚动/在线工作流中,把元模型的 inference 输出接回基座任务或基座训练循环。

5. 完整示例:DDG-DA 自适应市场动态

文档给出 Qlib 内置的元模型实现 DDG-DA(Data Distribution Generation for Predictable Concept Drift Adaptation),它"adapts to the market dynamics"。文档描述的四个步骤与源码 qlib/contrib/rolling/ddgda.pyDDGDA.run() 的调用一一对应:

文档步骤 源码方法 产出
1. 计算 meta-information 并封装为 MetaTask 实例,所有 meta-task 组成 MetaDatasetDS _dump_data_for_proxy_model()_dump_meta_ipt()MetaDatasetDS.__init__ 文件 handler_proxy.pklinternal_data_s{step}.pkl;mlflow 实验 data_sim_s{step}
2. 基于元数据集的训练数据训练 DDG-DA _train_meta_model() mlflow 实验 DDG-DA 中保存的 MetaModelDS
3. 对 DDG-DA 做推理得到 guide information get_task_list()meta_model.inference(mds) 文件 tasks_s{step}.pkl(每个任务被加上了 reweighter
4. 将 guide information 应用到预测模型 继承自 Rollingsuper().run() 训练滚动预测模型并汇总预测

几个值得注意的实现细节:

  • 代理模型(proxy model)机制:DDG-DA 先用一个简化代理模型(默认 LightGBM 计算特征重要性、按 sim_task_model 选择 linear/gbdt 统计相似性)在历史数据上滚动训练,再用 InternalData.setup() 把"每个代理模型在不同日期上的日频 Spearman 相关性(IC)表现"整理成 data_ic_df,这就是 meta-information 的原始形态(见 qlib/contrib/meta/data_selection/dataset.py)。_prepare_meta_ipt() 随后用 mask_overlap() 掩掉与自身训练期重叠(含 horizon 泄漏窗口)的列,防止信息穿越。
  • 元模型本体MetaModelDSqlib/contrib/meta/data_selection/model.py)内部是 PredNetnet.py)——一个"时间权重网络 + 加权岭回归闭式解"的组合:TimeWeightMetatime_perf 序列预测每个数据段的时间权重,preds_to_weight_with_clamptanh/clamp/sigmoid 方式裁剪权重;损失函数 ICLossutils.py)对每个交易日计算预测与标签的相关性并取负 IC 均值,loss_skip_thresh 参数用于跳过样本数过少的交易日。
  • 引导的落地形式MetaModelDS._prepare_task() 对每个基座任务浅拷贝后挂上一个 TimeReweighter,即"改写任务定义"具体体现为按时间分布对训练样本加权。这与 MetaTaskModel.inference 返回 List[dict] 的契约完全吻合。
  • 知识迁移get_task_list() 中训练侧与推理侧的 MetaDatasetDS 参数(steptrunc_dayshist_step_nfill_method)刻意保持一致,推理侧则设置 segments=0.0task_mode=MetaTask.PROC_MODE_TRANSFER,正好呼应了第 2 节中"元模型可迁移到其他数据集,只需要 meta_info"的设计。

运行 DDG-DA 基准

入口脚本是 examples/benchmarks_dynamic/DDG-DA/workflow.py,它定义 DDGDABench(DDGDA),默认使用 baseline/workflow_config_linear_Alpha158.yaml(Linear 基座,效率优先),也支持 LightGBM 配置。按 examples/benchmarks_dynamic/DDG-DA/README.md 的说明,运行命令为:

python workflow.py run
# 换用 LightGBM 基座模型:
python workflow.py --conf_path=../baseline/workflow_config_lightgbm_Alpha158.yaml run

运行前提与限制:

  • 需要先准备 Qlib 数据(脚本中在未设置 PROVIDER_URI 时会通过 GetData().qlib_data(exists_skip=True) 自动下载;设置 PROVIDER_URI 环境变量可指向已有数据);
  • 硬件最低要求:约 45G 内存、4G 磁盘,CPU 版 PyTorch 即可;
  • 基类的 Rolling 初始化参数(conf_pathhorizon=20step=20train_starttest_end 等,见 qlib/contrib/rolling/base.py)与 DDG-DA 特有参数(sim_task_modelalphaloss_skip_threshfea_imp_n=30segments=0.62hist_step_n=30meta_data_proc="V01" 等,见 DDGDA 构造器)均可通过 fire 命令行覆盖;
  • 注意源码中的提示:由于 mlflow 实验难以彻底删除(同名实验会移入 .trash 导致创建失败),运行示例前建议清理旧结果(删除 mlruns 目录)。

6. 小结与延伸阅读

回到文档的主线:Meta Controller 用三个最小抽象把"元层"与"基座层"解耦——MetaTask 定义"一个元任务长什么样"(FULL/TEST/TRANSFER 三态),MetaTaskDataset 定义"如何批量生产元任务"(prepare_tasks + _prepare_seg),MetaModel 定义"元模型如何被训练与如何使用"(fit/inference),并在 MetaTaskModel(改任务定义)与 MetaGuideModel(介入训练过程)之间给出两条落地路径。仓库中 DDG-DA 的 qlib/contrib/meta/qlib/contrib/rolling/ddgda.py 提供了从元信息构造、元模型训练到任务级加权的完整参考实现,是自定义元模型时最值得对照阅读的代码路径;配套的滚动基类 qlib/contrib/rolling/base.py 则说明了 RollingGen/task_generator 这一层在 Meta 模块与滚动重训之间共享的基础设施。

登录后查看全文
热门项目推荐
相关项目推荐