読者です 読者をやめる 読者になる 読者になる

Miyamoのブログ

技術ブログ(にしたい)

ゼロから作るDeep Learning 2章「パーセプトロン」

前:ゼロから作るDeep Learning 1章「Python入門」

前回に続いて,ゼロから作るDeep Learning Pythonで学ぶディープラーニングの理論と実装の2章「パーセプトロン」を進めていく.

f:id:miyamo765:20170426230335j:plain

 

1.パーセプトロンとは

人間の脳は神経細胞ニューロン)のネットワークで構成されている.これらを模倣した様々なアルゴリズムが提案されており,パーセプトロンはその初期段階の一つ.形式ニューロンに基づいており,1957年にアメリカのRosenblattによって考案された.

複数の入力に対してそれぞれの重みを掛け,その総和がある限界値を超えた場合に1を出力する.これを「ニューロンが発火する」と表現することもある.

f:id:miyamo765:20170425180106p:plain

限界値を閾値と呼び,{ \displaystyleθ}と表現することにすると,出力は以下の数式で表される.

{ \displaystyle y = \begin{cases}0 \, (w_1x_1 + w_2x_2 \le θ )\\1 \, (w_1x_1 + w_2x_2 > θ ) \end{cases}} \tag{1} \label{1}  

大なり記号の表示がうまくいかない…

それぞれの重みは固有であり,各信号の重要性をコントロールする

・重み大:重要性大

・重み小:重要性小

様々な入力とそれらに対する希望の出力を用意し, 様々な入力を試して出力が希望の値となるように重みを変更していくことで,学習が行われる(教師あり学習).

 

2.論理回路

論理回路を題材としてパーセプトロンを用いた問題を考える.

2.1 ANDゲート

x1 x2 y
0 0 0
0 1 0
1 0 0
1 1 1

上の真理値表を満たすように,{ \displaystyle w_1}{ \displaystyle w_2}{ \displaystyle θ}の値を設定することでANDゲートをパーセプトロンで表現する.値の選び方は無限にあり,例としては

{ \displaystyle (w_1, w_2, θ) = (0.5, 0.5, 0.7)}{ \displaystyle (w_1, w_2, θ) = (1.0, 1.0, 1.5)}

などが考えられる.このようにパラメータを設定することで,{ \displaystyle x_1}{ \displaystyle x_2}の両方が1のときだけ,{ \displaystyle y}閾値{ \displaystyle θ}を上回り,ANDゲートとして動作する.

 

2.2 NANDゲート

次にNANDゲートを考える. 

x1 x2 y
0 0 1
0 1 1
1 0 1
1 1 0

NANDゲートはANDゲートの出力を反転したものであるから,パラメータはANDゲートで設定した値の符号を反転することで実現できる.

{ \displaystyle (w_1, w_2, θ) = (-0.5, -0.5, -0.7)}{ \displaystyle (w_1, w_2, θ) = (-1.0, -1.0, -1.5)}

などである.

 

2.3 ORゲート

x1 x2 y
0 0 0
0 1 1
1 0 1
1 1

1

ORゲートのパラメータは以下のようなものが考えられる.

{ \displaystyle (w_1, w_2, θ) = (1.0, 1.0, 0.5)}{ \displaystyle (w_1, w_2, θ) = (0.5, 0.5, 0.2)} 

 

以上のように,パーセプトロンでAND,NAND,ORという論理回路を表現できることがわかった.パーセプトロンの構造は変えずに,パラメータの値を変えるだけで実現できたということが重要.機械学習では,パラメータの値を決める作業をコンピュータに自動で行わせる.

 

3.パーセプトロンの実装

PythonでANDを実装してみる.

import numpy as np

def AND(x1, x2):
	w1, w2, theta = 0.5, 0.5, 0.7
	tmp = x1*w1 + x2*w2
	if tmp <= theta:
		return 0
	elif tmp > theta:
		return 1
 		
x = np.array([AND(0, 0), AND(0, 1), AND(1, 0), AND(1, 1)])
print(x)

実行してみる.

$ python AND.py 
[0 0 0 1]

ANDゲートの出力となっていることがわかる.

ここで,式\eqref{1}において{ \displaystyle θ}{ \displaystyle -b}として,実装方式を以下のように修正する.

{ \displaystyle y = \begin{cases}0 \, (b + w_1x_1 + w_2x_2 \le 0)\\1 \, (b + w_1x_1 + w_2x_2 > 0) \end{cases}} \tag{2} \label{2}  

{ \displaystyle b}バイアス{ \displaystyle w_1}{ \displaystyle w_2}重みと呼ぶ.式\eqref{2}より,パーセプトロンでは入力信号に重みが乗算された値とバイアスの和が計算され,その値が0を上回れば1を出力(発火)し,そうでなければ0を出力することがわかる.

NumPyを用いて式\eqref{2}の方式でANDを実装してみる.

import numpy as np

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

x = np.array([AND(0, 0), AND(0, 1), AND(1, 0), AND(1, 1)])
print(x)

実行してみる.

$ python AND2.py 
[0 0 0 1]

ANDゲートの出力となっていることがわかる.

続いてNANDゲートとORゲートを実装して実行してみる.

import numpy as np

