【多任务学习】Multi-Task Learning Using Uncertainty to Weigh Losses for Scene Geometry and Semantics

·阅读摘要:
  本文提出针对CV领域的多任务模型,设置一个可以学习损失权重的损失层,可以提高模型精度。
·参考文献:
  [1] Multi-Task Learning Using Uncertainty to Weigh Losses for Scene Geometry and Semantics

  个人理解:我们使用传统的多任务时,损失函数一般都是各个任务的损失相加,最多会为每个任务的损失前添加权重系数。但是这样的超参数是很难去调参的,代价大,而且很难去调到一个最好的状态。最好的方式应该是交给深度学习。

  论文最重要的部分在损失函数的设置与推导。 这对我们优化自己的多任务学习模型有指导意义。

[1] Homoscedastic uncertainty as task-dependent uncertainty (同方差不确定性)

  作者的数学模型通过贝叶斯模型建立。作者首先提出贝叶斯建模中存在两类不确定性:

  · 认知不确定性(Epistemic uncertainty):由于缺少训练数据而引起的不确定性
  · 偶然不确定性(Aleatoric uncertainty):由于训练数据无法解释信息而引起的不确定性

  而对于偶然不确定性,又分为如下两个子类:

  · 数据依赖地(Data-dependant)或异方差(Heteroscedastic)不确定性
  · 任务依赖地(Task-dependant)或同方差(Homoscedastic)不确定性

  多任务中,任务不确定性捕获任务间相关置信度,反应回归或分类任务的内在不确定性。

【注】本篇论文的假设,是基于同方差不确定性的。关于同方差不确定性和异方差不确定性的通俗解释,可以参考知乎问题:https://www.zhihu.com/question/278182454/answer/398539763

[2] Multi-task likelihoods (多任务似然)

  基于极大似然估计,假设 f W \mathbf{f}^{\mathbf{W}} fW为网络输出, W W W为该项输出的权重,则对于回归任务有:
p ( y ∣ f W ( x ) ) = N ( f W ( x ) , σ 2 ) p(y∣\mathbf{f}^{\mathbf{W}}(x))=N(\mathbf{f}^{\mathbf{W}}(x),σ^2 ) p(yfW(x))=N(fW(x),σ2)
  对于分类任务有:
p ( y ∣ f W ( x ) ) = S o f t m a x ( f W ( x ) ) p(y∣\mathbf{f}^{\mathbf{W}} (x))=Softmax(\mathbf{f}^{\mathbf{W}} (x)) p(yfW(x))=Softmax(fW(x))
  多任务的概率:
p ( y 1 , … , y K ​ ∣ f W ( x ) ) = p ( y 1 ​ ∣ f W ( x ) ) … p ( y K ​ ∣ f W ( x ) ) p(y_1,…,y_K​ ∣\mathbf{f}^{\mathbf{W}}(x))=p(y_1​ ∣\mathbf{f}^{\mathbf{W}} (x))…p(y_K​ ∣\mathbf{f}^{\mathbf{W}} (x)) p(y1,,yKfW(x))=p(y1fW(x))p(yKfW(x))
  例如对于回归任务来说,极大似然估计转化为最小化负对数:
