実装初心者向けにディープラーニングの全体像、実装手順をわかりやすくまとめてみた

#対象者
機械学習、ディープラーニングを一通り勉強したが、実装するときにどう関連するのかわからない人。
頭の中を整理したい人。
詳しい数学的な説明はchainerチュートリアルを参照すると良い。
#解説内容
ディープラーニングでもっとも一般的な**教師あり学習**の手順を解説する。また、それに伴う周辺知識を説明する。
#ディープラーニングのモデルになったもの
ディープラーニングは人の神経細胞における情報伝達の仕組みを真似て作られた。これにより、精度が飛躍的に向上した。
#ニューラルネットワークの仕組み
##ニューロンのモデル化
ニューラルネットワークでは、人間の神経細胞の動きをコンピュータで再現した数式モデルを作る。個々の神経細胞は簡単な演算能力しか持たないが、お互いに繋がり連動することで高度な認識、判断をすることができる。行列や特別な関数の計算をしながら情報伝達の仕組みを数式で再現していく。
###ニューロンのモデル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616291/044ab567-88a5-ec97-2517-fabb286f5077.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616291/ba770518-09b0-107a-fe0e-1357065aa4bd.png)

ニューロンには多入力、1出力である。ニューラルネットワークの一つの層は複数のニューロンからなる。
**重み**:各入力に掛け合わせる係数。シナプスにおける伝達効率に相当し、値が大きいほど多くの情報が伝わる。学習中は自動更新されるので初期値しかいじらない。
**バイアス**:入力と重みをかけ合わせたものの総和に足す定数。ニューロンの興奮しやすさを調整するためのもの。学習中は自動更新されるので初期値しかいじらない。
**活性化関数**:ニューロンの興奮状態を表す関数。活性化関数がないとニューロンの演算は単なる積の総和になってしまい、ニューラルネットワークから複雑な表現をする力が失われてしまう。シグモイド関数やReLUなど様々な関数があり、扱う問題によってある程度最適な関数が決まっている。各層毎にユーザーが選択する必要がある。関数の説明は[活性化関数の種類](#活性化関数の種類)参照。
ちなみに記号として**w**は重み、**b**はバイアスとして表される。

(蛇足) 画像認識ライブラリのyoloは、学習済み(重みやバイアスや層数などが自動調整済み)のwightファイルをインポートすると直ぐに認識ができるようになる。ただし、学習した環境を考慮しないと間違った認識をしたり、追加で学習させても上手く収束しなかったりする。例えば[この記事](https://qiita.com/tetsuroito/items/e0944dfefd806e51364a)にあるように、アメリカで学んだ学習モデルだと「寿司」を「hotdog」と認識される。言い換えるなら育った環境(データセット)で性格(計算結果)が変わるとも言える。

##ニューロンのネットワーク化(ニューラルネットワーク)
ニューロンを複数接続してネットワーク化することでニューラルネットワークが構築される。(x、ｖ、ｙがニューロン) 図のような層状に並べる。
![news012_network1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616291/53c33eef-a2f3-0f00-fef1-06f6a0bc8edc.jpeg)
図 ニューラルネットワークのモデル　　　　　　　　　　　　(pythonで始める機械学習から引用)

ニューラルネットワークにおける層は、入力層、中間層、出力層に分類される。入力層と出力層は1つしか無いが、中間層は増やすことができる。中間層を増やすことによって計算の振る舞いが変わるので調整する必要がある。
通常のニューラルネットワークは、1つのニューロンからの出力が、次の層の全てのニューロンの入力とつながっている。
入力から出力に向けて情報が伝わることを**順伝播**。
出力から入力に向けて情報が遡っていくことを**逆伝播**という。逆伝播は出力結果を遡って重みとバイアスを更新するときに行われるもの。通常は自動的に行われるので、調整パラメータと仕組を知っておけば十分使えるレベルになる。
出力された値はデータセットの正解ラベルと比較して誤差が計算され、正解ラベルに近づくように重みとバイアスが自動調整される。
#ニューラルネットワークの種類
**全結合型**:「図 ニューラルネットワークのモデル」のように層間の全てのニューロンが接続されているもの。
**畳み込み型**:画像処理の分野でよく使われる。画像に対して畳み込みを行うことで、画像にある特徴を強めたり弱めたりすることができる。
**再帰型**:文脈を扱うことができるニューラルネットワークの一種。自然言語処理や系列データによく用いられる。
#機械学習の3つの手法
##1 教師あり学習
教師あり学習は学習データに正解ラベルを付けて学習させる方法。現在最も一般的な機械学習である。**学習するならまずはこれである。**多くの場合、学習データは人の手で正解ラベルを付けている。この作業をアノテーションという。**文字認識**、**画像分類**、**言語翻訳**などが教師あり学習に当たる。
##2 教師なし学習
学習データにラベルを付けないで学習する方法。データの圧縮、データのノイズ除去などの目的に使われることもある。教師なし学習では、次元削減とクラスタリングの2つのカテゴリがよく知られている。
レコメンドやセグメンテーションによる分類などに用いられる。
##3 強化学習
ユーザーが報酬を設定し、その報酬が最大になることを目的としてAIが試行錯誤しながら一番いい行動を探索する学習方法。満点を目指すようにAIが自ら行動を改善し続ける。



#ニューラルネットワークで扱う問題
##教師あり
ニューラルネットワークの教師あり学習で扱う問題は、分類問題と回帰問題に分けられる。
###回帰
回帰問題とは、データの傾向から連続的な数値を予測するもの。基本的な使い方として離散データを集めてそのデータから近似関数を作成させ、未知のデータの予測値を算出するもの。出力層のニューロンは1つ。
主な例として
・身長から体重を予測する
・ユーザーの買い物傾向から次に購入するものを予測する
・これまでの株価の傾向から明日の株価を予測する
・物件の情報から家賃を予測する
####単回帰
一つの入力から1つの結果を予測するもの。身長から体重など2つの関係性を表す場合に使われる。
####重回帰
物件の様々な情報から家賃を予測するなど多入力のものから1つの結果を予測するもの。こちらのほうがよく使われる。
###分類
分類問題とは、データを決められた複数の枠に分類する問題のこと。回帰問題と違い出力が複数ある。出力がそのまま分類したものの確率を表している。出力層のニューロンは分類したいものの数だけ用意する。
主な例として
・葉の画像から植物を分類する
・手書きの文字を分類する
・画像に映る乗り物が何かを判定する
##教師なし
###クラスタリング
データの中から類似点を探してグループ化すること。例えば、たくさんある花の中から「赤い花」「青い花」「紫の花」など色で分類してグループ化するのがある。


#実際に学習させる場合の流れ
##1 データセットの準備
###データセットとは
学習データxと正解ラベルyが1セットになったデータ群である。データセットは更に**訓練データ**と**テストデータ**に分かれる。訓練データはネットワークの学習に用いるが、テストデータは訓練データから作成したモデルの性能を評価するのに用いる。通常、訓練データはテストデータよりも数を多くする。
学習データにより学習したネットワークがテストデータでも良い結果を出せば、ネットワークが未知のデータにも対応できていることになる。テストデータで良い結果が出なければ、ネットワーク自体や学習方法に何らかの問題があることになる。ネットワークが未知のデータにも対応できる能力を**汎化性能**と呼ぶ。
###1.1 データの入手
学習データは手作業か、スクレイピングで自動で集める。集めるのは自動やることもできるが、ふさわしいデータかどうかは手作業で見極めるので一番大変な作業である。データの集め方は[こちらの記事](https://qiita.com/nonbiri15/items/f5c5c4357458bfeb03bb)が参考になる。
###1.2 データセットの作成
データセットは手作業で作るか、ライブラリを使う。「データセット　作り方」とか検索すれば出てくる。画像の場合は正解ラベルを**アノテーションツール**を使って作成する。
適切な結果を得るためには、画像だったら通常何千枚単位の枚数が必要だが、集めることは困難なので水増しを行うのが普通。

####データセットの構造
データセットの学習データと正解ラベルはそれぞれベクトルになっている。
例えば身長から体重を予測するための回帰問題のデータセットを作る場合は以下のような数値が並んだベクトルで表される。
[146.2 170.4 169.3 154.5 179.2]　データ
[46.9 63.8 58.6 53.1 70.6]正解ラベル
分類問題の場合は、正解ラベルは以下のように、正解が1で正解以外が全て0のベクトルになっている。
[0 0 1 0 0]
このように1が1つで残りが0の数値の並びを、**one-hot表現**という。
###1.3 データの前処理
正規化や標準化などデータを扱いやすい形式に整形する。例えば標準化は学習が安定し高速になる効果を持つ。
###1.4 (One-Hot表現への変換)
分類問題の場合は、正解値をonoe-hot表現で表す。そのため、実装の際は、one-hot表現への変換プログラムを挟む。出力層のニューロン数が3の場合は以下のようになる。
[1 0 0]
[0 1 0]
[0 0 1]
###1.5 訓練データとテストデータの分割
最後に訓練データとテストデータに分ける。訓練データは学習のために用いるが、テストデータは訓練データで出てきた学習結果の汎化性能を評価するために用いる。両方とも学習させることに変わりは無いが、学習後の結果をグラフで比べる。体感的にテストデータは訓練データの20%~30%がいいと思われる。
##2 各層の実装
学習に用いる中間層と出力層の型を作る作業。中間層と出力層それぞれの**活性化関数**及び**損失関数**を設定する。使い回しができるようにclassを使って書いておくといいだろう。パラメータは外から変更できるように変数として宣言しておくとよい。
理解が目的ではなく、サクッと学習だけさせたいなら他人のコピペで十分。
##3 パラメータの初期値の設定
**重みとバイアスの初期値**を設定する。
活性化関数の種類については[やっぱりよくわからない活性化関数とは](https://newtechnologylifestyle.net/%E3%82%84%E3%81%A3%E3%81%B1%E3%82%8A%E3%82%88%E3%81%8F%E5%88%86%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84%E6%B4%BB%E6%80%A7%E5%8C%96%E9%96%A2%E6%95%B0%E3%81%A8%E3%81%AF/)が参考になる。

##4 ハイパーパラメータの調整
初回はかんで設定し、学習結果に合わせて以下の4つの値を修正する。これらはテストデータで評価した出力によってユーザーが何度も調整する。それぞれの説明は[こちら](#ハイパーパラメータ)
・エポック
・バッチサイズ
・学習係数
・最適化アルゴリズム
##5 学習
学習はニューロン同士の結びつきを調整していく過程だ。学習は以下の3つの過程を経る。
###5.1 正解との誤差の導出
誤差を導出するために**損失関数**を用いる。
###5.2 勾配の導出
勾配を求めるためには**勾配降下法**を用いる。出てきた損失関数$L$を$w$で偏微分して勾配$\frac{∂L}{∂w}$が得られる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616291/3d955d5b-6208-960e-b114-8ca2f7d782f3.png)
(引用:chaierチュートリアル)
###5.3 バックプロパゲーション(誤差逆伝播法)
順伝播により得られた出力と、予め用意した正解との誤差を1層ずづ逆向きに伝播させる。伝播した誤差をもとに各層で重みとバイアスの更新量を求める。更新後の重みは以下のように求められる。

```math

w←w−η\frac{∂L}{∂w}
```
##6 正解率の評価
学習の結果、訓練データのうち何%を正しく判定できるようになったかを確かめる。テストデータのうち何%を正しく判定できるかは学習の成否を判断するための重要な指標である。同じハイパーパラメータで訓練データとテストデータを学習させ、epochs(学習回数)-loss(損失関数の損失値)のグラフを出力する。**出てきた二つのグラフを比較し、ユーザーが目で見て確認する。**グラフの動きから何がおきているかを推定し、ハイパーパラメータの調整を行なったのち再び学習を行う。


#ディープラーニングの多層化による問題
##局所最適解へのトラップ
勾配を求める際に局所的な最適解に囚われてしまい、全体の最適解にたどり着けなくなる問題。場合によっては勾配が極端に減少してしまい、学習が進まなくなる問題もある。全体で最適な解を見つけるためには一度局所的にベストな状態を離れる必要がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616291/afe2b1c6-00a4-2388-d831-da8939b25a4f.png)
(引用:chainerチュートリアル)
##過学習
ニューラルネットワークがある**特定の範囲のデータのみに最適化されて学習し、未知のデータに対応できなくなってしまうこと。**機械学習においては、訓練データに過剰に適合するあまり未知の入力データに対応して推定することができなくなってしまうことでもある。特定のパターンのみ最適化された局所最適解に陥っている状態ともいえる。いろいろなデータに対応できるように、生成されるネットワークは少しいい加減さがあるほうがよい。この過学習を抑制するために後述する様々なパラメータをユーザーが調整していく。
**中間層やニューロンの数が多すぎると表現力の過剰により過学習が発生する。**また、**訓練データのサンプル数不足**により発生することもある。
##勾配消失
主に活性化関数にシグモイド関数を使うことで起きる問題。シグモイド関数の勾配は最大値が0.25で0から離れるほど0に近づく。逆伝搬する際は、層を遡るごとに活性化関数の微分を各勾配にかけることになるが、シグモイド関数の場合、層を遡る毎に各勾配が小さくなっていき勾配消失が発生する。そのため、ディープラーニングでは活性化関数にはReLUを使うことが多い。
##学習に時間がかかる
多層のディープラーニングでは、重みとバイアスの数が膨大になる。そのため、学習には数日、数週間かかることもある。この問題に対処するためにはGPUを使う、スペックの高いマシンを使う、必要以上にネットワークを複雑にしないこと、パラメータを調整するなどがある。
#ユーザーが調整するパラメータ
多層化に伴う問題は、機械が自動で調整することができないので、ユーザーが結果に合わせて調整する必要がある。そのため、より良い結果を得るために何度も調整と学習を繰り返さなくてはならない。調整する項目としては以下の7つがある。どれをどう調整するかはある程度の経験が必要になってくる。よく調整するのはハイパーパラメータ、データの拡張、データの前処理だ。
##1 ハイパーパラメータ
###エポック
全ての訓練データを1回学習することを1エポックと数える。エポック数は多すぎても訓練データへの過剰適応が起こるので適度な回数で打ち切る。
###バッチサイズ
データセットをいくつかのサブセットに分けた際のそれぞれに含まれるデータ数のことを言う。計算の都合上2の累乗(8,16,64,256など)の値にする。学習時間やパフォーマンスに影響するパラメータである。詳しくは[こちらの](https://qiita.com/kenta1984/items/bad75a37d552510e4682)説明が参考になる。
学習では、バッチごとに重みとバイアスの更新が行われるので、**バッチサイズは重みとバイアスの修正を行う間隔**とも言い表せる。例えばデータ数が1024でバッチサイズが64だった場合、16回更新が行われることになる。こうしてサブセットに分けて更新することで**個々のデータに振り回されること、局所最適解に囚われることを防ぐことができる**。
###学習係数
勾配降下法の勾配にかける係数。これで勾配の量を調整することができる。学習係数が大きすぎると繰り返しパラメータ更新を行っていく中で損失関数の値が振動したり、発散したりしてしまう。逆に小さすぎると、収束に時間がかかってしまう。この値は最適な値は決まっていないため、経験的に探す必要がある。
###最適化アルゴリズム
勾配降下法では、勾配をもとに重みとバイアスを少しずつ調整し、誤差が最小になるようにネットワークを最適化する。この最適化の際に様々なアルゴリズムが存在する。各アルゴリズムの説明は[こちら](#最適化アルゴリズム一覧)
##2 重みとバイアスの初期値
学習の成否に関わる大事なハイパーパラメータ。ある程度小さな値でランダムにばらつきを持たせることが望ましい。
##3 早期終了
学習を途中で打ち切る手法。学習を進めるとテストデータの誤差が途中から増加し、過学習になってしまうことがあるので、その前に学習を終了させる。誤差が停滞し学習が進まなくなった場合も、時間短縮のために終了させる。
##4 データの拡張
訓練データのサンプル数が少ないと、過学習が起きやすくなる。その場合、サンプルの水増しを行って対処するのが一般的。様々なタイプのサンプルを学習させることでネットワークの汎化性能の向上に役立つ。[この記事](https://qiita.com/nuhsodnok/items/a3fb71bba4e0148e782f)では実際に画像を学習させた際にサンプル不足で過学習に陥っている様子が書かれてるので参考に。

##5 データの前処理
入力データに対して予め処理を施して扱いやすくしておくこと。前処理を行うことでネットワークの性能向上や学習の高速化が望める。
pythonを使っている場合は「pandas」というライブラリを使うと簡単に前処理ができる。
前処理の種類には正規化や標準化など様々ある。やり方は[この記事](https://qiita.com/kazukiii/items/2600987798c62dd29dfc)が参考になる。
##6 ドロップアウト
過学習抑制テクニック。出力層以外のニューロンを一定の確率でランダムに消去するテクニック。規模の大きなネットワークほど過学習を起こしやすいので、ドロップアウトを用いることでネットワークの規模を下げることができる。
##7 正則化
重みに制限を与えること。重みに制限を与えることで重みが極端な値をとり、**局所最適解にトラップされることを防ぐ。**


#活性化関数の種類
##ReLU
0以下の入力で出力が0。0より上の入力で入力と同じ出力をする関数。**分類問題によく使われる**。分類問題では0以下の入力は取りえないため、ノイズ除去のために使われることが多い。プログラムで実装する場合は、if文で0以下を切り捨てる処理をすれば実装できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616291/b47f7b7c-eab5-aff9-67f1-87a2f5ad02b5.png)

##シグモイド関数
入力値が大きくなると一定の値に収束するため、入力が大きなものには使われない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616291/93cdded5-509c-8357-61ea-8295e9696901.png)
(wikipedia)
##ソフトマックス関数
**分類問題を扱うのに適した関数。分類問題の出力層によく用いられる。**この関数のK=1からnまでの全ての出力を足し合わせると1になる。そのため、ソフトマックス関数は複数の入力値からなるベクトルXがいかなる値を取ろうとも**全出力の合計が1になるように正規化する性質を持つ。**そのため、出力層のニューロンの出力値の合計を1として扱う分類問題と相性が良い。

```math
y=\frac{e^{x}}{\sum_{k=1}^{N}e^{x_k}}
```
##恒等関数
入力をそのまま出力として返す関数。**回帰問題の出力層の活性化関数としてよく用いられる。**
#損失関数一覧

##平均二乗誤差
**回帰問題**をときたいときによく用いられる損失関数。

```math
L= \frac{1}{N}\sum_{n=1}^{N}(t_n-y_n)^2
```
##交差エントロピー誤差
**分類問題**をときたい際によく用いられる損失関数。利点は出力と正解値との隔離が大きいときに学習速度が早い点。

```math
L=\sum_{k=1}^{K}t_k(-\log(y_k))
```


#最適化アルゴリズム一覧
以下では代表的なものをメモしている。他の最適化アルゴリズムについては[こちら](https://qiita.com/ZoneTsuyoshi/items/8ef6fa1e154d176e25b8#%E7%A2%BA%E7%8E%87%E7%9A%84%E5%8B%BE%E9%85%8D%E9%99%8D%E4%B8%8B%E6%B3%95sgd-stochastic-gradient-descent)を参考に。
##SGD(確率的勾配降下法)
更新毎にランダムにサンプルを呼び出すアルゴリズム。局所的最適解に囚われにくいという特徴を持つ。簡単なコードで実装できるが、学習の進行に応じて更新量の調整ができないため、学習に時間がかかることが多い。
##AdaGard
更新量が自動的に調整される。学習が進むと次第に学習率が小さくなっていく。設定すべき定数が学習係数しかないため、調整に手間がかからない。
##RMSProp
AdaGradの、更新量の低下により学習が停滞する弱点を克服したもの。
##Adam
RMSpropを改良したもの。最もよく使われているらしい。







#参考
[チェイナーチュートリアル](https://tutorials.chainer.org/ja/tutorial.html)
[pythonで始める機械学習入門](https://www.atmarkit.co.jp/ait/articles/1811/20/news012.html)
[はじめてのディープラーニング　Pythonで学ぶニューラルネットワークとバックプロパゲーション](https://www.amazon.co.jp/dp/B07GWHP9YM/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)
[キカガク ディープラーニングの基礎](https://www.kikagaku.ai/tutorial/basic_of_deep_learning/learn/tensorflow_neural_network_basic_forward)
[PythonとKerasによるディープラーニング](https://www.amazon.co.jp/Python%E3%81%A8Keras%E3%81%AB%E3%82%88%E3%82%8B%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0-Francois-Chollet/dp/4839964262)
https://www.sbbit.jp/article/cont1/33345
https://qiita.com/nishiy-k/items/1e795f92a99422d4ba7b
https://qiita.com/Lickey/items/b97c3450d7def207bfbf
https://products.sint.co.jp/aisia/blog/vol1-9