☰
DeepCTR MMOE 多任务学习模型实战指南:源码解析、参数详解与完整训练示例
2026/9/27 11:09:23 网站建设 项目流程
  • 人工智能
  • 深度学习
  • 机器学习

【免费下载链接】DeepCTR

Easy-to-use,Modular and Extendible package of deep-learning based CTR models .

项目地址:https://gitcode.com/gh_mirrors/de/DeepCTR
点击查看免费下载

本文聚焦 DeepCTR 开源仓库中deepctr.models.multitask.mmoe模块(对应 Sphinx 文档 deepctr.models.multitask.mmoe.rst),完整讲解基于 Multi-gate Mixture-of-Experts(多门控专家混合)架构的多任务 CTR/CVR 建模方案。你将掌握 MMOE 的函数签名与全部参数语义、底层实现细节、参数约束校验逻辑,以及基于 examples/run_mtl.py 的端到端可运行训练评估流程。

一、MMOE 是什么:多任务学习中处理"任务相关性"的经典方案

在真实的推荐、广告、搜索业务中,模型往往需要同时预测多个目标,例如电商场景下的 CTR(点击率)与 CVR(转化率)、Census 收入预测场景下的"是否高收入"与"是否未婚"等。多任务学习(Multi-Task Learning, MTL)通过共享底层表示来提升数据利用率与泛化能力,但不同任务之间可能存在"负迁移"(negative transfer)——共享过深反而互相干扰。

MMOE(Multi-gate Mixture-of-Experts)由 Ma 等人在 KDD 2018 论文Modeling task relationships in multi-task learning with multi-gate mixture-of-experts中提出,其核心思想是:用多个并行的"专家网络"(Experts)共享输入表示,再为每个任务配备一个独立的"门控网络"(Gate),由门控网络按任务动态地对各专家输出做加权求和。这样每个任务都能学到适合自己的专家组合方式,从而在共享表示与任务独立性之间取得平衡。DeepCTR 将该架构实现为可直接调用的 Keras 模型工厂函数MMOE()。

二、架构与源码实现:一条调用链看懂 MMOE

MMOE 的完整实现位于 deepctr/models/multitask/mmoe.py,模型名MMOE与SharedBottom、ESMM、PLE一同在 deepctr/models/init.py 中导出,因此可以直接from deepctr.models import MMOE。

从源码结构看,MMOE()的构建流程可以拆解为如下四个阶段:

  1. 输入与特征处理:通过build_input_features(dnn_feature_columns)建立特征输入层,再经input_from_feature_columns(features, dnn_feature_columns, l2_reg_embedding, seed)将稀疏特征(SparseFeat)映射为嵌入向量、稠密特征(DenseFeat)归一化后,由combined_dnn_input拼接为统一的 DNN 输入张量dnn_input。

  2. 构建专家层(Experts):for i in range(num_experts)循环中,每个专家都是一个独立的DNN(expert_dnn_hidden_units, ...)全连接网络,输出被tf.stack沿axis=1堆叠成形状为(None, num_experts, dim)的张量expert_concat。源码片段如下:

expert_outs = [] for i in range(num_experts): expert_network = DNN(expert_dnn_hidden_units, dnn_activation, l2_reg_dnn, dnn_dropout, dnn_use_bn, seed=seed, name='expert_' + str(i))(dnn_input) expert_outs.append(expert_network) expert_concat = Lambda(lambda x: tf.stack(x, axis=1))(expert_outs) # None,num_experts,dim
  1. 构建门控网络(Gates)并加权融合:循环次数等于任务数(num_tasks,即"一个 MMOE 层对应num_tasks个门")。每个任务的 Gate 先经过一个可选的DNN(gate_dnn_hidden_units, ...)(默认()表示直接使用输入),再通过一个Dense(num_experts, use_bias=False, activation='softmax')输出num_experts维的归一化权重;随后用reduce_sum(x[0] * x[1], axis=1)将专家堆叠张量与门权重逐元素相乘并按专家轴求和,得到该任务专属的融合表示gate_mul_expert:
for i in range(num_tasks): # one mmoe layer: nums_tasks = num_gates gate_input = DNN(gate_dnn_hidden_units, dnn_activation, l2_reg_dnn, dnn_dropout, dnn_use_bn, seed=seed, name='gate_' + task_names[i])(dnn_input) gate_out = Dense(num_experts, use_bias=False, activation='softmax', name='gate_softmax_' + task_names[i])(gate_input) gate_out = Lambda(lambda x: tf.expand_dims(x, axis=-1))(gate_out) gate_mul_expert = Lambda(lambda x: reduce_sum(x[0] * x[1], axis=1, keep_dims=False), name='gate_mul_expert_' + task_names[i])([expert_concat, gate_out]) mmoe_outs.append(gate_mul_expert)
  1. 构建任务塔(Towers)与输出:每个任务从自己的 MMOE 融合表示出发,经过任务专属的DNN(tower_dnn_hidden_units, ...),再接一个无偏置的Dense(1, use_bias=False)产生 logit,最后经PredictionLayer(task_type, name=task_name)输出。PredictionLayer的实现位于 deepctr/layers/core.py:binary任务会施加 sigmoid 得到概率,regression任务则直接输出回归值。最终Model(inputs=inputs_list, outputs=task_outs)返回一个多输入多输出的 Keras 模型。