l o g p ( y ∣ f W ( x ) ) ∝ − 1 2 σ 2 ​ ∥ ∥ ​ y − f W ( x ) ∥ ∥ ​ 2 − l o g σ log{p(y∣\mathbf{f}^{\mathbf{W}}(x))}∝− \frac{1}{2σ^2}​ {∥∥​ y−\mathbf{f}^{\mathbf{W}} (x) ∥∥​}^2 −log\sigma logp(yfW(x))2σ21yfW(x)2logσ
  其中 σ \sigma σ 表示测量噪声的方差。

  双任务:

  假设是两个回归任务,那么概率如下:

   p ( y 1 , y 2 ​ ∣ f W ( x ) ) ​ = p ( y 1 ​ ∣ f W ( x ) ) ⋅ p ( y 2 ​ ∣ f W ( x ) ) = N ( y 1 ​ ; f W ( x ) , σ 1 2 ​ ) ⋅ N ( y 2 ​ ; f W ( x ) , σ 2 2 ​ ) p(y_1 ,y_2​ ∣\mathbf{f}^{\mathbf{W}} (x))​ =p(y_1​ ∣\mathbf{f}^{\mathbf{W}} (x))⋅p(y_2​ ∣\mathbf{f}^{\mathbf{W}} (x))=N(y_1​;\mathbf{f}^{\mathbf{W}} (x),σ_1^2​ )⋅N(y_2​ ;\mathbf{f}^{\mathbf{W}} (x),σ_2^2​ ) p(y1,y2fW(x))=p(y1fW(x))p(y2fW(x))=N(y1;fW(x),σ12)N(y2;fW(x),σ22)

  为了优化我们的 Loss 函数 L ( W , σ 1 , σ 2 ) \mathcal{L}\left(\mathbf{W}, \sigma_{1}, \sigma_{2}\right) L(W,σ1,σ2),取最小化负对数:

   = − l o g p ( y 1 ​ , y 2 ​ ∣ f W ( x ) ) =−logp(y_1​,y_2​ ∣\mathbf{f}^{\mathbf{W}} (x)) =logp(y1,y2fW(x))

   ∝ 1 2 σ 1 2 ​ ∥ y 1 ​ − f W ( x ) ∥ ​ 2 + 1 2 σ 2 2 ​ ∥ ​ y 2 ​ − f W ( x ) ∥ ​ 2 + l o g σ 1 ​ σ 2 ∝ {\frac{1}{2σ_1^2}​ }∥y_1​−\mathbf{f}^{\mathbf{W}} (x) ∥^​2 + \frac{1}{2σ_2^2}​ ∥​ y_2​ −\mathbf{f}^{\mathbf{W}} (x) ∥​^2 +logσ_1​ σ_2 2σ121y1fW(x)2+2σ221y2fW(x)2+logσ1σ2

   = 1 2 σ 1 2 ​ L 1 ​ ( W ) + 1 2 σ 2 2 ​ L 2 ​ ( W ) + l o g σ 1 ​ σ 2 ​ = \frac{1}{2σ_1^2}​ L_1​ (W)+ \frac{1}{2σ_2^2}​ L_2​ (W)+logσ_1​σ_2​ =2σ121L1(W)+2σ221L2(W)+logσ1σ2

  假设是一个回归任务和一个分类任务,仍然可以推导出上述结论:

   = 1 2 σ 1 2 ​ L 1 ​ ( W ) + 1 2 σ 2 2 ​ L 2 ​ ( W ) + l o g σ 1 ​ σ 2 ​ = \frac{1}{2σ_1^2}​ L_1​ (W)+ \frac{1}{2σ_2^2}​ L_2​ (W)+logσ_1​σ_2​ =2σ121L1(W)+2σ221L2(W)+logσ1σ2

  所以,根据整个多任务问题的联合 Loss 形式,那么我们需要优化的参数不仅有 W W W 还有 σ 1 \sigma_{1} σ1 σ 2 \sigma_{2} σ2

各个公式的证明

在这里插入图片描述
在这里插入图片描述

pytorch版代码实现

  首先要明确,损失函数中的参数不仅有 W W W 还有 σ 1 \sigma_{1} σ1 σ 2 \sigma_{2} σ2 都是需要经过反向传播来学习的。

  代码如下:


import math

import pylab
import numpy as np

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader


def gen_data(N):
    X = np.random.randn(N, 1)
    w1 = 2.
    b1 = 8.
    sigma1 = 1e1  # ground truth
    Y1 = X.dot(w1) + b1 + sigma1 * np.random.randn(N, 1)
    w2 = 3
    b2 = 3.
    sigma2 = 1e0  # ground truth
    Y2 = X.dot(w2) + b2 + sigma2 * np.random.randn(N, 1)
    return X, Y1, Y2


class TrainData(Dataset):

    def __init__(self, feature_num, X, Y1, Y2):

        self.feature_num = feature_num

        self.X = torch.tensor(X, dtype=torch.float32)
        self.Y1 = torch.tensor(Y1, dtype=torch.float32)
        self.Y2 = torch.tensor(Y2, dtype=torch.float32)

    def __len__(self):
        return self.feature_num

    def __getitem__(self, idx):
        return self.X[idx,:], self.Y1[idx,:], self.Y2[idx,:]


