Keras(케라스)로 배우는 딥러닝 예제 - AND, OR, XOR

안녕하세요 jay입니다.
오늘은 AND, OR, XOR 연산에 대해 알아보고,
Keras(케라스)를 활용해서 AND, OR, XOR 연산을 딥러닝으로 돌려보도록 하겠습니다.

0. Intro

예제를 돌리기 전, AND, OR , XOR에 대해 간단히 설명 드리도록 하겠습니다.(이 연산들은 비트연산입니다.)
비트연산이란(Bitwise operation) 한 개 혹은 두 개의 이진수에 대해 비트 단위로 적용되는 연산입니다.

1) AND

AND 연산은 두 값을 비교해, 두 값 모두 1이 있을 때에만 1을, 나머지 경우엔 0을 계산합니다.
Input값은 X1,X2이고 (1,1)일 때만 1입니다. 그래서 아래와 같이 한 직선으로 분류가 가능합니다. 

AND를 신경망으로 나타내면 X1, X2는 각각 0 또는 1이고, 최적의 가중치를 찾으라고 하면,(단 Threshold = 0.5) X1, X2가 각각 1일때 0.5가 넘어가면 안되고, 둘다 1일때는 0.5가 넘어도 되므로
W1 = 0.4 W2 = 0.3( 꼭 고정은 아니다 다른 값도 가능하다)이라 할 수 있습니다.




2) OR

OR 연산은 둘 중 하나라도 1이 있다면 1을, 아니면 0을 계산합니다.
Input값은 X1,X2이고 (0,0)을 제외하고 1입니다. 그래서 아래와 같이 한 직선으로 분류가 가능합니다.



OR를 신경망으로 나타내면 X1, X2는 각각 0 또는 1이고, 최적의 가중치를 찾으라고 하면,(단 Threshold = 0.5) X1, X2중 하나라도 혹은 둘다 1이 있다면, 1이 나타나야 하므로 0.5를 넘으면 됩니다.
W1 = 0.6 W2 = 0.5( 꼭 고정은 아니다 다른 값도 가능하다)라 할 수 있습니다.





3) XOR

XOR 연산은 0으로 같으면 0, 값이 1로 같으면 0, 다르면 1을 계산합니다.
하지만 아래와 같이 XOR은 하나의 직선으로 분류가 불가능합니다.


이런 선형 영역으로 나누는 한계를 극복하기 위해선 곡선으로 나누는 비선형 영역이 필요합니다. 즉 단층 퍼셉트론으로 비선형 영역을 분리할 수가 없습니다. 아래와 같이 층을 하나 늘림으로써 층을 쌓으면, 단층 퍼셉트론에서 표현하지 못하는 것을 구현할 수 있습니다.




1. Keras로 AND 연산 구현하기

import numpy as np
import keras

# 케라스 패키지 가져오기
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.optimizers import SGD

# 입력 / 출력 데이터 만들기
# X : 입력 데이터(X1,X2)
# y : 출력 데이터( 0 or 1)

X = np.array([[0,0],[0,1],[1,0],[1,1]])
y = np.array([[0],[0],[0],[1]])
X : 입력데이터 즉 X1, X2를 의미합니다.
y : 출력 데이터이며, 0 혹은 1의 값을 가집니다.

model = Sequential()

# units : 다음 레이어의 노드 수 정하기
# input_dim : input 차원
# Param # = (input 갯수 + 1) x 노드개수 

model.add(Dense(units=1, input_dim=2, activation='sigmoid'))

# 
print(model.summary())

"""
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_1 (Dense)              (None, 1)                 3         
=================================================================
Total params: 3
Trainable params: 3
Non-trainable params: 0
_________________________________________________________________
None
"""
Sequential() : Sequential()이라는 model의 instance를 만들었습니다. 이는 layer를 순차적으로, 선형으로 쌓는 것을 의미합니다.

Dense : Dense는 Dense layer를 의미하며, 다른 말로 Fully connected layers(완전 연결층)을 의미합니다.

units : 다음 layer의 노드 수를 의미합니다.
input_dim : input의 차원수를 의미합니다(여기선 X1,X2이므로 2입니다.)
activation : 활성화 함수를 의미합니다. 활성화 함수는 layer마다 하나씩 있습니다. 여기선 2진 분류에 레이어가 하나이므로, sigmoid를 사용했습니다.

# Compile - Optimizer, Loss function 설정
# binary classification

sgd = SGD(lr=0.1)

model.compile(loss='binary_crossentropy',
              optimizer=sgd)
loss : loss function(cost function)의 줄임말로, Y(주어진 데이터의 정답)과 Y'(우리가 세운 가설, 모델) 사이의 차이(오차)를 함수로 나타낸 것 입니다. 오차에 대한 함수이므로, 이 값이 작아질수록 성능이 올라갑니다.

