Pythonでいろいろな機械学習手法を実践

#概要
CSVファイルを読み込み、様々な手法でデータを学習するプログラムをPythonで実装する。ここで紹介するソースコードでは入力のCSVから教師データを作成し、学習およびモデルの精度確認までを行う。最後にCで実装したDeepLearningの独自のアルゴリズムについて記載する。

#機械学習手法
多種存在する学習手法のうちラベルデータ学習に適した機械学習手法概要を紹介する。

## K近傍法
検証対象のデータからパラメータ特徴空間中におけるユークリッド距離の近いK個の教師データのうち最多のラベルに分類する方法である。

## カーネル近似法
特徴空間にガウスカーネルによる非線形境界を設けることで障害種別を分類する方法である。ガウスカーネルのパラメータγによってモデル精度を調整する。γが小さいほど境界は直線的になり、大きいほど複雑な境界を作ることができるが過学習を起こしやすい傾向となる。

## 線形サポートベクターマシン
パラメータ特徴空間中において近傍の点から最小2乗距離が最大となるよう線形境界を設けることで分類する方法である。境界のマージンを最大化するため手法そのものが過学習に強い。

## 非線形サポートベクターマシン
教師データをもとの特徴空間から高次元特徴空間へと非線形写像することで線形サポートベクターマシンと同じ手法を非線形分類に拡張したものである。ここでは多項式カーネルを用いた非線形サポートベクターマシンを採用し、多項式カーネルのパラメータCによってモデル精度を調整する。Cが小さいほど境界近傍の誤分類を許容するソフトマージンとなって精度が下がり、大きいほど誤分類を許容しないハードマージンになり精度は上がるが過学習を起こしやすい傾向になる。

## 深層学習
人間の脳神経構造を模擬したニューラルネットワークを使用し、出力の誤差を最小化するように重みを更新する手法である。ここでは誤差にマージンを加えることで過度な誤差最小化を防ぐL2正則化を用いて過学習を抑止する。重み更新の際には教師データをミニバッチと呼ばれる単位でグループ化して誤差の平均を取り、平均化された誤差を最小化する。深層学習では誤差を最小化するための最適化アルゴリズムの選択、層数やミニバッチに含まれるデータ数であるバッチサイズなどのハイパーパラメータの調整、さらにニューラルネットワークでの積和演算を非線形化する活性化関数の種類を選択することによってモデル精度を調整する。

#chainerとscikit-learnをインストール
```
pip install chainer
pip install scikit-learn
```

#Pythonコード
https://github.com/jun6231jp/analysis/blob/master/statistical_analysis.py

##実行方法
データファイルを置くディレクトリと結果ファイルを置くディレクトリを作成する。
このソースコードでは下記ディレクトリとしている。

```
/home/user/py/data
/home/user/py/result
```

CSVファイルを作成する。要素数を自動で読み取り、末尾の要素がラベルとして認識される。
下記例であれば5入力幅でラベルは0~5の6種類になる。

```text:/home/user/py/data/DATA.txt
0,0,0,0,0,0
1,0,0,0,0,1
0,1,0,0,0,2
0,0,1,0,0,3
0,0,0,1,0,4
0,0,0,0,1,5
```

学習の方法、学習回数、活性化関数、最適化アルゴリズムなどはすべてオプション引数で指定する。

```text:ヘルプ表示
python statistical_analysis.py -h
```
```text:K近傍法でKをラベル数の10倍、学習回数を100回に設定
python statistical_analysis.py -kn -kp 10 -c 100
```
```text:ガウスカーネル近似でγを0.5に設定
python statistical_analysis.py -rbf -gm 0.5
```
```text:線形サポートベクターマシン
python statistical_analysis.py -lsvm 
```
```text:カーネルサポートベクターマシンでCを0.5に設定 
python statistical_analysis.py -ksvm -cp 0.5
```
```text:DeepLearningで活性化関数をシグモイド、Lasso回帰でバッチサイズをラベル数の10倍、層数を3にする
python statical_analysis.py -dl -s -ls -bs 10 -l 3
```
```text:DeepLearningで活性化関数をreLu、Ridge回帰で重み減衰係数0.0001、最適化アルゴリズムをAdamにする
python statistical_analysis.py -dl -r -rd -wd 0.0001 -adam
```

