Neural Network 공부했다.- Single Layer Neural Network
추천 시스템과 방법론들을 배우면서 잠시 잊고 있었는지는 모르겠지만, 이 강의의 최종 목표는 귀여운 고양이 사진이 있을 때 이를 '삐빅, 고양이다~' 라고 말해주는 인공지능을 설계하는 것이다. 그래서 지금까지는 그의 일환으로 Linear Regression과 Logistic Regression을 배웠던 것이고, 이번에는 Neural Network를 배우고자 하는 것이다. 강의에서는 들어가기 전에 복습부터 시켜준다.
Copyright © 2018. Alina Inc. All Rights Reserved.
Linear Regression이 무엇이었지?? Data들의 어떠한 경향을 알아내는 것이었다. 그러기 위해서 가설을 세웠고 이것을 Hypothesis라고 불렀다. Linear라는 이름에 걸맞게 이 방법에서는 선형적인 가설을 세웠고, 각 항에 알맞는 매개변수 θ들을 찾는 것이 목표가 되었었다. 그래서 이 θ를 찾는 방법으로 Cost Function의 계산과 Gradient Descent가 쓰였던 것!!
Copyright © 2018. Alina Inc. All Rights Reserved.
Logistic Regression은 무엇인가!! Linear Regression과는 달리 Classification에 대한 이야기였다. 내가 가진 항목들을 분석해서 새로 들어온 항목의 성격에 따라 어떤 범주에 속하게 될 것인지 확률로 내뱉어 주는 방법이었다. Linear Regression과 비슷하게 Hypothesis를 세우고 Cost를 계산해 매개변수들을 최적화해준다는 개념은 비슷하지만 알려주는 함수의 유형이 달랐다.
사실 Neural Network도 앞선 두 가지 방법들과 방법론적인 측면에서 큰 차이를 보이는 것은 아니다. 그럼 각설하고, Neural Network에 대해서 개념부터 알아보자.
Copyright © 2018. Alina Inc. All Rights Reserved.
가만히 살펴 보면 이는, Logistic Regression을 그저 그림의 형태로 나타낸 것일 뿐임을 알 수 있다. input data로 꽃의 각종 특성들을 넣어주고, 매개변수 θ를 통한 weight, Hypothesis를 지난 뒤에, 이를 모두 더하고 Softmax를 거친다! 단지 이를 그림으로 나타낸 것일 뿐이다. 왜 이를 먼저 제시하였냐면, Neural Network의 동작 원리도 이와 동일하기 때문이다.
Copyright © 2018. Alina Inc. All Rights Reserved.
28 * 28 pixel 사이즈의 이미지를 사용한다고 했을 때, 각 pixel에서의 값들을 모두 input으로 넣어 주고, 우리가 원하는 것은 이 이미지가 어떤 필기체 숫자인지 알아내는 것이므로, output은 0부터 9까지의 숫자 중 이 이미지가 어디에 속할 것인지이다. 위 그림에서는 함수를 거치고 Softmax를 거치는 과정은 생략을 해 두었다.
Copyright © 2018. Alina Inc. All Rights Reserved.
이는 용어를 정리해 둔 것인데, Hypothesis가 Activation Function으로 바뀐 것이나, 처음 나오는 매개변수의 이름이 Bias로 된 것 정도가 바뀌었을 뿐, 기존의 방식들과 동작은 동일하다는 것을 다시 한 번 강조하고 있다. 그럼, 다른 이름으로 불리는 이유가 있을 터인데, 무슨 차이가 있다는 것일까??
Copyright © 2018. Alina Inc. All Rights Reserved.
Network라는 이름에서 이를 유추할 수 있다. 그냥 Artificial Neuron들을 나열해 놓은 것이 아니라, 여러 Neuron들을 거미줄처럼 연결해 놓은 것이 핵심이다! 앞서 인간의 뇌와 유사하다는 이야기가 사진에 있었는데, 수많은 뉴런들이 서로 얽혀서 신경망을 구축하는 것과 비슷하게 인공 신경망을 구축하는 것이다. 그래서 한 Artificial Neuron에의 Input은 다른 Artificial Neuron의 output이었고, 이 Neuron의 output은 다른 Neuron의 Input이 되는 것이다!! 그림에서 아래 부분에 수식으로도 잘 나와있다.
Copyright © 2018. Alina Inc. All Rights Reserved.
기존의 방법들과 차이점으로 Activation Function에 대해서 좀 더 살펴보고자 한다. 이는 Neuron들 사이를 이어주는 함수이다. 그저 한 Neuron의 Output이 다른 Neuron의 Input이 되기만 한다면 이 겨결과는 그저 단일 계층의 Neural Network를 구성한 것에 지나지 않는다고 한다.
이 Activation Function을 거쳐야 비로소 패턴을 찾을 수 있게 된다고 한다. 다시 본론으로 돌아가서 앞의 두가지 Sigmoid와 TanH(하이퍼볼릭 탄젠트)함수가 Activation Function으로 주로 쓰이고 있었다고 한다. 그런데 제일 마지막의 ReLU를 사용해 보니까 비약적인 발전이 있어서 요즘에는 주로 ReLU나 이와 유사한 형태의 Activation Function을 사용하고 있다고 한다.
여기까지, 수많은 뉴런들을 구축하고 이를 Activation Function으로 연결을 시켜주면 복잡한 이미지도 인식할 수 있는 Neural Network가 완성되는 것이다~!!
Copyright © 2018. Alina Inc. All Rights Reserved.
위 그림과 같이 말이다. 그런데 이렇게 점차 Neuron들을 깊게 깊게 쌓아나가다 보면 각 계층을 지날수록 막연한 data를 학습하는 것이 아니라, data가 가지는 특정한 Pattern을 학습하는 경향이 있다는 사실을 발견했다. 그래서 중간에 있는 Neuron들은 Pattern Detector라고 불리기도 한다.
▶▶그럼 실습으로 들어간다.▶▶
Copyright © 2018. Alina Inc. All Rights Reserved.
필기체 숫자를 인식하는 것이 오늘의 목표이다. 엑셀 파일 정도만을 가지고 학습했던 이전에서 갑자기 이미지로 바뀌어서 혼동이 올 수도 있지만, 이미지 역시 숫자가 빼곡한 데이터일 뿐이라는 것을 잊지 말자.
Copyright © 2018. Alina Inc. All Rights Reserved.
이렇게 말이다. MNIST Dataset을 사용할 것이라고 한다. 이는 위에서 본 바와 같이 흑백 이미지인데 살펴보자면 대부분의 데이터는 0의 값(검은색)을 가지고 있고, 밝은 곳일수록 높은 숫자를 가지지는 것을 알 수 있다. 더불어 이 모양을 보면 이 데이터는 9를 나타내고 있었음을 알 수가 있다.
Single Layer Neural Network
Copyright © 2018. Alina Inc. All Rights Reserved.
Neuron이 단일 계층으로만 이루어진 가장 간단한 경우를 Single Layer Neural Network라고 한다.
우리가 해주어야 할 것들은, Input으로 우리가 학습시킬 MNIST Data 이미지(28 * 28 픽셀 전부)를 넣어준 다음, 이것이 어떤 숫자인지 알려주는 것이다. 각각의 픽셀 값들마다 지니는 weight들은 인공지능이 알아서 찾아 준다. 그리고 상당히 정확하다.
Copyright © 2018. Alina Inc. All Rights Reserved.
그리고, 특정 Layer를 지나면서 발견한 Pattern을 눈에 보이게 나타낼 수도 있는데, 이렇게 그림으로 나타낼 수도 있다. 위 그림이 무슨 의미이냐면, 파란색 부분에 높은 Gray Scale값을 가질수록 해당하는 숫자일 확률이 높다는 의미이다. 0이나 1같은 경우는 보면서 우리도 고개를 끄덕일 수 있지만, 2나 5같은 경우는 사실 인간이 보아서는 잘 모를 수도 있다. 어쨌든, 인공지능은 이렇게 생각한단다.
Copyright © 2018. Alina Inc. All Rights Reserved.
그럼 실질적으로 찾아주어야 하는 값들에 대해서 알아보자 784픽셀 각각에 대해서 output이 10개 이므로 weight 7,840개, 기본적으로 넣어주어야 하는 Bias 10개(output이 10개니까). 그래서 총 7850개의 weight들을 찾아주어야 한다. Single Layer임에도 상당히 많다... 그런데 우리는 걱정이 없다. 왜냐? 컴퓨터가 알아서 다 찾아줄 테니까......
그래서 사실, 이전에 비해서 다소 쉬워진 부분이 있다는 의견이 있다. 그저 Data들을 때려(?)넣고 적당한 Activation Function을 찾아주고 하는 정도의 작업만 거치면 적어도 90% 이상의 정확도를 가지는 인공지능을 뚝딱 만들 수 있다는 것이다. 다만, 연산해야 하는 양이 많아져서 프로세싱 파워가 더 필요해졌고, 그래서 GPU를 이용한 연산을 가능하게 하는 방법이 떠오르고, 그래서 반도체 시장이 살아나고~~ 하여튼, 실습을 해보자 .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | import math import numpy as np import matplotlib.pyplot as plt import tensorflow as tf # MNIST 필기체 숫자 dataset 읽어오기 위해 keras를 import합니다. from tensorflow import keras tf.set_random_seed(173) np.random.seed(173) def get_data(): mnist = keras.datasets.mnist to_categorical = keras.utils.to_categorical (train_data, train_labels), (test_data, test_labels) = mnist.load_data() # uint8 data type을 float32 data type으로 변환해서 float_train_data에 저장합니다. float_train_data = train_data.astype(np.float32) # 0.0~255.0범위의 pixel값을 0.0~1.0으로 변경합니다. float_train_data /= 255.0 # 3차원 array을 2차원 array로 변경합니다. float_train_data = np.reshape(float_train_data, [-1, 28 * 28]) # label을 one hot encoding을 하여 onehot_train_labels에 저장합니다. onehot_train_labels = to_categorical(train_labels, num_classes=10) # uint8 data type을 float32 data type으로 변환해서 float_test_data에 저장합니다. float_test_data = test_data.astype(np.float32) # 0.0~255.0범위의 pixel값을 0.0~1.0으로 변경합니다. float_test_data /= 255.0 # 3차원 array을 2차원 array로 변경합니다. float_test_data = np.reshape(float_test_data, [-1, 28 * 28]) # label을 one hot encoding을 하여 onehot_test_labels에 저장합니다. onehot_test_labels = to_categorical(test_labels, num_classes=10) return float_train_data, onehot_train_labels, float_test_data, onehot_test_labels def draw_mnist_image(image, title=''): # 그림에 title을 설정합니다. plt.title(title) # image가 28 * 28이라고 가정하고 그림을 그립니다. plt.imshow(np.reshape(image, [28, 28]), cmap='gray') # 그림을 화면에 보여줍니다. plt.show() # x_data에 필기체 숫자 image를 저장합니다. # y_data에 필기체 숫자 종류를 저장합니다. # x_test_data에 필기체 숫자 image의 test set을 저장합니다. # y_test_data에 필기체 숫자 종류의 test set을 저장합니다. x_data, y_data, x_test_data, y_test_data = get_data() x_input = tf.placeholder(tf.float32, [None, 28 * 28]) y_input = tf.placeholder(tf.float32, [None, 10]) weight_var = tf.Variable(tf.zeros([28 * 28, 10])) bias_var = tf.Variable(tf.zeros([10])) logit = bias_var + tf.matmul(x_input, weight_var) y_output = tf.nn.softmax(logit) cross_entropy = tf.nn.softmax_cross_entropy_with_logits_v2(labels=y_input, logits=logit) cost_output = tf.reduce_mean(cross_entropy) learning_rate = 0.01 train_step = tf.train.AdamOptimizer(learning_rate).minimize(cost_output) sess = tf.Session() step = 0 cost = 0 mini_batch = 1024 max_epoch = 7 # variable(weight, bias)들을 초기화합니다. sess.run(tf.global_variables_initializer()) # max_epoch만큼 반복하며 cost가 작아지는 weight, bias들을 찾습니다. for epoch in range(max_epoch): # mini_batch단위만큼 잘라서 반복합니다. for i in range(int(math.ceil(len(x_data) / mini_batch))): # Gradient Descent를 사용하여 cost가 약간 작아지도록 weight, bias들을 변경합니다. _, cost = sess.run( [train_step, cost_output], feed_dict={ x_input: x_data[i * mini_batch:(i + 1) * mini_batch], y_input: y_data[i * mini_batch:(i + 1) * mini_batch]}) step += 1 print('epoch: {}, train_step: {}, cost: {}'.format(epoch, step, cost)) y_pred = sess.run(y_output, feed_dict={x_input: x_test_data}) y_data_class = np.argmax(y_test_data, axis=1) y_pred_class = np.argmax(y_pred, axis=1) y_right_class = y_data_class == y_pred_class accuracy = np.mean(y_right_class) print('accuracy', accuracy) y_wrong_class = y_data_class != y_pred_class for i in range(10): title = 'ground truth: {}, prediction: {}'.format( y_data_class[y_wrong_class][i], y_pred_class[y_wrong_class][i]) draw_mnist_image(x_test_data[y_wrong_class][i], title) for i in range(3): print('y_data_class', y_data_class[y_wrong_class][i]) print('y_test_data', y_test_data[y_wrong_class][i]) print('y_pred_class', y_pred_class[y_wrong_class][i]) print('y_pred', y_pred[y_wrong_class][i]) sess.close() | cs |
실행을 시켜 보면 알 수 있지만 이상한 경우가 있다.
음, 원래는 5인 데이터인데 6이라고 잘못 판단한 경우이다. 인간이 보아도 이건 6같으므로 원래 의도는 5였을지 몰라도 인공지능이 잘 잡아낸 것 같다.
응?? 누가 봐도 3이다. 그런데 인공지능은 2라고 했다... 이렇게 인간이 생각하면 터무니없는 실수인 경우가 더럿 있다. 상기하자면 이는 Single Layer Neural Network이다. 상당히 기초적인 방법이었던 것이다. 오히려 그럼에도 93%정도의 정확도를 가진다고 하는 사실에 놀라야 하는것이 아닌가...라고 생각한다. (test_set에 대해서) 우리가 해준 일은, Data set을 넣어주고 짧은 코드를 적은 뒤, 기다린 것 뿐이다. 그런데 알아서 이렇게 잘 학습하였다!!
그래도, 아쉬운 것을 보충하기 위해서 생각해보자, 어떻게 하면 위와 같은 실수들을 줄일 수 있을까? 단일 계층이 아닌 여러 층을 쌓아서 Network를 더 복잡하게 구성하면 되지 않을까? 그래서 다음에는 Multi Layer Neural Network에 대해서 배워본다.