「ゼロから作るDeep Learning」自習メモ（その２）２章 パーセプトロン、半加算器、全加算器


「ゼロから作るDeep Learning」(斎藤 康毅　著　オライリー・ジャパン刊)を読んでいる時に、参照したサイト等をメモしていきます。　[その１](https://qiita.com/slow_learner/items/8272450c2b876fdc690c)←　→[その３](https://qiita.com/slow_learner/items/9447c5717d52d3e60930)

この本では、「ゼロから」作るために、pythonの基礎やパーセプトロンとか、土台からきちんと説明されています。
ただ、そのせいで、最初のうちは自分が何を作ろうとしているのか、わからなくなったりします。
結局、あ、そういうこと？　と腑に落ちたのは、P86の図と説明を読んでからでした。
>![kankyou6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686010/4db678ff-7c08-80dc-1e2b-529e84d4fcd4.jpeg)

私みたいな古い人間は、「過去のデータを分析して」となると、回帰分析とかの手法をプログラムで組んで係数を計算させて、それを使って答えを出して、なんて感じで、アルゴリズムは人間が与えて、コンピュータは計算するだけでした。
しかし、ニューラルネットワークやディープラーニングは「データ駆動」であり、
>ニューラルネットワークの利点は、すべての問題を同じ流れで解くことができる点にあります。たとえば、解くべき問題が「5」を認識する問題なのか、「犬」を認識する問題なのか、それとも、「人の顔」を認識する問題なのかといった詳細とは関係なしに、ニューラルネットワークは与えられたデータをただひたすら学習し、与えられた問題のパターンを発見しようと試みます。

どうしてそのようなことが可能になるのかというのが、この本には説明されているわけで、
それが、パーセプトロンであり、それを発展させたニューラルネットワークであり、その動作を行列で記述すると簡単に表現でき、しかもpythonのライブラリNumPyを使うと、プログラムもそのまま簡潔に記述できる、ということなわけです。

##２．パーセプトロン、半加算器、全加算器

パーセプトロンについての説明は、特に難しいわけではありません。
しかし、パーセプトロンの重みとバイアスを変えると、ANDやORの論理回路を作れるということには驚きました。


が

素直にその先に行けないのが、年寄りの悪いところ。
昔の情報処理概論では、論理回路が真っ先にあって、そこから半加算器、全加算器の説明があるのがお決まりでした。

なので、この本では省略されている半加算器、全加算器をpythonで実装してみます。

>P32の図
![p32.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686010/ec4a5116-dde9-a4d7-bab2-fcd87713792e.jpeg)

なぜか、XORゲートの記号が載せてありません。
![p32xor.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686010/a1af353d-271e-2c9d-83d6-21a99a4d6307.jpeg)
　XOR

```python
import numpy as np

def perceptron(x1, x2, w1, w2, b):
    tmp = w1*x1 + w2*x2 + b
    if tmp <= 0:
        return 0
    else:
        return 1

def AND(x1, x2):
    return perceptron(x1, x2, 0.5, 0.5, -0.7)
    
def NAND(x1, x2):
    return perceptron(x1, x2, -0.5, -0.5, 0.7)

def OR(x1, x2):
    return perceptron(x1, x2, 0.5, 0.5, -0.2)

def XOR(x1, x2):
    s1 = NAND(x1, x2)
    s2 = OR(x1, x2)
    y = AND(s1, s2)
    return y
```
で、これらを組み合わせて、半加算器
![p32han.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686010/80f24d4d-757d-86d5-a4dc-068d4297a34a.jpeg)

```python
# 半加算器 half adder
def HA(a, b):
    s = XOR(a, b)
    c = AND(a, b)
    return c, s
```
全加算器
![p32zen.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686010/40008fe8-21ee-c1a8-8982-c679be8ff247.jpeg)

```python
# 全加算器 full adder
def FA(a, b, c1):
    c2, s2 = HA(a, b)
    c3, s3 = HA(s2, c1)
    c4 = OR(c2,c3)
    return c4, s3
```

４ビット（０～１５）の足し算をする計算機

```python
def fourALU(a,b):
    c0, s0 = HA(a[0],b[0])
    c1, s1 = FA(a[1],b[1], c0)
    c2, s2 = FA(a[2], b[2], c1)
    c3, s3 = FA(a[3], b[3], c2)
    y = np.array([s0, s1, s2, s3, c3])
    return y

# 10進数を２進数にして配列に格納して戻す。
# ただし、下１桁目から格納するので、左右が逆になる
def i2arr(a):
    if a < 0:
        print(a," 加算範囲外")
        aa = np.array([0, 0, 0, 0])
    elif a > 15:
        print(a," 加算範囲外")
        aa = np.array([1, 1, 1, 1])
    else:
        a3 = a // 8
        m  = a % 8
        a2 = m // 4
        m  = m % 4
        a1 = m // 2
        a0 = m % 2
        aa = np.array([a0, a1, a2, a3])
    return aa

a = 4
b = 9
aa = i2arr(a)
ba = i2arr(b)
y = fourALU(aa, ba)
print(aa)
print(ba)
print(y)
print(a,"+",b,"=",y[0]+y[1]*2+y[2]*4+y[3]*8+y[4]*16)
```
実行結果は

```python
[0 0 1 0]
[1 0 0 1]
[1 0 1 1 0]
4 + 9 = 13
```

[その１](https://qiita.com/slow_learner/items/8272450c2b876fdc690c)←　→[その３](https://qiita.com/slow_learner/items/9447c5717d52d3e60930)

[読めない用語集](https://qiita.com/slow_learner/items/03eb3367119e98b5a22c)