微分と線形回帰（機械学習基礎）

## 微分と線形回帰の関係
　昨今、機械学習（AI）に非常に強い関心が寄せられています。
　TensorFlowやKerasなどのライブラリを使用して比較的簡単に機械学習を試すことができます。　しかしそれらは便利な反面、使用されている数学部分がブラックボックスになっています。この記事ではそれらを具体的なコードに起こして解説します。

### 機械学習の基礎（線形回帰）
　線形回帰は最も単純な機械学習アルゴリズムです。
　ほとんどの機械学習アルゴリズムは下記の３ステップで成り立っています。
###### ・モデル定義：y’=ax+b
###### ・損失関数定義：loss=Σ(y-y’)^2
###### ・損失関数を微分してパラメータ(a, b)を調整する
　微分と聞いてウンザリしている人も多いと思います。高校数学の微分で数学嫌いになった人も多いかと思いますが、コンピュータを使えば微分を比較的簡単に解くことができます。
  実際に微分を用いた線形回帰のコードを例示します。
  いったんコード全体を記載し後で個々の部分を解説します。
  
```python
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from numpy.random import *
import random

# 定数関連
DataCount = 1000# データ個数
r = 0.1# 学習率
delta = 0.001
TrainigCount = 200# 学習回数
################################################################################
# テスト用のデータセット作成
def ResultFunc(x):
    y = 0.3 * x + 0.1 #求めたい関数
    return y

def CreateDataset():
    rng = np.random.default_rng()
    x = rng.random(DataCount)# 0.0~1.0のランダム値
    dataset = np.zeros((DataCount, 2)).astype(np.float32)# (x, y)の組み合わせのペア
    for i in range(DataCount):
        dataset[i, 0] = x[i]
        dataset[i, 1] = ResultFunc(x[i]) + (random.random() - 0.5) * 0.2
    return dataset
################################################################################
# モデルと損失関数定義
def modelFunc(a, b, x):
    y_ = a * x + b
    return y_

def loss(dataset, a, b):
    loss_sum = 0.0
    for i in range(DataCount):
        x = dataset[i, 0]
        y = dataset[i, 1]
        loss_sum = loss_sum + (y - modelFunc(a, b, x)) ** 2
    return loss_sum / DataCount
################################################################################

if __name__ == '__main__':
    # テスト用のデータセット作成
    TestDataSet = CreateDataset()
    
    # モデル（y_= a*x + b）のa,bの初期値設定
    a = 1.0
    b = 1.0

    fig = plt.figure()
    ims = []
    for i in range(TrainigCount):
        # 点と関数の描写
        im1 = plt.plot(TestDataSet[:, 0], TestDataSet[:, 1], linestyle='None', marker='.', color='blue')
        plt.xlim([0, 1])
        plt.ylim([-0.1, 0.6])
        x = np.linspace(0, 1.0, 100)  # 横軸範囲指定
        y = modelFunc(a, b, x)
        im2 = plt.plot(x, y, color='red')
        ims.append(im1 + im2)

        # a,b の更新
        a_ = a - ((loss(TestDataSet, a + delta, b) - loss(TestDataSet, a, b)) / delta) * r
        b_ = b - ((loss(TestDataSet, a, b + delta) - loss(TestDataSet, a, b)) / delta) * r
        a = a_
        b = b_
        print('a, b=' + str(a) + ' , ' + str(b))

    ani = animation.ArtistAnimation(fig, ims, interval=100)
    # GIFとして保存する場合
    #ani.save('anim.gif', writer='pillow')
    plt.show()
```
このコードを実行すると直線がデータに沿った回帰する様子が描写されます。
このように収束する理由について解説します。
![anim.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4101406/eb21aec2-01fc-4f37-aa4a-65e0e2fb7b62.gif)

## 解説
### モデルと損失関数
まず、モデルを定義します。

```math
y'=a x + b
```
ここで定義しているa,bを最適化することで関数をデータに合うように調整します。その際、関数とデータが**どの程度一致しているかを表す関数**を表す関数を定義する必要があります。それが「**損失関数**」です。

下記のコードがモデルと損失関数（loss）を定義しているものです。損失関数は「データとモデルで求めた値の差の2乗」としています。

```python
# モデルと損失関数定義
def modelFunc(a, b, x):
    y_ = a * x + b
    return y_

def loss(dataset, a, b):
    loss_sum = 0.0
    for i in range(DataCount):
        x = dataset[i, 0]
        y = dataset[i, 1]
        loss_sum = loss_sum + (y - modelFunc(a, b, x)) ** 2
    return loss_sum / DataCount
```
この損失関数の微分を用いて変数a,bを更新します。
### 微分の定義とコード上での微分
数学において微分は下記のように定義されます。
```math
\frac{dy}{dx} = \lim_{\Delta x \to 0} \frac{f(x + \Delta) - f(x)}{\Delta}
```
難しい記述になっていますが、下記の画像のように微小量Δだけ変化させて傾きを求めています。数学では0に限りなく近くする操作を行いますがプログラムでは非常に小さい値を使用します。
![微分イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4101406/ffdb344c-fa61-43a9-bc74-34df563d4427.png)
損失関数の微分は下記のようになります。（正確にはaのみに着目した偏微分です）
```python
delta = 0.001

(loss(TestDataSet, a + delta, b) - loss(TestDataSet, a, b)) / delta)
```
この微分の値を用いてa,bを更新していくことで関数をデータに回帰させます。
```python
r = 0.1# 学習率
delta = 0.001

a_ = a - ((loss(TestDataSet, a + delta, b) - loss(TestDataSet, a, b)) / delta) * r
```

## さいごに
この記事ではプログラマが微分をと線形回帰（機械学習）の中身を理解するきっかけになることを目的に記載しました。本業の方からすると粗が目立つと思いますがわかりやすさ優先で簡単な表現に終始しました。
もしこの記事がきっかけ機械学習や数学に興味持った方がいればご自身で調べてみてください。