活性化関数についての簡単な説明といくつかの種類

# まえがき

一応、前回の[パーセプトロン](https://qiita.com/NNNiNiNNN/items/e1da0c9f10e738dc735f)の記事を読んでいる前提で説明します。

前回の単純パーセプトロンでは以下のように出力yを計算しました。

```math
 y = \begin{cases}
0 & (b + w_1w_1 + w_2 x_2 \leq 0)\\
1 & (b + w_1w_1 + w_2 x_2 > 0)
\end{cases}
```

これを以下の3式に書き換えてみましょう。

$$ y = h(a) $$



$$ a = b + w_1x_1 + w_2x_2 $$

```math
 h(a) = \begin{cases}
0 & (a \leq 0)\\
1 & (a > 0)
\end{cases}
```

3つに分解されただけで、やっていることは現状同じです。

さて、これを図で表してみましょう。
<img width="444" alt="ニューラル.png" src="https://qiita-image-store.s3.amazonaws.com/0/356208/7f19f8ab-6425-f7f7-cd1a-495d81fd8070.png">
汚い図ですね。

とにかくこういう処理で単層の計算を行っているわけです。
ここで肝心なのはaをyに変換するh(a)です。今は

```math
 h(a) = \begin{cases}
0 & (a \leq 0)\\
1 & (a > 0)
\end{cases}
```
を関数としていますが、これを別の関数に置き換えれば別の出力が得られるはずですね。この種類をいくつか見てみましょう。

どれも$y = ax$みたいな簡単な式（線形関数）ではありません。そもそも線形関数ならわざわざ重ねなくても一回で計算できるし。

# ステップ関数

```math
 h(a) = \begin{cases}
0 & (a \leq 0)\\
1 & (a > 0)
\end{cases}
```
これ。

## 実装してみよう
単純に条件を入力してみるとこうですね。

```python
def step_function(x):
if x > 0:
  return 1
else:
  return 0
```
$h(a)$自体はできているんですが、これではnumpy配列を扱えません。
以下のように書いてみます。

```python
import numpy as np
def step_function(x):
    return np.array(x > 0, dtype = int)
```

これは、$x>0$を満たしていたらTrue,満たしていなかったらFalseの配列を返す…のをさらに、int型に変換することで$x > 0$なら1、満たしていないなら0、という配列に変換しています。
グラフで表してみます。

```python
import numpy as np
import matplotlib.pylab as plt

def step_function(x):
    return np.array(x > 0, dtype = int)

x = np.arange(-5.0, 5.0, 0.1)
y = step_function(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)
plt.show()
```
![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/356208/7e69d782-55dc-05d0-6da6-3a27b71847de.png)
できました。

# シグモイド関数
以下の式で表します。


$$ h(x) = {1\over {1 + \mathrm{exp}(-x)}} $$

特徴として、$\infty > x > -\infty$の範囲で$1 > y > 0$の範囲をとること。$x = 0$で$y = 0.5$。

## 実装してみよう

```python
import numpy as np
def sigmoid(x):
    return 1 / (1 + np.exp(-x))
```
これでシグモイド関数をあらわすことができます。
グラフにしてみましょう。

```python
import numpy as np
import matplotlib.pylab as plt

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

x = np.arange(-10.0, 10.0, 0.1)
y = sigmoid(x)
plt.plot(x, y)
plt.ylim(-0.1, 1.1)
plt.show()
```
![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/356208/ca8ee389-75b7-0e59-38f6-486d6473bedb.png)

こんな感じです。すごくおおざっぱに言えば、なめらかなステップ関数といったような形をしています。

# LeRu関数
以下の式で表します。

```math
h(x) = \begin{cases}
x & (x > 0)\\
0 & (x \leq 0)
\end{cases}
```
ステップ関数で1だった所がxになってます。

## 実装してみよう
```python
import numpy as np
def relu(x):
    return np.maximum(0, x) # 0かxか大きい方を返す
```
ではグラフにしてみます。

```python
import numpy as np
import matplotlib.pylab as plt

def relu(x):
    return np.maximum(0, x)

x = np.arange(-5.0, 5.0, 0.1)
y = relu(x)
plt.plot(x, y)
plt.show()
```
![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/356208/4d05f566-f03b-9cad-9e96-1b2924c946b3.png)

こうなりました。

# ソフトマックス関数
主に出力層に用いります。
これは複数のaを利用してyを求める関数です。

$$ h(a_ k) ={ \mathrm{exp}(a_k)\over \sum^n _ {i = 1}\mathrm{exp}(a_i)}$$

証明は省略しますが、このように変形できます。
$$ y_ k ={ \mathrm{exp}(a_k +  C)\over \sum^n _ {i = 1}\mathrm{exp}(a_i + C)  }$$
これは[数値範囲をオーバーしないために](https://qiita.com/NNNiNiNNN/items/2f17f874f8a234bd10ad)する変形です。aに10000とか入っててもオーバーフローしないためにこの変形をする必要がある。

## 実装してみよう

```python
import numpy as np
def softmax(a):
  c = np.max(a)
  exp_a = np.exp(a - c) # これで必ずa-c <= 0。オーバーフローしなくなる。
  sum_exp_a = np.sum(exp_a)
  y = exp_a / sum_exp_a

  return y
 
```
出力してみましょう。

```python
a = np.array([0.3, 2.9, 4.0])
y = softmax(a)
print(y) # [0.01821127 0.24519181 0.73659691]
```
はいここで出力yに注目してください。
[0.01821127 0.24519181 0.73659691]の三つ。合計すると1になります。

つまりこれは与えられた三つの数字の大きさを比較し、「確率」に変換する関数といえます。

# 恒等関数

```math
h(a) = a
```

つまりそのまま。これも出力に用います。ソフトマックス関数使わずにこれでもそんなに問題ない。

## 実装してみよう
いる？

# まとめ
多数のxの入力をまとめてaを作り、それを活性化関数$h(a)$で変換する。これを繰り返して目的の出力を得るのがニューラルネットワークです。$h(a)$にはいろいろ種類があります。ここで触れた以外にもたくさんあります。
最後の二つのソフトマックス関数、恒等関数はどちらかというと出力用の関数。ちょっとジャンルが違います。

『ゼロから作るDeepLearning - Pythonで学ぶディープラーニングの理論と実装』を参考にしました。
前回:[パーセプトロン](https://qiita.com/NNNiNiNNN/items/e1da0c9f10e738dc735f)