从源码结构可以推断:MMOE 的门控权重完全由数据驱动、按任务学习,不同任务的 Gate 可以给同一批专家分配截然不同的权重,这正是它相比"所有任务共享同一底层"的 SharedBottom 更能缓解负迁移的原因。

三、API 参数详解:13 个参数的语义、默认值与取值范围

MMOE()的完整函数签名与默认值如下(来自 deepctr/models/multitask/mmoe.py):

MMOE(dnn_feature_columns, num_experts=3, expert_dnn_hidden_units=(256, 128), tower_dnn_hidden_units=(64,), gate_dnn_hidden_units=(), l2_reg_embedding=0.00001, l2_reg_dnn=0, seed=1024, dnn_dropout=0, dnn_activation='relu', dnn_use_bn=False, task_types=('binary', 'binary'), task_names=('ctr', 'ctcvr'))

各参数含义整理如下:

参数类型默认值说明
dnn_feature_columnsiterable必填深度部分使用的全部特征,由SparseFeat/DenseFeat构成,与input_from_feature_columns直接对接
num_expertsint3专家网络个数,必须大于 1,否则抛出ValueError("num_experts must be greater than 1")
expert_dnn_hidden_unitslist(256, 128)每个专家 DNN 的层数与各层神经元数;可为空列表
tower_dnn_hidden_unitslist(64,)任务专属 DNN(塔)的层数与各层神经元数;可为空列表(示例中即设为[],直接由 MMOE 融合结果产出 logit)
gate_dnn_hidden_unitslist()门控 DNN 的层数与各层神经元数;默认空表示门控直接从拼接输入做 softmax 加权
l2_reg_embeddingfloat0.00001施加在嵌入向量上的 L2 正则强度
l2_reg_dnnfloat0施加在 DNN 权重上的 L2 正则强度
seedint1024随机种子,用于保证权重初始化与 dropout 的可复现性
dnn_dropoutfloat0DNN 的 dropout 概率,取值范围[0, 1)
dnn_activationstr'relu'DNN 使用的激活函数
dnn_use_bnboolFalse是否在激活前使用 BatchNormalization
task_typeslist of str('binary', 'binary')每个任务的损失类型,'binary'表示二分类 logloss,'regression'表示回归损失,例如['binary', 'regression']
task_nameslist of str('ctr', 'ctcvr')每个任务的预测目标名,同时作为输出层与门控层的命名前缀
返回值——一个多输入多输出的 KerasModel实例,输出数量等于任务数

从 deepctr/layers/core.py 的DNN层实现看,dnn_dropout、dnn_use_bn、l2_reg_dnn、seed等参数最终都会透传给每一个专家、门控和任务塔 DNN,因此它们对模型的三类子网络是一致生效的。

四、参数约束与校验逻辑:写错会立即报错

MMOE()在建模前有一组显式的合法性校验(mmoe.py):

  • 任务数必须大于 1:num_tasks = len(task_names),若num_tasks <= 1抛出ValueError("num_tasks must be greater than 1")——MMOE 天然面向多任务,单任务请改用 DeepFM 等单目标模型;
  • 专家数必须大于 1:num_experts <= 1时抛出ValueError("num_experts must be greater than 1");
  • 任务类型与任务名数量一致:len(task_types) != num_tasks时抛出ValueError("num_tasks must be equal to the length of task_types");
  • 任务类型仅支持binary与regression:传入其他值(如'multiclass')会抛出ValueError("task must be binary or regression, ... is illegal")。

这些校验意味着:与 ESMM 强制要求恰好两个任务(见 esmm.py)不同,MMOE 理论上支持 2 个及以上的任意数量任务,只需保证task_names、task_types一一对应。

五、完整可运行示例:Census 收入数据双任务训练

仓库提供了 MMOE 的开箱即用示例 examples/run_mtl.py,使用 Census Income 样本(census-income.sample)同时预测"年收入是否超过 5 万美元"(label_income)与"是否未婚"(label_marital)两个二分类任务。核心流程如下:

1. 数据预处理:读取census-income.sample,将income_50k映射为二值标签、由marital_stat构造未婚标签;稀疏特征用fillna('-1')填充并做LabelEncoder编码,稠密特征用MinMaxScaler归一化到[0, 1]。

2. 构造特征列:稀疏特征封装为SparseFeat(feat, data[feat].max() + 1, embedding_dim=4),稠密特征封装为DenseFeat(feat, 1),通过get_feature_names得到模型输入名列表。

3. 定义并训练模型(关键代码):

