5分でわかる!パーセプトロンの仕組みと実装方法(Python)

ディープラーニング
スポンサーリンク

パーセプトロン(perceptron)は、今(2019年)から60年以上前にアメリカの心理学者フランク・ローゼンブラッド氏によって考案されたアルゴリズム(演算する手順)です。パーセプトロンは昔からあるアルゴリズムなのですが、ディープラーニングの大元となるアルゴリズムです。そのためディープラーニングを理解する上で、このパーセプトロンの仕組みを知っておくことが欠かせません。そこで今回は、パーセプトロン(正確には「単純パーセプトロン」)の仕組みと Python(バージョン3)での実装方法を、できるだけわかりやすくまとめてみました。

パーセプトロンからディープラーニングまでの歴史

1958年にパーセプトロンが発表されてから、長年のさまざまな研究の積み重ねによりディープラーニングに進化しました。

  • 1958年 パーセプトロン
  • 1969年 パーセプトロンの性能と限界に関する論文
  • 1986年 誤差逆伝播法(パーセプトロンの限界を克服)
  • 2006年 自己符号化器(ディープラーニングが可能になった)
  • 2010年代 ディープラーニング分野が形成される

参考資料:深層学習教科書 ディープラーニング G検定(ジェネラリスト) 公式テキスト(P53)

そして2012年には、ILSVRCという画像認識の精度を競い合う競技会で、ディープラーニングを利用したトロント大学のチームが圧勝します。これをきっかけにして、ディープラーニングがブームとなり、今ではさまざまな分野でディープラーニングが活用されるようになりました。

ごく簡単に言ってしまうと、パーセプトロンを ものご〜く複雑 にしたもがディープラーニングです。そのためディープラーニングを学ぶためには、この「パーセプトロン」の仕組みを理解しておくことがとても大切になります。

パーセプトロンの仕組み

パーセプトロンは、人間の脳神経回路を真似た学習モデルです。人口ニューロン(訳:神経細胞)とも呼ばれています。

脳神経回路と言われると、ものすごく複雑なものを想像してしまいますが、パーセプトロンの仕組みはごくごくシンプルで、複数の入力を重み付けして、0か1を出力するだけのものです。

パーセプトロンの構造

入力が2つのパーセプトロン(単純パーセプトロン)の構造を図にすると次のようになります。

単純パーセプトロンの図

バイアス(b)
 パーセプトロンは0か1を出力するのですが、バイアスは「1を出力する度合を調整するための値」です。記号では「b」と表記します。(バイアスはそのままの値を使うため、上の図では入力を1に固定していますが特に気にする必要はありません)また、バイアスを「重み」と呼ぶこともありますが、下の重み(w)とは役割に違いがあることに注意が必要です。

重み(w)
 重みは「入力の重要度を調整する値」です。例えば入力1を重要にしたいのであれば、重み1を 0.7、重み2を 0.3 のように調整します。記号では重み1を「w1」、重み2を「w2」のように表記します。

入力(x)
 パーセプトロンに入力される値です。入力は自由に増やすことができます。記号では入力1を「x1」、入力2を「x2」のように表記します。

出力(y)
 バイアスのところでも書きましたがパーセプトロンは、0か1出力します。記号では「y」と表記します。

また、図のそれぞれの「◯」のことを、「ノード」または「ニューロン」と呼びます。ディープラーニングの説明ではよく「各ノードを〜」とか「ここでニューロンが〜」のような説明が出てきますね。入力をノード、出力をニューロンと呼ぶことが多いようですが、出力を別のパーセプトロンの入力として使う場合もあるので、明確に区別しなくても特に問題ないようです。

パーセプトロンの動作

上のパーセプトロンの動作を式で表すと次のようになります。「バイアス」と「入力×重み」の合計が0以下なら0を出力し、0以上なら1を出力します。

バイアス +(入力1 × 重み1)+(入力2 × 重み2)= a
 
a ≦ 0 なら 0 を出力
a > 0 なら 1 を出力

記号を使って式を表すと下のようになります。数学が得意な方でしたらこちらの方が馴染みやすいと思います。

\(a = b + x_1w_1 + x_2w_2\)
 
\(y = \begin{cases}0\quad(a ≦ 0)\\1\quad(a > 0)\end{cases}\)

例えば、各値を次のように設定した場合は、パーセプトロンは「0」を出力します。

入力1:1
入力2:0
重み1:0.3
重み2:0.3
バイアス:-0.5

