본문 바로가기

딥러닝/신경망 기초

퍼셉트론(Perceptron)과 다층 퍼셉트론(MLP)

1. 퍼셉트론(Perceptron)이란?


: 프랑크 로젠블라트가 1957년에 고안한 알고리즘으로 Neural-Network(신경망)의 기원이 되는 알고리즘.

: 가장 오래되고 단순한 형태의 판별 함수 기반 예측 모형(discriminant function based predition model) 중 하나

: 퍼셉트론은 다수의 신호를 받아(input) 하나의 신호(0 또는 1)로 출력(output).


Perceptron Example



x1, x2라는 신호 입력이 y라는 신호로 출력이 되는 과정 자체가 퍼셉트론입니다.

이때 각 입력신호(x1,x2)는 weight(w1,w2)가 곱해지게 됩니다.

** 동그라미를 뉴런 혹은 노드라고 말한다.


1) Weight(가중치), Bias(편향치), Theta(임계점)


: 입력 신호는 각 weight와 곱해져 w1*x1 + w2*x2가 되고, 이 값에 bias(b)가 더해져 w1*x1 + w2*x2 + b가 된다.

: 여러 입력신호가 하나의 신호로 출력되어야 하기 때문에 bias는 뉴런(위 그림에서 동그라미를 의미)당 1개씩 더해진다.

: 또한 출력값이 0 또는 1로 출력되어야 하기때문에 w1*x1 + w2*x2 + b를 0 또는 1로 만들어줘야한다.

: 이때 사용하는 개념이 임계점(Theta)이고, w1*x1 + w2*x2 + b이 설정해놓은 임계점을 기준으로 0 또는 1로 바뀐다.

: 예를 들어, 'w1*x1 + w2*x2 + b < theta이면 0,  w1*x1 + w2*x2 + b > theta이면 1' 이런식으로!!



2. 단순 논리회로(AND, OR, NAND)


 x1

x2 

y : AND 

y : OR

y : NAND 

 0

 0

 1

 1

0

 1

 1

 0

0

 1

 1

 1

1

 1

 0


AND : 입력이 모두 1인 경우에만, 1을 출력(나머지 경우엔 0을 출력)


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


OR : 입력중 하나 이상이 1인 경우, 1을 출력(모두 0이면 0을 출력)



# OR 구현
def OR(x1, x2):
    """
    AND와 weights와 bias만 다르다
    """
    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


NAND : AND와 반대, 모두 1인 경우 0출력 출력(나머지 경우엔 1을 출력)



# NAND 구현
def NAND(x1, x2):
    """
    AND와 weights와 bias만 다르다
    """
    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


(위 그림의 직선 : w1*x1 + w2*x2 + b)


AND/NAND, OR은 해당 직선(판별함수라도도 할 수 있음)으로 두 영역(black, white)을 구분할 수 있다


3. 한계점 : XOR 문제


 x1

x2 

y : XOR 

0

 1 

 0 

 1 


XOR : OR의 반대가 아니다!!! 입력값 모두 1인 경우만 1을 출력(나머지 경우엔 0을 출력)



직선(w1*x1 + w2*x2 + b)으로 black/white 두 영역으로 나눌 수가 없다....


Python코드를 예를 들어보면,


np.random.seed(0)
X_xor = np.random.randn(200, 2)
y_xor = np.logical_xor(X_xor[:, 0] > 0, X_xor[:, 1] > 0)
y_xor = np.where(y_xor, 1, -1)
plt.scatter(X_xor[y_xor==1, 0], X_xor[y_xor==1, 1], c='b', marker='o', label='1', s=100)
plt.scatter(X_xor[y_xor==-1, 0], X_xor[y_xor==-1, 1], c='r', marker='s', label='-1', s=100)
plt.ylim(-3.0)
plt.legend()
plt.title("XOR problem")
plt.show()




3.1 해결책 : 다층 퍼셉트론(Multi-Layer Perceptron)


이 XOR 문제를 해결하기 위해 퍼셉트론 두 개를 이어 붙여 해결할 수 있다.


이것을 '층을 쌓는다'라 하며, 

이렇게 만들어진 퍼셉트론을 다층 퍼셉트론(Multi-Layer Perceptron)이라 한다..


# XOR 구현
# AND, NAND, OR 조합하여 구현하기
def XOR(x1, x2):
    """
    다층 구조를 가진 다층 퍼셉트론 
    """
    s1 = NAND(x1,x2) # 1층
    s2 = OR(x1,x2) # 1층
    y = AND(s1,s2) # 2층
    return y

Tensorflow로 다층 퍼셉트론(MLP)를 만들어보자.


: Tensorflow로 MNIST데이터를 분류하는 MLP를 만들어보자!

: 코드 위주로 설명 진행.


0. Data Load


