パーセプトロンについて

## パーセプトロンについて
今回はパーセプトロンについて共有していきます。
私が調べて学習した範囲なので、抜けている点や疑問点があるかもしれませんが、そこは各々調べてもらえたらと思います。

## パーセプトロンとは
- 複数の信号を入力として、1つの信号を出力する
- 出力は信号を流す(1)か流さない(0)の二値分類になる
- 閾値を超えるか否かで出力信号が決まる

step関数
![スクリーンショット 2021-02-17 20.42.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057107/3980273a-0121-9aee-812c-f52192a9507f.png)

## パーセプトロンとニューラルネットワークの違い
**活性化関数がstep関数で計算するものをパーセプトロンと呼ぶ。**

![スクリーンショット 2021-04-19 15.44.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057107/4e6a231d-a739-9439-8a38-51cd9567218e.png)

一方で、**活性化関数がstep関数以外で計算するものをニューラルネットワークと呼びます。**

## ANDゲート
**二値の条件を満たしている時(Trueの時)出力することができます。**

![スクリーンショット 2021-04-19 15.46.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057107/37c84e2b-bc60-57b5-2509-fb118c3edbc3.png)

![スクリーンショット 2021-04-19 15.44.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057107/077c23c8-a804-8fbc-f77b-e997e7178c50.png)

## NANDゲートとORゲート
**NANDゲート**
**二値の条件を満たしていない時にTrueになるのがNANDゲートです。**<br>
**逆に二値の条件を満たしている時はFalseになる。**<br>
**NADゲートはANDゲートの逆のゲートです。**

![スクリーンショット 2021-04-19 15.47.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057107/b3e0c282-677a-0510-7e71-b74fd829fa43.png)

**ORゲート**
**二値の条件のうちどちらかが満たしている(True)ならば出力することができます。**

![スクリーンショット 2021-04-19 15.49.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057107/ef913461-25aa-1ac4-8daa-4eefa726baf5.png)


![スクリーンショット 2021-04-19 15.49.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057107/47d7f238-732c-09e9-9ed0-205c9ac1b893.png)

## パーセプトロンの実装
では、ANDゲートから実装していきましょう。

```python:qiita.py
# ANDゲート
# まずは定義します

$ def AND(x0, x1):
    w0, w1, theta = 0.5, 0.5, 0.8
    tmp = x0*w0 + x1*w1
    if tmp <= theta:
        return 0
    elif tmp > theta:
        return 1
```

定義した関数を使ってみます！

```pyhton:qiita.py
$ AND(0, 0)
# 0

$ AND(1, 0)
# 0

$ AND(0, 1)
# 0

$ AND(1, 1)
# 1
```

はい。定義通りの結果を得ることができました。
ソースコード上にあるようにこれは簡単ですね。


次にNANDゲートを定義して使用してみましょう！

```python:qiita.py
# NANDゲート

$ def NAND(x0, x1):
    w0, w1, theta = -0.5, -0.5, -0.8
    tmp = x0*w0 + x1*w1
    if tmp <= theta:
        return 0
    elif tmp > theta:
        return 1
```

次に使用してみます。

```python:qiita.py
$ NAND(0, 0)
# 1

$ NAND(1, 0)
# 1

$ NAND(0, 1)
# 1

$ NAND(1, 1)
# 0
```

NANDゲートはANDゲートと逆の結果になるので、
定義通りに使用することができました！


次にORゲートにいきます！

```python:qiita.py
# ORゲート

$ def OR(x0, x1):
    w0, w1, theta = 1.0, 1.0, 0.8
    tmp = x0*w0 + x1*w1
    if tmp <= theta:
        return 0
    elif tmp > theta:
        return 1
```

使用します！

```python:qiita.py
$ OR(0, 0)
# 0

$ OR(1, 0)
# 1

$ OR(0, 1)
# 1

$ OR(1, 1)
# 1
```

簡単ですね。
次はバイアスを追加して定義して使用していきます！