##教師データ作成方法概要
Pythonコードの中では、機械学習前にまず教師データを生成する。
入力のテキストファイルである元データには、同一のパラメータに対し異なるラベルを持つデータが存在する場合がある。このときラベルは小さい数を優先し、一意データを作成する。この際、ラベルは離散値になる場合があるため、ラベル番号を0から順に振りなおす。次に、ラベルごとにデータ数が異なる場合があるため、データ数を多数のものに合わせ拡張データを作成する。最後にデータをシャッフルし教師データとする。
<img width="635" alt="教師データ作成.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152991/db56cdd0-8699-8f26-b5d6-11574bc74930.png">


##実行結果
結果ディレクトリに下記ファイルが作成される。

```text:K-近傍法、ガウスカーネル近似、サポートベクターマシン
/home/user/py/result/log.txt　実行ログ
```

```text:DeepLearning
/home/user/py/result/NN.dot ニューラルネットドットファイル       
/home/user/py/result/NN.png ニューラルネット画像       
/home/user/py/result/graph.png 学習過程誤差プロットグラフ
/home/user/py/result/net.npz 学習済みモデル
/home/user/py/result/log.txt 実行ログ      
```

下図はニューラルネット画像と学習過程誤差プロットグラフの例である。

<img width="400" alt="graph_mode0_ridge_sigmoid.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152991/a74d1640-b6da-61ad-b37a-48d81e4714bb.png">

<img width="400" alt="NN_mode0_ridge_sigmoid.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152991/0fce1e55-6050-83e1-a844-90699369564e.png">

#DeepLearningの独自アルゴリズム
学習の過程で外れ値を学習してしまうことで学習が収束しない場合がある。
そこで学習の中で外れ値を識別し対象から除外するようにした。
ニューラルネットワークの動きを細かく見て学習する意味を兼ねて、Cでライブラリから自作したものを紹介する。

https://github.com/jun6231jp/analysis/blob/master/dl.h
https://github.com/jun6231jp/analysis/blob/master/NN.c

入力のニューラルネットワークの入力幅や出力幅、層数、学習回数はコード内のプリプロセッサで定義するようにしている。
ここでは入力幅29、出力幅8、層数3、学習回数10000回としている。
SoftMaxの出力は正解ラベル1に対し出力0の場合誤差1、正解ラベル0に対し出力1の場合誤差-1としており-1～1の範囲で分布している。

##実行方法

```
./NN.out [活性化関数] [学習係数] [入力データファイルパス] [重み保存ファイルパス]

シグモイドで学習係数3とする場合
./NN.out 0 3 input_file output_file

```

##結果
横軸が学習回数、縦軸がSoftMaxの出力の誤差をラベル種別ごとに色分けしてプロットしたものである。SoftMaxの出力の誤差を正解ラベルと計算結果との差としており、絶対値に直していないため上記の図と異なり0を中心に上下に広がる形のグラフになっている。N回目の学習時には１～N回までのSoftMax出力の最大値の平均値を計算する。これを最大誤差包絡線と呼ぶことにする。最大誤差包絡線をプロットしたものがグラフ中の誤差0.8付近の緑線である。ここでは最大誤差包絡線を外れ値の識別閾値として使用しており、誤差の絶対値が最大誤差包絡線を超えるものは学習対象外とする。閾値内のデータは収束し、外れ値は無視されている様子がグラフからわかる。

<img width="400" alt="学習.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152991/7225fe9f-4d0b-baa0-94ed-36dae5d45e3e.png">