import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('data/', one_hot=True)


1. Parameter Setting


이미지 데이터 1개가 28x28(흑백)으로 구성되어있는데,

위처럼 데이터를 불러오면 28x28=784로 한줄로 펴진 vector로 온다.

그래서 n_input이 784인 것이다.


n_input = 784
n_hidden_1 = 256
n_hidden_2 = 128
n_classes = 10

# set input and output
x = tf.placeholder(dtype='float', shape=[None, n_input])
y = tf.placeholder(dtype='float', shape=[None, n_classes])

# set network parameters(weights, biases)
stddev = 0.1
weights = {
    # 가중치의 초기값은
    # 평균 : 0(default), 표준편차 : 0.1 인 정규분포에서 random으로 뽑는다
    # hidden layer1의 노드 수는 256개, hidden layer2의 노드 수는 128개
    # out layer의 노드 수 = label 갯수 = 10개(0~9, 숫자 10개)
    'h1' : tf.Variable(initial_value=tf.random_normal(shape=[n_input, n_hidden_1],stddev=stddev)), # 784 x 256 matrix
    'h2' : tf.Variable(initial_value=tf.random_normal(shape=[n_hidden_1, n_hidden_2], stddev=stddev)), # 256 x 128 matrix
    'out' : tf.Variable(initial_value=tf.random_normal(shape=[n_hidden_2, n_classes], stddev=stddev)), # 128 x 10 matrix
}
biases = {
    'b1' : tf.Variable(initial_value=tf.random_normal(shape=[n_hidden_1])), # 256개
    'b2' : tf.Variable(initial_value=tf.random_normal(shape=[n_hidden_2])),
    'out' : tf.Variable(initial_value=tf.random_normal(shape=[n_classes])),
}
print("Network Ready!!!")


2. Define Graph


multilayer_perceptron 함수에서 최종 출력값을 logit(Wx+b 형태)으로 뽑고,

이를 Cross Entropy에 적용

→ tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=pred))


# model
def multilayer_perceptron(_x, _weights, _biases):
    layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(_x, _weights['h1']), _biases['b1'])) # 1번째 layer 통과
    layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, _weights['h2']), _biases['b2'])) # 2번째 layer 통과
    # return은 logit을 뽑아야 한다.(softmax 취하기 전 형태)
    # softmax취해서 return하면 성능 떨어짐...
    return (tf.matmul(layer_2, _weights['out']) + _biases['out']) 

# prediction
pred = multilayer_perceptron(x, weights, biases)

# Loss and Optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=pred))
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost)
correct = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct, 'float'))

# Initialize
init = tf.global_variables_initializer()
print("Function Ready!!!")


3. Run


training_epochs = 20
batch_size = 100
display_step = 4

# Launch the Graph
sess = tf.Session()
sess.run(init)

# Optimize
for epoch in range(training_epochs):
    avg_cost = 0
    total_batch = int(mnist.train.num_examples / batch_size)
    # Iteration
    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size=batch_size)
        feeds = {x: batch_xs, y: batch_ys}
        sess.run(optimizer, feed_dict=feeds)
        avg_cost += sess.run(cost, feed_dict=feeds)
    avg_cost = avg_cost / total_batch
    # Display
    if (epoch+1) % display_step == 0:
        print("Epoch: %03d/%03d cost: %.9f" % (epoch, training_epochs, avg_cost))
        feeds = {x: batch_xs, y: batch_ys}
        train_acc = sess.run(accuracy, feed_dict=feeds)
        print("Train Accuracy: %.3f" % (train_acc))
        feeds = {x: mnist.test.images, y: mnist.test.labels}
        test_acc = sess.run(accuracy, feed_dict=feeds)
        print("Test Accuracy: %.3f" % (test_acc))
print("Optimization Finished!!")

출력:

Epoch: 003/020 cost: 0.119634462

Train Accuracy: 0.980
Test Accuracy: 0.964
Epoch: 007/020 cost: 0.047141746
Train Accuracy: 0.990
Test Accuracy: 0.975
Epoch: 011/020 cost: 0.018645706
Train Accuracy: 1.000
Test Accuracy: 0.977
Epoch: 015/020 cost: 0.006685954
Train Accuracy: 1.000
Test Accuracy: 0.981
Epoch: 019/020 cost: 0.002408720
Train Accuracy: 1.000
Test Accuracy: 0.979
Optimization Finished!!




Activation Function을 ReLU로 바꿔보자


1. Parameter Setting


n_input = 784
n_hidden_1 = 256
n_hidden_2 = 128
n_hidden_3 = 64
n_classes = 10

# set input and output
x = tf.placeholder(dtype='float', shape=[None, n_input])
y = tf.placeholder(dtype='float', shape=[None, n_classes])