-0.5 +(1 × 0.3)+(0 × 0.3)= -0.2
-0.2 ≦ 0 なので 0 を出力

入力はそのままで、重みとバイアスを変えてみます。こうした場合パーセプトロンは「」を出力します。

入力1:1
入力2:0
重み1:0.7(重みとバイアスだけ変える)
重み2:0.7
バイアス:-0.3

-0.3 +(1 × 0.7)+(0 × 0.7)= 0.4
0.4 > 0 なので 1 を出力

実際に計算してみると当たり前のことに思えますが、ここで注目すべきは式はそのままで、「重みとバイアスを調整するだけで出力を変えられる」ということです。これがパーセプトロンの利点であり、ディープラーニングの根底を支える仕組みです。

それでは続いてこのパーセプトロンを実装してみましょう。

パーセプトロンの実装(Python)

ANDゲート

もしかしたらお気づきかもしれませんが、先ほどの1つめの例は、ANDゲート(すべての入力が1であれば1を出力し、それ以外は0を出力)のパーセプトロンです。(ちなみに2つめの例は ORゲートです)

ANDゲート
入力1(x1)入力2(x2)出力(y)
000
100
010
111

この パーセプトロンの ANDゲートを Python の関数として実装すると次のようになります。プログラムになると少しむずかしく見えますが、やっていることはパーセプトロンの動作の式をそのまま実装しただけです。

and_gate.py

# パーセプトロンの ANDゲート
# x1(入力1)x2(入力2)
def and_gate(x1, x2):
  
    w1  = 0.3 # 重み1
    w2  = 0.3 # 重み2
    b   = -0.5 # バイアス

    a   = b + x1 * w1 + x2 * w2

    if a <= 0:
        y = 0
    else:
        y = 1

    return y # 出力

# 確認用コード
print(and_gate(0, 0))
print(and_gate(1, 0))
print(and_gate(0, 1))
print(and_gate(1, 1))

上のコードをファイル名「and_gate.py」(名前はなんでも構いません)として保存し、確認のため実行してみます。(Python はバージョン3です)

$ python and_gate.py
0
0
0
1

しっかり ANDゲートとして動作していますね。

ORゲート

続いて ORゲート(どちらかの入力が1であれば1を出力し、それ以外は0を出力)の実装です。

ORゲート
入力1(x1)入力2(x2)出力(y)
000
101
011
111

先ほどの ANDゲートのコードの重みとバイアスを変えるだけで(実際には関数名も変えていますが)、ORゲートを実装できてしまいます。

or_gate.py

# パーセプトロンの ORゲート
def or_gate(x1, x2):

    w1  = 0.7 # 重みとバイアスだけ変える
    w2  = 0.7
    b   = -0.3

    # ここから下は同じ
    a   = b + x1 * w1 + x2 * w2

    if a <= 0:
        y = 0
    else:
        y = 1

    return y

# 確認用コード
print(or_gate(0, 0))
print(or_gate(1, 0))
print(or_gate(0, 1))
print(or_gate(1, 1))

動作確認の結果です。

$ python or_gate.py
0
1
1
1

NANDゲート

最後に NANDゲート(すべての入力が1であれば0を出力し、それ以外は1を出力)を実装してみましょう。重みとバイアスをどのように調整すればよいでしょうか?

NANDゲート
入力1(x1)入力2(x2)出力(y)
001
101
011
110

NANDゲートは、ANDゲートと逆の動作をしますので、ANDゲートの重みとバイアスの符号を逆にすれば NANDゲートを実装できます。

nand_gate.py

# パーセプトロンの NANDゲート
def nand_gate(x1, x2):

    w1  = -0.3 # 重みとバイアスの符号を逆にする
    w2  = -0.3
    b   = 0.5

    # ここから下は同じ
    a   = b + x1 * w1 + x2 * w2

    if a <= 0:
        y = 0
    else:
        y = 1

    return y

# 確認用コード
print(nand_gate(0, 0))
print(nand_gate(1, 0))
print(nand_gate(0, 1))
print(nand_gate(1, 1))

動作確認の結果です。

$ python nand_gate.py
1
1
1
0

おわりに

この記事を書くのにあたって、書籍「ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装」を参考にさせて頂きました。パーセプトロンだけではなく、ディープラーニングを理解するために必要な知識をとても丁寧にわかりやすく説明されています。これからディープラーニングを学ぼうとされている方に、絶対オススメの一冊です。

コメント

タイトルとURLをコピーしました