深層学習／正則化の効果を見える化する

#1.はじめに
　深層学習の勉強を始めました。今回は、正則化について、簡単にまとめてみます。

#2.データの作成
　方程式 $y=-x^3+x^2+x$ を元に、x は -10〜10を50分割した値、y は方程式にそのxを代入した結果に 0〜0.05の乱数を加えた値としてデータを作成します。

```python
from sklearn.preprocessing import PolynomialFeatures
from sklearn import linear_model
import numpy as np
import matplotlib.pyplot as plt

# データの生成
np.random.seed(0)
X = np.linspace(-10, 10, 50)
Y_truth = 0.001 * (-X **3 + X**2 + X)
Y = Y_truth + np.random.normal(0, 0.05, len(X))

plt.figure(figsize=(5, 5))
plt.plot(X, Y_truth, color='gray')
plt.plot(X, Y, '.', color='k')
plt.show()
```
![スクリーンショット 2019-12-26 15.31.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209705/7c147bbe-16f1-2631-ee2d-7f900450f011.png)
作成したデータです。実線が真の値（方程式の値）、点が実際に観測する値（yにノイズを加えた値）という想定です。

#3.多項式回帰の導入
　過学習は自由度が高いほど起こりやすいので、あえて30次元の多項式回帰を導入します。

```python
# グラフ表示
def graph(Y_lr, name):
    plt.figure(figsize=(6, 6))
    plt.plot(X, Y_truth, color='gray', label='truth')
    plt.plot(xs, Y_lr, color='r', markersize=2, label=name)
    plt.plot(X, Y, '.', color='k')
    plt.legend()
    plt.ylim(-1, 1)
    plt.show()

# 表示設定
xs = np.linspace(-10, 10, 200)  

# 多項式回帰の導入    
poly = PolynomialFeatures(degree=30, include_bias=False)  
X_poly = poly.fit_transform(X[:, np.newaxis])   
```
　グラフ表示や表示の設定をした後、PolynomialFeaturesをインスタンス化し、フィットしています。次元は30次元(degree=30)です。

#4.正則化なし
　まず、正則化なしで多項式回帰を行います。

```python
# 正則化なし           
lr0 = linear_model.LinearRegression(normalize=True)
lr0.fit(X_poly, Y)
Y_lr0 = lr0.predict(poly.fit_transform(xs[:, np.newaxis]))
graph(Y_lr0, 'No Regularization')
```
![スクリーンショット 2019-12-26 15.32.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209705/bd46ed3d-cab2-4029-e4eb-b55d964c9347.png)

　30次元の多項式と自由度が高いので、数多くの点を器用に通過することが出来てしまい、典型的な過学習に陥っています。真の値とは掛け離れてしまって、これでは汎化性能は望めません。

#5.L2正則化
　L2正則化とは、Ridge(リッジ)回帰で知られた手法で、係数が大きくなり過ぎない様に制限を加えるもので、パラメータのL2ノルムを損失に加えます(Cは定数)。
$L(W)+c|w|^2$

```python
# L2正則化
lr2 = linear_model.Ridge(normalize=True, alpha=0.5)
lr2.fit(X_poly, Y)
Y_lr2 = lr2.predict(poly.fit_transform(xs[:, np.newaxis]))
graph(Y_lr2, 'L2')
```
![スクリーンショット 2019-12-26 15.33.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209705/453fd7fa-8ac4-d958-e764-056e228706e2.png)
まあまあ、上手く回帰出来ている感じです。

#6.L1正則化
　L1正則化とは、Lasso(ラッソ)回帰で知られた手法で、同様に係数が大きくなり過ぎない様に制限を加えるもので、パラメータのL1ノルムを損失に加えます(Cは定数)。
$L(W)+c|w|$

```python
# L1正則化
lr1 = linear_model.LassoLars(normalize=True, alpha=0.001)
lr1.fit(X_poly, Y)
Y_lr1 = lr1.predict(poly.fit_transform(xs[:, np.newaxis]))
graph(Y_lr1, 'L1')
```
![スクリーンショット 2019-12-26 15.34.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209705/d98679fa-d95c-5ac7-5a39-75290d7cc073.png)
ジャストフィットにかなり近い形です。L1正則化と比較すると、L2正則化の方がより上手く回帰出来ている様です。

#7.次元係数の比較
　正則化なし、L2正則化、L1正則化それぞれ30個の次元係数を比較します(次元が低い方から並べています）。

```python
import pandas as pd
result = []
for i in range(len(lr0.coef_)):
      tmp = lr0.coef_[i], lr2.coef_[i], lr1.coef_[i]
      result.append(tmp)
df = pd.DataFrame(result)
df.columns = ['No Regularization', 'L2', 'L1']
print(df)
```
![スクリーンショット 2019-12-26 15.43.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209705/1e3e73cf-f98e-cb91-22a6-9954c0c81440.png)
　L2はNo Regularizationと比べて係数が小さくなっているのが分かると思います。L1はさらに、完全に0のところが多い表現(スパースな表現)になっています。

　L1正則化は、過学習抑制＋次元削減も出来るのは、嬉しいですね。