Pytorch模型訓練(4) - Loss Function

《Loss Function》
  本文總結Pytorch中的Loss Function
  Loss Function是深度學習模型訓練中非常重要的一個模塊,它評估網絡輸出與真實目標之間誤差,訓練中會根據這個誤差來更新網絡參數,使得誤差越來越小;所以好的,與任務匹配的Loss Function會得到更好的模型。
  但本文不會討論什麼任務用什麼損失函數,只是總結下Pytorch中的Loss Function

0 博客目錄

Pytorch模型訓練(0) - CPN源碼解析
Pytorch模型訓練(1) - 模型定義
Pytorch模型訓練(2) - 模型初始化
Pytorch模型訓練(3) - 模型保存與加載
Pytorch模型訓練(4) - Loss Function
Pytorch模型訓練(5) - Optimizer
Pytorch模型訓練(6) - 數據加載

1 Loss 基類

  Pytorch在loss function實現時,先對共有參數進行基類封裝,而不同loss function將繼承下面這兩個基類

class _Loss(Module):
    def __init__(self, size_average=None, reduce=None, reduction='mean'):
        super(_Loss, self).__init__()
        if size_average is not None or reduce is not None:
            self.reduction = _Reduction.legacy_get_string(size_average, reduce)
        else:
            self.reduction = reduction

  _Loss基類:繼承自Mudule,傳入了3個外來參數

  1)size_average:bool類型,可選參數,是否均值化損失值。默認True,表示在當前Batch中將損失值均值化;若爲False,則只將Batch中損失相加;當reduce=False,它被忽略;已經不推薦使用
  2)reduce:bool類型,可選參數,是否均值化損失值。默認True,表示會根據size_average做相應操作;若爲False,返回每批元素的損失並忽略size_average;已經不推薦使用
  3)reduction:string類型,可選參數,按指定對損失做相應操作。默認‘mean’:表示對損失進行均值化;‘none’:表示不做操作;‘sum’:求和操作。
  值得注意的是,前2個參數雖然正在被放棄的路上,但若前2個參數只要有一個不爲None,則reduction就會被覆蓋,見上述代碼的if-else語句

class _WeightedLoss(_Loss):
    def __init__(self, weight=None, size_average=None, reduce=None, reduction='mean'):
        super(_WeightedLoss, self).__init__(size_average, reduce, reduction)
        self.register_buffer('weight', weight)

  _WeightedLoss基類:繼承自_Loss,比_Loss多weight參數

  4)weight:Tensor類型,可選參數,用來調節不同損失的權重。如果使用,一般要求它的尺寸要與batch相同,否則被視爲所有元素權重一樣

2 Pytorch Loss

2.1 L1Loss

torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')

  criterion:計算輸入x與目標y之間的平均絕對誤差(mean absolute error (MAE))

在這裏插入圖片描述

  也就是說,如果求平均,返回就是一個標量;否則返回就是和label輸入維度一樣的張量

  Examples:

loss = nn.L1Loss()
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
output = loss(input, target)
output.backward()

2.2 MSELoss

torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')

  criterion:計算輸入x與目標y之間的平均平方誤差(mean squared error (squared L2 norm) )

在這裏插入圖片描述

  Examples:

loss = nn.MSELoss()
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
output = loss(input, target)
output.backward()

2.3 NLLLoss

torch.nn.NLLLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')

  criterion:負對數似然損失(The negative log likelihood loss)。常用於訓練分類問題中
  可設置1D Tensor的weight參數,爲每個類分配權重,當訓練不平衡樣本時,尤其有用

在這裏插入圖片描述

  參數ignore_index:指定忽略某個目標值,在計算平均值時,將被忽略
  可以在NN結尾加上LogSoftmax layer來獲取對數似然值,若不想加額外層,則可用CrossEntropyLoss代替

  Examples:

m = nn.LogSoftmax()
loss = nn.NLLLoss()
# input is of size N x C = 3 x 5
input = torch.randn(3, 5, requires_grad=True)
# each element in target has to have 0 <= value < C
target = torch.tensor([1, 0, 4])
output = loss(m(input), target)
output.backward()


