end0tknr's kipple - 新web写経開発

http://d.hatena.ne.jp/end0tknr/ から移転しました

pytorch for python における損失関数 (誤差関数)

損失関数の種類

問題例 損失関数 概要
回帰 nn.MSELoss 平均二乗誤差
nn.L1Loss 平均絶対値誤差
二値分類 nn.BCELoss バイナリ交差エントロピ
nn.BCEWithLogitsLoss ロジット・バイナリ交差エントロピ
多クラス分類 nn.CrossEntropyLoss ソフトマックス交差エントロピ誤差

回帰 - nn.MSELoss - 平均二乗誤差損失関数の種類

{ \Large {
  L(y, t) =  \frac{1}{B} \sum _{i=1}^{B} (y_i - t_i)^2
} }
{ \hspace{6pc}
  ( L: 損失関数 , y: 推論値 , t: 正解データ , B: バッチサイズ )
}

回帰 - nn.L1Loss - 平均絶対値誤差

{ \Large {
  L(y, t) =  \frac{1}{B} \sum _{i=1}^{B} |y_i - t_i |
} }

二値分類 - nn.BCELoss - バイナリ交差エントロピ

{ \Large {
  L(y, t) =  \\
    - \frac{1}{B} \sum_{i=1}^{B}
    [ w_i \{ t_i ・ log(p_i) + (1 - t_i) ・ log(1 - p_i) \} ]
} }
{ \hspace{6pc}
  ( w: 重み , t_i: 正解ラベル(1,0) , p_i: 確率 )
}

二値分類 - nn.BCEWithLogitsLoss - ロジット・バイナリ交差エントロピ

{ \Large {
  L(y, t) = \\
   - \frac{1}{B} \sum_{i=1}^{B}
      [ w_i \{ t_i ・      log( Sigmoid(y_i)) + \\
\hspace{6pc}               (1 - t_i) ・ log(1 - Sigmoid(y_i)) \} ]
} }

「ロジット」とは?

まず、確率( { \Large{ p }} )に対し、 それが起こらない確率との比 ( { \Large{ \frac{p}{1-p} }} )を「オッズ」と呼び、 更にこのlogをとったものをロジットと呼ぶ(以下)。

{ \Large {
  logit(p) = log \left( \frac{p}{1-p} \right) = log(p) - log(1-p)
} }

また、ロジットはロジスティック関数の逆関数でもある

多クラス分類 - nn.CrossEntropyLoss - ソフトマックス交差エントロピ

{ \Large {
  L(y, t) = \\
   - \frac{1}{B} \sum_{i=1}^{B}
      \left[ \frac{ \sum_{k=0}^{N-1} w^k ・t_i^k ・ log( exp(y_i^k) ) }
                   { \sum_{j=0}^{N-1} exp(y_j^k) } \right] = \\
   - \frac{1}{B} \sum_{i=1}^{B}
      \left[ \frac{ \sum_{k=0}^{N-1} w^k ・t_i^k ・y_i^k }
                   { \sum_{j=0}^{N-1} exp(y_j^k) } \right]
} }

pytorchによる例:

#!/usr/local/python3/bin/python3
# -*- coding: utf-8 -*-
import torch
import torchvision
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import torchvision.transforms as transforms
import numpy as np
from matplotlib import pyplot as plt


def main():
    # MSELoss
    x = torch.randn(4)
    y = torch.randn(4)
    print("x: ",x)
    print("y: ",y)
    criterion = nn.MSELoss()
    loss = criterion(x, y)
    print("MSELoss: ",loss)

    # L1Loss
    criterion = nn.L1Loss()
    loss = criterion(x, y)
    print("L1Loss: ",loss)

    # CrossEntropyLoss
    x = torch.randn(1, 4)
    y = torch.LongTensor([1]).random_(4)
    criterion = nn.CrossEntropyLoss()
    loss = criterion(x, y)
    print("CrossEntropyLoss: ",loss)
    
if __name__ == '__main__':
    main()

↑こう書くと、↓こう表示されます

$ ./foo.py 
x:  tensor([-1.3960, -0.1662, -0.3867, -1.3959])
y:  tensor([ 0.3319,  0.7981,  0.5625, -0.0747])
MSELoss:  tensor(1.6406)
L1Loss:  tensor(1.2407)
CrossEntropyLoss:  tensor(1.4561)

その他参考

pythonによる数値微分 - end0tknr's kipple - 新web写経開発