model = MMOE(dnn_feature_columns, tower_dnn_hidden_units=[], task_types=['binary', 'binary'], task_names=['label_income', 'label_marital']) model.compile("adam", loss=["binary_crossentropy", "binary_crossentropy"], metrics=['binary_crossentropy'], ) history = model.fit(train_model_input, [train['label_income'].values, train['label_marital'].values], batch_size=256, epochs=10, verbose=2, validation_split=0.2) pred_ans = model.predict(test_model_input, batch_size=256) print("test income AUC", round(roc_auc_score(test['label_income'], pred_ans[0]), 4)) print("test marital AUC", round(roc_auc_score(test['label_marital'], pred_ans[1]), 4))

注意两个多任务建模要点:

  • 损失必须是列表:compile时loss传入与任务数等长的列表(这里是两个binary_crossentropy),metrics同理;
  • 标签必须是列表:fit的y传入[train['label_income'].values, train['label_marital'].values],predict返回的pred_ans也是一个列表,pred_ans[0]、pred_ans[1]分别对应两个任务的预测概率,因此需要用roc_auc_score(test['label_income'], pred_ans[0])与roc_auc_score(test['label_marital'], pred_ans[1])分别评估两个任务的 AUC。

回归任务的适配方式同理:把对应位置的task_type改为'regression',loss改为'mean_squared_error',标签换成连续值即可(该约定与测试工具 tests/utils_mtl.py 中binary→binary_crossentropy、regression→mean_squared_error的映射一致)。

六、测试验证:MMOE 的可用性如何被保证

仓库的 tests/models/MTL_test.py 专门覆盖了 MMOE:

model = MMOE(dnn_feature_columns, num_experts=3, expert_dnn_hidden_units=(8,), tower_dnn_hidden_units=(8,), gate_dnn_hidden_units=(), task_types=['binary', 'binary'], task_names=['income', 'marital']) check_mtl_model(model, model_name, x, y_list, task_types=['binary', 'binary'])

check_mtl_model(定义于 tests/utils_mtl.py)会依次验证:模型能否compile(adam + 逐任务 loss 列表)、能否fit一个 epoch、能否save_weights/load_weights往返、能否save_model/load_model(加载时需传入custom_objects)完整保存。这一测试链说明 MMOE 是"可训练、可保存、可加载"的完整 Keras 模型,可直接接入线上推理流程。

七、与其他多任务模型的定位差异

DeepCTR 的deepctr.models.multitask子包(deepctr/models/multitask/init.py)共提供四种多任务模型:

  • SharedBottom:所有任务共享同一个底层 DNN,结构最简单,适合任务高度相关的场景;
  • MMOE(本文主角):多专家 + 每任务独立门控,用数据驱动方式学习任务相关性;
  • PLE:在 MMOE 基础上进一步引入"任务专属专家 + 共享专家"与多层门控(num_levels、gate_dnn_hidden_units均可配置),针对性缓解负迁移;
  • ESMM:专为 CTR/CVR 全空间建模设计,强制两个binary任务并通过ctcvr = ctr * cvr相乘建模转化链路(见 esmm.py)。

架构示意可参考仓库 docs/pics/multitaskmodels/MMOE.png,直观展示了多专家(experts)经多门控(gates)加权后分别接入各任务塔的拓扑结构。

选型建议(基于源码结构的推断,非官方结论):当多个业务目标间相关性较弱、或单个共享塔效果明显不均衡时,MMOE 是性价比很高的折中方案;若任务间负迁移严重,可进一步尝试 PLE。

八、使用注意事项小结

  1. 任务数约束:task_names长度必须 ≥ 2,且与task_types等长;每个task_type只能是'binary'或'regression';
  2. 专家数约束:num_experts必须 ≥ 2,默认 3 个专家是平衡容量与训练成本的常用起点;
  3. 多输出约定:compile/fit/predict均使用与任务数等长的列表;评估时逐个任务计算指标(如 AUC);
  4. 特征列复用:dnn_feature_columns与单任务 Deep 模型(如 DeepFM)完全一致,SparseFeat的embedding_dim、DenseFeat的transform_fn等用法通用,可通过deepctr.feature_column的SparseFeat/DenseFeat/get_feature_names直接复用;
  5. 模型持久化:加载保存的模型文件时需要传入deepctr.layers提供的custom_objects(测试中可见 tests/utils_mtl.py)。

综上,DeepCTR 的MMOE()以约百行源码完整实现了 KDD 2018 的多门控专家混合架构,配合run_mtl.py示例与MTL_test.py测试,是快速上手多任务 CTR 建模的低门槛入口:只需准备特征列与任务标签,即可在同一模型内同时输出多个任务概率,并逐个任务评估与调参。

  • 人工智能
  • 深度学习
  • 机器学习

【免费下载链接】DeepCTR

Easy-to-use,Modular and Extendible package of deep-learning based CTR models .

项目地址:https://gitcode.com/gh_mirrors/de/DeepCTR
点击查看免费下载

相关推荐

上一篇:Draco 压缩一篇讲透:从参数到验证
下一篇:Kimi K2:MuonClip 优化器如何稳训出 1 万亿参数的 MoE 模型

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询