Deep Learning に関するまとめノート -4.2 損失関数-

# 説明の概要
　ここでは私がDeep Learningの勉強をしているときに本を読むだけでは分からなかったことを自分なりに解釈し、後で見返したときにスムーズに思い出せることを目的とする。コードの内容もなるべく丁寧に説明してるつもりなので参考になれば幸いです。
## 4.2 損失関数 編  

　ニューラルネットワークの学習において性能を上げるには最適な重みパラメータに近づける必要がある。この損失関数を使用して探索の手がかりにする。
　まず、最初に話してしまうと損失関数から出力されるのは
　　　　　　0.6094374124342252
　　　　　　0.4750000000000001　
　といった数値である。
この数値は性能がいいと小さく、悪いと大きくなりこの例では下の数値の方が値が小さいため、性能が高いと言える。
　損失関数の出力の値を手がかりにし、重みパラメータをどの向きにどの大きさで更新するのかの参考にするのである。

### 損失関数の種類  
損失関数にも色々あるが、ここでは二乗和誤差と交差エントロピー誤差についての説明を行っていく。
#### 1. 二乗和誤差(Mean Squared Error)
二乗和誤差は以下の式  

```math
E = \frac{1}{N}\sum_{i=1}^{N}(y_i -t_i)^2
```  
で表すことができる。　　
　式の説明をすると、出力値のデータ(y<sub>i</sub>)と正解値のデータ(t<sub>i</sub>)の差を二乗してN個で平均する。  
二乗するのは誤差を正の値にするため。正の値にするのなら絶対値をとって  
  
```math
E = \frac{1}{N}\sum_{i=1}^{N}|y_i -t_i|
```  
こうしてもいいのでは？と思ったのだが、どうやら微分を計算するときに2乗のほうが楽だかららしい。
なるほど!絶対値の微分は場合分けとかあるもんね...  
　
さらには微分したときに2が前に出るので1/2を加えて  

```math
E = \frac{1}{2}*\frac{1}{N}\sum_{i=1}^{N}(y_i -t_i)^2
```  
とすることもあるようだ。  

#####二乗和誤差を使った例 
今回は上の式のNを１として関数を定義して結果を見ていく。
yはSoftmax関数による出力結果である。
 
```python 
import numpy as np

#正解データ(one-hot-label)
t = [0,0,1,0,0]

#二乗和誤差の関数を定義
def mean_squared_error(y,t):
    return 0.5 * np.sum((y-t)**2)

# パターン１(正解データに近い)
y1 = [0.01,0.02,0.9,0.05,0.02]
# パターン２(正解データから遠い)
y2 = [0.5,0.1,0.2,0.2,0.1]

out1 = mean_squared_error(np.array(y1),np.array(t))
out2 = mean_squared_error(np.array(y2),np.array(t))

```
それぞれの結果は
`print(out1) >>> 0.006699999999999998`
`print(out2) >>> 0.4750000000000001`
となり誤差は正解データに近いと少なく、遠いと多くなった。
よってこの場合はパターン１の出力結果の方が教師データにより適合していることを２乗和誤差は示している。

#### 2. 交差エントロピー誤差(Cross Entropy Error)
交差エントロピー誤差は以下の式

```math
E = -\sum_{k}t_klog_e{y_k}
```  
で表すことができる。

二乗和誤差と違うのは出力データと正解データをかけていることである。
これについてどのような利点があるかを説明すると、
正解データはone-hot 表現であり、正解ラベルのみ１，それ以外は０となる。
ということは上の式に当てはめるとEの値は

  **正解ラベルのみ -log<sub>y<sub>k</sub></sub>**
  それ以外は 0 

となることが分かるだろうか。
これにより交差エントロピー誤差は正解ラベルの出力結果により決まり、
正解ラベルに対応する出力ラベルが**小さ**ければEの値は大きくなり誤差が大きいことを示す。
##### 交差エントロピー誤差を使った例
二乗和誤差のときと同様に関数を定義していくが、
その前に、コード内で定義してある deltaについての説明を行っていく。

y = logx　のグラフを見ると分かるとおり、x->0においてlim y は**負の∞**になることが分かる。
仮に正解ラベルに対応する出力ラベルが**0**だった場合、交差エントロピー誤差を数値で表すことができなくなり、それ以上計算を進めることができなくなってしまうのである。 

これを回避するために微小な値であるdelta(コード内では10<sup>-7</sup>)を入れてlog中身が0になることを防いでいるのである。

```python 
import numpy as np

#正解データ(one-hot-label)
t = [0,0,1,0,0]

#交差エントロピー誤差の関数を定義
def cross_entropy_error(y,t):
    #deltaを定義(スペース開けないように注意!)
    delta = 1e-7
    return -np.sum(t * np.log(y + delta))

# パターン１(正解データに近い)
y1 = [0.01,0.02,0.9,0.05,0.02]
# パターン２(正解データから遠い)
y2 = [0.5,0.1,0.2,0.2,0.1]

out1 = cross_entropy_error(np.array(y1),np.array(t))
out2 = cross_entropy_error(np.array(y2),np.array(t))

```  
それぞれの結果は
`print(out1) >>> 0.1053604045467214`
`print(out2) >>> 1.6094374124342252`
となり、二乗和誤差のときと同様に正解データに近いほど値は小さくなることが分かっただろうか。  

##まとめ
- 損失関数はパラメータ(重みとバイアス)を更新していく重要な指標である。
- 損失関数の出力値が小さいほど最適なパラメータに近い。


---
##参考書  

[ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装 (日本語)](https://www.amazon.co.jp/%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E4%BD%9C%E3%82%8BDeep-Learning-%E2%80%95Python%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%E3%81%AE%E7%90%86%E8%AB%96%E3%81%A8%E5%AE%9F%E8%A3%85-%E6%96%8E%E8%97%A4-%E5%BA%B7%E6%AF%85/dp/4873117585/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=W6DVSLVW0BUS&dchild=1&keywords=%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E4%BD%9C%E3%82%8Bdeep+learning&qid=1599743190&sprefix=%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%2Caps%2C285&sr=8-1)]