機械学習入門(1:パーセプトロンと活性化関数)
パーセプトロン
パーセプトロンとは、複数の値を入力して1つの値を出力する装置。
AND回路とかOR回路もパーセプトロン。
説明の前にまず、numpyとmatplotlibをimportしておきます。
import numpy as np import matplotlib.pyplot as plt
AND回路
AND回路は2つとも1の場合にのみ1を返し、他の場合は0を返すパーセプトロン。
コードはこんな感じ。なんで0.5、0.5、0.7なのかは、x1とx2に0か1を代入してみるとわかる。
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
x1、x2を入力すると、AND回路が変換して0か1を返す。
print(AND(0, 0)) print(AND(1, 0)) print(AND(0, 1)) print(AND(1, 1))
出力:
0
0
0
1
OR回路
OR回路はどっちも0の場合のみ0。それ以外は1を返すパーセプトロン。
さきほどのthetaをマイナスにしてb(バイアス)としている。この値はニューロンの発火のしやすさをコントロールする。
def OR(x1,x2): x = np.array([x1,x2]) w = np.array([0.5, 0.5]) b = -0.2 tmp = np.sum(w*x) + b if tmp <= 0: return 0 else: return 1
print(OR(0, 0)) print(OR(1, 0)) print(OR(0, 1)) print(OR(1, 1))
出力:
0
1
1
1
これって、こんな風に表すことができる。
$$ y\quad =\quad \left\{ \begin{matrix} { 0\quad (b\quad +\quad x }_{ 1 }{ w }_{ 1 }\quad +\quad { x }_{ 2 }{ w }_{ 2 }\quad \leqq \quad 0 \\ { 1\quad (b\quad +\quad x }_{ 1 }{ w }_{ 1 }\quad +\quad { x }_{ 2 }{ w }_{ 2 }\quad >\quad 0 \end{matrix} \right\} $$
OR回路だけじゃなくて、すべての回路はこの形になっている。
NAND回路
AND回路の逆であるNAND回路はこんな感じ。
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
print(NAND(0, 0)) print(NAND(1, 0)) print(NAND(0, 1)) print(NAND(1, 1))
出力:
1
1
1
0
ちなみにこのNAND回路だけでコンピュータを作ることが可能。単純なものを大量に積み重ねるとものすごい能力を発揮するものを作ることができるのだ。深い。
XOR回路
これまでの回路は単層のパーセプトロンで表現できていたが、XOR回路になると表現できない。そこで層を重ねて表現する。
AND回路とOR回路、NAND回路の3つのパーセプトロンを組み合わせると、XOR回路を作ることができる。
def XOR(x1, x2): s1 = NAND(x1, x2) s2 = OR(x1, x2) y = AND(s1, s2) return y
print(XOR(0, 0)) print(XOR(1, 0)) print(XOR(0, 1)) print(XOR(1, 1))
出力:
0
1
1
0
つまり、パーセプトロンの層を重ねることで、単層のパーセプトロンでは表現できないことを表現できるようになったということ。
パーセプトロンを重ねることで、加算器やエンコーダ(2進数を10進数に変換する)も作ることができるし、理論上たった2層のパーセプトロンでコンピュータを作ることだってできる。
そしてこのパーセプトロンはニューラルネットワークの基礎になる。
ちなみにこのXOR回路は、一階でつけた階段の電気を、二階で消す時に使われるやつ。
活性化関数
活性化関数とは、パーセプトロンに入力された複数の値に、それぞれ重みをかけたものを合算し、ある閾値を超えた場合と超えなかった場合(バイアスを加算して0より小さい場合と0以上の場合)に、どんな値を返すかを定義する関数のこと。
こんなやつ
$$ h(x)=\begin{cases} 0\quad (x\leqq 0) \\ 1\quad (x>0) \end{cases} $$
具体的に言えば、
$$ { a= b + x }_{ 1 }{ w }_{ 1 } + { x }_{ 2 }{ w }_{ 2 } $$
で、
$$ y = h^{ }\left( a \right) $$
なわけである。一つのニューロンの中で、$latex a $というノードが$latex y $というノードへ変換されているというわけだ。
活性化関数にはステップ関数、シグモイド関数、ReLu関数などがある。 上の活性化関数はステップ関数。上で説明したAND回路、OR回路、NAND回路、XOR回路は活性化関数としてステップ関数が使われている。まあ出力が0か1なのだから当たり前だけど。
ステップ関数
閾値を超えれば1、超えなければ0を返す活性化関数のこと。
def step_function(x): return np.array(x > 0, dtype=np.int)
x = np.arange(-5.0, 5.0, 0.1) y = step_function(x) plt.plot(x, y) plt.ylim(-0.1, 1.1)
シグモイド関数
ステップ関数を緩やかにした活性化関数。昔はニューラルネットワークで主に使われていた。
def sigmoid(x): return 1 / (1 + np.exp(-x))
x = np.arange(-5.0, 5.0, 0.1) y = sigmoid(x) plt.plot(x, y) plt.ylim(-0.1, 1.1)
パーセプトロンではニューロン間を0か1のどちらかの値しか返さないのに対して、ニューラルネットワークでは連続的な実数値の信号が流れる。
ステップと関数とシグモイド関数は、入力信号が重要な情報であれば大きな値を出力し、入力信号が重要でなければ小さな値を出力するということが図からわかる。
ステップ関数もシグモイド関数も非線形関数。活性化関数には非線形関数を使わなければならず、線形関数を使ってはならない。なぜなら、活性化関数に線形関数を使うと、ニューラルネットワークで層を深くする意味がなくなるから。
たとえば、
$$ h\left( x \right)=cx $$
という活性化関数があったとする。
$$ y = h^{ }\left( h\left( h\left( x \right) \right) \right) $$
のように3層のニューラルネットワークで計算すると、これは
$$ y=c\times c\times c\times x $$
の計算であり、
$$ y=a\times x\quad (a={ c }^{ 3 }) $$
と等しく、隠れ層のないネットワークで表現できるから。
ReLu関数
入力が0以下ならば0を返し、入力が0より大きければ、入力をそのまま返す活性化関数。
現在の主流。
def relu(x): return np.maximum(0, x)
x = np.arange(-5.0, 5.0, 0.1) y = relu(x) plt.plot(x, y) plt.ylim(-0.1, 6)
数式で表すと、
$$ h\left( x \right) =\left\{ \begin{matrix} x\quad (x>0) \\ 0\quad (x\leqq 0) \end{matrix} \right\} $$