class MultiTaskLossWrapper(nn.Module):
    def __init__(self, task_num, model):
        super(MultiTaskLossWrapper, self).__init__()
        self.model = model
        self.task_num = task_num
        self.log_vars = nn.Parameter(torch.zeros((task_num)))

    def forward(self, input, targets):

        outputs = self.model(input)

        precision1 = torch.exp(-self.log_vars[0])
        loss = torch.sum(precision1 * (targets[0] - outputs[0]) ** 2. + self.log_vars[0], -1)

        precision2 = torch.exp(-self.log_vars[1])
        loss += torch.sum(precision2 * (targets[1] - outputs[1]) ** 2. + self.log_vars[1], -1)

        loss = torch.mean(loss)

        return loss, self.log_vars.data.tolist()


class MTLModel(torch.nn.Module):
    def __init__(self, n_hidden, n_output):
        super(MTLModel, self).__init__()

        self.net1 = nn.Sequential(nn.Linear(1, n_hidden), nn.ReLU(), nn.Linear(n_hidden, n_output))
        self.net2 = nn.Sequential(nn.Linear(1, n_hidden), nn.ReLU(), nn.Linear(n_hidden, n_output))

    def forward(self, x):
        return [self.net1(x), self.net2(x)]
np.random.seed(0)

feature_num = 100
nb_epoch = 2000
batch_size = 20
hidden_dim = 1024

X, Y1, Y2 = gen_data(feature_num)
pylab.figure(figsize=(3, 1.5))
pylab.scatter(X[:, 0], Y1[:, 0])
pylab.scatter(X[:, 0], Y2[:, 0])
pylab.show()

train_data = TrainData(feature_num, X, Y1, Y2)
train_data_loader = DataLoader(train_data, shuffle=True, batch_size=batch_size)

model = MTLModel(hidden_dim, 1)

mtl = MultiTaskLossWrapper(2, model)
mtl

# https://github.com/keras-team/keras/blob/master/keras/optimizers.py
# k.epsilon() = keras.backend.epsilon()
optimizer = torch.optim.Adam(mtl.parameters(), lr=0.001, eps=1e-07)

loss_list = []
for t in range(nb_epoch):
    cumulative_loss = 0
    
    for X, Y1, Y2 in train_data_loader:

        loss, log_vars = mtl(X, [Y1, Y2])

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        cumulative_loss += loss.item()

    loss_list.append(cumulative_loss/batch_size)
pylab.plot(loss_list)
pylab.show()

print(log_vars)
[4.2984442710876465, -0.2037072628736496]
# Found standard deviations (ground truth is 10 and 1):
print([math.exp(log_var) ** 0.5 for log_var in log_vars])
[8.578183137529612, 0.9031617364804738]

【注】假设 L o s s = a ∗ L 1 ( W ) + b ∗ L 2 ( W ) Loss = a * L_1(W) + b * L_2(W) Loss=aL1(W)+bL2(W),我们这样简单的学习参数 a a a b b b是不行的,这样Loss会越来越小,永无止境。我们需要设置 L o s s Loss Loss有正则项,使得它有最小值,这样学习才对。

多任务学习利用不确定性来加权损失用于场景几何和...... 多任务学习是一种机器学习方法,旨在通过同时学习多个相关的任务来提高模型的性能。在场景几何和...中,我们可以利用多任务学习来同时学习场景几何和...两个任务,并利用不确定性来加权损失函数。 不确定性是指模型对于不同任务的预测结果的置信度或可靠性。通过测量模型的不确定性,我们可以了解模型对于不同任务的自信程度,并根据其不确定性来决定在损失函数中的权重。 具体来说,在训练过程中,我们可以采用如下的多任务学习框架:首先,我们定义两个任务,即场景几何和...。然后,我们构建一个网络模型,该模型有两个分支,分别用于处理场景几何和...任务。每个分支都有自己的损失函数,用于衡量模型在相应任务上的性能。 在计算总体损失时,我们可以使用不确定性来加权每个任务的损失函数。一种常见的方法是使用模型的输出结果的方差或置信度来表示不确定性。如果模型对于某个任务有较高的置信度,我们可以将该任务的损失函数的权重设为较大值;相反,如果模型对于某个任务的置信度较低,我们可以将该任务的损失函数的权重设为较小值。 通过利用不确定性加权损失函数,我们可以让模型在训练过程中更加关注自身较为确定的预测任务,从而提高模型在这些任务上的性能。这种方法可以提高多任务学习的效果,使得模型能够更好地学习场景几何和...两个任务。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

征途黯然.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值