ゼロから作るDeepLearning #1 -急ブレーキ方向転換-

※以下の企画です

https://qiita.com/tatataichi/private/56936a028e625e62af8e

前回に続いてdjangoのpart2の続きをやっていきます…と言いたいところだったのですが、私の業務内容が来年から大きく変わる可能性があり、djangoは不要になる可能性が高まりました。
業務内容への還元を意図して勉強していたものだったので、継続する理由も薄まったので、業務にも活かせてかつ個人の興味にも関係する書籍に変更させていただこうと思います。

結論から言うと、**『ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装』** をやります。実はこれは一度読んでいるものですが、数年立っているので復習ということで…

https://www.oreilly.co.jp/books/9784873117584/

頑張っていきます〜

# 2章 パーセプトロン
いきなり2章から入るのですが、これは本書の1章が「Python入門」という内容であったためです。
『Pythonチュートリアル』もやったのでこれはスキップしようと思います。

## パーセプトロンで作る論理演算
### 単純パーセプトロン
パーセプトロンとは以下の式で考えられる、複数の信号を入力し一つの出力を得るもの。
いわばこの仕組みが深層学習の構成最小要素とも考えられ…るとか言い切っちゃうと多分違うんだろうな。
でも、多分それくらい基本的なこと。

```math
y = 
\left\{
\begin{array}{ll}
0 & (w_{1}x_{1} + w_{2}x_{2} \leqq \theta) \\

1 & (w_{1}x_{1} + w_{2}x_{2} > \theta)
\end{array}
\right.
```
$\theta$は閾値を表し、閾値を超えると出力が1になる（**発火する**とも表現する）。
$w_{n}$は重みで、上記の式は$x_{n}$の状態に重みを掛けて、総和を取った結果が閾値を超えているかどうかで出力が決まるというもの。

自分の頭の整理のためのアウトプットなので、多少分かりづらくても目をつぶってほしいすみません。

### AND回路
**AND回路**は論理回路の一つで、**すべての入力値が1なら1を出力して、それ以外は0になる**というもの。
表（論理値表ともいう）に表すと以下のようになる。
| $x_{1}$ | $x_{2}$ | y |
|:-:|:-:|:-:|
|  0 | 0  | 0  |
|  0 | 1  | 0  |
|  1 | 0  | 0  |
|  1 | 1  | 1  |

上表の組み合わせを2入力のパーセプトロンで表そうとするなら、$w_{1}=0.5,　w_{1}=0.5,　\theta=0.7$とかで考えられる。もちろんこれ以外にもたくさん当てはまるものがある。

では、これらをPythonで実装してみる。

```python:AND回路
def AND(x1, x2):
  w1, w2, theta = 0.5, 0.5, 0.7
  ans = x1*w1 + x2*w2
  if ans <= theta:
    return 0
  elif ans > theta:
    return 1
```
```python:実行結果
>> AND(0,1)
0

>> AND(0,1)
1
```

### バイアスの導入
バイアスは、**出力信号が1を出力しやすくするための調整数字**みたいなやつ。
バイアスは入力信号の総和を求めた後、閾値と比較をする前に加算される。

```math
w_{1}x_{1} + w_{2}x_{2} + b
```
上式の$b$がバイアス。
すなわち、バイアスが大きいとき、たとえば-20のような数字になると、入力値が$\theta + 20$を超えないと発火しなくなる。
実際に深層学習を行う際は、この重みとバイアスをいい感じに調整する必要が出てくる。

それでは、バイアスを先程のコードにも導入してみる。
ここで書籍の内容に従って、全体の記述方法を少し変える。具体的には`numpy`の配列を用いて、今後の拡張性を高めておく。

```python:バイアスの導入
import numpy as np

def AND(x1, x2):
  x = np.array([x1,x2])
  w = np.array([0.5, 0.5])
  b = -0.7
  ans = np.sum(w*x) + b
  if ans <= 0:
    return 0
  else:
    return 1
```
実行結果はあえて載せないが、全く同じ結果が返ってくる。

