ANDゲートやNANDゲートはパーセプトロンで表現できた.しかし,XORゲートはパーセプトロンでは表現できない.しかし,XORゲートはANDゲートとNANDゲート,そして,ORゲートの組み合わせによって表現することができる.
例えば,Pythonでは以下のように実装できる.
def AND_gate(input1, input2):
if input1 == 1 and input2 == 1:
return 1
else:
return 0
def OR_gate(input1, input2):
if input1 == 1 or input2 == 1:
return 1
else:
return 0
def NAND_gate(input1, input2):
if input1 == 1 and input2 == 1:
return 0
else:
return 1
def XOR_gate(input1, input2):
nand_output = NAND_gate(input1, input2)
or_output = OR_gate(input1, input2)
and_output = AND_gate(nand_output, or_output)
return and_output
# テスト
print("0 XOR 0 =", XOR_gate(0, 0)) # 0
print("0 XOR 1 =", XOR_gate(0, 1)) # 1
print("1 XOR 0 =", XOR_gate(1, 0)) # 1
print("1 XOR 1 =", XOR_gate(1, 1)) # 0
出力は以下の通り.
0 XOR 0 = 0
0 XOR 1 = 1
1 XOR 0 = 1
1 XOR 1 = 0
XORゲートはパーセプトロンでは表現できないのであるが,2層のニューラルネットワークで実装することはできる.すなわち,1つ目の層を入力層とし,2つ目の層を隠れ層とし,隠れ層に非線形の活性化関数[例えばシグモイド関数]を使用することで実装できる.
Pythonを用いると次のようになる.
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
# XORゲートの入力と出力
X = np.array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
y = np.array([[0],
[1],
[1],
[0]])
# モデルの定義
model = Sequential()
# 隠れ層(8ノード)
model.add(Dense(8, input_dim=2, activation='relu'))
# 出力層
model.add(Dense(1, activation='sigmoid'))
# モデルのコンパイル
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# モデルの訓練
model.fit(X, y, epochs=1000, batch_size=4)
# テスト
# 予測値を取得して出力
print("0 XOR 0 =", model.predict(np.array([[0, 0]]))[0][0])
print("0 XOR 1 =", model.predict(np.array([[0, 1]]))[0][0])
print("1 XOR 0 =", model.predict(np.array([[1, 0]]))[0][0])
print("1 XOR 1 =", model.predict(np.array([[1, 1]]))[0][0])
出力は次のようになる.
0 XOR 0 = 0.1734419
1/1 [==============================] - 0s 40ms/step
0 XOR 1 = 0.8513512
1/1 [==============================] - 0s 32ms/step
1 XOR 0 = 0.88226503
1/1 [==============================] - 0s 39ms/step
1 XOR 1 = 0.12337355
ここで,これらの出力は,XOR_gate関数のテスト結果を示している.XORゲートの出力は0または1である必要がある.この結果は確率値を示していて,0.5以上の場合は1に,0.5未満の場合は0に丸められることによりXORゲートとして機能する.
なお,ここで,
model = Sequential()
という箇所で,Sequentialモデルを作成している.このSequentialモデルは,順番に層を積み重ねてモデルを構築するための簡単な方法である.
model.add(Dense(8, input_dim=2, activation='relu'))
という箇所では,モデルに1つ目の層を追加している.追加される層は全結合層[Dense層]である.この層には8つのニューロン[ノード]があり,入力の次元は2となる.また,活性化関数としてReLU[Rectified Linear Unit]をしている.ReLUは,入力が0未満の場合は0になり,それ以外の場合はそのまま出力するというものである.
model.add(Dense(1, activation='sigmoid'))
この箇所では,モデルに2つ目の層を追加している.これも全結合層であり,活性化関数としてシグモイド関数を指定している.シグモイド関数は,0から1の間の値を出力し,確率を表現するためによく使用される.
このように,Sequential( )を使用してモデルを定義し,add( )メソッドを使用して層を追加している.また,それぞれの層は,Denseを使用して定義され,activation引数を通じて活性化関数を指定している.
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
ここでは,モデルが学習を行う準備を整えるプロセスであるコンパイルを行っている.モデルの学習プロセスを定義するcompile( )メソッドのうち,loss='binary_crossentropy では損失関数を指定している.ここでは二値分類問題を扱っているため,二項交差エントロピー[binary crossentropy]を選択している.この二項交差エントロピーは,2つのクラスの予測の精度を測るために使用されるもの.
optimizer='adam'では,最適化アルゴリズムを指定している.ここではAdam optimizerを選択している.Adamは,確率的勾配降下法[SGD]の一種であり,勾配の移動平均と二乗勾配の移動平均を使用して学習率を調整し高速な収束を実現するものである.
metrics=['accuracy']では,モデルの評価メトリクスを指定している.ここではモデルが正しく分類したサンプルの割合である精度[accuracy]を選択している.
Mathematics is the language with which God has written the universe.