大家好,我是DASOU
在多任务中,通常是把各loss统一到一个数量级,请问这么做的原理是什么呢?
今天分享一个技术硬核文章,详细的聊聊多任务这点事;
个人感觉这是一个非常有意思的问题。之前在训练多任务神经网络的时候遇到过类似的问题,在我的问题中,损失函数有两项贡献,
这两项 f 和 g,分别对应着分类损失和分割损失。随着学习的进行,这两个损失函数减小的速度很不一致。往往是一项减小的非常快,另一项减小的超级慢。 看到这个问题的时候,我回想,应该可以对不同的损失项使用不同的学习率,即 Adaptive learning rate。其实 Adaptive Learning Rate 不是新东西,在 Adagrad, RMSProp, Adam 等等优化算法中,都有这个适配学习率的贡献。但那里的适配学习率,是对高维参数空间 不同的方向,使用不同的学习率。 对更新快的方向,使用小一点的学习率,对更新慢的方向,使用大一点的学习率。 比如在 Adagrad 算法中,适配学习率的梯度下降算法公式为, 其中 是学习率, 是损失函数对网络参数的梯度,普通的 SGD 应该是 。这里将学习率除以一个适配的常数 ,其中 是一个很小的正数,防止除零发散, 是个对角矩阵,其第 i 个矩阵元对应沿第i个方向梯度 的平方,从时间0到时间 t 的累加。 对于多任务学习,上面的适配学习率并没有起到用处,根据 展开的话, 传统的适配学习率用在多任务学习上有如下形式, 如果 和 的数量级不一致,上述公式不能为不同的损失函数项提供适配的学习率。按照同样的思路,我们可以要求, 对更新快的任务,使用小一点的学习率,对更新慢的任务,使用大一点的学习率。 其中 和 分别是不同任务项梯度平方的时间累积。这种方法可以简单推广到 RMSProp 和 Adam。 在Keras库中,没有对不同的任务使用 Adaptive 的学习率。贴一段 CycleGAN 的代码,里面有一个判别误差,一个重建误差和有两个 Cycle 重建误差,所以最终的误差函数有4项,分别是 mse, mae, mae, mae。但优化算法使用的是同一个 Adam。 model = Model([input_gen, input_id],
[output_d, output_id, output_f, output_b])
# define optimization algorithm configuration
opt = Adam(lr=0.0002, beta_1=0.5)
# compile model with weighting of least squares loss and L1 loss
model.compile(loss=['mse', 'mae', 'mae', 'mae'],
loss_weights=[1, 5, 10, 10],
optimizer=opt)
loss_weights 确实可以在一开始将4个任务的学习率增大 1,5,10 和 10 倍。但并没有对不同的任务使用不同的优化算法,除非最后一个选项 optimizer=opt 改成, optimizers=[opt, opt, opt, opt]
根据 Keras 文档中对 compile 函数的描述,optimizer 表示一个优化函数,而不是一个列表。而 loss_weights 是要用在加权求和中,得到一个整体的 loss,然后用同一个 optimizer 对神经网络的参数进行更新。 (更新)最近尝试训练一个字体风格转换程序,对不同的任务使用不同的 optimizer,发现在初期确实有效。这个程序意图将楷书 A 风格转换为行书 B。定义了两种损失,一种是自编码损失,另一种是辅助损失,即使用第三种字体--宋体,保证对同样的字,A编码后的潜变量等于A_c 编码的潜变量;对同样的字,B编码后的潜变量等于 B_c 编码的潜变量。这样,将行书翻译回正常体,让神经网络更好的映射。 如果使用传统的多任务方法,使用一个优化器,损失函数差不多定义为 前两项是自编码损失,后两项是翻译到第三方字体时的编码自洽性损失。结果发现,就算将后两项的损失权重调小1000倍,它们还是起主导,很快让编码器学会将所有的字都编码成常数,后两项损失直接变为0。前两项自编码项不起作用。从第一个Epoch开始,结果就变成了这样, 如果对前两项使用一个优化器,对后两项使用另一个优化器, 至少在前十个 Epoch,训练是正常进行的。结果如下, 不过到了第20个Epoch的时候,后两项又开始起决定性作用,结果变回到使用一个优化器的情形。 还有一个技巧,不知道有没有人尝试过。即先对一个任务做训练,训练到一定阶段,再启动第2个任务。 在下面这篇知乎文章中见到分别对两个任务的共享参数,两个任务的私有参数,使用3个 Adam 独立训练的小技巧。实现方法是 Tensorflow, 应该可以很快扩展到其他机器学习库。 另外,下面回答中游凯超提到的 《Multi-Task Learning Using Uncertainty to Weigh Losses for Scene Geometry and Semantics》很有启发。那篇文章对不同任务的损失函数项按照方差进行归一化。感觉与 Glorot/Xavier/He 权重初始化,以及 Batch/Layer/Instance/Group normalization 的思路都很像。也就是说,如果不同任务的私有参数(甚至是最后一层的参数或loss 本身),满足的分布方差不一样,也会出现有的任务梯度消失,有的任务梯度爆炸的问题。 如果神经网络参数初始化的时候,已经使用了 Glorot/Xavier/He 的方法,那么每一层所有参数满足的分布是归一化的。但没有保证每个任务的私有参数,都单独进行了归一化。 将不同任务的参数分组初始化,正规化以及优化,可能是个好玩的研究方向。 PS:本文仅代表作者个人想法,没有在多个任务上验证过这个想法的合理性。大家可以结合实际情况具体判断。