### NAND, ORの実装
論理回路のNAND回路とOR回路も実装していく。
NANDは**NOT-ANDのことで、ANDの真理値表をすべてひっくり返したもの**。
| $x_{1}$ | $x_{2}$ | y |
|:-:|:-:|:-:|
|  0 | 0  | 1  |
|  0 | 1  | 1  |
|  1 | 0  | 1  |
|  1 | 1  | 0  |

OR回路は、**入力値のうち、片方が1なら出力も1**というもの。
| $x_{1}$ | $x_{2}$ | y |
|:-:|:-:|:-:|
|  0 | 0  | 0  |
|  0 | 1  | 1  |
|  1 | 0  | 1  |
|  1 | 1  | 1  |

それぞれコードに起こしてみる。

```Python:NAND
def NAND(x1, x2):
  x = np.array([x1,x2])
  w = np.array([-0.5, -0.5])
  b = 0.7
  ans = np.sum(w*x) + b
  if ans <= 0:
    return 0
  else:
    return 1
```
```Python:OR
def OR(x1, x2):
  x = np.array([x1,x2])
  w = np.array([0.5, 0.5])
  b = -0.2
  ans = np.sum(w*x) + b
  if ans <= 0:
    return 0
  else:
    return 1
```
真理値表に当てはめてみて辻褄があうのであれば、重みとバイアスの値は上記に固執する必要はない。

## 単純パーセプトロンの限界
単純パーセプトロンではANDやOR、NANDなどは表せても、XORという回路は表現できない。
これは、かっこよく言うと **「線形」は表現できても「非線形」は表現できない**みたいな感じになる。

本書に従ってOR回路を例えに出すと、真理値表は以下の通りで
| $x_{1}$ | $x_{2}$ | y |
|:-:|:-:|:-:|
|  0 | 0  | 0  |
|  0 | 1  | 1  |
|  1 | 0  | 1  |
|  1 | 1  | 1  |

これを2次元平面にプロットすると考えると、点 (0, 0) は出力 0グループ、それ以外の点は出力 1グループ みたいに分類して考える。
これらは0と1の間に直線1本を引くことで分けることが可能（たとえば、x + y = 0.5 という直線を引けば、片側が 0、もう片側が 1 になる）。
直線で入力・出力の関係をきっちりわけられるものは「**線形**」であるという。


一方で、XOR回路は以下のような真理値表となっており
| $x_{1}$ | $x_{2}$ | y |
|:-:|:-:|:-:|
|  0 | 0  | 0  |
|  0 | 1  | 1  |
|  1 | 0  | 1  |
|  1 | 1  | 0  |

これを同様に2次元平面にプロットすることを考えると、出力 0グループ の点 (0, 0) と (1, 1) が対角線上に、出力 1グループ の点 (0, 1) と (1, 0) が逆の対角線上に位置する。
これらを1本の直線できっちり分けることは不可能で、曲線や複数の直線が必要になる。
この状態のことを「**非線形**」という。

ということで、非線形なものは単純パーセプトロンでは表現できないので、**多層パーセプトロン**というものが必要になる。

### 多層パーセプトロン
論理演算の細かい話になってしまうので、今回は端折るが、XORはNANDとORとANDを組み合わせることで表現することができる。
入力値をNANDとORで受けて、それらの結果を集約してANDに入力するというイメージ。
二段階の入力・出力構造であることからも「**"多層"パーセプトロン**」という言葉のイメージは容易にできる。

色々スキップしているが、早速Pythonでコードを書いてみる。

```python:XOR
import numpy as np

def XOR(x1, x2):
  s1 = NAND(x1, x2)
  s2 = OR(x1, x2)
  y = AND(s1, s2)
  return y
```
```python:出力結果
print(XOR(0,0))
print(XOR(0,1))
print(XOR(1,0))
print(XOR(1,1))

0
1
1
0
```

できた！
S1とS2が一層目のパーセプトロンの出力結果、yが二層目の結果ということで、多層パーセプトロンであると言える。

# まとめ
急遽書籍変更したが、めちゃくちゃ楽しい内容なのでいい感じ。
1回読了しているが、直近ニューラルネットワークに関わることも増えてきたので、非常によい復習になると思う。
さすがにパーセプトロンの内容だけだとまだまだアレだけど。
次回もやっていきます〜〜