1. 多目标建模推荐系统的“既要又要还要”做推荐系统的同学估计都经历过这种“幸福的烦恼”老板说我们这个视频推荐不能光看点击率啊用户点进去看两秒就关了这有啥用我们还得提升用户的观看时长。过两天运营同学又来了说光看时长也不行我们得让用户多点赞、多评论增加互动率。你看这就是典型的“既要、也要、还要”。在技术层面这就叫多目标建模。简单说就是用一个模型同时预测多个业务指标。比如输入一个视频和用户特征模型不仅要告诉我“用户有多大可能点击它”还要告诉我“用户大概会看多久”甚至“会不会点赞转发”。这可比单目标模型复杂多了单目标就像你只关心孩子考试分数多目标则是你希望他德智体美劳全面发展。那为什么非要一个模型干多件事呢分开训练几个模型不香吗我刚开始也这么想但踩过坑就明白了。第一是效率问题线上推理时如果每个目标都部署一个独立的大模型计算资源和响应时间都扛不住。第二是数据利用问题有些目标比如转化率的样本非常稀疏单独训练效果很差但如果和点击率这种样本丰富的任务一起学就能“蹭”到知识学得更好。第三也是最重要的综合排序问题。如果点击率模型排出来的第一名转化率模型觉得它排第一百名那到底听谁的多目标模型能在内部就做好权衡输出一个综合最优的排序结果。所以多目标建模成了推荐、广告、搜索这些领域的标配。今天我就结合自己这些年趟过的路给大家掰开揉碎了讲讲从最基础的Shared-Bottom到如今工业界主流的MMOE这些算法到底是怎么一回事在实际项目中又该怎么选、怎么调。2. 算法演进三部曲从“大锅饭”到“自助餐”多目标建模的算法发展很有意思它就像一个组织管理方式的演进。咱们一个个来看。2.1 Shared-Bottom底层共享的“大锅饭”模式Shared-Bottom是最朴素、最直观的多任务学习结构。你可以把它想象成一个公司所有部门共用一套基础支持团队比如行政、财务、IT。这个共享的底层网络Shared Bottom就是那个支持团队它从输入数据比如用户和商品特征中学习通用的、底层的特征表示。在这个共享层之上每个业务目标都有自己的“专属小团队”也就是Tower网络。点击率任务有自己的Tower观看时长任务也有自己的Tower。它们接收共享层提炼好的通用特征然后各自加工最终输出自己目标的预测值。用公式表示就是y_k h_k ( f(x) )。其中f(x)是共享底层h_k是第k个目标的塔。它的优点很明显省参数防过拟合大部分参数都在底层共享模型整体更紧凑对于数据量不是特别大的场景能有效防止每个任务单独过拟合。简单好实现结构清晰搭建起来快是验证多任务学习可行性的首选。但它的“大锅饭”缺点也很致命负迁移Negative Transfer这是最头疼的问题。如果两个任务相关性很低甚至互相冲突比如“点赞”和“踩”。它们被迫使用同一套底层特征就会互相干扰。好比让财务部同时服务销售部和研发部两边需求完全不同财务部可能最后哪边都服务不好整体效率反而下降。跷跷板现象Seesaw Phenomenon训练时经常发现点击率指标上去了观看时长却下来了调一调时长上去了点击率又跌了。就像按跷跷板很难同时让两边都高。这是因为共享层要同时满足多个任务的梯度更新不同任务的梯度方向如果不一致就会“打架”导致优化困难。所以Shared-Bottom 就像一个温和的“计划经济”适用于目标任务高度相关、冲突小的场景。比如电商里“加入购物车”和“购买”这两个行为序列强相关共享底层知识收益很大。但一旦任务复杂起来它就力不从心了。2.2 MOE与OMOE引入专家的“委员会”机制为了解决“大锅饭”的问题研究者们想到了“委员会”决策机制也就是MOE。MOE 的全称是Mixture of Experts混合专家。它不再只有一个共享底层而是设置了一组比如3个或5个专家网络。每个专家都是一个独立的神经网络你可以理解为公司里不同领域的资深顾问有的擅长分析用户兴趣有的擅长挖掘内容质量有的擅长捕捉实时热点。那么对于每一个输入样本到底该听哪位或多位专家的意见呢这就需要引入一个门控网络。门控网络Gate会学习一个权重分布根据当前输入的特征决定分配给每个专家多少“话语权”。最后模型的输出是各个专家输出的加权和。OMOE就是One-gate MOE即所有任务共享同一个门控网络。公式是y_k h_k ( ∑ [g(x)_i * f_i(x)] )。所有任务都通过这一个Gate来决定专家权重。这比Shared-Bottom进步了灵活性增强不同的输入可以激活不同的专家组合实现了条件计算。对于多样化的数据模型容量更大。缓解负迁移专家之间相对独立任务间干扰降低。但 OMOE 还是有个问题所有任务共享同一个Gate。这意味着不管你是要预测点击率还是观看时长模型认为对专家的权重分配策略应该是一样的。这显然不合理就像开一个会讨论销售和研发两件事却只让同一个人共享Gate来决定听哪个专家的他很难同时满足两边迥异的需求。2.3 MMOE多门控的“精准定制”时代于是MMOE应运而生全称Multi-gate Mixture-of-Experts。它的核心改进简单而有效为每个任务配备一个独立的门控网络。在MMOE中那组专家是所有任务共享的“公共专家库”。但是点击率任务有自己的专属Gate网络观看时长任务也有自己的专属Gate网络。点击率的Gate会学习“对于预测点击率这个目标我应该更相信专家A稍微参考专家B忽略专家C”。而观看时长的Gate则会学到另一套完全不同的权重“预测时长嘛专家B最重要专家A和C辅助一下”。公式变为y_k h_k ( ∑ [g_k(x)_i * f_i(x)] )。注意门控权重g_k的下标多了个k代表这是第k个任务的门控。这才是真正的“自助餐”模式公共食堂共享专家提供了各种菜肴特征表示但每个员工任务根据自己的口味和需求专属Gate自由搭配出最适合自己的餐盘。MMOE的优势一下子就拉开了显式建模任务关系通过为每个任务学习独立的专家权重模型能够显式地刻画不同任务之间的关联与差异。相关性高的任务学出来的门控权重分布可能相似相关性低的任务权重分布则差异很大。极大缓解跷跷板效应每个任务都能找到对自己最有利的专家组合梯度冲突大大减少。实验中也反复证明在目标任务相关性较低时MMOE的效果显著优于Shared-Bottom和OMOE。参数效率高增加的任务专属Gate网络通常很小比如一层全连接增加的参数量几乎可以忽略不计但带来的效果提升却是巨大的。所以MMOE成为了工业界多目标建模的主流基线模型。它平衡了效果、灵活性和复杂度是应对“既要又要还要”这个经典难题的一把利器。3. 实战选型指南不看广告看疗效理论说得再好到底用哪个模型还得业务效果说了算。选型不是拍脑袋得看两个关键因素目标任务之间的相关性以及你的业务场景复杂度。3.1 核心决策因子目标相关性分析这是选型的第一准则。你需要量化或定性评估你要优化的几个目标之间到底是“好兄弟”还是“死对头”。高相关性目标比如“点击”和“收藏”。用户通常是因为喜欢才会点击喜欢了才可能收藏这两个行为背后的用户意图高度一致。再比如电商场景的“详情页浏览”和“加入购物车”。对于这类目标Shared-Bottom 这种简单共享的模式往往就够用了因为知识共享的收益远大于冲突。OMOE 在这种情况下的效果会和 MMOE 接近。低相关性或负相关目标这是MMOE大显身手的地方。经典例子就是“点赞”和“踩”它们本质上是互斥的。又比如“点击率”和“观看完成率”。用户可能被标题党吸引点击高CTR但发现内容垃圾马上关闭低完成率。这类目标如果强行共享底层必然导致负迁移。必须使用MMOE这种能为任务定制化筛选知识的模型。序列依赖目标这是一种特殊的相关性比如“点击率”和“转化率”。转化一定发生在点击之后样本空间有包含关系。对于这种场景Shared-Bottom、MOE系列都不是最优解ESMM这类专门为序列依赖设计的模型才是“对症下药”。它通过建模“点击-转化”的联合概率解决了CVR模型训练样本仅有点击样本与推理样本全量曝光样本分布不一致的核心难题。我画过一个简单的决策图辅助判断目标间是否有强序列依赖如CTR-CVR ├── 是优先考虑 ESMM 及其变种。 └── 否评估目标间相关性。 ├── 高相关性可从 Shared-Bottom 开始追求极简。 └── 低相关性/复杂多目标毫不犹豫选择 MMOE 作为基线。3.2 从MMOE到PLE当专家也分“公私”MMOE虽然强但它假设所有专家都是“公共”的。但在现实中有些知识可能只对某个特定任务有用别的任务用不上甚至有害。比如判断视频是否值得“投币”一种深度互动可能需要理解一些非常硬核的内容质量特征而这些特征对于预测普通的“点击”可能帮助不大。这就引出了MMOE的升级版CGC和PLE。CGC在MMOE共享专家的基础上为每个任务引入少量独有的专家。这样模型结构就包含了“共享专家”和“任务专属专家”两部分。每个任务的门控网络只接收自己的专属专家和共享专家的输出然后进行加权融合。这样任务既能从公共知识中受益又能保留和强化自己独有的特征提取能力。PLE可以理解为多层堆叠的CGC。它认为特征的提取和共享应该是渐进式、分层的。在底层任务专属专家和共享专家进行初步的信息提取与交互在更高层它们继续交互和融合从而学习到更高级、更抽象的共享表示和任务特定表示。PLE被证明在任务冲突非常激烈的复杂场景下比如同时优化视频有效播放率和完播率效果显著优于MMOE。所以你的选型路径可以进一步细化简单双目标相关性高试试 Shared-Bottom。多目标3相关性复杂直接用 MMOE 基线十有八九比Shared-Bottom好。上线MMOE后跷跷板现象依然明显考虑升级到 CGC为关键任务引入专属专家。业务目标非常多如5个以上且冲突严重对效果追求极致挑战更复杂的 PLE 结构。记住模型复杂度越高训练成本、调参难度和过拟合风险也越大。永远从最简单的有效模型开始。4. 工业级调优实践魔鬼在细节里选定MMOE作为基线后真正的挑战才刚刚开始。下面这些坑都是我实打实踩出来的经验。4.1 网络结构设计与参数设置专家数量与维度这是最重要的超参数之一。专家数量太少比如2个模型容量不够无法充分建模多样性太多比如8个以上不仅计算量增加还容易导致某些专家“退化”门控网络几乎不给它权重造成浪费。我的经验是对于常见的2-4个目标专家数量设置在3-6个之间是个不错的起点。每个专家的隐藏层维度可以比Shared-Bottom的共享层小一些因为现在有多专家并行。门控网络设计门控网络通常很简单一两层全连接层接一个Softmax输出权重。关键是要确保门控网络的输入包含足够丰富的特征信息以便做出准确的“专家选择”。通常我们会将原始的输入特征或经过一个浅层转换后的特征直接输入给门控网络。Tower网络设计顶部的任务塔网络不宜过深过复杂。因为大部分特征提取工作已经由共享专家们完成了Tower的作用更多是进行任务特定的微调。通常1-2层全连接层足矣。Tower过深反而可能学出一些噪声破坏从专家层传递来的共享信息。这里给一个我用TensorFlow大概实现的MMOE核心层代码方便理解结构import tensorflow as tf from tensorflow.keras.layers import Layer, Dense class MMOELayer(Layer): def __init__(self, num_experts4, expert_dim64, num_tasks2): super(MMOELayer, self).__init__() self.num_experts num_experts self.expert_dim expert_dim self.num_tasks num_tasks # 定义多个专家网络每个专家是一个MLP self.experts [Dense(expert_dim, activationrelu) for _ in range(num_experts)] # 为每个任务定义一个门控网络 self.gates [Dense(num_experts, activationsoftmax) for _ in range(num_tasks)] def call(self, inputs): # inputs: [batch_size, input_dim] expert_outputs [] # 计算每个专家的输出 for expert in self.experts: expert_outputs.append(expert(inputs)) # 每个shape: [batch_size, expert_dim] # 堆叠起来: [batch_size, num_experts, expert_dim] expert_outputs tf.stack(expert_outputs, axis1) task_outputs [] # 为每个任务计算加权专家输出 for i in range(self.num_tasks): gate_weights self.gates[i](inputs) # [batch_size, num_experts] # 扩展维度用于加权求和 gate_weights_expanded tf.expand_dims(gate_weights, axis-1) # [batch_size, num_experts, 1] # 加权求和: [batch_size, expert_dim] weighted_expert_output tf.reduce_sum(gate_weights_expanded * expert_outputs, axis1) task_outputs.append(weighted_expert_output) # 返回一个列表每个元素是对应任务的融合后特征 return task_outputs4.2 损失函数与梯度优化损失权重平衡多任务损失通常是各任务损失的加权和L_total w1 * L1 w2 * L2 ...。这个权重w怎么设拍脑袋设1:1往往不行。因为不同任务的损失值量级可能差异巨大比如CTR的Loss在0.1量级观看时长的MSE Loss可能在100的量级。直接相加会导致量级大的任务主导训练。我常用的策略有人工网格搜索根据业务重要性尝试几组权重如[1.0, 0.5, 0.1]观察验证集上各个任务指标的变化选取一个平衡点。不确定性加权这是一篇论文提出的方法让模型自动学习每个任务损失的权重。其思想是任务噪声越大越难学其损失权重应该越小。实现起来也不复杂效果有时不错。GradNorm更高级的方法直接在梯度层面进行动态调整让不同任务的梯度范数以相近的速度下降。实现复杂一些但在任务冲突严重的场景下效果显著。梯度裁剪多任务训练时梯度“打架”更剧烈容易出现梯度爆炸。在优化器如Adam中设置全局梯度裁剪是一个非常好的稳定训练的习惯。4.3 样本与特征工程样本对齐这是多任务学习独有的问题。你的训练样本必须包含所有任务的标签吗不一定但需要处理。对于某个样本缺失某个任务标签的情况比如有点击无转化常见的处理是在计算该任务的损失时将其权重置零或直接忽略该样本对该任务的贡献。在TensorFlow中可以通过样本权重矩阵来实现。特征共享与独占并不是所有特征都适合所有任务。例如“商品价格”特征对“购买转化率”目标至关重要但对“点击率”可能影响模式不同甚至可能因为价格高而抑制点击。在MMOE框架下一种实践是让门控网络和专家网络看到全部特征让模型自己去学。另一种更精细的做法是可以为不同任务设计不同的特征输入子集但这会增加工程复杂度。我建议先从全特征输入开始。线上服务MMOE模型相比单目标模型计算量确实会增加多个专家并行计算。在部署时需要对专家网络的计算进行优化比如利用模型并行或更好的算子融合。好消息是由于专家网络通常是并行的在现代GPU上也能获得不错的加速比。调优是一个持续的过程没有银弹。我的习惯是先固定一个简单的损失权重如1:1把模型跑通确保各个任务loss都能正常下降。然后重点调整专家数量和维度观察验证集效果。最后再去精细调整损失权重和更高级的优化策略。每次改动最好只动一个变量这样才能清晰地知道是什么带来了变化。多目标建模的调优更像是一门平衡的艺术需要在多个业务指标的此起彼伏中找到那个让整体业务价值最大化的甜蜜点。