# 2D loss example (used, for example, with image inputs)
N, C = 5, 4
loss = nn.NLLLoss()
# input is of size N x C x height x width
data = torch.randn(N, 16, 10, 10)
conv = nn.Conv2d(16, C, (3, 3))
m = nn.LogSoftmax()
# each element in target has to have 0 <= value < C
target = torch.empty(N, 8, 8, dtype=torch.long).random_(0, C)
output = loss(m(conv(data)), target)
output.backward()

2.4 CrossEntropyLoss

torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')

  criterion:交叉熵損失,常用於分類任務,它是nn.LogSoftmax和nn.NLLLoss的結合體

在這裏插入圖片描述

  Examples:

loss = nn.CrossEntropyLoss()
input = torch.randn(3, 5, requires_grad=True)
target = torch.empty(3, dtype=torch.long).random_(5)
output = loss(input, target)
output.backward()

2.5 PoissonNLLLoss

torch.nn.PoissonNLLLoss(log_input=True, full=False, size_average=None, eps=1e-08, reduce=None, reduction='mean')

  criterion:服從泊松分佈的負對數似然損失

在這裏插入圖片描述

  最後一項可以省略或用Stirling formula近似。 近似值用於大於1的目標值,對於小於或等於1的零,將損失設爲零。

  參數log_input:
    若爲True:loss = exp(input)−target∗input
    若爲False:loss = input−target∗log(input+eps)
  參數full:是否計算全部loss,如增加Stirling formula近似
    target∗log(target)−target+0.5∗log(2πtarget)
  參數eps:防止log(0)現象,默認1e-8

  Examples:

loss = nn.PoissonNLLLoss()
log_input = torch.randn(5, 2, requires_grad=True)
target = torch.randn(5, 2)
output = loss(log_input, target)
output.backward()

2.6 KLDivLoss

torch.nn.KLDivLoss(size_average=None, reduce=None, reduction='mean')

  criterion:KL離散損失(The Kullback-Leibler divergence Loss)
  KL散度是對連續分佈有用距離度量,並且在對(離散採樣的)連續輸出分佈的空間執行直接回歸時通常是有用的。
  與NLLLoss一樣,給定的輸入包含對數概率, 但是,與NLLLoss不同,輸入不限於2D Tensor;目標以概率形式給出。

在這裏插入圖片描述

2.7 BCELoss

torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean')

  criterion:二分類交叉熵損失,常用於分類任務

在這裏插入圖片描述

  此函數可以認爲是nn.CrossEntropyLoss函數的特例。其分類限定爲二分類,y 必須是{0,1}。還需要注意的是,input 應該爲概率分佈的形式,這樣才符合交叉熵的應用。所以在 BCELoss 之前,input 一般爲sigmoid激活層的輸出

  Examples:

m = nn.Sigmoid()
loss = nn.BCELoss()
input = torch.randn(3, requires_grad=True)
target = torch.empty(3).random_(2)
output = loss(m(input), target)
output.backward()

2.8 BCEWithLogitsLoss

torch.nn.BCEWithLogitsLoss(weight=None, size_average=None, reduce=None, reduction='mean', pos_weight=None)

  criterion:結合來sigmoid的BCELoss,與CrossEntropyLoss類似,比單獨sigmoid+BCELoss更加穩定

在這裏插入圖片描述

2.9 MarginRankingLoss

torch.nn.MarginRankingLoss(margin=0.0, size_average=None, reduce=None, reduction='mean')

  criterion:計算輸入x1,x2(2個1D張量)與y(1或-1)的損失
  計算兩個向量之間的相似度,當兩個向量之間的距離大於 margin,則 loss 爲正,小於margin,loss 爲 0

在這裏插入圖片描述

2.10 HingeEmbeddingLoss

torch.nn.HingeEmbeddingLoss(margin=1.0, size_average=None, reduce=None, reduction='mean')

  criterion:給定輸入張量x和標籤張量y(1或-1)的損失
  通常用於測量兩個輸入是相似還是不相似,例如, 使用L1成對距離作爲x,並且通常用於學習非線性嵌入或半監督學習

在這裏插入圖片描述

2.11 MultiLabelMarginLoss

torch.nn.MultiLabelMarginLoss(size_average=None, reduce=None, reduction='mean')

  criterion:用於一個樣本屬於多個類別時的分類任務
  例如一個多分類任務,樣本 x 屬於第 0類,屬於第 1 類,不屬於第 2 類,不屬於第 3 類

