損失関数のまとめ (Huber,Log-Cosh,Poisson,CustomLoss,MAE,MSE)

##目次##
1. 平均絶対誤差 (MAE)
2. 平均二乗誤差 (MSE)
3. Huber損失
4. Log-cosh損失
5. Poisson損失
6. Hinge損失
7. Custom-Loss関数

間違いがあったら下のコメントか編集リクエストを頂けると有難いです。

##平均絶対誤差 (MAE)##

![mae (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335630/4524d41c-c4f5-a7e5-0533-22e84658d26f.png)
引用元：https://heartbeat.fritz.ai/5-regression-loss-functions-all-machine-learners-should-know-4fb140e9d4b0

(上図はMAEの微分をプロットしている)

詳しくはMSEの項目で説明するが、<b>MAEの一つの特徴として外れ値に寛容なことが言える。損失を二乗しないのでMSEのように外れ値のときの損失がそこまで大きくならないからだ。</b>

<b>MAEには損失関数の微分が常に一定になるという問題がある。</b>これは損失がどのような値であっても同じスピードで損失を埋めることを意味する。損失が小さいときに損失が大きいときと同じスピードで学習されては最適化できないだろう。損失が小さいとき、つまりモデルが細かい調整をするときはゆっくりと学習させるべきである。これはlearning_rateを予め小さく設定すること実現できるがベストとは言えない。

##平均二乗誤差 (MSE)##

![mse1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335630/1fae9db5-545d-485b-fccc-5910a23dde9c.png)
![mse2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335630/1500d761-b4af-6d90-cad0-4381224cb03e.png)

(上図はMSEの微分をプロットしている)

<b>MAEは外れ値に寛容であったのに対し、MSEは寛容ではない。これは予測値と実測値の差を二乗しているからである。</b>例えばMAEの損失が3だとするとMSEは9になる。ここでもしMAEの損失を大きくして（外れ値は損失が大きい）30とするとMSEは900になる。このことからMSEは外れ値に寛容でなく外れ値から大きく学習しようとする性質があることが分かる。このことは<b>MAEがデータの中央値寄りなのに対し、MSEは平均値に近いと考えると分かりやすいだろう。</b>ではどちらを選ぶべきか。もしも外れ値がビジネス的な立ち位置で重要な場合はMSEを選ぶべきだろう。ちゃんと外れ値からの損失をモデルに組み込もうとしてくれるからである。ただしこの場合、他のデータの予測能力が劣ることも視野に入れなければならない。逆に外れ値がそこまで重要でない（ノイズに近い）データの場合はMAEを使うべきである。ただし外れ値が完全なノイズの場合は外れ値をデータから除去してMSEを使うべきである。

##Huber Loss##
<b>Huber Lossとは損失が大きいとMAEに似た機能をし、損失が小さいとMSEの機能になる。</b>MAEとMSEの良いとこどりである。その機能通りSmooth Absolute Lossとも言われている。このMSEとMAEの切り替わりは𝛿で設定する。これにより外れ値に寛容でありながらMAEの欠点を克服できる。

![huber.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335630/c7343302-dd1b-17c2-f907-302195e88838.png)


##Log-cosh Loss##
<b>Huber Lossと同じように、基本MAEだが損失が小さくなるとMSEに近くなる。</b>マクローリン展開により$cosh(x)=e^\frac{x^2}{2}$。よって$log(cosh(x))$はxが0に近いとき$\frac{x^2}{2}$と同じような動きをする。逆にxが大きいときはテイラー展開により$abs(x)-log(2)$に近い動きをする。

<b>もう一つの利点は２回微分可能であることだ。</b>なぜ2回微分可能が良いのか。それはGBDTは基本ニュートン法で最適な値を探すからである。2回微分可能であれば、ある種のモメンタム（運動量、勢い）をモデルに学習させることができる。

![logcosh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335630/9b9cc4fe-3af0-7ff4-b6b1-8eb68d83f9a5.png)


##ポアソン損失 (Poisson Loss)##
主にカウントデータで使われる。ポアソン分布が元である。<b>ポアソン分布とはX軸をとある事象が起こる数、Y軸をその夫々の回数が起こる確率とを表す分布である</b>。

![poisson.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/335630/8a6dc5f0-a197-a255-16bd-19cab50450a3.png)


<b>予測値の分布とポアソン分布の損失がポアソン損失である。</b>

##ヒンジ損失 (Hinge Loss)##
ヒンジ損失に関しては[このサイト](https://mathwords.net/hinge)が分かりやすい。

```math
f_1(x) = \left\{
\begin{array}{ll}
0 & (x \leq 0) \\
x-a & (x > a)
\end{array}
\right.
```
上の式は下の式と同等である。

```math
f_1(x) = max(0,x-a)
```

この式も

```math
f_2(x) = \left\{
\begin{array}{ll}
b-x & (x \leq b) \\
0 & (x > 0)
\end{array}
\right.
```

以下と同じである。

```math
f_2(x) = max(0,b-x)
```

よってこれらを合わせると以下の等式になる。

```math
t = ±1 \\
L(y) = max(0, 1-t*y)
```

ヒンジ損失はSVM等で使われる。

##Custom Loss Function##
<b>ライブラリに無い関数はcustom loss functionとして自分で設定が可能だ。</b>この場合gradとhessianを返り値とする必要がある。hessianとは二次導関数のことである。以下はlog-cosh損失の実装だ。

```py

def logcoshobj(preds, dtrain):
    labels = dtrain.get_label()
    grad = np.tanh(preds - labels) #log-coshを微分→tanh(予測値-ラベル値)
    hess = 1.0 - grad*grad
    return grad, hess
```
引用：https://www.kaggle.com/c/allstate-claims-severity/discussion/24520

なおobjective=logcoshobjと設定する必要がある。

eval_metricをカスタム関数としたい場合は以下のようにする。

```py
def accuracy(preds, train_data):
    labels = train_data.get_label()
# 返り値は「出力したいmetricの名前」「損失値」「そのメトリックが高くなればモデルも良くなるかの真偽値
    return 'customed_accuracy', np.mean(labels == (preds > 0.5)), True
```
３個目の返り値について例えばaccuracyであればTrueだし、loglossなどの損失関数ならばFalseである。

なお、feval=accuracyと設定する必要がある。


##参考文献##
http://www.cs.cornell.edu/courses/cs4780/2015fa/web/lecturenotes/lecturenote10.html
http://rishy.github.io/ml/2015/07/28/l1-vs-l2-loss/
https://heartbeat.fritz.ai/5-regression-loss-functions-all-machine-learners-should-know-4fb140e9d4b0