SGD : optimizer중 하나로, Cost함수(Loss 함수)를 최적으로 낮추는 방법 중 하나입니다. (Cost function이 낮아질수록 성능이 올라갑니다.)

lr : Learning rate의 줄임말로, Cost함수를 낮추는 속도, 혹은 step(보폭)이라고 생각하시면 됩니다.

compile : complie로 Optimizer와 loss function을 설정할 수 있습니다.


# batch_size = 1 : 한문제 풀고 답 확인
# 4/4 : 4개의 데이터, batch_size가 1이니깐
# loss : 오차값

model.fit(X,y, batch_size = 1, nb_epoch=500)

"""
Epoch 1/500
4/4 [==============================] - 0s 2ms/step - loss: 0.2573
Epoch 2/500
4/4 [==============================] - 0s 1ms/step - loss: 0.2558
Epoch 3/500
4/4 [==============================] - 0s 1ms/step - loss: 0.2544
                            :
                            :
                            :
"""
fit : X와 y를 batch_size 1, 500번의 epoch으로 fitting합니다.(모델을 생성합니다.)
epoch : 전체 반복 횟수
batch_size : 몇개의 문제를 풀고, 몇개 답을 맞출 것인가? , 한개 풀고 한번 정답을 맞추면 느리지만 정확도가 올라갑니다. 한번에 모든 문제를 다 풀고 정답을 한번에 맞추면 속도는 빠르지만, 정확도가 내려갑니다.

#testing model

test = np.array([[1,1]])
pred = model.predict(test)

print(pred) # [[0.89384836]
print(model.get_weights())
"""
[array([[4.6259313],
       [4.625702 ]], dtype=float32), array([-7.120965], dtype=float32)]
"""
test를 위해 검증 데이터(1,1)을 만들고 predict메소드를 통해 예측값을 출력합니다.
[1,1]을 넣었을 때, 0.8938이라는 1에 가까운 값을 예측했습니다.

get_weights() : 모든 가중치 및 bias를 출력해주는 메소드입니다.



2. Keras로 OR 연산 표현하기

OR는 사실 y를 제외하고 AND와 거의 똑같습니다.

import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.optimizers import SGD,Adam

# X : input data
# y : label data

X = np.array([[0,0],[0,1],[1,0],[1,1]])
y = np.array([[0],[1],[1],[1]])
X : 입력데이터 즉 X1, X2를 의미합니다.
y : 출력 데이터이며, 0 혹은 1의 값을 가집니다. OR이므로, [0,1], [1,0], [1,1]일때 1의 값을 가집니다.

model = Sequential()

model.add(Dense(units=1, input_dim=2, activation='sigmoid'))

print(model.summary())

"""
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_2 (Dense)              (None, 1)                 3         
=================================================================
Total params: 3
Trainable params: 3
Non-trainable params: 0
_________________________________________________________________
None
"""
Sequential() : Sequential()이라는 model의 instance를 만들었습니다. 이는 layer를 순차적으로, 선형으로 쌓는 것을 의미합니다.

Dense : Dense는 Dense layer를 의미하며, 다른 말로 Fully connected layers(완전 연결층)을 의미합니다.

units : 다음 layer의 노드 수를 의미합니다.
input_dim : input의 차원수를 의미합니다(여기선 X1,X2이므로 2입니다.)
activation : 활성화 함수를 의미합니다. 활성화 함수는 layer마다 하나씩 있습니다. 여기선 2진 분류에 레이어가 하나이므로, sigmoid를 사용했습니다.

sgd = SGD(lr=0.1)
adam = Adam()# adam은 최적의 lr을 찾아줘서 lr 넣지 않는다.

model.compile(loss='binary_crossentropy',
             optimizer=adam)

model.fit(X,y, batch_size=1, nb_epoch=500)

"""
Epoch 1/500
4/4 [==============================] - 0s 19ms/step - loss: 0.6543
Epoch 2/500
4/4 [==============================] - 0s 2ms/step - loss: 0.5135
Epoch 3/500
4/4 [==============================] - 0s 2ms/step - loss: 0.4561
                                 :
                                 :
                                 :
"""
loss : loss function(cost function)의 줄임말로, Y(주어진 데이터의 정답)과 Y'(우리가 세운 가설, 모델) 사이의 차이(오차)를 함수로 나타낸 것 입니다. 오차에 대한 함수이므로, 이 값이 작아질수록 성능이 올라갑니다.

SGD : optimizer중 하나로, Cost함수(Loss 함수)를 최적으로 낮추는 방법 중 하나입니다. (Cost function이 낮아질수록 성능이 올라갑니다.)

Adam : optimizer중 하나로, Cost함수(Loss 함수)를 최적으로 낮추는 방법 중 하나입니다. 현재까지 성능이 가장 잘 나오는 방법으로 유명합니다. Adam은 RMSpro + Momentum이 결합된 형태이며, 방향, step size(학습속도) 조절을 적절하게 해주는 알고리즘입니다.