# set network parameters(weights, biases)
stddev = 0.1
weights = {
    'h1' : tf.Variable(initial_value=tf.random_normal(shape=[n_input, n_hidden_1],stddev=stddev)),
    'h2' : tf.Variable(initial_value=tf.random_normal(shape=[n_hidden_1, n_hidden_2], stddev=stddev)),
    'h3' : tf.Variable(initial_value=tf.random_normal(shape=[n_hidden_2, n_hidden_3], stddev=stddev)),
    'out' : tf.Variable(initial_value=tf.random_normal(shape=[n_hidden_3, n_classes], stddev=stddev)),
}
biases = {
    'b1' : tf.Variable(initial_value=tf.random_normal(shape=[n_hidden_1])),
    'b2' : tf.Variable(initial_value=tf.random_normal(shape=[n_hidden_2])),
    'b3' : tf.Variable(initial_value=tf.random_normal(shape=[n_hidden_3])),
    'out' : tf.Variable(initial_value=tf.random_normal(shape=[n_classes])),
}
print("Network Ready!!!")


2. Define Graph


# model
def multilayer_perceptron(_x, _weights, _biases):
    layer_1 = tf.nn.relu(tf.add(tf.matmul(_x, _weights['h1']), _biases['b1']))
    layer_2 = tf.nn.relu(tf.add(tf.matmul(layer_1, _weights['h2']), _biases['b2']))
    layer_3 = tf.nn.relu(tf.add(tf.matmul(layer_2, _weights['h3']), _biases['b3']))
    # return은 logit을 뽑아야 한다.(softmax 취하기 전 형태)
    # softmax취해서 return하면 성능 떨어짐...
    return (tf.matmul(layer_3, _weights['out']) + _biases['out']) 

# prediction
pred = multilayer_perceptron(x, weights, biases)

# Loss and Optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=pred))
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost)
correct = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct, 'float'))

# Initialize
init = tf.global_variables_initializer()
print("Function Ready!!!")


3. Run


training_epochs = 20
batch_size = 100
display_step = 4

# Launch the Graph
sess = tf.Session()
sess.run(init)

# Optimize
for epoch in range(training_epochs):
    avg_cost = 0
    total_batch = int(mnist.train.num_examples / batch_size)
    # Iteration
    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size=batch_size)
        feeds = {x: batch_xs, y: batch_ys}
        sess.run(optimizer, feed_dict=feeds)
        avg_cost += sess.run(cost, feed_dict=feeds)
    avg_cost = avg_cost / total_batch
    # Display
    if (epoch+1) % display_step == 0:
        print("Epoch: %03d/%03d cost: %.9f" % (epoch, training_epochs, avg_cost))
        feeds = {x: batch_xs, y: batch_ys}
        train_acc = sess.run(accuracy, feed_dict=feeds)
        print("Train Accuracy: %.3f" % (train_acc))
        feeds = {x: mnist.test.images, y: mnist.test.labels}
        test_acc = sess.run(accuracy, feed_dict=feeds)
        print("Test Accuracy: %.3f" % (test_acc))
print("Optimization Finished!!")

출력:

Epoch: 003/020 cost: 0.040441343

Train Accuracy: 1.000
Test Accuracy: 0.974
Epoch: 007/020 cost: 0.011998331
Train Accuracy: 0.990
Test Accuracy: 0.978
Epoch: 011/020 cost: 0.004996898
Train Accuracy: 1.000
Test Accuracy: 0.979
Epoch: 015/020 cost: 0.004258974
Train Accuracy: 0.990
Test Accuracy: 0.979
Epoch: 019/020 cost: 0.002940170
Train Accuracy: 1.000
Test Accuracy: 0.978
Optimization Finished!!


다른거 손대지 않고 Graph만 바꿔주면 된다는 것이 TensorFlow의 장점!




참고 

 "데이터사이언스 스쿨"

https://datascienceschool.net/view-notebook/342b8e2ecf7a4911a727e6fe97f4ab6b/


"밑바닥으로 시작하는 딥러닝"

http://www.hanbit.co.kr/store/books/look.php?p_code=B8475831198 


소스코드

https://github.com/Junhojuno/DeepLearning-Beginning/blob/master/DeepLearning_from_the_bottom/1.Perceptron.ipynb

https://github.com/Junhojuno/DeepLearning-Beginning/blob/master/5.MLP_NumberClassifier.ipynb

'딥러닝 > 신경망 기초' 카테고리의 다른 글

Recurrent Neural Network (RNN)  (0) 2018.11.04
Convolutional Neural Network(CNN)  (0) 2018.11.01
이미지 데이터 다루기  (0) 2018.10.31
소프트맥스(Softmax)  (0) 2018.10.25
활성화 함수(Activation Function)  (0) 2018.10.24