1. 多任务学习到底在解决什么问题——先谈单任务模型的三个瓶颈做推荐、搜索、广告、内容理解这类深度学习落地的朋友最近几年应该都有一个共同的体感多任务学习MultiTask Learning, MTL已经不是一个可选项而是默认选项。就拿推荐系统来说一次曝光同时要预估用户会不会点、点了会不会购买、买了会不会停留更久这三个目标过去大家都习惯各训一个模型美其名曰专人专事。但我自己把三套管线在线上跑了一年多之后越来越觉得哪儿不对劲。先说说单任务模型最直接的三个瓶颈。第一套瓶颈出在特征工程上点击率模型要构造用户历史点击序列特征时长模型也要构造同样的序列特征转化模型还要再来一遍。同一个用户行为日志被三套特征管线各自清洗、各自加工白白浪费大量开发时间。第二套瓶颈是数据问题像转化、退款这类行为在业务里天然是稀疏的单任务模型面对这种小样本标签很容易出现过拟合特征稍微多一点就学到了噪声而不是信号。第三套瓶颈是线上成本三套模型意味着三份特征服务、三份模型推理、三份存储和监控在线延迟和机器成本全都在翻倍。多任务学习解决的正是这三件事底层网络共享一套表示高层为每个任务保留独立的分支训练时多个监督信号同时反传既减少了重复的特征工作又通过共享表示带来了隐式的数据增强——说白了任务A学到的模式可以帮任务B在数据不足的地方补课线上也只用部署一个模型。我见过不少团队在刚开始接触这个概念时以为它只是把损失函数加起来这么简单结果上线后效果还不如单任务。这篇文章就是想把多任务学习从结构设计、损失平衡到工程落地的完整链条拆开讲清楚读者无论你是刚入门的研究生还是正在改造线上系统的工程师都能在里面找到可以直接抄作业的部分。2. 硬共享与软共享的取舍模型结构设计的灵魂2.1 硬参数共享最经典也最容易低估的结构所谓硬参数共享就是多个任务共用同一个底层网络只在顶层分离出各自的任务头task tower。结构上可以理解为一根粗管道多个细出口。底层卷积或Transformer的权重被所有任务一起更新顶层的每个head只接收自己需要的语义信息。这种结构在论文里最常见也是工程上最稳健的方案——它天然防止了某个任务在底层过早私有化大幅降低了过拟合风险。共享部分学到的表征越通用每个任务就越能从中受益。我早期做某个内容理解项目时同时要判断文本的情感极性、话题类别和是否包含营销信息三个任务的输入一样、语义底层高度重叠就用了这种最简单的共享结构。实测下来情感和话题两个任务都明显比各自单独训练强原因是话题分类提供了大量领域先验情感分类的边界被约束得更合理。但这里有个很容易踩的坑任务相关性不够的时候硬共享会让任务之间互相拖后腿。我见过有人在同一个底座上同时做商品点击预测和商品图片美学评分这两个任务的信息层次差异太大底层表示被拉扯得面目全非最终两个指标都跌了。所以硬共享的前提是先问一句这些任务真的在共享同一套底层语义吗2.2 软参数共享给每个任务留一点私心当任务之间相关性没那么强、但又不能完全分开训练时软参数共享就派上用场了。它的核心思想是每个任务拥有自己的一套参数但通过某种机制让这些参数互相渗透。最直观的做法是在损失函数上加上参数距离约束比如让不同任务对应层参数的L2距离尽量小更精致一点的做法是在网络结构层面做cross-stitch让任务A中间层的输出按一个可学习的权重缝一部分给任务B这个权重是反向传播时自动学出来的。我自己更偏爱另一种软共享的变体共享一个主网络但每个任务在中间层插一个轻量级的自适应模块类似对共享表示做一次task-specific的线性变换。这样既保留了大部分共享参数带来的数据和计算优势又给了每个任务调整表示空间方向的自由度。软共享的代价是参数量和工程复杂度上去了你必须为每个任务维护一份完整的中间状态和梯度显存占用会比硬共享高不少。所以我的选型经验其实很直白任务相关性高选硬共享不知道怎么判断相关性就先用硬共享试基线实在掉点再向软共享迁移。2.3 从Shared-Bottom到MoE系注意力式的动态路由如果说硬共享和软共享是两种极端中间地带还有一大类基于专家混合Mixture of Experts, MoE的方法。这类结构的核心是把共享底层拆成多个独立的专家子网络由一个门控网络根据输入特征决定每个任务激活哪些专家以及各占多少权重。最出名的是多任务版本的MMoE思路另外还有更精细化的PLE结构后者把专家明确划分为共享专家和任务专属专家再通过门控进行组合。我在某个跨语言项目里用过这类方案。当时要把中文、英文、法文三个语种的文本同时接入同一个语义理解模型硬共享的问题在于三种语言的语法差异太大单一共享层很难兼顾单独的软共享又让参数量爆炸。最终方案是每个语言配一个专属专家再加上一个跨语言的共享专家门控网络学会为每个语种和每个下游任务动态分配专家权重。效果比单独训练和硬共享都好而且训练收敛明显更快。这类结构的难点在于门控网络的稳定性训练初期门控容易震荡导致某个专家被饿死——始终拿不到梯度最后变成死参数。我在实践中会加一个专家使用率的正则项保证每个专家都有最低限度的激活概率。下表是我对这些结构在几个关键维度上的实测对比仅供参考结构类型参数量任务相关性要求训练稳定性适用场景硬参数共享低高稳定任务高度相关的强语义场景软参数共享中中较稳定任务间有语义差异但有交叠MoE系/MMoE/PLE高低需额外调参任务差异大、需要动态路由3. 损失权重与梯度冲突多任务训练最容易翻车的地方3.1 加权求和为什么经常失灵结构定好之后绝大多数人第一反应就是写一行loss w1 * loss_A w2 * loss_B然后调w1和w2。如果只调了几天就放弃我只能说这太正常了——手动调权重本质是在和三个变量同时搏斗各任务损失函数的数值量级、各任务梯度的范数量级、各任务收敛速度的差异。举个具体例子二分类交叉熵的数值通常在0到1之间而一个回归任务的MSE可能动辄几十甚至上百。把这两个任务简单相加回归梯度会把分类梯度完全淹没分类任务等于白训练。即便你用了个聪明的初始化把两个损失拉到同一量级训练过程中它们的梯度范数也会动态变化。某个任务一旦先收敛它的梯度变小另一个任务就会反过来主导更新方向。这就是我反复跟身边同事强调的多任务训练调的不是损失函数本身而是让多个任务的学习节奏对齐。最朴素的对齐手段是手动按经验设固定权重并在训练中定时观察各任务的loss曲线哪个任务掉得慢就临时给它加点权重。这个方法土但作为第一版基线足够用而且能帮你快速发现任务间是否存在根本性的冲突。3.2 自动权重机制让模型自己学会分配注意力手动调权重有个天花板就是任务数量一多组合空间实在太大。三个任务还能穷举八个任务就完全没法手工试了。这时候可以用一类自动平衡方法核心思路是让一个可学习的参数去控制各任务在总损失中的权重。这类方法里最经典的是GradNorm思路它不直接更新任务权重而是更新一个权重参数目标函数是让各任务的梯度范数尽量保持在同一尺度梯度范数大的任务对应的权重会被减小梯度范数小的任务权重会被增大保证没有任务被边缘化。实现上需要你额外维护一套每任务梯度范数的滑动统计并在反向传播时参与权重参数的梯度计算。另一条路线是从梯度向量本身下手。如果任务A的梯度和任务B的梯度夹角大于90度说明这两个方向的更新互相抵消这就是所谓的梯度冲突。解决思路很直接检测到冲突时把其中一个梯度投影到另一个梯度的正交方向上去更新让两个任务的更新方向不再互相伤害。这类处理冲突的改进算法在曝光点击转化这类多目标推荐场景下非常有效因为点击和转化天然存在一定的负相关梯度冲突是常态。实测下来在冲突明显的任务组上这类算法的相对提升往往比在任务高度相关的场景下更显著。3.3 我在实践中总结的损失平衡实操清单经过多个项目的折腾我把损失平衡的实操流程总结成了一份清单每次起新实验都按这个顺序走先把各任务损失归一化到相近量级。常用做法是每种损失除以它自己的初始值让训练一开始所有任务贡献的梯度大致可比。固定权重训练50到100个step观察各任务loss下降曲线。如果某个任务基本不动就要检查是梯度冲突还是学习率问题。再上自动权重机制作为基线跑一轮完整实验。如果收益不明显说明任务之间可能本身就不该共享参数回到结构设计那一层去思考。训练过程中同时记录每个任务对共享层的梯度范数。我习惯每500步打一次日志观察梯度范数是否出现持续发散一旦发散就需要降低对应任务的学习率或权重。这套流程看起来不复杂但能把大量玄学问题变成可诊断的系统问题。很多团队在损失平衡上翻车不是因为方法不够先进而是连最基本的梯度范数监控都没做。4. 从论文到工程多任务学习的落地经验4.1 任务相关性的量化判断别拍脑袋决定共享前面反复提到任务相关性但实际项目里怎么判断我的经验是至少要结合三种信号。第一种是业务信号两个任务是不是在预测同一种用户行为的不同阶段比如浏览到点击、点击到加购、加购到支付这种漏斗式的任务天然相关。第二种是标签层面的信号直接算任务标签之间的相关系数或互信息正相关强说明共享收益大负相关强则要警惕梯度冲突。第三种是模型层面的信号把每个任务的单任务模型中间层输出提取出来算一下表示向量的相似度如果表示空间本身就很接近共享之后的损失就小。最忌讳的做法是看到多任务学习效果好就直接把所有指标塞进一个模型。我在某个项目里曾被要求把购买预测和退货预测放进同一个模型乍一看都是电商行为但它们的时间窗口、用户意图方向完全不同实际共享后购买指标掉得最狠。后来我们干脆拆成两组购买和加购一组退货单独一组效果才恢复正常。项目里不存在任务越多越好这回事多任务学习能化解一定的任务差异但化解不了无限的任务差异。4.2 样本配比、训练稳定性和评估指标的坑多任务学习的数据还没进模型之前就有一个隐蔽的坑任务之间的样本覆盖率不一致。比如点击任务每个曝光样本都有标签转化任务只有少量样本有正标签时长任务又只有一部分样本有有效标签。如果按batch随机采样转化任务在每个batch里只能分到很少的样本梯度贡献被稀释得厉害。解决手段常见的有两种一是设置一个损失掩码没有标签的任务不参与该样本的loss计算二是按任务重要性做过采样给稀疏任务更高概率的样本抽取权重。后者我比较推荐因为它同时解决了标签稀疏和梯度稀释两个问题。训练稳定性上还有两个细节很容易被忽略。一是多任务模型的学习率通常要比单任务模型调得更保守一些因为多个梯度方向叠加同样的学习率可能让共享层参数震荡更剧烈。我习惯把多任务基线模型的学习率设为单任务模型的0.7倍左右起步。二是EMA参数滑动平均在多任务场景下收益特别明显因为多任务模型的loss曲线本身波动就大EMA能帮你在推理时拿到一个更平滑、更稳定的权重版本。评估指标是另一个容易想当然的地方。多任务模型的整体目标往往不是一个指标而是多个指标之间有一个业务加权公式。你不能只看某个任务单独涨了没有要看业务复合指标。更严谨一点我会额外监控每个任务相对于各自单任务baseline的涨跌幅度并计算多任务收益矩阵——横轴是任务A的收益纵轴是任务B的收益每个点代表一个实验配置。这个矩阵能直观暴露负迁移凡是落在任务A涨、任务B跌区域的配置说明存在任务冲突需要回到结构或权重层面再做平衡。4.3 线上推理时的工程细节多任务模型训练完了线上推理也有几个容易被忽视的坑。首先多个任务头意味着推理时可能只需要其中一部分输出但模型前向计算通常还是会完整跑完所有head。如果某些head只在训练时用、线上根本不需要那就在保存推理图时把不用的head剪掉能省一块推理延迟。其次多个head的输出尺度可能差异很大如果下游要统一消费这些分数最好在模型内部做一次校准或归一化有些团队会为每个任务头单独配一个calibration层。第三务必为每个任务头单独设置监控指标因为多任务模型的某个head可能在整体loss下降的同时悄悄退化——这种局部退化是线上事故的高发来源。5. 负迁移是怎么发生的——我的排查链路与修复经验负迁移是多任务学习里最让人头大的现象加了任务B之后任务A的指标反而比单独训练时还差。我在项目里整理了一套排查链路按顺序走基本能定位问题根源。第一步先看数据覆盖。确认任务A的样本在加了任务B之后是否被降权了。如果任务B样本量巨大、任务A样本量小共享层更新的主导方向会被任务B带走任务A等于被淹没。这种问题我会优先调整采样配比而不是调损失权重。第二步看梯度方向。我会把任务A和任务B的梯度在某个中期训练step分别抽出来计算它们之间的夹角。如果大量夹角大于90度说明冲突是结构性存在的。此时要么换用梯度冲突处理类算法要么把共享层拆开只共享部分底层。这一步能排查掉大部分所谓多任务就没用的假象——很多时候不是多任务没用而是任务对选错了。第三步看不同训练阶段的loss曲线。如果任务A在训练初期掉得很好中期开始反弹而任务B一路下降这通常是共享层表示被任务B征用了。我遇到过这样的情况任务A需要的是细节特征任务B需要的是全局特征共享层容量有限后期任务B的强梯度逼迫共享层丢掉了一部分对任务A有用的细节。修复方案是把这两个任务在某个中间层之后做分离让它们各自保留一条细节通路。排查完之后还有一个心理预期问题多任务学习不是银弹有些任务组合天然就不该共享。我自己现在做项目前的第一件事不是搭模型而是画一张任务关系脑图——哪些任务共享输入特征哪些任务共享业务目标哪些任务虽然同域但目标方向相反。这张图画清楚了后面至少能少走一半弯路。6. 多任务学习后续还能怎么玩——几个我认为值得关注的方向这个领域发展到现在结构、损失、工程都有了大量成熟方案但我关注的更多是它在更大上下文里的延伸。第一个方向是任务可迁移性和持续学习。现实业务中任务会源源不断地增加每次加任务都重训一遍模型成本太高。如何让新任务只训练自己的小分支同时复用已有共享层并且不破坏老任务的表现这是我在生产环境里特别想解决的问题。目前一些基于参数隔离和弹性共享的思路已经很有启发但离即插即用还有距离。第二个方向是大模型时代的多任务形态。现在大家都默认用统一的大模型做各种任务用指令或prompt来区分任务这某种程度上是把多任务学习从结构共享变成了能力共享。但这里有一个新的失衡问题不同任务的训练数据量差异巨大很容易出现某些任务霸权地占住模型容量。我认为多任务学习里关于损失平衡、梯度冲突的研究在大模型微调阶段依然完全适用而且会更重要。第三个方向是跨模态的多任务。图像、文本、语音的信号形式完全不同却共享同一个表示空间任务之间如何互相增强而不是互相干扰这个问题的难度比同模态多任务高一个量级。我最近在做一个图文内容理解的小实验发现图像任务和文本任务在共享层上的梯度冲突模式跟同模态场景明显不同值得单独研究。最后分享一个我个人压箱底的经验无论你用多花哨的多任务结构第一版永远先用共享底层独立head等权重跑通把数据管线和评估体系搭扎实再逐步升级结构和损失平衡策略。我在好几个项目里都是这样做的看似绕远实际上是最快路径——因为多任务学习百分之八十的收益来自共享表示本身剩下的百分之二十才来自花哨的trick。先把大头拿到手再打磨细节这个顺序一定不会错。