ゼロから作る DeepLearning(Go) Part.2 ~ パーセプトロン ~
はじめに
こんにちは。みです。
これは、「ゼロから作る DeepLerning ①」を Python ではなく、GO を使用してまとめてみた内容です。
参考:ゼロから作る DeepLerning ①
良ければご覧ください。
****↓ 前回はこちら ↓****
前回:ゼロから作る DeepLearning(Go) Part.1
***************
目次
- Python 入門(GO での代用)
- パーセプトロン ← 今回はこちら ★
- ニューラルネットワーク
- ニューラルネットワークの学習
- 誤差逆伝播法
- 学習に関するテクニック
- 畳み込みニューラルネットワーク
- ディープラーニング
パーセプトロン
2.1 パーセプトロンとは
「人口ニューロン」、「単純パーセプトロン」と呼ばれるもの。
複数の信号を入力として受け取り、一つの信号を出力する。
信号とは、電流や川の持つ、「流れ」のイメージ。
電流が同船を流れ、電子を策に送り出すように、パーセプトロンの信号も流れを作り、情報を先へと伝達していく。
二つの信号を受け取るパーセプトロンの例
$x_1,x_2$は入力信号。
$w_1,w_2$は重み。(w は weight の頭文字。)
図の〇は、「ニューロン」や「ノード」と呼ばれます。
入力信号は、ニューロンに送られる際その固有の重みが乗算される。($w_1x_1,w_2x_2$)
ニューロンでは、送られてきた信号の総和が計算される。
→ その結果ある限界値を超えた場合にのみ、1を出力する。
この限界値を閾値(いきち)と呼び、$\theta$で表す。
以上のことを数式で表すと以下のようになる。
二つの信号を受け取るパーセプトロンの数式
$$
y=
\begin{cases}
0\quad(w_1x_1 + w_2x_2 \leqq\theta) \
1\quad(w_1x_1 + w_2x_2 >\theta)
\end{cases}
$$
パーセプトロンは、複数ある信号のそれぞれに重みを持つ。
重みは、各信号の重要性をコントロールする要素である。
$w_1 > w_2 $の時、$w_1$の信号の重要性は高くなる。
2.2 単純な論理回路
2.2.1 AND ゲート
AND ゲートとは、2 つの入力が 1 のときのみ 1 を出力する。
AND ゲートの真理値表
$x_1$ | $x_2$ | y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
2.2.2 NAND ゲートと OR ゲート
NAND ゲートとは、NOT AND を意味する。
AND ゲートを逆にしたもの。
NAND ゲートの真理値表
$x_1$ | $x_2$ | y |
---|---|---|
0 | 0 | 1 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
OR ゲートは、入力信号が少なくとも一つでも 1 があれば、1 を出力する。
OR ゲートの真理値表
$x_1$ | $x_2$ | y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
2.3 パーセプトロンの実装
2.3.1 簡単な実装
ANDゲートの実装
func And(x1 float64, x2 float64) {
fmt.Printf("x1 = %g,x2 = %g\n", x1, x2)
w1, w2, theta := 0.5, 0.5, 0.7
tmp := x1*w1 + x2*w2
fmt.Printf("result:")
if tmp <= theta {
fmt.Println(0)
} else {
fmt.Println(1)
}
}
func main(){
And(0, 0) //0を出力
And(1, 0) //0を出力
And(0, 1) //0を出力
And(1, 1) //1を出力
}
結果
$ go run main.go
x1 = 0,x2 = 0
result:0
x1 = 1,x2 = 0
result:0
x1 = 0,x2 = 1
result:0
x1 = 1,x2 = 1
result:1
2.3.2 重みとバイアス導入
AND ゲートは単純なので、実装が簡単でしたが、別の実装方法に変更する。
$\theta$→-b (バイアス)に変更する。
変更後パーセプトロンの数式
$$
y=
\begin{cases}
0\quad(b + w_1x_1 + w_2x_2 \leqq0) \
1\quad(b + w_1x_1 + w_2x_2 >0)
\end{cases}
$$
2.3.3 重みとバイアスによる実装
$\theta$を b に変更し、gonum を使用して AND,NAND,OR ゲートを実装する。
ANDゲートの実装
func (p *perceptron) And(x1 float64, x2 float64) float64 {
x := mat.NewDense(1, 2, []float64{x1, x2})
w := mat.NewDense(1, 2, []float64{0.5, 0.5})
b := -0.7
tmp := mat.Sum(p.calc.MulElem(x, w)) + b
if tmp <= 0 {
return 0
} else {
return 1
}
}
fmt.Println("AND")
fmt.Println(m.p.And(0, 0)) //0を出力
fmt.Println(m.p.And(0, 1)) //0を出力
fmt.Println(m.p.And(1, 0)) //0を出力
fmt.Println(m.p.And(1, 1)) //1を出力
結果
$ go run main.go
AND
0
0
0
1
NANDゲートの実装
func (p *perceptron) NotAnd(x1 float64, x2 float64) float64 {
x := mat.NewDense(1, 2, []float64{x1, x2})
w := mat.NewDense(1, 2, []float64{-0.5, -0.5})
b := 0.7
tmp := mat.Sum(p.calc.MulElem(x, w)) + b
if tmp <= 0 {
return 0
} else {
return 1
}
}
fmt.Println("NAND")
fmt.Println(m.p.NotAnd(0, 0)) //1を出力
fmt.Println(m.p.NotAnd(0, 1)) //1を出力
fmt.Println(m.p.NotAnd(1, 0)) //1を出力
fmt.Println(m.p.NotAnd(1, 1)) //0を出力
結果
$ go run main.go
NAND
1
0
0
0
ORゲートの実装
func (p *perceptron) Or(x1 float64, x2 float64) float64 {
x := mat.NewDense(1, 2, []float64{x1, x2})
w := mat.NewDense(1, 2, []float64{0.5, 0.5})
b := -0.2
tmp := mat.Sum(p.calc.DivElem(x, w)) + b
if tmp <= 0 {
return 0
} else {
return 1
}
}
fmt.Println("OR")
fmt.Println(m.p.Or(0, 0)) //0を出力
fmt.Println(m.p.Or(0, 1)) //1を出力
fmt.Println(m.p.Or(1, 0)) //1を出力
fmt.Println(m.p.Or(1, 1)) //1を出力
結果
$ go run main.go
OR
0
1
1
1
2.4 パーセプトロンの限界
パーセプトロンを用いれば、三つの論理回路を実装することができた。
2.4.1 XOR ゲート
XOR ゲート「排他的論理和」と呼ばれる論理回路。
$x_1$と$x_2$のどちらかが 1 の時だけ、1 が出力されます。
(排他的とは、自分以外は拒否することを意味する。)
これは、これまでのパーセプトロンでは、実現できない。
XOR ゲートの真理値表
$x_1$ | $x_2$ | y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
AND、OR ができて、XOR が実現できない理由を視角的に考えてみます。
OR ゲートの視角的挙動
重み・パラメーター(b,$w_1$,$w_2$)=(-0.5,1.0,1.0)
式:
$$
y=
\begin{cases}
0\quad(-0.5 + x_1 + x_2 \leqq0) \
1\quad(-0.5 + x_1 + x_2 >0)
\end{cases}
$$
この式は、$ -0.5 + x_1 + x_2 = 0$の直線で分断された二つの領域を作成する。
図に表すと以下のようになる。
※図は大雑把なイメージです。
$(x_1,x_2) = (0,0)$の時 0(〇)
$(x_1,x_2) = (0,1),(1,0),(1,1)$の時 1(△)
すべて直線によって正しく分けることができる。
2.4.2 線形と非線形
XOR ゲートは、先の OR ゲートのように 1 本の直線では表すことができません。
※直線という制約をなくせば表すことができる。
図に表すと以下のようになる。
※図は大雑把なイメージです。
パーセプトロンの限界は、1 本の直線で分けた領域だけしか表現できない点。
XOR ゲートの図のようなく曲線はパーセプトロンでは表現できない。
曲線による領域を非線形、直線による領域を線形と呼ぶ。
2.5 多層パーセプトロン
パーセプトロンは、層を重ねることで非線形を表現できるようになる!
2.5.1 既存ゲートの組み合わせ
XOR ゲートの表現を AND、NAND、OR を使用して表現してみる。
上記の図が本当に XOR を実現できているのか真偽値表を埋めてみます。
XOR ゲートの真理値表
$x_1$ | $x_2$ | $s_1$ | $s_2$ | y |
---|---|---|---|---|
0 | 0 | 1 | 0 | 0 |
0 | 1 | 1 | 1 | 1 |
1 | 0 | 1 | 1 | 1 |
1 | 1 | 0 | 1 | 0 |
$x_1$、$x_2$、y に着目してみると、XOR ゲートの出力になっています。
2.5.2 XOR ゲートの実装
先ほどの XOR ゲートを Go で実装してみます。
func (p *perceptron) XOr(x1 float64, x2 float64) float64 {
s1 := p.NotAnd(x1, x2)
s2 := p.Or(x1, x2)
y := p.And(s1, s2)
return y
}
fmt.Println("XOR")
fmt.Println(m.p.XOr(0, 0)) //0を出力
fmt.Println(m.p.XOr(0, 1)) //1を出力
fmt.Println(m.p.XOr(1, 0)) //1を出力
fmt.Println(m.p.XOr(1, 1)) //0を出力
結果
$ go run main.go
XOR
0
1
1
0
今回作成した XOR は多層構造になったネットワークでした。
層を複数重ねたパーセプトロンを多層パーセプトロンという
※AND、OR などは単層のパーセプトロン
2.6 NAND からコンピューターへ
多層パーセプトロンは、これまでの回路より複雑な回路を作成できる。
例)
- 足し算を行う加算器
- 2 進数を 10 進数に変換するエンコーダ
- パリティチェック用の回路
- コンピュータ
コンピュータの処理は、NAND ゲートの組み合わせだけで再現できる = パーセプトロンでも、コンピュータを表現できるということ。
2.7 まとめ
パーセプトロンはシンプルなので理解事態はしやすいものでした。
コンピュータのような複雑そうな処理をしているものが、意外とパーセプトロンを組み合わせるだけでできるとは驚きでした。。。
パーセプトロン、奥が深いです。