lr : Learning rate의 줄임말로, Cost함수를 낮추는 속도, 혹은 step(보폭)이라고 생각하시면 됩니다.

compile : complie로 Optimizer와 loss function을 설정할 수 있습니다.

fit : X와 y를 batch_size 1, 500번의 epoch으로 fitting합니다.(모델을 생성합니다.)
epoch : 전체 반복 횟수
batch_size : 몇개의 문제를 풀고, 몇개 답을 맞출 것인가? , 한개 풀고 한번 정답을 맞추면 느리지만 정확도가 올라갑니다. 한번에 모든 문제를 다 풀고 정답을 한번에 맞추면 속도는 빠르지만, 정확도가 내려갑니다.

test = np.array([[1,1]])
pred = model.predict(test)

print(pred) # [[1.]]

test = np.array([[0,1]])
pred = model.predict(test)

print(pred) # [[0.99866116]]
test를 위해 [1,1], [0,1] 데이터를 가지고 검증을 해보았습니다.
[1.1]일때 1, [0,1]일때 0.9986 즉 1에 가까운 수가 나왔습니다. 모델 설계가 잘 되었다는 것을 알 수 있습니다.


print(model.get_weights())

"""
[array([[12.705443],
       [12.21775 ]], dtype=float32), array([-5.603148], dtype=float32)]
"""

get_weights() : 모든 가중치 및 bias를 출력해주는 메소드입니다.

3. Keras로 XOR 구현하기

XOR은 AND와 OR와 달리 하나의 퍼셉트론으로 구현을 할 수가 없습니다.
따라서 아래와 같이 2개의 퍼셉트론으로 모델을 구현해보도록 하겠습니다.


import numpy as np
import keras
from keras.models import Sequential
from keras.layers import Dense, Activation
from keras.optimizers import SGD

# X : 입력데이터
# y : 출력데이터

X = np.array([[0,0],[0,1],[1,0],[1,1]])
y = np.array([[0],[1],[1],[0]])
X : 입력데이터 즉 X1, X2를 의미합니다.
y : 출력 데이터이며, 0 혹은 1의 값을 가집니다. XOR이므로 0,1,1,0

model = Sequential()

model.add(Dense(units = 8, input_dim=2, activation='relu'))
model.add(Dense(units=1, activation = 'sigmoid'))

print(model.summary())

"""
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_3 (Dense)              (None, 8)                 24        
_________________________________________________________________
dense_4 (Dense)              (None, 1)                 9         
=================================================================
Total params: 33
Trainable params: 33
Non-trainable params: 0
_________________________________________________________________
None
"""

units : 성능을 위해 8개로 둡니다. Hidden layer층이 하나 생깁니다. Hidden layer층의 activation을 relu, output단의 activation을 sigmoid로 합니다(2진 분류이기 때문에)

sgd = SGD(lr=0.1)

model.compile(loss='binary_crossentropy',
              optimizer=sgd)

model.fit(X,y, batch_size = 1, nb_epoch=500)

"""
Epoch 1/500
4/4 [==============================] - 0s 17ms/step - loss: 0.0043
Epoch 2/500
4/4 [==============================] - 0s 2ms/step - loss: 0.0043
Epoch 3/500
4/4 [==============================] - 0s 2ms/step - loss: 0.0043
                            :
                            :
                            :
"""
loss : loss function(cost function)의 줄임말로, Y(주어진 데이터의 정답)과 Y'(우리가 세운 가설, 모델) 사이의 차이(오차)를 함수로 나타낸 것 입니다. 오차에 대한 함수이므로, 이 값이 작아질수록 성능이 올라갑니다. 여기선 binary_crossentropy를 사용했습니다.

SGD : optimizer중 하나로, Cost함수(Loss 함수)를 최적으로 낮추는 방법 중 하나입니다. (Cost function이 낮아질수록 성능이 올라갑니다.)

test = np.array([[1,1]])
pred = model.predict(test)
print(pred) # [[0.00055529]]

test = np.array([[0,1]])
pred = model.predict(test)
print(pred) # [[0.9990766]]

test = np.array([[0,0],[1,1],[0,1],[1,0]])
pred = model.predict(test)
print(pred)

"""
[[8.433895e-03]
 [5.552918e-04]
 [9.990766e-01]
 [9.990759e-01]]
"""

[1,1]일때 0에 가까운 수, 0,1일때 1에 가까운 수가 나왔습니다.
다시 [0,0]부터 [1,1]까지 예측을 해봤을 때 각각 0,0,1,1에 가까운 수가 나왔습니다.
고로 우리가 모델을 잘 세웠다는 것을 알 수 있습니다.

댓글