第2回：ニューラルネットワーク概要①

## <font color="ForestGreen">**前回では**</font>
さて、前回で回帰をやったことで、機械学習における学習がなんとなくつかめたのではないかと思います。
今回はニューラルネットワークを用いて、本格的に学習を行っていきます。
が、書くことが結構多かったので２回に分けたいと思います。
今回はニューラルネットワークというものの説明をプログラミング抜きで試みます。
そして次回は実際にpythonを用いて簡単なニューラルネットワークを実装していきます。
それでは始めましょう！
## <font color="ForestGreen">**その前に**</font>
機械学習とはどのように行うかをまとめておきたいと思います。
機械学習は**学習フェーズ**と**推論フェーズ**に分かれます。

例えば、**年齢**と**体重**から<font color="Magenta">**握力**</font>を推測する場合を考えてみましょう。
 **【学習フェーズ】**
まずは<font color="OrangeRed">**学習の仕組みを持つプログラム**</font>を作ります。
:eye: その際、１から作るのではなく頭のいい人達がすでに提供してくれているライブラリを使えますので安心してください。
次にそのプログラムに大量のデータを投入します（これを**訓練データ**と呼びます）。
このデータは[入力：出力]のペアのデータで、こういう感じの入力だったら結果はこうだったよ！
というふうに、答え付きのデータです。


３０歳で６７キロのこの人の握力は４６キロだったよ。
１５歳で５６キロのこの人の握力は３６キロだったよ。


と、このように[入力：出力]のペアのデータをプログラムに投入するのです。
するとプログラムがこれらのデータ入力から出力をいい感じに説明できる式を以下のように見つけ出します。

```math
y = aA + bB
```
　　　　　　　　　　　　　　　　　　　　　　　y:握力、A:年齢、B:体重

当然、実際はこんなに単純な式ではないですが、イメージはこれでオッケーです。
この式において、いい感じのaとbを発見すること。これが学習です。


 **【推論フェーズ】**
さあ、プログラムは**年齢**と**体重**から<font color="Magenta">**握力**</font>を説明できる式を得ました。
この式はある人の**年齢**と**体重**が与えられたら本当に<font color="Magenta">**握力**</font>を推測できるのでしょうか？
ではさっそく**訓練データ**の入力のデータを使って、、、ってこれダメですよね。
**訓練データ**に合うように式をつくったんだから**訓練データ**を推測できるのは当たり前です。
ここは**訓練データ**以外のデータを使ってこの式を試さないと、この式が**訓練データ**だけに当てはまる使えないものである
可能性があります（この**訓練データ**だけにピッタリあてはまっちゃうことを<font color="Red">**過学習**</font>といって機械学習の悩みのタネです）。

こういう場合に使う**訓練データ**とは異なるデータを**テストデータ**といいます。
この**テストデータ**を先ほどの式に投入して正答率を出してやります。
そして正答率がOKといえるほど高かった場合に初めて、未知の入力に対しての予想に使えるものが完成したといえるのです。

まとめると、学習フェーズで訓練データを用いて学習し、推論フェーズでテストデータを用いて正答率を出すのです。
この過程を経て、競馬予想AIソフトを作っていきます。

## <font color="ForestGreen">**ニューラルネットワーク**</font>
上で出てきた<font color="OrangeRed">**学習の仕組みを持つプログラム**</font>を、<font color="OrangeRed">**ニューラルネットワーク**</font>を用いて作ります。
pythonで実装していきたいと思いますが、上で述べた通り、実際のコードを載せるのは次回ということにして、
今回はプログラム作成の前準備として<font color="OrangeRed">**ニューラルネットワーク**</font>の仕組みを学びます。
上で訓練データにあう式を見つけることを学習と言いましたが、
それはつまり式におけるいい感じのaとbを決定することです。
このaやbにあたるものを**重み**といいます。
<font color="OrangeRed">**ニューラルネットワーク**</font>はこの**重み**を訓練データから自動で学習できるという性質を持っています。
<font color="OrangeRed">**ニューラルネットワーク**</font>は層を形成し、それは例えば以下のようになります。（よく見る図だと思います）