def NAND(x1, x2):
	x = np.array([x1, x2])
	w = np.array([-0.5, -0.5])	#重みとバイアスのみ変更
	b = 0.7
	tmp = np.sum(w*x) + b
	if tmp <= 0:
		return 0
	else:
		return 1
		
x = np.array([NAND(0, 0), NAND(0, 1), NAND(1, 0), NAND(1, 1)])
print(x)
$ python NAND.py 
[1 1 1 0]

NANDゲートの出力となっていることがわかる.

import numpy as np

def OR(x1, x2):
	x = np.array([x1, x2])
	w = np.array([1.0, 1.0])	#重みとバイアスのみ変更
	b = -0.5
	tmp = np.sum(w*x) + b
	if tmp <= 0:
		return 0
	else:
		return 1
		
x = np.array([OR(0, 0), OR(0, 1), OR(1, 0), OR(1, 1)])
print(x)
$ python OR.py
[0 1 1 1]

ORゲートの出力となっていることがわかる.

AND,NAND,ORが同じ構造のパーセプトロンであることは既に述べたが,実装においても重みとバイアスの値の設定箇所のみが異なることからそれがわかる.

 

4.パーセプトロンの限界

XORゲート(排他的論理和)について考える.

x1 x2 y
0 0 0
0 1 1
1 0 1
1 1

0

XORは今までのパーセプトロン(単層パーセプトロン)では実現できない.

理由をORゲートの挙動と比較して視覚的に考える.

ORゲートの重みパラメータが{ \displaystyle (b, w_1, w_2) = (-0.5, 1.0, 1.0)}のとき,パーセプトロンの式は次のようになる.

{ \displaystyle y = \begin{cases}0 \, (-0.5 + x_1 + x_2 \le 0)\\1 \, (-0.5 + x_1 + x_2 > 0) \end{cases}} \tag{3} \label{3}  

式\eqref{3}で表されるパーセプトロン{ \displaystyle -0.5 + x_1 + x_2 = 0}の直線で分断された領域を作る.つまり,0と1が直線によって分けられる(●が0,▲が1).

f:id:miyamo765:20170426224442p:plain

(Matplotlibでグラフ作ろうとしたけどよくわからなかったのでgnuplot入れてみたけど使い方がよくわからないので結局パワポで作ったゴミ)

続いて,XORゲート.

f:id:miyamo765:20170426224533p:plain

1と0を直線によって分けることはどうやってもできない.このように,1本の直線で分けた領域しか表現できないのが,パーセプトロンの限界である.しかし,曲線だと分けることができる.

f:id:miyamo765:20170426224554p:plain

曲線の塗りつぶし方わかんね.

直線による領域を線形な領域,曲線による領域を非線形な領域と言う.

 

 

5.多層パーセプトロン

単層パーセプトロンではXORを表現できなかったが,”層を重ねる”ことでXORが表現できる.

まず,XORを既存ゲートを組み合わせて表現してみる.

真理値表より,XORは「{ \displaystyle x_1}{ \displaystyle x_2}どちらかは1かつ両方が1でないとき」に1をとる.つまり,

{ \displaystyle x_1 \, XOR \, x_2 \, =  \, (x_1 \, OR \, x_2) \,\, AND \,\, (x_1 \, NAND \, x_2)}

とAND,NAND,ORを用いて表現できる.つまり,「パーセプトロンの出力を別のパーセプトロンの入力にする」というやり方で実装することができる({ \displaystyle s_1}がOR,{ \displaystyle s_2}がNANDで最後がAND).

f:id:miyamo765:20170426225328p:plain

ANDやORが単層パーセプトロンであったのに対して,XORは2層のパーセプトロンになっている.このように,層を複数重ねたパーセプトロンのことを多層パーセプトロン(multi-layered perceptron)と呼ぶ.

単層パーセプトロンでは実現できなかったことが,層を増やすことによって実現できるようになったと解釈できる.つまり,層を重ねることで柔軟な表現が可能になり,非線形な問題も解けるようになったと言える.

実装して実行してみる.

import numpy as np

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

def NAND(x1, x2):
	x = np.array([x1, x2])
	w = np.array([-0.5, -0.5])
	b = 0.7
	tmp = np.sum(w*x) + b
	if tmp <= 0:
		return 0
	else:
		return 1
		
def OR(x1, x2):
	x = np.array([x1, x2])
	w = np.array([1.0, 1.0])
	b = -0.5
	tmp = np.sum(w*x) + b
	if tmp <= 0:
		return 0
	else:
		return 1

def XOR(x1, x2):
	s1 = OR(x1, x2)
	s2 = NAND(x1, x2)
	y = AND(s1, s2)
	return y
	
x = np.array([XOR(0, 0), XOR(0, 1), XOR(1, 0), XOR(1, 1)])
print(x)
$ python XOR.py 
[0 1 1 0]

XORの出力が得られていることがわかる.

 

6.NANDからコンピュータへ

多層パーセプトロンにより,より複雑な回路(加算器やエンコーダなど)も実現できる.

コンピュータはNANDゲートの組み合わせによって再現可能であり,NANDゲートはパーセプトロンによって再現可能であるから,(理論上)パーセプトロンによってコンピュータが行う処理も表現することができる.

 

 

参考にしたサイト 

hokuts.com