いまさらの微分（勾配降下法の基本）

# 微分とは
ある点における傾き（変化の割合）を示す
ここで、変化の割り合いということが機械学習に使われる
ということで基本から整理してみました。

# 基本的な微分で理解しよう
### y = x<sup>2</sup>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/6490eafd-b326-07ba-ab2e-8e9fb71c2152.png)
このグラフの微分は ``y = 2x``なので、
ある点x<sub>i</sub>における傾きは2x<sub>i</sub>となる。

- x<sub>i</sub> = 2 の時 => 傾きは``2 × 2 = 4``
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/ba34c077-468e-c9ab-0f13-27151009d577.png)

- x<sub>i</sub> = -3 の時 => 傾きは``2 × (-3) = -6``
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/299187c0-6ff3-0846-b126-7873964996b0.png)

- x<sub>i</sub> = 0 の時 => 傾きは``2 × 0 = 0``
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/c1c09065-06a5-c596-72af-8c0e7b2fcc6b.png)

# 機械学習への応用
y = x<sup>2</sup>で``x = 0``の時、``傾き(変化の割合)は0``であることがわかりました。
つまりグラフの最小値の時、傾き0となりました。（※グラフの最大値でも傾きは0となります)
この``傾きが0``となるxを探索していくことで学習していきます。

## 最小値の探索
xの初期値を適当に与え、最小値を探していきます。

```python:
import matplotlib.pyplot as plt
%matplotlib inline

x = []
y = []

# グラフを作成
for i in range(-1000, 1000):
  for j in range(0, 100):
    k = i + j/100
    x.append(k)
    y.append(k**2)

plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("y")
plt.yticks([200000, 400000, 600000, 800000, 1000000])
plt.ticklabel_format(style='plain',axis='y')
plt.ylim(-0.1, 1000000)

# 初期値を適当に決める
x_tmp = -800
y_tmp = (-800)**2

# 学習率（ステップ幅）
eta = 0.2

# 最小値を探索していく
for step in range(50):
  x_before = x_tmp
  y_before = y_tmp
  x_tmp = x_tmp - (eta * 2 * x_tmp)
  y_tmp = x_tmp ** 2
  plt.plot([x_before, x_tmp], [y_before, y_tmp], color='r')
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/0bf953fe-c546-6553-b3bc-5e5d5bfc3423.png)

グラフからxが-800から0に向かって変化していく。
学習率はモデルによって調整する必要があります。

## 学習率を小さくすると
学習が進みません

```python:
x = []
y = []

for i in range(-1000, 1000):
  for j in range(0, 100):
    k = i + j/100
    x.append(k)
    y.append(k**2)

plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("y")
plt.yticks([200000, 400000, 600000, 800000, 1000000])
plt.ticklabel_format(style='plain',axis='y')
plt.ylim(-0.1, 1000000)

# 初期値を適当に決める
x_tmp = -800
y_tmp = (-800)**2

# 学習率（ステップ幅）
eta = 0.01

# 最小値を探索していく
for step in range(50):
  x_before = x_tmp
  y_before = y_tmp
  x_tmp = x_tmp - (eta * 2 * x_tmp)
  y_tmp = x_tmp ** 2
  plt.plot([x_before, x_tmp], [y_before, y_tmp], color='r')
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/f70c1e4e-6af5-72c2-8acf-1d63c7ba805c.png)

## 学習率を大きくすると
0を超えて発散してく

```python:
x = []
y = []

for i in range(-1000, 1000):
  for j in range(0, 100):
    k = i + j/100
    x.append(k)
    y.append(k**2)

plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("y")
plt.yticks([200000, 400000, 600000, 800000, 1000000])
plt.ticklabel_format(style='plain',axis='y')
plt.ylim(-0.1, 1000000)

# 初期値を適当に決める
x_tmp = -800
y_tmp = (-800)**2

# 学習率（ステップ幅）
eta = 0.9

# 最小値を探索していく
for step in range(50):
  x_before = x_tmp
  y_before = y_tmp
  x_tmp = x_tmp - (eta * 2 * x_tmp)
  y_tmp = x_tmp ** 2
  plt.plot([x_before, x_tmp], [y_before, y_tmp], color='r')
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/8b70b942-86ae-a97e-3d5b-ae47bb3c6272.png)

y = x<sup>2</sup>だとうまく発散しなかったので、
y = 10x<sup>2</sup>+100に変更してみます。
すると微分は``20x``

```python
x = []
y = []

for i in range(-1000, 1000):
  for j in range(0, 100):
    k = i + j/100
    x.append(k)
    y.append(10*(k**2) + 100)

plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("y")
plt.yticks([2000000, 4000000, 6000000, 8000000, 10000000])
plt.ticklabel_format(style='plain',axis='y')
plt.xlim(-1200, 1200)
plt.ylim(-0.1, 10000000)

# 発散させる(赤色)
# 初期値を適当に決める
x_tmp = -200
y_tmp = (10 * (x_tmp**2)) + 100

# 学習率（ステップ幅）
eta = 0.11

# 最小値を探索していく
for step in range(50):  
  plt.scatter(x_tmp, y_tmp, color="r")
  x_before = x_tmp
  y_before = y_tmp
  x_tmp = x_tmp - (eta * (20 * x_tmp))
  y_tmp = (10 * (x_tmp**2)) + 100
  plt.plot([x_before, x_tmp], [y_before, y_tmp], color='r')

# 最小値を探索させる(黄色)
# 初期値を適当に決める
x_tmp = -800
y_tmp = (10 * (x_tmp**2)) + 100

# 学習率（ステップ幅）
eta = 0.01

# 最小値を探索していく
for step in range(50):
  plt.scatter(x_tmp, y_tmp, color="y")
  x_before = x_tmp
  y_before = y_tmp
  x_tmp = x_tmp - (eta * (20 * x_tmp))
  y_tmp = (10 * (x_tmp**2)) + 100
  plt.plot([x_before, x_tmp], [y_before, y_tmp], color='y')

plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/683664/ab7e4d11-ab4d-e682-06be-b5c44b0fbf42.png)

学習率を抑えた黄色は最小値を探索しているが、学習率が高い赤色は最小値を目指すことなく発散していく。

# 勾配降下法と微分
機械学習の学習時に、勾配降下法を用いて学習を進めます。
その時に最小値を探索していく手段として微分が使われています。


# 参考資料
[機械学習と微分と最急降下法について](https://note.com/mucun_wuxian/n/n4e572a955daf)
[[機械学習] 最急降下法](https://python.atelierkobato.com/steep/#outline__1_3)
[勾配降下法を入門しよう！初心者向けにやさしく解説♪](https://aizine.ai/glossary-gradient-descent/)
[ニューラルネットワークの学習を司る「微分」を学ぶ](https://thinkit.co.jp/article/14586)