深度學習中一些常用的內建損失函数
這是最近的第二篇,目前只寫了交叉熵,以後有時間會加上別的。
交叉熵(CrossEntropy)
nn.CrossEntropyLoss
nn.BCELoss
nn.BCEWithLogitsLoss
n_classes > 1
這應該是與分類相關最常見的一個損失函数,在目標檢測中對每個框的類別分数,和語義分割中對每個像素點的類別置信度訓練時,都可以使用這個損失函数。語義分割中的每一個像素就等效於目標檢測中的一個框,和圖像分類中的一整張圖。
在 PyTorch 中,交叉熵在 nn.CrossEntropyLoss
,它就是將 nn.LogSoftmax
和 nn.NLLLoss
兩個合在一起。
對於 LogSoftmax,也就是在 softmax 的值上求了一个對数:
其中 j
是所有的類別,總數為 n_classes。
但是使用 LogSoftmax 比分成兩步数值上會更穩定:由於指數的存在,當輸入值 xi 過小時,在 softmax 時可能向下溢出而变為 0(在 log 之後就會是無限大);過大時,指数計算可能會向上溢出。而計算 softmax 的 log 時可對分子分母同時除以(最)大的指数值:
這樣就避免了上述問題,同時可以看到計算速度會加快不少。對輸出的每個值都(在類別通道上)完成上述計算之後,NLLLoss (negative log likelihood loss) 就是對每一個 box,取出其 GT 對應的通道上的 LogSoftmax(xi)
值,取相反数,最後所有取出的值相加。
class NLLLoss()
在構造時有三個參数,一個是 weight
,表示對某一個 class,取出來值取相反数後,乘上一個權重;另一個是 ignore_index
,表示真實標籤中需要忽略的值,一般圖像中邊界和無法辨別的區域會用一個負值標記;reduction="mean"
表示對所有 dimension 求解之後,求和並除以 batch * prod(dimension)
,而 "sum"
表示求和後直接輸出,"none"
表示直接輸出数組 shape = (batch, d1, ..., dk)
。
下面測試一下,假設是圖像分類 batch = 3, n_classes = 4
,那麼 model output logits 應是一個 (3, 4)
的 tensor,而 GT 應該是 (3,)
tensor(其他 task 只是有更多 dimension N C d1 ... dk
)
1 | prediction_logtis = torch.rand(3, 4) # (batch, C) |
手動計算一下 loss:(1.5554 + 1.4317 + 1.2842) / 3 = 1.4238
。
這種是 label 為 long int 的形式,在 tensorflow 中為 v1: sparse_softmax_cross_entropy_with_logits
v2: tf.keras.losses.SparseCategoricalCrossentropy
1 | tf_pred = prediction_logtis.detach().numpy() |
此外 tf 還允許一種 one hot 形式的 label,v1: softmax_cross_entropy_with_logits_v2
v2: tf.keras.losses.CategoricalCrossentropy
,例如上面的 label 可以改為
1 | # torch |
對於 one-hot 的形式,還可以改為使用 soft label,表示其概率上不獨立,即 label:0 -> [1, 0, 0] -> [0.9, 0.09, 0.01]
,tensorflow 可以直接使用,pytorch 需要自定義一個,即上述手動的乘法。我發現 mmcls/soft_cross_entropy 有一個現成的自定義 CrossEntropyLoss
實現,和上面一回事。
對於 nn.CrossEntropyLoss
,如前所述,就是把兩步合在了一起,所以它的公式如下:
它的參数也與 NLLLoss 相同,這裡以一個 Batch Size = 2, classes = 3, size = (3, 3)
的輸出為例,即語義分割任務,看看兩者是不是相等的:
1 | prediction = torch.rand(2, 3, 3, 3) |
可以看到二者結果完全相同。
n_class = 1
交叉熵還有一個二元(Binary)形式的 nn.BCELoss
,它要求 GT 只能是 0
或 1
兩個值,比如 Faster R-CNN 中的 RPN 模塊的訓練就可以使用它,只有兩類後,公式簡化如下:
可以使用 torch.nn.functional.binary_cross_entropy
,與 sklearn.metrics.log_loss
完全相同。
sigmoid/softmax in binary
The sigmoid function is used for the two-class logistic regression, whereas the softmax function is used for the multiclass logistic regression.
對於 sigmoid,最後輸出一個值,輸入是 x
,參數是 θ
,那麼 sigmoid 的輸出為
p(y = 0|x) = 1 - p(y = 1|x)
,所以
對於 softmax,最後的輸出是兩個值,輸入是 x
,兩個輸出的參數分別是 θ_n
,那麼 softmax 的輸出為
其中 nn.BCEWithLogitsLoss
將 sigmoid 激活和 BCELoss 結合,同樣更數值穩定。