推荐系统(7)-----多目标排序综述(转)+多任务学习(MTL)(转)
一、多目标排序(转)
1、概念
多目标排序:指有两个或两个以上的目标函数,目的是寻求一种排序使得所有的目标函数都达到最优或满意。
在工业界推荐系统中,大多是基于隐式反馈来进行推荐的,用户对推荐结果的满意度通常依赖很多指标(比如,淘宝基于点击,浏览深度(停留时间),加购,收藏,购买,重复购买,好评等行为的相关指标),在不同的推荐系统、不同时期、不同的产品形态下,这些指标的重要程度或者所代表的意义会有所不同,如何优化最终推荐列表的顺序来使得众多指标在不同的场景下尽可能达到最优或者满意,这是一个多目标排序问题。
2、为什么
因为工业界都基于隐式反馈进行推荐,因此在评估用户满意度的时候会有不同程度的偏差:
Global bias:不同目标表达不同的偏好程度。比如淘宝,购买表达的偏好程度要高于点击、浏览所表达的偏好程度;
Item bias:单个目标衡量不全面;
比如今日头条,仅以点击率为目标,可能会存在标题党;
比如抖音短视频,只是以视频播放完成度为目标,可能会存在设置悬念而后需要关注才能观看的视频,用户看完了可能也不满意;
还有微博,如果仅以转发分享为目标,但内容可能存在类似转发保平安,或者是拼多多之类的营销;
User bias:用户表达满意度的方式不同.比如淘宝,用户表示喜欢可能会以收藏或者加购的形式,不同的人偏好也不一样;
综合目标收益最大化。比如快手,要鼓励用户发布视频,该目标虽然与用户满意度不是那么相关,但对于平台的生态来说也是至关重要的,所以利用多目标可以兼顾更大的范围,使综合目标收益最大化。
3、解决多目标排序方案
- 多模型分数融合
- 排序学习(LTR)
- 多任务学习(MTL)
(1)多模型分数融合
多模型融合的方式也是比较经典传统的做法,每个目标训练一个模型,每个模型算出一个分数,然后根据自身业务的特点,通过某种方式将这些分数综合起来,计算出一个总的分数再进行排序,综合分数的计算通常会根据不同目标的重要性设定相应的参数来调节。
下面以类似淘宝的电商推荐系统为例,了解一下经典的多模型分数融合实现多目标排序的具体流程。
上图流程图展示的是一个工业界很常用的推荐流程,包括召回(Match)、排序(Rank)、重排序(Rerank)、推荐(Recommend)过程。
当完成召回候选阶段之后,就有了可供推荐的候选 Item,然后从数据库中获取 User 和 Item 特征(特征缓存),从参数服务器获取模型参数(权重缓存),就可以进行预估。这里假定淘宝有五个预估目标,分别是点击率 CTR、购买转化率 CVR、收藏率 collect,加购率 cart、停留时长 stay,这五个目标分别对应五个模型,排序阶段的作用就是利用模型根据各自目标来给候选 Item 计算一个预估值(分数),排序阶段结束每个 Item 都会有五个不同的目标预估分数,如何用这些分数,是交给下一个流程来处理的。
重排序模块有两个主要作用,一个是融合,也就是将排序阶段传递来的多个目标分数进行融合,形成一个分数,另外一个是约束,也就是规制过滤。
分数融合的一种思路是利用一个带参数公式来实现,如下:
可以发现,在计算 score 时,除了各个目标以及对应的参数外,公式中还多了两个部分,一个是价格 price 以及对应的参数 β,另外一个是规则权重 rule_wight。
公式中添加价格,是因为价格是影响最终满意度非常重要的一个因素,比如对于同一个物品,它的价格通常是随着营销策略浮动的,不同的价格转化率就会不同,因为在降价的时候,商品销量通常会明显升高;而对于不同物品,价格便宜的物品转化率也会更高,因为便宜的物品受众用户更广,试错成本也低,而一些比较昂贵的物品,受众用户较窄,试错成本很高,自然转化率就会较低,所以加入价格 price,可以很好的区分这些情况。
另外一个规则权重,其实是把规制过滤也放到了分数融合里面,当然有些场景下,规制过滤是单独的一个部分,这个单独的约束部分,可以称为规则系统(Rules),它也是推荐系统中非常重要的一环。
商品按最终预估分排序后,会进入规则系统依次进行核对,判断是否满足规则系统。这些规则可能包含如下几种:
① 同一 XX N 出 1:该规则主要目的是使推荐满足多样性、惊喜性等目标,比如同一个类目只能推一个,同一个品牌只能推一个,当然,这里的 1 也可以任意合理的数值;
② 活动扶持:比如最近在双十一活动,那么会推荐更多参与了活动的商品;
③ 新品扶持:新品刚上市,相关指标预估分会很低,或者面临冷启动问题,会有相应扶持;
④ 低俗打压:比如快手,不能因为部分低俗视频流量高,就过多曝光,这样会影响整个产品个人的印象,因此会打压低俗,进行产品调性的控制;
⑤ 流量控制:为了让流量更均匀的分发到各个商品上,发掘长尾,不能给某一商品过多展示的机会,比如限制某一商品一天只能曝光 100 万次。
有了公式,那么超参数(α,β,a,b,c 等)如果进行学习获取?
先假设没有上面的经验公式,我们很容易想到的一种思路是类似于集成学习中一种多模型融合方法 Stacking,即将多个目标模型预估出的结果作为输入,然后用一个简单的线性回归进行线性加权融合,学习到各个目标的权重,这样我们就可以预估综合分数了。但是我们却忽略了一个重要的问题,该如何设置样本的 Label 呢?事实上,并没有一个真实的综合分数可供我们去训练学习,因此,这种办法很难真正去实现。而在工业界,更多的做法是人工调试,但如此又会带来很多问题,比如模型灵活度不够。
这种经典的多模型分数融合方法,虽然易于理解和扩展,但也存在很多问题和难点:
-
部分目标数据稀疏,模型准确率低
比如相比点击率转化率样本数据稀疏;
-
在线服务计算量大
ranker 模块要对 5 个模型进行计算,代价可能比较大,参数、优化、维护都会成倍增加;
-
多个目标间重要性难以量化
不同的动作提供不同程度的反馈,但由于用户偏好不同,有些动作所代表的重要性很难量化,比如分享和评论在不同用户身上的重要性可能是不一样的;
-
分数融合的超参难以学习,两种解决思路:
-
人工标注为 Label
用显示反馈数据来学习隐式反馈的超参,但工业界收集显示反馈数据成本非常高,而且非常主观。
-
长期目标为 Label
推荐系统的一个核心目的是给企业带来长期收益,所以可以用长期目标作为 Label,比如客户留存率,但是长期目标周期长,学习模型需要很长时间来收集 Label,容易错失机会;另外就是用长期目标试错成本高,策略不好的话无法及时发现,也就无法及时更改,可能导致用户流失而不能及时有效挽回。
综合而言,还是人工调参更加现实。
-
-
规则不够智能化
比如规则 5 个只能出 1 个,但是可能客户就想买鞋,然而并没有推荐很多。传统的规则系统主要是基于全局的角度上考虑的,没有考虑到用户的上下文去分析即时需求,不够智能,可以考虑采用强化学习的方法。
-
前两个问题工业界解决体系比较完善,比如下面提到的另外两种方法,主要目的就是尽可能使多目标排序的预估更快更准,第三个问题偏产品设计,而最后两种并没有比较完善的解决方法。
(2)排序学习(Learning To Rank,LTR)
首先要明白一点,多模型融合中我们通过模型计算预估值或者是综合打分,其根本目的是为了给推荐物品排序,而不是真正的打分。因此我们可以使用排序学习方法来解决多目标问题,比如 BPR 或者 LambdaMART 算法,排序学习的概念和相关算法在之前的文章🔖《推荐系统中的排序学习》已经详细介绍过。
相比多模型融合中 Label 标注,排序学习模型的的 Label 标注相对更容易一点,因为只关心相对关系,而不需要真实的打分数据。一种常见的标注方法是对多目标产生的物品构建 Pair,比如用户对物品 i 产生的购买,对物品 j 产生了点击,假定我们觉得购买的目标比点击的目标更重要,就可以让 i>uj,其他目标以此类推。有了顺序对后,我们便可以训练排序学习模型,这样一个模型便可以融合多个目标,而不用训练多个模型。
排序学习解决多目标排序问题的优缺点有哪些呢?
优点:
-
- 直接优化排序目标,排序效果好
- 单模型融合多目标,工程代价小,serving 压力小
缺点:
-
-
样本数量大,训练速度慢
排序学习虽然能够减少模型数量,但是要想学习多个目标排序关系,其合起来构建的样本数量会很大(假设有 m 个正样本,n 个负样本,PointWise 是 m + n 个参数,PairWise 则对于单个用户可能是 m x n),会导致训练速度非常慢;
-
有些偏序关系不容易构造
实际工业数据中并没有排序学习算法中那些完美的假设,有些目标间可能不存在偏序关系,也不存在传递性,还有一些目标所代表的重要性会因用户偏好而存在差异,这样的话,偏序关系并不容易构造;
-
多目标间的关系不易调整
举例理解,比如淘宝双十一之前一个周,目标更多是让用户加购或收藏(偏序关系:加购 > 购买),而双十一当天系统更加偏向于转化为目标(偏序关系:购买 > 加购),要知道排序关系的确定其实是从样本中来体现的,如果为了重新定义目标的重要度而全部重新构造样本,这样很多流程也会随之改变,代价会非常大。
-
(3)多任务学习(Multi-Task Learning,MTL)
对于前面两种方法,或多或少都有些难以避免的缺陷,工业界是如何作取舍呢?在此之前,大部分公司的做法就是多模型分数融合方法,一个模型一个目标,不过只用较少的几个关键目标进行融合;也有一小部分公司直接用排序学习,用一个模型就搞定;而那些先进的大公司,通常会使用多任务学习来实现多目标排序。1
多任务学习就是本节的重头戏, 它也是最近两年非常热门的多目标排序的解决方案。多任务学习属于迁移学习的一种,通过共享参数,学习出多个分数,最后结合起来。典型的算法有谷歌的 MMOE(Multi-gate Mixture-of-Experts)以及阿里的 ESMM(Entire Space Multi-Task Model)。
接下来,我们详细介绍多任务学习的相关知识点和推荐系统中的经典应用。
二、迁移学习(转)
多任务学习 MTL 其实是迁移学习的一种,这一小结我们先了解一下迁移学习这个体系。
2.1.迁移学习介绍
在机器学习、深度学习和数据挖掘的大多数任务中,我们都会假设 training 和 inference 时,采用的数据服从相同的分布(distribution)、来源于相同的特征空间(feature space)。但在现实应用中,这个假设很难成立,往往遇到一些问题:
- 带标记的训练样本数量有限。比如,处理 A 领域(target domain)的分类问题时,缺少足够的训练样本。同时,与 A 领域相关的 B(source domain)领域,拥有大量的训练样本,但 B 领域与 A 领域处于不同的特征空间或样本服从不同的分布。
- 数据分布会发生变化。数据分布与时间、地点或其他动态因素相关,随着动态因素的变化,数据分布会发生变化,以前收集的数据已经过时,需要重新收集数据,重建模型。
这时,知识迁移(knowledge transfer)是一个不错的选择,即把 B 领域中的知识迁移到 A 领域中来,提高 A 领域分类效果,不需要花大量时间去标注 A 领域数据。迁移学习,做为一种新的学习范式,被提出用于解决这个问题。
迁移学习(Transfer Learning,TL)是属于机器学习的一种研究领域。它专注于存储已有问题的解决模型,并将其利用在其他不同但相关问题上。比如说,用来辨识汽车的知识(或者是模型)也可以被用来提升识别卡车的能力。
在任务间迁移知识是人类与生具有的能力,通过完成某个任务所获得的知识,同样可用于解决其他相关的任务。传统机器学习和深度学习算法通常在设计上是独立工作的,这些算法训练用于解决特定的问题,学习中也并未保留任何可从一种模型迁移到另一种模型上的知识,一旦特征空间的分布发生变化,就需要从头开始重新构建模型。迁移学习设计用于解决这些相互隔离的学习方式,可以利用先前训练模型中的知识(即特征,权重等)训练新的模型,实现从其它任务获取的知识去解决相关的问题,甚至可以解决诸如新任务具有较少数据等问题。
迁移学习可以解决哪些问题?
- 大数据与少标注的矛盾:虽然有大量的数据,但往往都是没有标注的,无法训练机器学习模型。人工进行数据标定太耗时。
- 大数据与弱计算的矛盾:普通人无法拥有庞大的数据量与计算资源。因此需要借助于模型的迁移,比如图像识别中进行对训练好的模型进行 fine-tuning 完成自己的任务。
- 普适化模型与个性化需求的矛盾:即使是在同一个任务上,一个模型也往往难以满足每个人的个性化需求,比如特定的隐私设置。这就需要在不同人之间做模型的适配。
- 特定应用(如冷启动)的需求。
迁移学习使得我们能够利用前期学习任务中的知识,并将这些知识应用于新的相关任务。 因此在迁移学习的过程中,必须能够回答如下三个重要的问题:
- 迁移什么(What to transfer): 给定一个目标领域,如何找到相对应的源领域,或者说我们需要走确定哪些知识可以从源迁移到目标。在回答这个问题时,我们会试图确定哪些知识是特定于源的,哪些知识在源和目标之间的是共同的。然后进行迁移?(源领域选择)
- 何时迁移(When to transfer): 什么时候可以进行迁移,什么时候不可以?在某些场景中,迁移知识可能要比改进知识更糟糕(该问题也称为 “负迁移”)。我们的目标是通过迁移学习改善目标任务的性能或结果,而不是降低它们。(避免负迁移)
- 如何迁移(How to transfer): 如何进行迁移学习?我们需要确定跨域或跨任务实现知识实际迁移的方法。该问题涉及如何改进现有的算法和各种技术(设计迁移方法)
2.2 迁移学习的基本概念(未看)
2.3 迁移学习的分类
三、多任务学习 (转)
多任务学习其实是迁移学习的一个分支,或者可以说是迁移学习中一类特殊的解决方法。多任务学习同时学习若干任务,并不区分源和目标。与经典的迁移学习相比,多任务学习的学习器最初并不知道目标任务,它一次接收多个任务的相关信息。
3.1.单任务学习和多任务学习
单任务学习时,各个任务之间的模型空间(Trained Model)是相互独立的,而多任务学习时,多个任务之间的模型空间(Trained Model)是共享的,对比如下图所示:
另外一个明显对比是利用神经网络结构来学习,多任务学习时,多个任务之间的浅层表示共享(shared representation),而单任务学习时,各个任务的学习是相互独立的,如下图:
3.2 多任务学习的定义
多任务学习(Multitask learning)是基于共享表示(shared representation),把多个相关的任务放在一起学习的一种机器学习方法。多任务学习涉及多个相关的任务同时并行学习,梯度同时反向传播,利用包含在相关任务训练信号中的特定领域的信息来改进泛化能力。
一般来说,优化多个损失函数就等同于进行多任务学习(与单任务学习相反)。 即使只优化一个损失函数(如在典型情况下),也有可能借助辅助任务来改善原任务模型。
可以发现,多任务学习的定义中,有两个非常关键的限定,也是多任务得以实现的前提条件:多个任务之间必须具有相关性以及拥有可以共享的底层表示。
在多任务学习的定义中,共享表示是一个非常重要的限定,个人认为共享表示对于最终任务的学习有两类作用:
- 促进作用,通过浅层的共享表示互相分享、互相补充学习到的领域相关信息,从而互相促进学习,提升对信息的穿透和获取能力;
- 约束作用,在多个任务同时进行反向传播时,共享表示则会兼顾到多个任务的反馈,由于不同的任务具有不同的噪声模式,所以同时学习多个任务的模型就会通过平均噪声模式从而学习到更一般的表征,这个有点像正则化的意思,因此相对于单任务,过拟合风险会降低,泛化能力增强。
因此在深度神经网络中,执行多任务学习有两种最常用的方法:
多任务学习,如何设计一个更好的参数共享机制?| AAAI 2020
- 参数的硬共享机制(基于参数的共享,Parameter Based)
共享 Hard 参数是神经网络 MTL 最常用的方法。在实际应用中,通常通过在所有任务之间共享隐藏层,同时保留几个特定任务的输出层来实现,如下图所示:
共享 Hard 参数大大降低了过拟合的风险。实际上,有论文表明过拟合共享参数的风险为 O(N)——其中 N 是任务数——小于过拟合特定任务参数,即输出层。这很直观:我们同时学习的工作越多,我们的模型找到一个含有所有任务的表征就越困难,而过拟合我们原始任务的可能性就越小。
- 参数的软共享机制(基于约束的共享,Regularization Based)
另外一种方式是共享 Soft 参数,每个任务都有自己的参数和模型。模型参数之间的距离是正则化的,以便鼓励参数相似化,例如使用 L2 距离进行正则化。
3.3.动机
多任务学习的动机有不同的方式:从生物学的角度,多任务学习可以看作是受到人类学习的启发。对于学习新任务,我们经常应用通过学习相关任务获得的知识。
- 例如,宝宝首先学会识别面部,然后可以应用这些知识来识别其它对象。
- 从教学的角度,我们经常通过学习任务来获得必要的技能,以便掌握更复杂的技术。学习武术(比如柔道)的恰当方式也适用于学习编程。
- 以流行文化为例,一个例子是《空手道少年(1984)》(感谢 Margaret Mitchell 与 Adrian Benton 提供灵感)。在电影中,老师宫城先生教导了空手道孩子看起来是无关紧要的任务,如打地板和给车打蜡。事后看来,这些可以让他掌握与学习空手道相关的宝贵技巧。
最后,从机器学习的角度:我们可以将多任务学习看作归纳转移的一种形式。归纳传递可以通过引入归纳偏置(inductive bias)来帮助改进模型,这导致模型比其它模型更喜欢某些假设。例如,一种常见形式的归纳偏置是 L1 正则化,这导致偏好稀疏解。在 MTL 模型下,归纳偏置由辅助任务提供,这导致模型更喜欢假设而不是解释多个任务。正如我们将在下面看到的,这通常会导致更好的一般化解决方案。
3.4.为什么多任务学习是有效的
多任务学习之所以有效,是因为多任务学习的方式引入了归纳偏置(inductive bias),
归纳偏置有两个效果
- 一个是互相促进,可以把多任务模型之间的关系看作是互相先验知识,也称归纳迁移(inductive transfer),有了对模型的先验假设,可以更好的提升模型的效果;
- 另外一个效果是约束作用,借助多任务间的噪声平衡以及表征偏置来实现更好的泛化性能。
我们下面详细解释:
-
利用 MTL 减少深度学习对大数据量的依赖(隐式数据增加)
解决数据稀疏性其实本身也是迁移学习的一个特性,在多任务学习中也同样会体现。以图像物体识别为例,假如 A 任务是识别汽车,而 B 任务是识别出越野车,可以知道,当样本数量有限时,B 任务的样本数量要远远小于 A 任务的样本数量。那么这个时候,多目标学习可以利用样本数量比较多的 A 任务,从 A 任务学习到一些处理后的高维抽象的 feature map 或者部分参数应用到 B 任务的学习,可以一定程度上缓解 B 任务数据稀疏问题。
-
多任务间相互促进,对特征学习和表征更加充分,体现在以下三个方面:
-
多个模型特性互相弥补
不同的任务训练处的模型可以相互看做是一种 inductive transfer(先验知识),通过提供 inductive bias(某种对模型的先验假设)来提升模型效果**。
点击率预估模型善于学习表面特征,其中包括标题党,美图带来的点击诱惑;而转化模型学习更深层的特征,比如体验、服务质量。MTL 可以很好地将这些特征充分学习到。
-
注意力机制
如果一个任务非常嘈杂或数据量有限并且高维,模型可能难以区分相关与不相关的特征。MTL 可以帮助模型将注意力集中在重要的特征上,因为其它任务将为这些特征的相关性或不相关性提供额外的证据。
-
窃听(eavesdroping)或者提示(hint)
某特征 G 很容易被任务 B 学习,但是难以被另一个任务 A 学习。这可能是因为 A 以更复杂的方式与特征进行交互,或者因为其它特征阻碍了模型学习 G 的能力。通过 MTL,我们可以允许模型 “窃听”,即通过任务 B 学习 G。最简单的方法是通过 “提示”,即直接训练模型来预测最重要的特征。
-
-
多任务间相互约束,提高泛化性,体现在以下两个方面:
-
隐式数据增加带来的正则化约束
由于不同的任务具有不同的噪声模式,所以同时学习多个任务的模型能够学习更一般的表征(类似 bagging 的思想)。只学习任务 A 有可能过拟合任务 A,而联合地学习 A 和 B 使模型能够通过平均噪声模式获得更好的表征。这也是一种特殊的正则化方式。
-
表征偏置
MTL 任务偏好其它任务也偏好的表征,这会造成模型偏差。但这将有助于模型在将来泛化到新任务,因为可以通过学习足够大的假设空间,在未来某些新任务中得到更好的泛化表现(解决冷启动), 前提是这些任务都是同源的。
-
3.4.多任务学习与其他学习方法的对比
- 迁移学习(transfer learning)定义一个源域一个目标域,从源域学习,然后把学习的知识信息迁移到目标域中,从而提升目标域的泛化效果。迁移学习一个非常经典的案例就是图像处理中的风格迁移。
- 多任务学习(Multitask learning)是迁移学习的一种,对多个任务之间的相关性建模,同时学习多个任务,这些任务可能拥有不同的数据或特征。比如人脸识别中,同时识别人脸的性别和预估人脸主人的年龄。
- 多标签学习(Multilabel learning)是多任务学习中的一种,对多个标签之间的相关性建模,同时学习多个标签,多个标签之间共享相同的数据或特征。多标签学习就是多标签分类学习,指的是一条数据可能有一个或者多个标签(类别标签数量不统一), 比如一个病人的体检报告,它可能被标记上,高血压,高血糖等多个标签。
- 多类别学习(Multiclass learning)是多标签学习任务中的一种,也称多分类学习,对多个相互独立的类别(classes)进行建模。多类别学习指的是 一条数据只有一个标签,但是标签有多种类别,经典的鸢尾花分类就是标准的多类别学习任务。
四、基于MTL的深度学习研究(转)
4.1.图像
通常的方法是共享卷积层,同时学习特定任务的全连接层。
(1)深度关系网络
http://arxiv.org/abs/1506.02117 ,除了图 中可以看到的共享和特定任务层的结构之外,他们在全连接层上使用矩阵先验(matrix priors),这样可以让模型学习任务之间的关系,类似于一些之前看过的贝叶斯模型。然而,这种方法仍然依赖于预定义的共享结构,这可能对于已经充分研究的计算机视觉问题是可行的,但是其证明对于新任务来说容易出错。
(2)全自适应特征共享
http://arxiv.org/abs/1611.05377 提出了一个从窄网络(thin network)开始的自下而上的方法,并在训练过程中使用一个促进类似任务分组的标准,贪婪地动态拓宽网络。动态创建分支的拓宽过程可以在图 4 中看到。但是,贪婪方法可能无法发现全局最优的模型,而将每个分支正好分配给一个任务不允许模型学习更复杂任务交互。
(3)十字绣网络
https://doi.org/10.1109/CVPR.2016.433 从两个独立的模型架构开始,如共享 Soft 参数一样。然后,他们使用称为十字绣(cross stitch)的单位,以允许模型通过学习前面层的输出的线性组合来确定如何使特定任务的网络利用其它任务的知识。图 5 为模型架构,其中它们仅在池化(pooling)和全连接层之后使用十字绣单位。
4.2.NLP
NLP最近的工作侧重于为多任务学习找到更好的任务层次:显示当低级任务用作辅助任务时应该在低层(lower layer)监督,如通常用于预处理的 NLP 任务(如词性标注/part-of-speech tagging 和命名实体识别/named entity recognition)。
(1)联合多任务模型
(2)Multi-Task Learning Using Uncertainty to Weigh Losses for Scene Geometry and Semantics.[加权损失与不确定性]
与学习共享的结构不同, 通过考虑每个任务的不确定性应用正交方法(orthogonal approach)。然后,他们通过基于最大化任务决定的不确定性的高斯似然估计,求导多任务损失函数,并以此来调整成本函数中的每个任务的相对权重。每一像素的深度回归(per-pixel depth regression)、语义和实例分割的架构可以在图 7 中看到。
图 7:用于多任务学习的基于不确定性的损失函数加权(Kendall 等人,2017)。
五、 多任务学习在推荐算法中的应用
1、ESMM
2、ESM2
3、MMOE
6、知乎
六、深度MTL的一些经验(转)
从参数硬共享(hard parameter sharing)的基础方法开始。硬共享表示我们使用一个共享的子网络,下接各个任务特定的子网络。
在 TensorFlow 中,实现这样一个模型的简单方法是使用带有 multi_head 的 Estimator。这个模型和其他神经网络架构相比没什么不同,所以你可以自己想想,有哪些可能出错的地方?
1、第一点:整合损失
我们的 MTL 模型所遇到的第一个挑战是为多个任务定义一个损失函数。既然每个任务都有一个定义良好的损失函数,那么多任务就会有多个损失。
我们尝试的第一个方法是将不同损失简单相加。很快我们就发现,虽然某一个任务会收敛得到不错的结果,其他的却表现很差。进一步研究后,可以很容易地明白原因:不同任务损失的尺度差异非常大,导致整体损失被某一个任务所主导,最终导致其他任务的损失无法影响网络共享层的学习过程。
一个简单的解决方案是,将损失简单相加替换为加权和,以使所有任务损失的尺度接近。但是,这引入了另一个可能需要不时进行调节的超参数。
- 预测不确定性角度:论文《Multi-Task Learning Using Uncertainty to Weigh Losses for Scene Geometry and Semantics》,提出引入不确定性来确定 MTL 中损失的权重:在每个任务的损失函数中学习另一个噪声参数(noise parameter)。此方法可以接受多任务(可以是回归和分类),并统一所有损失的尺度。这样,我们就能像一开始那样,直接相加得到总损失了。
与损失加权求和相比,该方法不仅得到了更好的结果,而且还可以不再理会额外的权重超参数。论文作者提供的 Keras 实现参见:https://github.com/yaringal/multi-task-learning-example/blob/master/multi-task-learning-example.ipynb。
- 构建所有loss的Pareto,以一次训练的超低代价得到多种超参组合对应的结果。Intel在2018年NeurlPS发表的Multi-Task Learning as Multi-Objective Optimization。
https://zhuanlan.zhihu.com/p/138597214
2、第二点:调节学习速率
调节神经网络有一个通用约定:学习速率是最重要的超参数之一。所以我们尝试调节学习速率。我们发现,对于某一个任务 A 而言,存在一个特别适合的学习速率,而对于另一个任务 B,则有不同的适合学习速率。如果选择较高的学习速率,可能在某个任务上出现神经元死亡(由于大的负梯度,导致 Relu 函数永久关闭,即 dying ReLU),而使用较低的学习速率,则会导致其他任务收敛缓慢。应该怎么做呢?我们可以在各个「头部」(见上图,即各任务的子网络)分别调节各自的学习速率,而在共享网络部分,使用另一个学习速率。
虽然听上去很复杂,但其实非常简单。通常,在利用 TensorFlow 训练神经网络时,使用的是:
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss)
AdamOptimizer 定义如何应用梯度,而 minimize 则完成具体的计算和应用。我们可以将 minimize 替换为我们自己的实现方案,在应用梯度时,为计算图中的各变量使用各自适合的学习速率。
all_variables = shared_vars + a_vars + b_vars all_gradients = tf.gradients(loss, all_variables) shared_subnet_gradients = all_gradients[:len(shared_vars)] a_gradients = all_gradients[len(shared_vars):len(shared_vars + a_vars)] b_gradients = all_gradients[len(shared_vars + a_vars):] shared_subnet_optimizer = tf.train.AdamOptimizer(shared_learning_rate) a_optimizer = tf.train.AdamOptimizer(a_learning_rate) b_optimizer = tf.train.AdamOptimizer(b_learning_rate) train_shared_op = shared_subnet_optimizer.apply_gradients(zip(shared_subnet_gradients, shared_vars)) train_a_op = a_optimizer.apply_gradients(zip(a_gradients, a_vars)) train_b_op = b_optimizer.apply_gradients(zip(b_gradients, b_vars)) train_op = tf.group(train_shared_op, train_a_op, train_b_op)
友情提醒:这个技巧其实在单任务网络中也很实用。
3、第三点:将估计作为特征
当我们完成了第一阶段的工作,为预测多任务创建好神经网络后,我们可能希望将某一个任务得到的估计(estimate)作为另一个任务的特征。在前向传递(forward-pass)中,这非常简单。估计是一个张量,可以像任意一个神经层的输出一样进行传递。但在反向传播中呢?
假设将任务 A 的估计作为特征输入给 B,我们可能并不希望将梯度从任务 B 传回任务 A,因为我们已经有了任务 A 的标签。对此不用担心,TensorFlow 的 API 所提供的 tf.stop_gradient 会有所帮助。在计算梯度时,它允许你传入一个希望作为常数的张量列表,这正是我们所需要的。
all_gradients = tf.gradients(loss, all_variables, stop_gradients=stop_tensors)
和上面一样,这个方法对 MTL 网络很有用,但不止如此。该技术可用在任何你希望利用 TensorFlow 计算某个值并将其作为常数的场景。例如,在训练生成对抗网络(Generative Adversarial Network,GAN)时,你不希望将对抗示例反向传播到生成过程中。