```python:qiita.py
# 定義
# 重みとバイアスの導入

import numpy as np

x = np.array([0, 1, 2])
w = np.array([0.5, 0.5, 0.5])
b = -0.8
```

```python:qiita.py
# 重み付き入力
$ x*w
# array([0. , 0.5, 1. ])

# 重み付き入力の合計
$ np.sum(x*w)
# 1.5

# y = wx + b
$ np.sum(x*w)+b
# 0.7
```

皆さん理解しているかと思いますが、
上記のソースコードを基本としてANDとNAND、ORゲートをバイアスを追加して定義、使用していきます！

```python:qiita.py
# バイアスの追加
# ANDゲート

$ def AND(x0, x1):
    x = np.array([x0, x1])
    w = np.array([0.5, 0.5])
    b = -0.8
    tmp = np.sum(x*w) + b
    if tmp <= 0:
        return 0
    else:
        return 1

for xs in [(0, 0), (1, 0), (0, 1), (1, 1)]:
    y = AND(xs[0], xs[1])
    print(str(xs) + '->' + str(y))

# 出力結果
# (0, 0)->0
# (1, 0)->0
# (0, 1)->0
# (1, 1)->1
```

次にNANDゲートです！

```python:qiita.py
$ def NAND(x0, x1):
    x = np.array([x0, x1])
    w = np.array([-0.5, -0.5])
    b = 0.8
    tmp = np.sum(x*w)+b
    return np.where(tmp <= 0, 0, 1)

for xs in [(0, 0), (1, 0), (0, 1), (1, 1)]:
    y = NAND(xs[0], xs[1])
    print(str(xs) + '->' + str(y))

# 出力結果
# (0, 0)->1
# (1, 0)->1
# (0, 1)->1
# (1, 1)->0
```

次にORゲートです！


```python:qiita.py
$ def OR(x0, x1):
    x = np.array([x0, x1])
    w = np.array([1.0, 1.0])
    b = -0.8
    tmp = np.sum(x*w)+b
    return np.where(tmp <= 0, 0, 1)

for xs in [(0, 0), (1, 0), (0, 1), (1, 1)]:
    y = OR(xs[0], xs[1])
    print(str(xs) + '->' + str(y))

# 出力結果
# (0, 0)->0
# (1, 0)->1
# (0, 1)->1
# (1, 1)->1
```

## XORゲート
**NANDとOR、ANDを組み合わせた既存ゲートの組み合わせを多層パーセプトロンと言い、<br>
本来パーセプトロンでは非線形回帰は表示できないが、<br>
XORゲートは多層パーセプトロンで表示できます。<br>** 

![スクリーンショット 2021-04-19 17.55.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057107/b4013426-8079-0bfe-f09c-d96d5663ec01.png)


**通常の線形回帰では結果が(1, 0), (0, 1), (1, 1)の時は1を出力し、(0, 0)の時は0を出力する。**<br>
**非線形回帰では結果が(1, 0), (0,1)の時は1を出力し、(0, 0), (1, 1)の時は0を出力する。**


```python:qiita.py
$ def XOR(x0, x1):
    s0 = NAND(x0, x1)
    s1 = OR(x0, x1)
    y = AND(s0, s1)
    return y

for xs in [(0, 0), (1, 0), (0, 1), (1, 1)]:
    z = XOR(xs[0], xs[1])
    print(str(xs) + '->' + str(z))

# 出力結果
# (0, 0)->0
# (1, 0)->1
# (0, 1)->1
# (1, 1)->0
```


以上の結果からパーセプトロンは層を重ねるとより柔軟な表現ができるようになると思います！
XORゲートは非線形で比例しないので、ANDとNAND、ORゲートを合わせて、多層パーセプトロン(ニューラルネットワーク)を作成することで柔軟な表現ができるようなります。

## 最後に
今回はパーセプトロンを共有しました！
次回も機械学習をメインに投稿していきます。