在這裏插入圖片描述

2.12 SmoothL1Loss

torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction='mean')

  criterion:如果元素絕對誤差小於1,使用平方均值;否則,使用絕對均值

在這裏插入圖片描述

  在存在異常值時,比MSELoss敏感度低,並且在某些情況下可以防止梯度爆炸

2.13 SoftMarginLoss

torch.nn.SoftMarginLoss(size_average=None, reduce=None, reduction='mean')

  criterion:用於優化輸入張量x和目標張量y(1或-1)之間的兩類分類邏輯損失

在這裏插入圖片描述

2.14 MultiLabelSoftMarginLoss

torch.nn.MultiLabelSoftMarginLoss(weight=None, size_average=None, reduce=None, reduction='mean')

  criterion:基於最大熵,優化輸入張量x和多目標張量y(N, C)之間一對多損失

在這裏插入圖片描述

2.15 CosineEmbeddingLoss

torch.nn.CosineEmbeddingLoss(margin=0.0, size_average=None, reduce=None, reduction='mean')

  criterion:基於餘弦距離,利用目標張量y(1或-1),度量輸入張量x1和x2之間相似度

2.16 MultiMarginLoss

torch.nn.MultiMarginLoss(p=1, margin=1.0, weight=None, size_average=None, reduce=None, reduction='mean')

  criterion:多分類的hinge損失(margin-based loss)

在這裏插入圖片描述

  若加上權重,則

在這裏插入圖片描述

2.17 TripletMarginLoss

torch.nn.TripletMarginLoss(margin=1.0, p=2.0, eps=1e-06, swap=False, size_average=None, reduce=None, reduction='mean')

  criterion:3元損失,度量輸入x1,x2,x3之間的相似度

在這裏插入圖片描述

  triplet:a(anchor),p(positive),n(negative)
  人臉驗證中常常用到,它的目的就是讓p與a儘量相似(同一個人不同樣本),而n與a儘量不相似(不同人的樣本)

  Examples:

triplet_loss = nn.TripletMarginLoss(margin=1.0, p=2)
input1 = torch.randn(100, 128, requires_grad=True)
input2 = torch.randn(100, 128, requires_grad=True)
input3 = torch.randn(100, 128, requires_grad=True)
output = triplet_loss(input1, input2, input3)
output.backward()

2.18 CTCLoss

torch.nn.CTCLoss(blank=0, reduction='mean')

  criterion:The Connectionist Temporal Classification loss

3 CPN Loss

  CPN中 Global loss和Refine loss

# define loss function (criterion) 
criterion1 = torch.nn.MSELoss().cuda() # for Global loss
criterion2 = torch.nn.MSELoss(reduce=False).cuda() # for Refine loss

3.1 Global loss

  它用的平均平方誤差,直接像MSELoss實例一樣

 for global_output, label in zip(global_outputs, targets):
      num_points = global_output.size()[1]
      global_label = label * (valid > 1.1).type(torch.FloatTensor).view(-1, num_points, 1, 1)
      global_loss = criterion1(global_output, torch.autograd.Variable(global_label.cuda(async=True))) / 2.0
      loss += global_loss
      global_loss_record += global_loss.data.item()

3.2 Refine loss

  它在設計時,要求動態地將loss值比較大的幾個channels進行反向學習,所以在實例化criterion2時,傳入參數reduce=False,取消均值操作;而增加下列操作

    refine_loss = criterion2(refine_output, refine_target_var)
    refine_loss = refine_loss.mean(dim=3).mean(dim=2)
    refine_loss *= (valid_var > 0.1).type(torch.cuda.FloatTensor)
    refine_loss = ohkm(refine_loss, 8)
    loss += refine_loss
    refine_loss_record = refine_loss.data.item()

  ohkm函數(計算loss較大幾個目標的loss)

    def ohkm(loss, top_k):
        ohkm_loss = 0.
        for i in range(loss.size()[0]):
            sub_loss = loss[i]
            topk_val, topk_idx = torch.topk(sub_loss, k=top_k, dim=0, sorted=False)
            tmp_loss = torch.gather(sub_loss, 0, topk_idx)
            ohkm_loss += torch.sum(tmp_loss) / top_k
        ohkm_loss /= loss.size()[0]
        return ohkm_loss
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章