![neuralNW.png](https://qiita-image-store.s3.amazonaws.com/0/244596/df183b2e-f777-bb50-7ea3-1f646c0b16e2.png)
fig.1 ニューラルネットワーク概念図

一番左の入力層に**訓練データ**を入力します。すると自動的に計算が右に進んでいきます。
そして、一番右の出力層に結果が出力されます。
例えば入力層に年齢と体重を入力すると、何らかの演算の末に出力層から握力を出力します。
このとき、<font color="OrangeRed">**ニューラルネットワーク**</font>は全体として

```math
y = aA + bB
```
　　　　　　　　　　　　　　　　　　　　　　　y:握力、A:年齢、B:体重
のような式の役割をしているのです。
そして、本来ならば入力から出力をはじきだす式はこんなに単純であるハズはありません。
例えば以下のような式になるのかもしれません。

```math
y = \frac{ae^{ibA} + \sqrt{bA^2+aB^2} }{cosbA + isinaB}
```
　　　　　　　　　　　　　　　　　　　　　　　y:握力、A:年齢、B:体重

いや、ビビらなくて大丈夫です。これは適当ですから。
ですが、年齢と体重から握力を計算する式はこれよりかなり複雑な式になるでしょう。
ましてや、年齢と体重と身長と親の握力と運動頻度から握力を計算するとなるともっともっと複雑です。
複雑な式を自分で設定して、最適な重みをみつける。想像しただけでもう無理です。
そんなあなたに<font color="OrangeRed">**ニューラルネットワーク**</font>なのです。

## <font color="ForestGreen">**ニューラルネットワークを使うと何が嬉しいのか**</font>
さあ、あえてここで初めて<font color="OrangeRed">**ニューラルネットワーク**</font>とは何か定義を述べると、ただの計算モデルです。
しかしただの計算モデルといいつつもタダモノではないのです。
再び先ほどの図を示します。

![neuralNW.png](https://qiita-image-store.s3.amazonaws.com/0/244596/7169c6a7-4ed4-1248-c18a-eeda5e2e557d.png)
再掲 fig.1

入力層と出力層の間に層がありますよね。これを中間層（隠れ層）といい、これが複雑な式の役割を担うのです。
一つ一つは単純な演算にも関わらず、いくつも重ねることで、複雑な演算を表現することができます。
これが<font color="OrangeRed">**ニューラルネットワーク**</font>でモデルを構築する理由です。
<font color="OrangeRed">**ニューラルネットワーク**</font>の最高な点は、我々人間はもはや式すら意識する必要がないということです。
訓練データを入力し答え合わせして誤差を修正することを何度も何度も繰り返すことで、
最適なある重みを持った何らかの式が勝手に構築されるのです。
そしてその式などもはや我々は知る必要がありません。
入力から出力を高精度ではじき出してくれれば中身はどうでもいいのです。

ということで競馬予想に必要なのは、「適切な<font color="OrangeRed">**ニューラルネットワーク**</font>を実装した<font color="OrangeRed">**学習の仕組みを持つプログラム**</font>」です。

## <font color="ForestGreen">**ニューラルネットワークの学習の仕組み**</font>
それでは具体的にニューラルネットワークはどのように学習するのかを見ていきましょう。
学習とは一言で言うと、「重みを訓練データから自動的に決定する」ことです。
ステップで示すと以下の通りです。

**ステップ①:**ある重みからなるニューラルネットワークに**訓練データ[入力]**を入力する。
**ステップ②:**ニューラルネットワークは入力されたデータをある重みに基づいて**左から右**に演算し、出力する。
**ステップ③:**出力したデータと**訓練データ[出力]**を比較し、誤差を計算する。
**ステップ④:**誤差を基に**右から左**に演算し[^1]、重みをどれだけ変えると誤差が最も小さくなるかを計算する。
**ステップ⑤:**ステップ④を手掛かりに誤差を一番減らすように重みを少しだけ更新する。
**①～⑤を繰り返す**
繰り返した結果、訓練データの入力と出力の関係をうまく説明できる重みをもつニューラルネットワークが構築される。
[^1]: :eye:ここは難しいので次回詳しくやります
以上の流れとなります。
今後のために今の流れを専門用語に置き換えて言い直してみます。
同じことを言っているので、自分のものになるまで反芻してみてください。

**ステップ①:**ある重みからなるニューラルネットワークに**訓練データ[入力]**を入力する。
**ステップ②:**ニューラルネットワークは**順伝播**を行い、演算結果を出力する。
**ステップ③:**出力したデータと**教師データ（訓練データ[出力]）**を比較し、**損失関数**を計算する。
**ステップ④:****損失関数**を基に**逆伝播**し、**勾配**を計算する。
**ステップ⑤:****勾配方向**に重みを少しだけ更新する。
**①～⑤を繰り返す**
繰り返した結果、訓練データの入力と出力の関係をうまく説明できる重みをもつニューラルネットワークが構築される。

さあ、それではこの専門用語たちは実際どのような動作を表すのかを見ていきましょう。
しかし、ここまで結構長くやってきました。集中力はそんなに続きません。
この続きは次回にまわし、<font color="OrangeRed">**ニューラルネットワーク**</font>の回は全３回としましょう。

## <font color="ForestGreen">**まとめ**</font>
今回はニューラルネットワークの全体像をざっくりと説明しました。
そして１回で説明が終わるほど単純なものでもないし、しっかりと理解するためには理論を２回、実装を１回の
全３回構成が最低でも必要だと思いました。分かりやすく説明していくつもりなのでお付き合いください。
今回と次回で<font color="OrangeRed">**ニューラルネットワーク**</font>の仕組みはバッチリ！
と言えるようにするつもりです。
次回は以下の言葉を中心に説明していくつもりです。
**【活性化関数】**
**【順伝播】**
**【逆伝播】**
**【損失関数】**
**【勾配】**

せーの！:eye:サハスラーラ:eye:

:eye:理解しやすくするため、書籍とは違い、同じことを何度も記載することがあります。冗長に感じたらごめんなさい。